Extracting mantissa and exponent from double in c#
Solution 1
The binary format shouldn't change - it would certainly be a breaking change to existing specifications. It's defined to be in IEEE754 / IEC 60559:1989 format, as Jimmy said. (C# 3.0 language spec section 1.3; ECMA 335 section 8.2.2). The code in DoubleConverter should be fine and robust.
For the sake of future reference, the relevant bit of the code in the example is:
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 & (1L << 63)) != 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 negative ? "-0" : "0";
}
/* Normalize */
while((mantissa & 1) == 0)
{ /* i.e., Mantissa is even */
mantissa >>= 1;
exponent++;
}
…
}
The comments made sense to me at the time, but I'm sure I'd have to think for a while about them now. After the very first part you've got the "raw" exponent and mantissa - the rest of the code just helps to treat them in a simpler fashion.
Solution 2
The representation is a IEEE standard and shouldn't change.
https://msdn.microsoft.com/en-us/library/system.double(v=vs.110).aspx
The Double type complies with the IEC 60559:1989 (IEEE 754) standard for binary floating-point arithmetic.
EDIT: The reason why decimal has a getBits and double does not is that decimal preserves significant digits. 3.0000m == 3.00m but the exponents/mantissas are actually different. I think floats/doubles are uniquely represented.
dvenema
Updated on April 13, 2021Comments
-
dvenema about 3 years
Is there any straightforward way to get the mantissa and exponent from a double in c# (or .NET in general)?
I found this example using Google, but I'm not sure how robust it would be. Could the binary representation for a double change in some future version of the framework, etc?
The other alternative I found was to use System.Decimal instead of double and use the Decimal.GetBits() method to extract them.
Any suggestions?
-
Judge Maygarden over 15 yearsA double does not necessarily have to be 64-bits in C/C++. I've worked on several systems where it is 32-bits (i.e. the same as a float). Is C# different?
-
Boti over 15 yearsyes, it is defined in the spec as 64 bits. that's a good point about the double (and long/int/long long ) fiasco in C/C++
-
Boti over 15 yearsIf I understand the spec correctly, there are two forms of the format, a normalized version and an un-normalized version. the bulk of the code handles converting the unnormalized mantissa/exponent to normalized form
-
user507401 over 13 yearsI don't get the "subtract another 52" part. What's going on there?
-
Jon Skeet over 13 years@Jay R: It's slightly hard to explain, to be honest - the comment does about as good a job as I can think of. I guess it's easiest to give an example, but I'm afraid my brain is frazzled at the moment :(
-
user507401 over 13 yearsNow that I've thought more about it, I get the 1075. 1023 plus 52 shifts to bring the mantissa from a very large number * 2^exponent to a small number.
-
Slava about 11 years@Jimmy when (or if) C# would support at least half platforms that C/C++ support then you can say something about fiasco in C/C++.
-
Daniel almost 11 years@JonSkeet Could you at some time check out my question here ( stackoverflow.com/questions/17829139/… )? I'm currently using part of this code and seem to be missing something.
-
Oleg Vazhnev over 10 yearsif someone can post similar code to convert
decimal
to mantissa and exponent? I guessDecimal.GetBits()
method should be used. -
Oleg Vazhnev over 10 yearsupd: I found here an example which calculates mantissa, but exponent is not calculated stackoverflow.com/a/764102/93647
-
Jon Skeet over 10 years@javapowered: The code in this answer does calculate the exponent and mantissa. It's not clear what else you'd need.
-
Oleg Vazhnev over 10 years@JonSkeet right I was talking about another question stackoverflow.com/questions/763942/…. I asked in this question because when I posted my first comments I not found this, another, "decimal" question.
-
Slipp D. Thompson over 9 yearsWhy is a single-character string with
0
text returned under a specific condition? I'm attempting to use your implementation in my project but am unsure of the larger context of this algorithm. I'm assuming a function without
args formantissa
andexponent
, but that sole string return is throwing off my understanding. -
Jon Skeet over 9 years@SlippD.Thompson: If the mantissa isn't 0, there will be at least one non-zero digit. I suspect that if I removed that special case, it would end up returning the empty string instead of "0" if you passed in 0.
-
Slipp D. Thompson over 9 years@JonSkeet I'm not completely following why strings are involved in the first place. Or rather, a string. There are no other
return
s norstring
s in the code sample. -
Jon Skeet over 9 years@SlippD.Thompson: The link in the question is to my
DoubleConverter
code - whose purpose is to convert adouble
into its exact string representation. Follow the link for the complete code. -
Slipp D. Thompson over 9 years@JonSkeet I see now; you quoted a portion of the code the OP was unsure about. I'll admit I skimmed the english here and went straight to the code. ;-/ In the context of an SO answer, it wouldn't hurt to have a few extra lines of context. // Actually, I'll just do it. I hope you don't mind.
-
Xonatron over 6 yearsLink needs updating.
-
D.R. over 5 years@JonSkeet: Your check for the sign
bits < 0
is incorrect for the double value-0
. You should, imho, instead check for(bits & (1<<63)) > 0
. -
Jon Skeet over 5 years@D.R.: Thank you, yes. Fixed.
-
Mike Marynowski over 4 years@D.R. @JonSkeet Are those two statements not 100% equivalent? Both produce
true
for-0.0
andfalse
for0.0
...or am I missing something here? -
Mike Marynowski over 4 yearsI think @D.R. was thinking about the
double d
value and not thelong bits
value when he said that. If the 64th bit of along
is not zero then thelong
is negative so either should work fine :) -
Michael about 4 yearsI've run this code and I find that the correct way to "Bias the Exponent" is to do it after normalizing with the code:
exponent = 1075 - exponent;
This works correctly for the application I'm designing but I'm not sure why or if I'm making an error? -
Jon Skeet about 4 years@Michael: I suspect you're treating the exponent in the opposite way to the way I am, that's all. (Shift left vs shift right.)
-
Michael about 4 yearsThanks, yeah, this is all hazy to me but thanks for this example it was a life saver!
-
pogosama about 3 yearsEdit queue is full, so I'll put the updated link here: docs.microsoft.com/en-us/dotnet/api/system.double