1

1666.42859f * 1.4f
2333.0
(int)(1666.42859f * 1.4f)
2332



(decimal)(1666.42859f * 1.4f)
2333
(int)(decimal)(1666.42859f * 1.4f)
2333



(int)(double)((double)1666.42859f * (double)1.4f)
2332
(int)(float)((double)1666.42859f * (double)1.4f)
2333
(int)(float)(double)(1666.42859f * 1.4f)
2333

vtff vtff vtff vtff vtff vtff

Maintenant je cherche une solution élégante pour résoudre ce problème -_-


(Oui, je n'étais encore jamais tombé dans un cas concret où le fonctionnement des float sur x86 me les briserait autant… Il faut une première à tout.)




EDIT:

Premier truc crado qui me vient à l'esprit…private static unsafe int SafeTruncateSingle(float f) { var a = stackalloc float[1]; a[0] = f; return (int)a[0]; }triso
(Ça a l'air de fonctionner, mais en théorie un compilateur pas complètement con devrait savoir optimiser cette méthode… :/)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

2

Je ne comprends pas pourquoi tu dois faire un stackalloc et tout, tu n'avais pas dit que simplement :
private static int SafeTruncateSingle(float value) {
    return (int)(float)(double) value;
}

devrait marcher ?

Ca me rappele d'ailleurs un truc que j'avais du taper en java :
topics/61689-jeu-videz-votre-presse-papier/846
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

3

Call : PpHd appelé(e) sur ce topic...

Je crois qu'il masterise côté flottants.

4

c'est quoi ton compilateur, ton langage, et ton mode d'arrondi dans les calculs ?

Si on a:
x = 1666.42859;
y = 1.4;
z = x *y

en précision flottante (p=24 bits) si la multiplication se fait avec arrondi au plus proche :
x=0.1101000001001101101101110E11 (convertion base 10 vers base 2 inexacte)
y=0.1011001100110011001100110E1 (convertion base 10 vers base 2 inexacte)
z=0.1001000111010000000000000E12 (avec arrondi à la valeur au dessus, tombant sur un entier)
soit
x=1.66642859e+03 y=1.39999998e+00 z=2.333e+03
soit (int)z = 2333

en précision flottante (p=24 bits) si la multiplication se fait avec arrondi vers zéro :
x=0.110100000100110110110111E11
y=0.101100110011001100110011E1
z=0.100100011100111111111111E12
soit
x=1.66642859e+03 y=1.39999998e+00 z=2.33299976e+03
soit (int)z = 2332

tu peux arrondir au lieu de tronquer sinon. M'enfin tout dépend de ton besoin à la base. Quel est-il ?

5

Ça ressemble à du requin des mers.

6

grin
(Et oui c'est bien du Sea Shark)
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

7

./4 > C'est du C# avec, il me semble, le compilateur JIT x86 (.NET 4.5). (Le souci c'est que le compilateur JIT sera différent selon la machine utilisée, voir même la version (future) de .NET, donc ce n'est pas un truc sur lequel je peux me reposer -_-)
À priori, le mode d'arrondi est "au plus proche", et le FPU est réglé sur la précision double (et non la précision étendue, même si autorisé par les specs).
Les spec C#/CLI autorisent gracieusement les opérations à être effectuées à une précision supérieure (ça alors !) donc, à priori, ce qui se produit pour "(int)(1666.42859f * 1.4f)" correspond à ça :
(int)(double)((double)1666.42859f * (double)1.4f)
2332

À priori, le résultat intermédiaire devrait donc être celui-ci : 1666.4285888671875 * 1.3999999761581421 = 2332.9999846833089d

Cela s'arrondit à un float qui vaut 2333.0f (le .0 affiché m'indique qu'il y a un petit truc en plus, mais flemme de regarder ce que c'est), et qui se convertit bien en entier 2333. Le souci c'est que le compilateur et/ou le runtime ne se sent pas obligé de convertir le résultat intermédiaire (même en insérant un cast explicite vers float), donc je retombe sur 2332…

Mon code original utilisait Math.Ceiling (prend un double, retourne un double), donc je tombais bon là dessus mais je me foirais dans d'autres cas, ce qui m'a amené à faire autrement… :/


Au final, j'ai fini par arrondir comme tu le suggères. Je sais de toutes façons que je dois forcément retomber sur un entier à la fin du calcul, là au moins ça élimine les ambiguïtés, et ça devrait fonctionner de manière similaire quel que soit le couple JIT/CPU…

En tout cas, merci.


(PS : c'est du code qui travaille avec une API basé sur des double et une autre basée sur des float (ben voyons…), et qui travaillent toutes deux avec des pixels réels (int) et des pixels logiques ("DIP", soit avec des float, soit avec des double), donc il y a forcément des conversions à faire de l'une à l'autre. Les erreurs de précision ne me dérangent pas le moins du monde (pour l'instant) tant que l'on reste dans le domaine de la virgule flottante, mais par contre, lorsque je convertis en entier, il faut que le résultat soit bon au pixel près, sinon aucun intérêt. grin)

./5 & ./6 > grin
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

8

GoldenCrystal (./7) :
Les spec C#/CLI autorisent gracieusement les opérations à être effectuées à une précision supérieure (ça alors !) d

C'est gênant, vu que ça peut introduire des erreurs de calcul, si je me souviens bien. Si je n'ai pas oublié mes cours d'arithmétique en virgule flottante, il y a un souci avec les Intel x86 qui travaillent en interne sur 80 bits et qui tronquent le résultat à 53 bits (mais bon, soyons honnête, ça faussait le dernier dans un cas un peu tordu)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

9

flanker (./8) :
GoldenCrystal (./7) :
Les spec C#/CLI autorisent gracieusement les opérations à être effectuées à une précision supérieure (ça alors !) d

C'est gênant, vu que ça peut introduire des erreurs de calcul, si je me souviens bien. Si je n'ai pas oublié mes cours d'arithmétique en virgule flottante, il y a un souci avec les Intel x86 qui travaillent en interne sur 80 bits et qui tronquent le résultat à 53 bits (mais bon, soyons honnête, ça faussait le dernier dans un cas un peu tordu)

Surtout ca invalide toutes les preuves pour prouver que ton algorithme produite le bon résultat...

10

Y a pas une histoire comme quoi si tu enchaînes les calculs, l'arrondi à 64 bits ne se fait pas forcément et les calculs se font uniquement en 80 bits ?
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

11

Ben c'est ce qui se passe avec les float justement, sauf que la précision du FPU x86 est réglée sur 64 bits par le CLR au lieu de 80 ^^ (Mais c'est pas documenté explicitement, en théorie ça pourrait être 80 puisque les specs l'autorisent…)
En toute logique tu n'auras donc pas ce problème avec des double en .NET… Pour l'instant.
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

12

GoldenCrystal (./11) :
Ben c'est ce qui se passe avec les float justement, sauf que la précision du FPU x86 est réglée sur 64 bits par le CLR au lieu de 80 ^^ (Mais c'est pas documenté explicitement, en théorie ça pourrait être 80 puisque les specs l'autorisent…)
En toute logique tu n'auras donc pas ce problème avec des double en .NET… Pour l'instant.

Pour complément:
- En 64 bits, tu utilises les instructions sse2, pas la fpu, donc des ieee-64 bits tout le temps.
- Et la fpu des 386 est réglé en 80 bits sous linux par défault (donc c'est juste lorsque tu stockes le résultat dans un double qu'un conversion en 64 bits survient).

13

(Concernant .NET, de ce que j'avais lu, le JIT x64 n'utilise(ait?) pas de SSE2 en dehors des opérations de copie mémoire et des conversions en entier.)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

14

C'est con, car le fpu est plus lent que le sse2 sur les nouveaux procs...
Mais peut être qu'ils voulait dire pas de sse2 explicite dans le code ?

15

Je crois que c'est à ce post que je pensais, mais en fait ça ne mentionne pas le JIT x64, juste le JIT x86 sur un processeur x64. Ma mémoire me joue des tours…
Dans la pratique, je viens de regarder le code assemleur généré pour un build x64 et je vois bien plein d'instructions sse(2). top
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

16

Y'a un truc que je ne pige pas. Que tes calculs se fassent en float ou en double, l'erreur n'est pas assez grande pour que ça soit arrondi à 2332 au lieu de 2333 si tu es en mode "arrondi au plus proche". Or c'est ce que tu obtiens. Comment ça se fait ?
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

17

Y a un des arrondis qui se fait vers 0, non ?
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

18

Justement, GC a dit que le mode d'arrondi était configuré en "entier le plus proche", donc je ne vois pas pourquoi il y a des arrondis vers zéro qui viennent s'intercaler.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

19

Je n'ai pas trouvé comment visualiser la valeur du registre de contrôle FPU dans VS2012… -_-
Mais après quelques recherches Google, il semble que la valeur qui devrait se trouver dans le registre de contrôle pour une appli .NET devrait être 0x027F. (Y'a pas de raison qu'elle soit différente dans mon cas, sinon il y a un gros souci chez MS tongue)

Ça s'interprète donc visiblement comme :
0x0200 53-bit precision
0x0040 Interrupts disabled
0x0020 Allow inexact precision
0x0010 Allow underflow
0x0008 Allow overflow
0x0004 Allow divide by zero
0x0002 Allow denormals
0x0001 Allow invalid numbers
0x0000 Round to nearest

./18 > Je tire ça de là :
The rounding mode defined in IEC 60559:1989 shall be set by the CLI to “round to the nearest
number,” and neither the CIL nor the class library provide a mechanism for modifying this
setting. Conforming implementations of the CLI need not be resilient to external interference
with this setting. That is, they need not restore the mode prior to performing floating-point
operations, but rather, can rely on it having been set as part of their initialization.
For conversion to integers, the default operation supplied by the CIL is “truncate towards zero”.
Class libraries are supplied to allow floating-point numbers to be converted to integers using any
of the other three traditional operations (round to nearest integer, floor (truncate towards –infinity), ceiling (truncate towards +infinity)).
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

20

OK, donc le mode d'arrondi n'est pas le même pour la conversion en entiers que pour les calculs sur les flottants/doubles... C'est bizarre ça, quelqu'un sait pourquoi ?
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

21

Je ne sais pas, pour moi ça a toujours été naturel que les float/double soient tronqués vers zéro grin
(C'est pas également le comportement par défaut en C/C++ ?)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

22

Si, effectivement (j'ai vérifié entre temps - j'avais un doute, ça fait un moment que j'ai plus eu besoin d'y toucher).

Mais ça n'explique pas pourquoi le C a choisi ce comportement, arrondir au plus proche minimise l'erreur et ça me semble beaucoup plus logique... Et sur x86 en tout cas, avoir un mode d'arrondi différent dans ce cas tue les perfs : http://www.mega-nerd.com/FPcast/
(l'article est vieux, donc il y a pu avoir des changements depuis, mais en tout cas c'était vrai à l'époque)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

23

Zerosquare (./16) :
Y'a un truc que je ne pige pas. Que tes calculs se fassent en float ou en double, l'erreur n'est pas assez grande pour que ça soit arrondi à 2332 au lieu de 2333 si tu es en mode "arrondi au plus proche". Or c'est ce que tu obtiens. Comment ça se fait ?

Si je crois bien que si dans certains cas bien tordu, oui (cf. http://www.exploringbinary.com/double-rounding-errors-in-floating-point-conversions/ ). Mais je ne suis pas sûr que ca soit ce cas qui nous intéresse.

24

Zerosquare (./22) :
Si, effectivement (j'ai vérifié entre temps - j'avais un doute, ça fait un moment que j'ai plus eu besoin d'y toucher).

Mais ça n'explique pas pourquoi le C a choisi ce comportement, arrondir au plus proche minimise l'erreur et ça me semble beaucoup plus logique... Et sur x86 en tout cas, avoir un mode d'arrondi différent dans ce cas tue les perfs : http://www.mega-nerd.com/FPcast/
(l'article est vieux, donc il y a pu avoir des changements depuis, mais en tout cas c'était vrai à l'époque)

C'est comme çà que la norme C a choisi. C'est surement historique, et ca a introduit des hacks pour les jeux PC.
Mais aujourd’hui on est en SSE2 tout le temps, donc le FPU, c'est le passé !!

25

./22 > De fait, vu qu'on sait à présent que sur le JIT x86 (et non x64 tongue) ils utilisent SSE2 pour les troncations d'entier et le FPU pour le reste, je suppose que ça doit aller… ^^
./24 > (Sauf dans les applications .NET compilées en AnyCPU pour Windows 8 !)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

26

Youpi, encore un héritage encombrant du C tongue
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

27

c'est là où je suis heureux de plus coder! (en entreprise)

Désolé, mais quand je vois tout ce que vous dites, ça me déprime smile
avatar
https://air-gaming.com/tests/ si vous voulez de la bonne lecture :=)

28

(Dans mon cas c'est pour un projet perso… Des problèmes de float c'est le paradis comparé à mon boulot. Sans rire…)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

29

J'ai un doute avec votre conversation, arrondire vers 0 c'est tronquer completement la partie décimale quelque soit la valeur apres la virgule?
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

30

Oui.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité