Question

J'effectue des conversions de types de données où je dois représenter uint, long, ulong et decimal comme valeurs à virgule flottante double IEEE 754.Je veux pouvoir détecter si le type de données IEEE 754 ne peut pas contenir la valeur avant d'effectuer la conversion.

Une solution par force brute serait d'enrouler un try-catch autour d'un casting pour doubler la recherche. OverflowException.En lisant certains des Documentation CLR implique que certaines conversions modifient simplement la valeur en silence, sans aucune exception.

Existe-t-il un moyen infaillible de procéder à cette vérification ?Je recherche l'exhaustivité plutôt que la facilité de mise en œuvre.J'ai le sentiment que je vais lire attentivement la spécification IEEE 754 et vérifier attentivement matissa et exposant...

Je devrais ajouter que je suis la plupart soucieux de représenter avec précision les nombres entiers et que la perte de précision en virgule flottante est une préoccupation secondaire (mais mérite toujours d'être prise en compte).

MODIFIER: Int32 peut être entièrement exprimé en IEE-754.Également Decimal le type de données fait vraiment partie de la question.

Mise à jour importante : si vous faites référence à cette question, vous devriez également lire cette question : IEEE-754 Double (virgule flottante 64 bits) vs.Long (entier 64 bits) revisité

Il note une faille dans la réponse où certaines valeurs très grandes peuvent également être représentées exactement par IEEE-754.Bien que cela puisse signifier que la valeur fera correctement un aller-retour, pour mon objectif initial (cela fera-t-il un aller-retour vers JavaScript), ce ne sera pas le cas.

Il semble également y avoir un bogue dans le type System.Double des CLR car il n'autorise pas correctement l'aller-retour de ces valeurs.

Était-ce utile?

La solution

Une solution simple pourrait ressembler à ( si x est un entier ):

if ((int)(double)x != x) { 
  // won't convert
} else {
  // will convert
}

et ainsi de suite pendant longtemps, etc.

(double) x convertira x d'un int en un double. Le (int) le reconvertit ensuite. Donc (int) (double) x convertit la forme d'un int en double puis retour. Le code vérifie essentiellement que la conversion en double est réversible (et donc que le double peut stocker la valeur exacte de l'int).

Autres conseils

Cela dépend principalement de la plage de numéros avec laquelle vous travaillez. Tant que vous vous trouvez à moins de 15 chiffres (pour un double ), vous devriez être sur la côté sûr pour les nombres entiers.

En gros, vous devez prendre en compte le nombre de chiffres significatifs. Donc, tant que votre nombre est inférieur à la limite de chiffres significatifs, il restera exact; si elle grossit, vous perdez en précision (même si ce sont des nombres entiers).

Donc tant que votre numéro est < 2 ^ 53, vous êtes généralement bon.

IEEE 754 Double a 52 bits pour la mantisse et vous convertissez de/vers entier/long donc c'est assez facile à tester.Si votre entier consomme moins de 52 bits alors il devrait être convertible sans problème en double IEEE 754.

Je suppose (je le sais avec certitude dans le cas de Java mais pas de C# et je suis paresseux pour vérifier) ​​que int est de 32 bits et long est de 64 bits.Donc, bien sûr, int peut tenir en double sans aucun problème, à la fois signer et annuler la signature.

Pour ulong, vous avez simplement si tous les bits supérieurs au 52ème bit sont un comme ((aULong && 0xFFF0000000000000) == 0).

Pendant longtemps, vous devez prendre en compte son signe.Étant donné que Long est le 2ème complément mais que IEEE754 ne l'est pas (il a juste un bit négatif), il pense qu'il est sûr de simplement convertir le long négatif en positif (*-1) et de vérifier comme positif.Donc, si le long est négatif, chronométrez-le d'abord avec -1 (ne faites rien pour le positif).Ensuite, vérifiez-le comme ulong.

J'espère que cela t'aides.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top