IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

 C++ Discussion :

précision de std::minus<T>() laisse à désirer


Sujet :

C++

  1. #1
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut 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.09999L'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
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    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 actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    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


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    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
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    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 actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    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 ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. 3 précisions sur l'utilisation des "std::vector"
    Par Invité dans le forum SL & STL
    Réponses: 9
    Dernier message: 10/01/2006, 00h42
  2. [EJB]Précision de la datasource (Mysql)
    Par cameleon2002 dans le forum JBuilder
    Réponses: 2
    Dernier message: 11/09/2003, 17h55
  3. Réponses: 8
    Dernier message: 13/01/2003, 17h45
  4. Timer de précision
    Par guigui dans le forum MFC
    Réponses: 1
    Dernier message: 04/12/2002, 15h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo