2010-10-24 4 views
0

(bind imbriquée) Je le code suivant (je suis désolé pour la longueur):<functional> problèmes avec MSVC 2010

double primeValue(const func1D &func, 
        const double lowerBound, const double upperBound, 
        const double pole) 
{ 
    // check bounds 
    if(lowerBound >= upperBound) 
     throw runtime_error("lowerBound must be smaller than upperBound!"); 

    // C++0x way of writing: fullFunc(x) = func(x)/(x-a) 
    func1D fullFunc = 
      bind(divides<double>(),    // division of 
        bind(func, _1),     // f(x), with _1 = x 
        bind(minus<double>(), _1, pole)); // by x-a, with _1 = x 

    // pole not in domain 
    if(pole<lowerBound || pole>upperBound) 
    { 
     cout << "Case 1" << endl; 
     return integrateSimpson(fullFunc, 1000, lowerBound, upperBound); 
    } 
    // pole closer to upper bound 
    else if(upperBound-pole < pole-lowerBound ) 
    { 
     cout << "Case 2" << endl; 
     // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a) 
     func1D specialFirstFunc = 
       bind(std::divides<double>(),        // division of 
         bind(minus<double>(),         // numerator: 
          bind(func, _1),         // f(x) minus 
          bind(func, bind(minus<double>(), 2.*pole, _1))), //f(2a-x) 
         bind(minus<double>(), _1, pole));     // denominator: x-a 
     const double trickyPart = integrateSimpson(specialFirstFunc, 1000, pole+.000001, upperBound); 

     const double normalPart = integrateSimpson(fullFunc, 1000, lowerBound, 2.*pole-upperBound); 
     cout << "Tricky part: " << trickyPart << endl; 
     cout << "Normal part: " << normalPart << endl; 
     return trickyPart + normalPart; 
    } 
    else // pole closer to lower bound 
    { 
     cout << "Case 3" << endl; 
     // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a) 
     func1D specialFirstFunc = 
       bind(std::divides<double>(),        // division of 
         bind(minus<double>(),         // numerator: 
          bind(func, _1),         // f(x) minus 
          bind(func, bind(minus<double>(), 2.*pole, _1))), //f(2a-x) 
         bind(minus<double>(), _1, pole));     // denominator: x-a 
     const double trickyPart = integrateSimpson(specialFirstFunc, 1000, lowerBound, pole-.00001); 

     const double normalPart = integrateSimpson(fullFunc, 1000, 2.*pole-lowerBound, upperBound); 
     cout << "Tricky part: " << trickyPart << endl; 
     cout << "Normal part: " << normalPart << endl; 
     return trickyPart + normalPart; 
    } 
} 

Il intègre des fonctions sur l'axe réel qui contient une singularité (pôle) en utilisant la concept de valeurs principales du domaine mathématique de l'analyse complexe. Les bind et function parties modifient la fonction originale f (x) à

(f (x) -f (2 * pôle-x))/(xa)

Il donne même il corriger résultat pour ma fonction de test simple. Détails supplémentaires que je peux fournir si nécessaire:

typedef std::function<double (double)> func1D; 
double integrateSimpson(func1D, const size_t nSteps, const double lowerBound, const double upperBound); 

Ce dernier s'intègre en utilisant la simple règle d'intégration de Simpson. Le code peut être fourni, mais n'est pas très pertinent pour le problème en question. Ceci compile avec GCC 4.4+ (testé avec les versions préliminaires 4.4.5 et 4.5.2, CFLAGS = "- O2 -std = C++ 0x -pedantic -Wall -Wextra"), mais produit des erreurs d'en-tête internes (C2664) sur MSVC 2010. (Je peux fournir une sortie d'erreur si nécessaire, il n'y a aucune référence à mon code (!)).

Ai-je trouvé un bogue dans MSVC?

Merci!

+4

"Ai-je trouvé un bogue dans MSVC?" - Je ne serais pas surpris si tu le faisais. :) – casablanca

+0

