2008-12-23 4 views
23

Existe-t-il un moyen simple d'obtenir la mantisse et l'exposant à partir d'un double dans C# (ou .NET en général)?Extraire la mantisse et l'exposant du double dans C#

J'ai trouvé this example en utilisant google, mais je ne suis pas sûr de sa robustesse. La représentation binaire pourrait-elle être un double changement dans une future version du framework, etc?

L'autre alternative que j'ai trouvée était d'utiliser System.Decimal au lieu de double et d'utiliser la méthode Decimal.GetBits() pour les extraire.

Des suggestions?

Répondre

26

Le format binaire ne devrait pas changer - ce serait certainement un changement radical par rapport aux spécifications existantes. Il est défini comme étant au format IEEE754/IEC 60559: 1989, comme l'a dit Jimmy. (Section 1.3 des spécifications de langage C# 3.0, section 8.2.2 de l'ECMA 335). Le code dans DoubleConverter devrait être fin et robuste.

Par souci de référence ultérieure, le bit correspondant du code dans l'exemple est:

public static string ToExactString (double d) 
{ 
    … 

    // Translate the double into sign, exponent and mantissa. 
    long bits = BitConverter.DoubleToInt64Bits(d); 
    // Note that the shift is sign-extended, hence the test against -1 not 1 
    bool negative = (bits < 0); 
    int exponent = (int) ((bits >> 52) & 0x7ffL); 
    long mantissa = bits & 0xfffffffffffffL; 

    // Subnormal numbers; exponent is effectively one higher, 
    // but there's no extra normalisation bit in the mantissa 
    if (exponent==0) 
    { 
     exponent++; 
    } 
    // Normal numbers; leave exponent as it is but add extra 
    // bit to the front of the mantissa 
    else 
    { 
     mantissa = mantissa | (1L<<52); 
    } 

    // Bias the exponent. It's actually biased by 1023, but we're 
    // treating the mantissa as m.0 rather than 0.m, so we need 
    // to subtract another 52 from it. 
    exponent -= 1075; 

    if (mantissa == 0) 
    { 
     return "0"; 
    } 

    /* Normalize */ 
    while((mantissa & 1) == 0) 
    { /* i.e., Mantissa is even */ 
     mantissa >>= 1; 
     exponent++; 
    } 

    … 
} 

Les commentaires ont fait sens pour moi à l'époque, mais je suis sûr que je dois penser pour un moment à leur sujet maintenant. Après la première partie, vous avez l'exposant "brut" et la mantisse - le reste du code aide simplement à les traiter d'une manière plus simple.

+0

Si je comprends correctement la spécification, il existe deux formes de format, une version normalisée et une version non normalisée. la majeure partie du code gère la conversion de la mantisse/exposant non normalisée en forme normalisée – Jimmy

+0

Je n'obtiens pas la partie "soustraire une autre 52". Que se passe-t-il ici? –

+0

@Jay R: C'est un peu difficile à expliquer, pour être honnête - le commentaire fait à propos d'un aussi bon travail que je peux penser. Je suppose qu'il est plus facile de donner un exemple, mais je crains que mon cerveau ne soit pour le moment :( –

1

La représentation est une norme IEEE et ne devrait pas changer.

https://msdn.microsoft.com/en-us/library/system.double(v=vs.110).aspx

type double conforme à la norme CEI 60559: 1989 (IEEE 754) de série binaire arithmétique à virgule flottante.

EDIT: La raison pour laquelle decimal a un getBits et le double n'est pas que decimal préserve des chiffres significatifs. 3.0000m == 3.00m mais les exposants/mantisses sont réellement différents. Je pense que les flotteurs/doubles sont uniquement représentés.

+0

Un double ne doit pas nécessairement être 64 bits en C/C++. J'ai travaillé sur plusieurs systèmes où il est 32 bits (c'est-à-dire la même chose qu'un flotteur). Est-ce que C# est différent? –

+3

oui, il est défini dans la spécification comme 64 bits. c'est un bon point sur le fiasco double (et long/int/long) en C/C++ – Jimmy

+0

@Jimmy quand (ou si) C# supporterait au moins la moitié des plateformes supportées par C/C++ alors vous pouvez dire quelque chose sur fiasco en C/C++. – Slava

Questions connexes