2010-10-06 9 views
1

Je me demande si un nombre est représenté d'une manière dans une représentation en virgule flottante, est-ce qu'il va être représenté de la même manière dans une représentation qui a une plus grande taille. En d'autres termes, si un nombre a une représentation particulière en tant que float, aura-t-il la même représentation si float est transtypée en double, puis de la même façon lorsqu'il est transtypé en long double. Je me demande parce que j'écris une implémentation BigInteger et tout nombre à virgule flottante qui est passé dans J'envoie à une fonction qui accepte un long double pour le convertir. Ce qui m'amène à ma prochaine question. Évidemment, les points flottants n'ont pas toujours de représentations exactes, donc dans ma classe BigInteger, que dois-je essayer de représenter quand on me donne un float. Est-il raisonnable d'essayer de représenter le même nombre que celui donné par std::cout << std::fixed << someFloat; même si ce n'est pas le même que le nombre passé? Est-ce la représentation la plus précise que je serai en mesure d'obtenir? Si oui, ...Quelques questions sur les points flottants

Quelle est la meilleure façon d'extraire cette valeur (en base une puissance de 10), au moment où je suis juste en train de l'attraper comme une chaîne et de le passer à mon constructeur de chaîne. Cela fonctionnera, mais je ne peux pas m'empêcher de penser qu'il y a un meilleur moyen, mais prendre le reste quand je divise par ma base n'est pas précis avec les flotteurs. Finalement, je me demande s'il y a un équivalent en virgule flottante de uintmax_t, c'est un nom de type qui sera toujours le plus gros type à virgule flottante sur un système, ou est-ce qu'il n'y a pas de point parce que long double sera toujours le c'est la même chose qu'un double).

Merci, T.

Répondre

9

Si par vous dire « exactement la même représentation binaire en mémoire, sauf pour le rembourrage » « même représentation », alors non. La double précision a plus de bits de l'exposant et de la mantisse, et a également un biais d'exposant différent. Mais je crois que toute valeur de simple précision est exactement représentable en double précision (sauf peut-être des valeurs dénormalisées).

Je ne suis pas sûr de ce que vous voulez dire lorsque vous dites "les points flottants n'ont pas toujours des représentations exactes". Certes, toutes les valeurs décimales à virgule flottante n'ont pas de valeurs exactes à virgule flottante binaire (et vice versa), mais je ne suis pas sûr que ce soit un problème ici. Tant que votre entrée à virgule flottante n'a pas de partie fractionnaire, un format "BigInteger" suffisamment grand devrait être capable de le représenter exactement.

La conversion via une représentation en base 10 n'est pas la meilleure solution. En théorie, tout ce dont vous avez besoin est un tableau de bits de longueur ~ 1024, initialisez tout à zéro, puis décalez les bits de la mantisse par la valeur de l'exposant. Mais sans en savoir plus sur votre mise en œuvre, je ne peux pas en dire beaucoup plus!

+0

Merci pour votre réponse. Je ne suis pas sûr de comprendre ce que vous voulez dire quand vous dites "un format BigInteger devrait être capable de le représenter exactement". Certes, un BigInteger devrait être en mesure de le représenter, mais comment puis-je obtenir la valeur en premier lieu. Il y a des nombres (sans partie fractionnaire) que le compilateur accepte comme un flottant valide mais quand je les imprime, j'obtiens un nombre différent. Est-ce un problème avec 'cout' alors et le nombre est toujours représenté exactement. Désolé, c'est un peu incohérent, je suis juste un peu confus à ce sujet. Aussi si cela aiderait si je poste le contour de mon ... – tjm

+0

... mise en œuvre, je suis heureux de le faire. C'est un peu long cependant. (et très difficile en ce moment). – tjm

+0

Je suppose que vous voulez dire quelque chose comme 'float f = 123456789123456789.0f;' C'est une limitation du point flottant, pas de "BigIntegers". BigIntegers devrait être capable de représenter toutes les valeurs (intégrales) possibles des flotteurs, mais pas vice versa. –

2

double inclut toutes les valeurs de float; long double inclut toutes les valeurs de double. Donc, vous ne perdez aucune information sur la valeur par la conversion en long double. Cependant, vous perdez des informations sur le type d'origine, ce qui est pertinent (voir ci-dessous).

Afin de suivre les sémantiques C++ courantes, la conversion d'une valeur à virgule flottante en nombre entier devrait tronquer la valeur, pas arrondir.

Le problème principal concerne les grandes valeurs qui ne sont pas exactes. Vous pouvez utiliser la fonction frexp pour trouver l'exposant de base 2 de la valeur en virgule flottante. Vous pouvez utiliser std::numeric_limits<T>::digits pour vérifier si la plage d'entiers peut être exactement représentée.Mon choix de conception personnel serait d'affirmer que la valeur fp est dans la plage qui peut être exactement représentée, c'est-à-dire une restriction sur la portée de tout argument réel.

Pour cela, vous avez besoin de surcharges prenant les arguments float et double, car la plage qui peut être représentée dépend exactement du type de l'argument.

Lorsque vous avez une valeur fp qui est dans la plage autorisée, vous pouvez utiliser floor et fmod pour extraire des chiffres dans n'importe quel système numérique que vous voulez.

+1

+1. Bien que je ne suis pas d'accord avec votre choix de conception. Cela va à l'encontre de l'idée d'étendre naturellement la sémantique C++. Je peux certainement assigner un float 32 bits avec une mantisse 24 bits à un int 64 bits si la valeur - après troncature - tient dans 64 bits. – sellibitze

+0

+1 de moi aussi, et merci pour votre réponse, c'est utile. Malheureusement je préférerais ne pas descendre artificiellement la limite des valeurs, si C++ l'accepte, je voudrais l'accepter, je ne sais pas exactement quelle valeur je devrais accepter! – tjm

+0

'floor (abs (v))', avec le signe comme valeur d'origine 'v'. La raison pour laquelle j'ai suggéré de ne pas accepter une valeur "inexacte" est que le point de l'arithmétique entière arbitraire ou étendue est généralement d'avoir des résultats exacts. J'aurais dû ajouter une phrase de belette "par défaut", je veux dire, pourquoi ne pas simplement supporter les deux? :-) –

0

oui, allant du flotteur IEEE à doubler ETENDUE, vous verrez des bits du format plus petit au plus grand format, par exemple

 
single 
S EEEEEEEE MMMMMMM..... 
double 
S EEEEEEEEEEEE MMMMM.... 

6.5 single 
0 10000001 101000... 
6.5 double 
0 10000000001 101000... 
13 single 
0 10000010 101000... 
13 double 
0 10000000010 101000... 

Le mantisse vous justifier à gauche, puis ajouter des zéros.

L'exposant est justifié à droite, signe étendre le suivant à msbit puis copier le msbit.

Un exposant de -2 par exemple. prendre -2 soustraire 1 qui est -3. -3 dans le complément à deux est 0xFD ou 0b11111101 mais les bits de l'exposant dans le format sont 0b01111101, le bit inversé. Et pour le double a -2 exposant -2-1 = -3. ou 0b1111 ... 1101 et cela devient 0b0111 ... 1101, le msbit est inversé. (exposants bits = twos_complement (exponent-1) avec le msbit inversé).

Comme on le voit ci-dessus un exposant de 3 à 1 mars = 2 0b000 ... 010 inverser le bit supérieur 0b100 ... 010

Alors oui vous pouvez prendre les bits de précision unique et les copier à la emplacements appropriés dans le nombre double précision. Je n'ai pas de référence flottante à portée de main mais je suis sûr que cela fonctionne de la même manière.

+0

qui est dans un format à virgule flottante comme IEEE 754. Si vous voulez convertir du format IEEE 754 à TI dsp par exemple, cela ne fonctionne pas de cette façon, ne peut pas copier les bits. Typiquement, bien que dans le même standard, les diverses précisions étendent la mantisse plus vers la droite et l'exposant vers la gauche, ajoutant plus de précision sans redéfinir leur fonctionnement. –