1. #1
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut Différents résultats pour le même calcul sur CPU et GPU.

    Bonjour, je travaille sur ma propre librarie de réseaux de neurones et en ce moment j'essaye de copier mon code CPU sur GPU (l'utilisateur aurait de choix d'utiliser le GPU ou non).

    J'ai réussi à faire fonctionner mon code sur GPU.

    Sur des petits réseaux (avec peu de calcul), ça fonctionne bien mais sur beaucoup de calculs, environ 1 fois sur 2 le résultat n'est pas exact (je tire des valeurs initiales random au début).

    par exemples :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    0.3387047350406646728515625 != 0.33870494365692138671875
    
    0.14186990261077880859375!= 0.141869843006134033203125
    Dans cette exemple j'effectue 775 mutiplications et 56 additions sur des float et le résultat GPU et CPU est légèrement différent.

    Auriez-vous une idée d'où peut venir cette erreur de calcul ? Es-ce normal ou es-ce de ma faute ?

    Je ne pense pas que ça vienne de mon algo sinon les résultats serait significativement différent.
    Es-ce que ça pourrait venir d'un truc du genre 0.5f au lieu de 0.5 et du coup il y a certain calcul qui serait fait en double sur l'un et en float sur l'autre ?

    Es-ce que x1 et x2 fournissent toujour le même résultat ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    float x1 = 0.125 * 0.587;
    float x2 = 0.125f * 0.587f;

    PS : Mon code est beaucoup trop gros pour vous le montrer ici.

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    4 760
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : juin 2007
    Messages : 4 760
    Points : 15 449
    Points
    15 449

    Par défaut

    réponse simple: non en général.

    En fait, 0.125f est un float, tandis que 0.125 est un double

    Ces deux types sont des représentations de nombres à virgule flottante.
    Si on s'épargne quelques détails techniques, la représentation est à peu près "m * 2^e" avec m et e deux entiers.
    Ainsi, 0,125 c'est à dire 1/8 se représente avec m = 1 et e = -3.

    Il y a plein de nombres qui n'ont pas de représentation exacte, car leur écriture en base 2 n'est pas limité à un certain nombre de chiffres (voire, n'est pas finie, comme 0.1)
    a priori, c'est le cas de 0.857.

    La différence entre les deux types, ce sont les tailles disponibles pour ces deux entiers.
    Ainsi, les erreurs de précisions ne sont pas les mêmes en float et en double.

    Le double étant plus précis, on recommande en général de ne faire les calculs qu'en double, et de n'utiliser les float que pour du stockage.

    Note que le problème s'empire avec les calculs, car certaines opérations ne sont pas exactes.
    Ainsi, 0.1+0.9 peut ne pas valoir 1.0.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut

    Oui, ça je savais mais ce que je voulais savoir c'est si quand je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    float x = 0.125;
    float y = 0.2569 * x;
    Le compilateur fais le calcul de y en double puis convertie le résultat en float ou il effectue direcment le calcul en float ?

  4. #4
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut

    Je précise que ne souhaite pas faire mes calculs en double car cela doublerais mon temps de calculs. Je réfléchie même à effectuer mes calculs sur des floatant de 16 bits ce que doublerais quasiment mon temps de calcul sur GPU avec la nouvelle fonctionnalité de CUDA.

  5. #5
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    8 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : janvier 2007
    Messages : 8 954
    Points : 23 774
    Points
    23 774

    Par défaut

    Citation Envoyé par Matthieu76 Voir le message
    Le compilateur fais le calcul de y en double puis convertie le résultat en float ou il effectue direcment le calcul en float ?
    Cela peut dépendre des compilateurs, mais bien souvent le calcul est fait dans le format du premier opérande de l'opération. Il y a préalablement une tentative de conversion implicite des opérandes suivant dans le format du premier opérande.
    Ensuite seulement, il y a tentative de conversion du résultat final vers le format de retour.

    Certains compilateurs vont, au contraire, tenter préalablement de tout convertir dans le format de retour avant d'effectuer les opérations.

    Je ne sais pas ce qui en est pour ton compilateur exactement.

    Citation Envoyé par Matthieu76 Voir le message
    Je précise que ne souhaite pas faire mes calculs en double car cela doublerais mon temps de calculs. Je réfléchie même à effectuer mes calculs sur des floatant de 16 bits ce que doublerais quasiment mon temps de calcul sur GPU avec la nouvelle fonctionnalité de CUDA.
    Si tu arrive à trouver ce format.

    Il n'existe que 2 formats officiels de nombre à virgule flottante, le format Simple Précision (32 bits) dénommé Single, ou Float selon les langages, et le format Double précision (64 bits) dénommé Double dans la plupart des langages.
    Il n'existe pas de format en dessous de 32 bits. Il existait autrefois des formats intermédiaires entre 32 et 64 bits, mais ils ont été rendu obsolète par le format Double précision et ne sont plus utilisé depuis longtemps.
    Il peut exister des formats plus précis que 64 bits, mais sont généralement propres à certains systèmes et ne sont pas reconnus par tous les langages.
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  6. #6
    Membre émérite
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 478
    Points : 2 263
    Points
    2 263

    Par défaut

    Bonjour,
    Lors d'un calcul entre un float et un double, le float est systématiquement converti en double, puis l'opération est effectuée. Si le résultat attendu est un float il y aura ensuite une autre conversion vers float.
    Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
    result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
    This pattern is called the usual arithmetic conversions, which are defined as follows:
    (11.1) — If either operand is of scoped enumeration type (7.2), no conversions are performed; if the other operand
    does not have the same type, the expression is ill-formed.
    (11.2) — If either operand is of type long double, the other shall be converted to long double.
    (11.3) — Otherwise, if either operand is double, the other shall be converted to double.
    (11.4) — Otherwise, if either operand is float, the other shall be converted to float.
    (11.5) — Otherwise,...
    Attention utiliser des float pour optimiser peut être un leurre, car
    * une conversion double vers float est nettement plus coûteuse qu'une multiplication
    * souvent les coprocesseurs peuvent être plus rapides sur des calculs double.
    * mais c'est l'inverse dans le cas de calculs parallèles (p.e. 4 ou 8 multiplications simultanées)
    * je n'y connais rien en GPU, mais il fait certainement du calcul parallèle et est certainement plus optimum sur un des 2 types.

    Ton exemple indique une différence sur la 7ème décimale, or c'est justement la limite de précision des float, il ne faut pas s'attendre à mieux. C'est tout à fait possible d'avoir un résultat différent même en utilisant un même processeur en jouant sur les options de compilation (calcul flottants: fast, strict ou precise).

  7. #7
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut Ouais ...

    Citation Envoyé par dalfab Voir le message
    Ton exemple indique une différence sur la 7ème décimale, or c'est justement la limite de précision des float, il ne faut pas s'attendre à mieux. C'est tout à fait possible d'avoir un résultat différent même en utilisant un même processeur en jouant sur les options de compilation (calcul flottants: fast, strict ou precise).
    Merci beaucoup de ta réponse.

    Dans mon code j'ai 2 compilateur, j'ai MVSC2015 pour mon code C++ et j'utilise le compilateur Nvidia pour mon code GPU.
    Tu penses que ça pourrais venir de la méthode de calcul du compilateur plutôt que d'un calcul par erreur effectué en double plutôt qu'en float ?

  8. #8
    Membre émérite
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 478
    Points : 2 263
    Points
    2 263

    Par défaut

    Une erreur sur le 7ème décimale peut être causée par les deux, et il est très probable que ce soit le cas. Cette décimale correspond au dernier bit de précision d'un float.
    Si je fais 2.3f * 2.4f * 2.5f * 2.6f rien ne me garantit que j'aurais le même résultat que 2.6f * 2.5f * 2.4f * 2.3f. A cause de l'erreur d'arrondi sur le dernier bit, la multiplication n'est plus commutative!

    Essaie de changer l'option "modèle de virgule flottante" sous MSVC, et je pense que les résultats vont changer.

  9. #9
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    8 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : janvier 2007
    Messages : 8 954
    Points : 23 774
    Points
    23 774

    Par défaut

    Par contre, 2.3f * 2.4f * 2.5f * 2.6f calculé sur le CPU ou sur le GPU devrait donner le même résultat.
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  10. #10
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut

    Citation Envoyé par sevyc64 Voir le message
    Par contre, 2.3f * 2.4f * 2.5f * 2.6f calculé sur le CPU ou sur le GPU devrait donner le même résultat.
    Même si j'ai 2 compilateurs différents ?

  11. #11
    Membre émérite
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 478
    Points : 2 263
    Points
    2 263

    Par défaut

    Citation Envoyé par Matthieu76 Voir le message
    Même si j'ai 2 compilateurs différents ?
    Cela dépend du mode flottant. On suppose ici que les 4 valeurs sont des variables. En mode strict, le calcul sera ((2.3f*2.4f)*2.5f)*2.6f; en mode fast, il va surement se ramener à 2 contraintes au lieu de 3 et effectuer (2.3f*2.4f)*(2.5f*2.6f).
    Sinon pour des multiplications, je pense que tous les copro arrondissent de la même façon, donc pour une même séquence on devrait avoir le même résultat.

  12. #12
    Membre habitué Avatar de Matthieu76
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2013
    Messages : 164
    Points : 143
    Points
    143

    Par défaut

    Ok, merci j'ai maintenant assez d'info pour résoudre mon problème.

    J'avais absolument pas vérifié si je fessais x*y*z ou z*y*x car pour moi ça donnais le même résultat.

  13. #13
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    4 760
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : juin 2007
    Messages : 4 760
    Points : 15 449
    Points
    15 449

    Par défaut

    L'arithmétique flottante n'est pas exacte (au sens mathématique).
    De ce fait, toutes les opérations sont sensibles à l'ordre d'exécution des opérateurs.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 26/03/2014, 17h18
  2. [XL-2003] Appel de 2 variables sur 2 itérations pour un même calcul
    Par ludivine gerber dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 08/03/2012, 12h01
  3. [XL-2003] Mystère de précision de résultat pour la même macro sur deux ordis (xls2003)
    Par agilles dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 16/12/2011, 16h07
  4. Réponses: 17
    Dernier message: 30/05/2011, 10h14

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