问题
How to correctly convert Delphi Extended type to C# decimal?
I have tried code from this post https://stackoverflow.com/a/34550718/2550543 ,with some values it works fine, but not with all.
Example :
000000000000A08C0B40 == 4500, correct
0050AA7D3A1E33D30140 == 6,59999, correct
00D0F753E3A59BC4F73F == 25769803,776, should be 0.006
00A0703D0AD7A3B0FD3F == 1481763717,12, should be 0.345
Yep, both incorrect values ends with 3F byte, if that means something ...
Can somebody help me with that? :)
Code i have used so far :
var extendedSize = 10;
var buf = new byte[extendedSize];
// Populate buffer with something like: { 0x00, 0x68, 0x66, 0x66, 0x66, 0x66, 0x66, 0xA2, 0x02, 0x40 } = 10.15
// Read(buf, extendedSize);
var sign = (buf[extendedSize - 1] & 0x80) == 0x80 ? -1 : 1;
buf[extendedSize - 1] = (byte)(buf[extendedSize - 1] & 0x7F);
var exp = BitConverter.ToUInt16(buf, extendedSize - 2);
var integral = (buf[extendedSize - 3] & 0x80) == 0x80 ? 1 : 0;
// Calculate mantissa
var mantissa = 0.0;
var value = 1.0;
var fractal = BitConverter.ToUInt64(buf, 0);
while (fractal != 0)
{
value = value / 2;
if ((fractal & 0x4000000000000000) == 0x4000000000000000) // Latest bit is sign, just skip it
{
mantissa += value;
}
fractal <<= 1;
}
return sign * (1 << (exp - 16383)) * (integral + mantissa);
回答1:
return sign * (1 << (exp - 16383)) * (integral + mantissa);
Here be careful of your optimizations. Left shift works as a fast power of two if the right side argument is positive. For negative numbers this does not work as you would expect since the result of the power operation must be a floating point number for negative exponents and bit shifts will only produce an integer result. You can recover the correct answer by removing this "optimization" :
return sign * (Math.Pow(2, exp - 16383)) * (integral + mantissa);
I've also corrected the code in the linked answer from your question. Do note the caveats from that answer as well - this implementation does not correctly handle denormal numbers, NaN, INF, and other special cases. It could (should) also catch cases of extended values which are normal but fall outside the representable range of double. It would be up to you to decide whether that is important for your use case.
来源:https://stackoverflow.com/questions/56736279/convert-delphi-extended-to-c-sharp