Je sais que 511 divisé par 512 équivaut à 0,998046875. Je sais aussi que la précision des flotteurs est de 7 chiffres. Ma question est, quand je fais ce mathématique en C ++ (GCC), le résultat que j'ai obtenu est 0.998047, qui est une valeur arrondie. Je préférerais simplement obtenir la valeur tronquée de 0,998046, comment puis-je faire cela?
5 Réponses :
Si vous êtes juste intéressé par la valeur, vous pouvez utiliser un double, puis multiplier le résultat de 10 ^ 6 et le plancher. Divisez à nouveau de 10 ^ 6 et vous obtiendrez la valeur tronquée. P>
Eh bien, voici un problème. La valeur de sortie: p> A voir 511/512 code>, en tant que
float code>, est exact. Aucun arrondi n'est fait. Vous pouvez vérifier cela en demandant plus de sept chiffres:
float code> est stocké pas comme un nombre décimal, mais binaire. Si vous divisez un nombre par une puissance de 2, telle que 512, le résultat sera presque toujours exact. Ce qui se passe est la précision d'un
float code> n'est pas simplement 7 chiffres, il est vraiment 23 bits em> de précision. P>
24 bits en raison du fait qu'il est possible d'obtenir un bit de plus en conservant le nombre normalisé.
Exactement. Le seul arrondi qui se produit dans l'exemple des internateurs est quand il imprime la valeur. Et comme @Aprogrammer a dit, il a 24 b> bits de précision.
Cela répond à cette question même si j'ai toujours le problème de compensation de pixels dans mon code d'origine, mais c'est pour l'aide!
Mathématiquement, il est toutefois 7,22 chiffres décimaux de la précision en raison de la tranchée de chiffres, il est nécessaire d'utiliser jusqu'à 9 chiffres décimaux pour représenter un flotteur particulier. Voir ma réponse ici
@Thomasmcleod, 6.92, pas 7.22. Par exemple 0x1.0624D2P-10 = 9,999999349E-04 et 0x1.0624D4P-10 = 9,99999465E-04 sont deux float successifs, ce qui représente donc 9,999994E-04 est problématique.
@Aprogrammer, tu es correct, c'est 6.92 (23 log 2). Cependant, cela nécessite toujours 8 chiffres décimaux pour différencier les flotteurs adjacents (car la 0,92 peut faire partie de 2 chiffres décimaux).
@Aprogrammer: Vous oubliez le bit implicite: il est en fait 24 bits de précision, donc 7,2247Quage est la bonne réponse.
@Olof, veuillez regarder l'histoire. Je suis celui qui a mentionné le bit implicite. La formule à utiliser est le sol ((P-1) log_10 b) (+ 1 si B est une puissance de 10). J'ai donné un exemple pourquoi. Voici un autre (pour 80 bits Long Double): 0x8.3126E978D4FDF39P-13 = 9.99999999999999999747E-04 et 0x8.3126E978D4FDF3AP-13 = 9,99999999999999999853F-04
Je sais aussi que la précision des flotteurs est de 7 chiffres. P> blockQuote>
non. Le format point flottant le plus commun est binaire et a une précision de 24 bits. Il est quelque part entre 6 et 7 chiffres décimaux, mais vous ne pouvez pas penser en décimal si vous voulez comprendre comment les travaux d'arrondi. P>
comme B est une puissance de 2, C est exactement représentable. C'est pendant la conversion dans une représentation décimale que l'arrondi se produira. Les moyens standard d'obtenir une représentation décimale n'offrent pas la possibilité d'utiliser la troncature au lieu de l'arrondi. Une façon de demander un chiffre de plus et l'ignorerait. P>
Mais notez que le fait que c est exactement représentable est une propriété de sa valeur. Certaines valeurs apparemment simples (comme 0,1) n'ont pas une représentation exacte dans les formats Binary FP. P>
24 bits de précision n'est pas "entre 6 et 7 chiffres décimaux" car la plage de 0 à 2 ^ 24-1 est égale à 0 à 16777215 La bonne réponse est donc comprise entre 7 et 8 chiffres depuis 7 chiffres (9999999) est évidemment inférieur à 16777215 et 8 chiffres (99999999) est évidemment plus de 16777215.
@OLOF, 0x1.0624D2P-10 = 9,999999349E-04 et 0x1.0624D4P-10 = 9.99999465E-04 Sont deux float successifs, ce qui représente donc 9,999994E-04 est problématique et vous n'avez pas 7 chiffres décimaux de précision.
@Olofforshell, votre analyse est simple mais incorrecte. Étant donné que les valeurs binaires et les valeurs décimales ne sont pas alignées avec précision, il est possible de sauver une valeur même si la plage est plus grande. Il faut une gamme 2x ce que vous pensez avoir besoin pour éliminer cette possibilité, vous perdez donc un peu.
@ @ Ransom: 16777215 est le plus grand entier étrange qui peut être représenté comme un flotteur. En effet, il correspond à 2 ^ 24-1 i e contient des binaires consécutives à une rangée correspondant aux 24 bits (23 explicites + 1 implicites) dans le flotteur signifiant. À partir de 16777216, tous les autres entier peuvent être représentés jusqu'à 2 ^ 25-2. En réalité, les gammes sont "0 à 2 ^ 24-2 ^ 0 par 2 ^ 0" suivies de "2 ^ 24 à 2 ^ 25-2 ^ 1 par 2 ^ 1", "2 ^ 25 à 2 ^ 26-2 ^ 2 par 2 ^ 2 "et ainsi de suite.
Cette valeur "arrondi" est la plus chaude ce qui est affiché à travers une méthode de sortie plutôt que ce qui est réellement stocké. Vérifiez la valeur réelle dans votre débogueur. P>
Avec iostream et Stdio, vous pouvez spécifier la précision de la sortie. Si vous spécifiez 7 chiffres signifiants, convertissez-le en une chaîne, puis tronquez la chaîne avant l'affichage, vous obtiendrez la sortie sans arrondir. P>
Vous ne pouvez pas penser à une raison pour laquelle vous voudriez cependant faire cela, et étant donné l'explication de la sous-marché de l'application, vous feriez mieux d'utiliser la double précision, cependant, ce qui sera probablement des problèmes de vol d'une autre chose à ailleurs. p>
Votre question n'est pas unique, elle a été répondu à de nombreuses fois auparavant. Ce n'est pas un simple sujet et simplement parce que les réponses sont affichées ne signifie pas nécessairement qu'ils seront de bonne qualité. Si vous parcourez un peu, vous trouverez les très bonnes choses. Et cela vous prendra moins de temps. P>
Je parie que quelqu'un va -1 me faire commenter et ne pas répondre. P>
Qu'est-ce qui est fondamental pour comprendre le point flottant consiste à réaliser que tout est affiché dans des chiffres binaires. Parce que la plupart des gens ont du mal à saisir cela, ils essaient de le voir du point de vue des chiffres décimaux. P>
sur le sujet du 511/512, vous pouvez commencer par regarder la valeur 1.0. Dans le point flottant, cela pourrait être exprimé comme i.000000 ... * 2 ^ 0 ou un jeu de bits implicite (à 1) multiplié par 2 ^ 0 c'est-à-dire égaux 1. Depuis 511/512, il est inférieur à 1, vous devez commencer par le prochain. Puissance inférieure -1 Donner I.000000 ... * 2 ^ -1 c'est-à-dire 0.5. Notez que la seule chose qui a changé est l'exposant. Si nous voulons exprimer 511 en binaire, nous en obtenons 9 - 111111111 ou dans un point flottant avec un bit implicite I.11111111 - que nous pouvons diviser par 512 et mettre en place avec l'exposant de -1 donner I.1111111100 ... * 2 ^ -1. P>
Comment ça se traduit par 0,998046875? P>
Bien pour commencer par le bit implicite représente 0,5 (ou 2 ^ -1), le premier bit explicite 0,25 (2 ^ -2), le bit explicite suivant 0,125 (2 ^ -3), 0,0625, 0,03125 et ainsi de suite jusqu'à ce que vous ayez représenté le neuvième bit (huitième explicite). Les résumer et vous obtenez 0.998046875. À partir de la ligne I.11111111, nous constatons que ce nombre représente 9 chiffres binaires de précision et, de coïncidence, 9 précision décimale. P>
Si vous multipliez 511/512 par 512, vous obtiendrez i111111111100 ... * 2 ^ 8. Ici, il y a les neuf chiffres binaires de précision, mais seulement trois chiffres décimaux (pour 511). P>
Considérez I.111111111111111111111 (I + 23) * 2 ^ -1. Nous recevrons une fraction (2 ^ (24-1) ^ / (2 ^ 24)) avec 24 chiffres de précision binaire et 24 décimales. Compte tenu d'un formatage approprié Printf, tous les 24 chiffres décimaux seront affichés. Multipliez-le par 2 ^ 24 et vous avez encore 24 chiffres binaires de précision, mais seulement 8 décimales (pour 16777215). P>
considère maintenant I.1111100 ... * 2 ^ 2 qui sort à 7.875. I11 est la partie entière et 111 la partie fraction (111/1000 ou 7 / 8e). 6 chiffres binaires de précision et 4 décimales. P>
Penser la décimale lorsque le point flottant est totalement préjudiciable pour la comprendre. Gratuit toi! P>
-1 Pour un texte pouvant être réutilisé Verbatim sous de nombreuses questions.
@EvenGeniseregev: Aidez-vous! Il s'agit de certaines des subtilités de mathématiques à virgule flottante. De mon expérience personnelle sur le sujet et en considérant que plus ou moins les mêmes questions sont postées encore et encore, je dirais que c'est un sujet qui se classe bien au-dessus de la moyenne en complexité ou, peut-être, de complexité perçue. Ceux qui répondent souvent semblent être les plus intéressés par des points mais ont relativement peu de connaissances en matière de sujet à partager - il est souvent incorrect.
@Olofforshell, je suppose que l'idée est que vous devriez être précis, et vous pouvez être ici, en descendant et en commentant de réponses incorrectes. Je ne dis pas que c'est à vous de faire cela seul, mais au fil du temps, la communauté apportera les réponses les plus correctes et utiles au sommet. C'est une bonne caractéristique de ce site, qu'il fonctionnerait toujours bien même si cette page était inondée de réponses incorrectes.
Vous ne pouvez pas utiliser les doubles pour plus de précision et tronquer cela?
C'est le code de jeu et, tandis que le double résoudrait le problème comme indiqué, je fais ce calcul pour le rendu de texture et un double ajoutait probablement une performance touchée. Le problème est que l'arrondi provoque un décalage de pixels dans les textures.
Votre commentaire révèle que vous ne savez pas vraiment ce que vous faites. "Un pixel décalage dans les textures"? Dites-nous plus à ce sujet, et peut-être que nous pouvons aider.
C'est votre débogueur qui arrondit la valeur.
@Nick - Peut-être que si vous nous montrez le code causant l'erreur de 1 pixel, nous pouvons vous aider avec cela (comme une question distincte, probablement ...)
Ne soyez pas trop sûr que
double code> s provoque une performance touchée. Sur de nombreux systèmes lorsque vous utilisez
float code>, tout convertit tout en
double code>, fait tout le calcul, puis convertit les dos vers
float code> - donc c'est réellement Faire plus de travail lorsque vous utilisez
float code>.
La double précision n'est généralement que d'une performance significative lors du traitement d'une grande quantité de données, simplement parce que deux fois plus besoin d'être déplacés dans et hors de la mémoire. Les opérations de points flottants réalisent probablement le même temps. Vous ferez peut-être mieux de faire cela avec des arithmétiques à point fixe pour éviter les artefacts d'artefacts à virgule flottante imprévisibles.
Comme @dietrich a souligné dans la solution, la réponse à cette question était due à la mise en forme de l'impression dans le débogueur. Cela signifie que ce n'est pas cette valeur causant le décalage de la texture. Je pourrais poster une question de suivi après que j'explore cela un peu plus. Merci a tous!
@Quantumechanic - Ce n'est pas vrai sur x86 / x64 et ce n'est pas vrai sur PowerPC. De quels systèmes parlez-vous? (Et des conversions entre
float code> et
double code> sont fondamentalement libres de toute façon).
@Clifford - Non, les opérations ne prennent pas le même temps. Ils sont mis en œuvre avec différents opcodes sur la plupart des FPU et font différentes quantités de travail.
@Deitrich: Comme je l'ai expliqué, le chargement des registres de la mémoire peut prendre plus de temps (bien que probablement pas si vous utilisez un système d'exploitation de 64 bits), mais sur un processeur X86 moderne, la plupart (sinon tout, je n'ai pas vérifié de manière exhaustive), les instructions FPU ne diffèrent pas. Dans les cycles de processeur entre une seule et double précision, par exemple FDIV est identique pour MEM32 et les opérandes MEM64. Différentes quantités de travail peut-être, mais la largeur du moteur d'exécution du Pentium FPU est de 80 bille; C'est plus de transistors pour changer peut-être, mais le processus est parallèle non séquentiel. Les autres FPU varient.