Cela peut être lié: http://stackoverflow.com/questions/2425277/visual-studio-2010-and-stdfunction Mais je ne comprends pas ce que la réponse acceptée suggère de faire ... – rubenvb

Répondre

0

Pourquoi ne pas simplement utiliser un lambda? Tout le matériel de liaison a été déprécié pour ce genre de but.

double primeValue(const func1D &func, 
        const double lowerBound, const double upperBound, 
        const double pole) 
{ 
    // check bounds 
    if(lowerBound >= upperBound) 
     throw runtime_error("lowerBound must be smaller than upperBound!"); 

    // C++0x way of writing: fullFunc(x) = func(x)/(x-a) 
    auto fullFunc = [=](double d) { 
     return func(d)/(d - pole); 
    }; 

    // pole not in domain 
    if(pole<lowerBound || pole>upperBound) 
    { 
     cout << "Case 1" << endl; 
     return integrateSimpson(fullFunc, 1000, lowerBound, upperBound); 
    } 
    // pole closer to upper bound 
    else if(upperBound-pole < pole-lowerBound ) 
    { 
     cout << "Case 2" << endl; 
     // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a) 
     auto specialFirstFunc = [=](double x) -> double { 
      double numerator = func(x) - func(2*pole - x); 
      return numerator/(x - pole); 
     }; 
     const double trickyPart = integrateSimpson(specialFirstFunc, 1000, pole+.000001, upperBound); 

     const double normalPart = integrateSimpson(fullFunc, 1000, lowerBound, 2.*pole-upperBound); 
     cout << "Tricky part: " << trickyPart << endl; 
     cout << "Normal part: " << normalPart << endl; 
     return trickyPart + normalPart; 
    } 
    else // pole closer to lower bound 
    { 
     cout << "Case 3" << endl; 
     // C++0x way of writing g(x) := [f(x)-f(2a-x)]/(x-a) 
     auto specialFirstFunc = [=](double x) -> double { 
      double numerator = func(x) - func(2*pole - x); 
      return numerator/(x - pole); 
     }; 
     const double trickyPart = integrateSimpson(specialFirstFunc, 1000, lowerBound, pole-.00001); 

     const double normalPart = integrateSimpson(fullFunc, 1000, 2.*pole-lowerBound, upperBound); 
     cout << "Tricky part: " << trickyPart << endl; 
     cout << "Normal part: " << normalPart << endl; 
     return trickyPart + normalPart; 
    } 
} 

Pour ce que vous avez réellement trouvé si oui ou non un bogue dans MSVC, je ne sais pas, mais votre solution est certainement moyen inutile - ce code est beaucoup plus propre et plus facile à entretenir.

+1

Eh bien, comme la plupart Linux distro et moi-même utilisons toujours GCC 4.4, lambda ne sont pas une option. Je ne pense pas que 'std :: bind' ait déjà été déprécié ... Mais les lambda sont beaucoup plus courts que ceux qui m'ont été démontrés: http://stackoverflow.com/questions/4008369/combining-stdfunction-objects – rubenvb

+0

@rubenvb : Lambdas ont été spécifiquement introduites dans le langage parce que bind lier, entre autres raisons. Frappez simplement un #ifdef dessus. Très probablement, les bibliothèques MSVC sont quelque peu obsolètes avec ce que C++ 0x a maintenant comme standard - par exemple, _1 est défini comme std :: placeholders :: _ 1 au lieu de simplement std :: _ 1. J'ai vérifié ce lien - il a explicitement défini la référence ou la valeur pour chaque variable qu'il a capturé, alors que j'ai mis le mien pour capturer tout en valeur. – Puppy

+0

@DeadMG: Eh bien, la solution de contournement lambda sonnait bien, mais je pense que l'implémentation interne utilise de toute façon 'std :: bind' (elle donne la même erreur: s). J'ai vérifié les branches '# ifdef' utilisées, et il compile les lambda en utilisant' std :: bind' en interne ... – rubenvb

Questions connexes