Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Membre habitué
    précision de std::minus<T>() laisse à désirer
    Bonjour à tous,

    Je viens de me rendre compte d'un léger écart de valeurs lorsque j'utilise std::transform() conjointement avec std::minus<float>().
    Pour la faire courte, voici le code :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <iostream>
    #include <algorithm>
     
    int main() {
     
     
    	std::vector<float> va(4, 3.1f);
    	std::vector<float> vb(4, 3.0f);
     
    	std::transform(va.cbegin(), va.cend(), vb.begin(), va.begin(), std::minus<float>());
     
    	for(auto & v:va) {
    		std::cout << v << ' ';
    	}
    	std::cout << '\n';
     
     
    	return 0;
    }


    rien de bien méchant ; globalement on demande de faire va -= vb.
    Cependant, là où je m'attends à avoir le résultat 0.1 0.1 0.1 0.1, j'obtiens les valeurs suivantes : 0.09999... 0.09999... 0.09999... 0.09999
    L'erreur est probablement minime, néanmoins, si je fais une bête boucle, j'ai un résultat juste au moins.

    Vous savez comment régler ce problème ?

    Le code est compilé sous Linux avec G++ via geany avec les options suivantes :
    g++ -Wall --std=c++1z
    Merci d'avance.

  2. #2
    Membre expert
    Ce n'est std::minus le problème, mais la précision liée au flottant.

    PS: std::minus<float>() ->std::minus<>() ou mieux, std::minus().

  3. #3
    Membre habitué
    Hmmm... Réponse énigmatique, mais je vais mieux me renseigner sur les std::minus().

    Par contre, je ne vois pas en quoi la problématique viendrait des floats ; quand je fais :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    float a{3.1f};
    float b{3.0f};
    float c{a-b};

    j'ai bien 0.1 et pas 0.09999 ; pourquoi pas avec std::minus ?

    Edit : rectification ! Effectivement, le calcul ci-dessus me donne bien 0.09999 ! Très surprenant et je ne m'attendais pas à ça. En fin de compte, tout est normal.... Néanmoins, cela me surprends tout de même ; comment fait-on si on cherche à avoir une vraie précision ? Je peux dire, certes, je n'ai pas besoin d'aller à du 10E-12 mais que 3.1 - 3 fasse bien .1 et pas .09. C'est pas très pro à l'affichage quand même...

  4. #4
    Rédacteur/Modérateur

    Parce qu'un float n'est presque jamais une valeur parfaite mais une approximation.
    C'est un fait bien documenté et très logique dû au format binaire.
    Et ton simple test ne prouve rien d'autre que le compilateur s'en sort possiblement un peu mieux en ayant les valeurs directement et pouvant éliminer quelques étapes et approximations et erreurs.

    Si tu veux faire des calculs exacts, il faut utiliser un type à virgule fixe.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Membre expert
    Citation Envoyé par BioKore Voir le message
    je vais mieux me renseigner sur les std::minus().
    C'est la combinaison des guides de déduction (c++17) et du paramètre par défaut à void (c++14) pour déduire le type des paramètres et du résultat au moment de l'appel de operator() (voir cppreference.com).

  6. #6
    Membre habitué
    Citation Envoyé par Bousk Voir le message
    Parce qu'un float n'est presque jamais une valeur parfaite mais une approximation.
    C'est un fait bien documenté et très logique dû au format binaire.
    Et ton simple test ne prouve rien d'autre que le compilateur s'en sort possiblement un peu mieux en ayant les valeurs directement et pouvant éliminer quelques étapes et approximations et erreurs.

    Si tu veux faire des calculs exacts, il faut utiliser un type à virgule fixe.
    Merci pour l'explication ; mais c'est juste la première fois que je me retrouve face à ce cas... Le résultat est le même, bien entendu, qu'il s'agisse d'un type float ou double (virgule flottante dans les deux cas).
    Par contre, première foi que j'entends parler du type à virgule fixe... Ca fait parti des standards ou il faut construire le type nous-même ?

###raw>template_hook.ano_emploi###