To see why this happens we need to look in to the internals of Decimal.
In the source for Convert.ToDouble(Decimal)
we see it does
public static double ToDouble(decimal value) {
return (double)value;
}
In the source for Decimal we can see its explicit conversion operator for double
public static explicit operator double(Decimal value) {
return ToDouble(value);
}
And its double ToDouble(Decimal)
call
[System.Security.SecuritySafeCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern double ToDouble(Decimal d);\
We then need to go to the native implementation of the ToDouble call
FCIMPL1(double, COMDecimal::ToDouble, FC_DECIMAL d)
{
FCALL_CONTRACT;
ENSURE_OLEAUT32_LOADED();
double result = 0.0;
// Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
VarR8FromDec(&d, &result);
return result;
}
FCIMPLEND
Which leads us to VarR8FromDec
which is a windows function inside OleAut32.dll
which we don't have the source to.
Likely the issue is OleAut32.dll
is not doing the max percision conversion it could be doing.
If you want to convert with max percision you need to first go to string with the R
format then parse the string.
If you are curious, I ran VarR8FromDec
through a decompiler and here is what it is doing internally
HRESULT __stdcall VarR8FromDec(const DECIMAL *pdecIn, DOUBLE *pdblOut)
{
BYTE v2; // dl@1
BYTE v3; // bl@2
double v4; // st7@4
HRESULT result; // eax@8
v2 = pdecIn->scale;
if ( v2 > 0x1Cu || (v3 = pdecIn->sign, v3 & 0x7F) )
{
result = -2147024809;
}
else
{
if ( (pdecIn->Mid32 & 0x80000000u) == 0 )
v4 = ((double)pdecIn->Hi32 * 1.844674407370955e19 + (double)*(signed __int64 *)&pdecIn->Lo32) / sub_1006AC0D(v2);
else
v4 = ((double)*(signed __int64 *)&pdecIn->Lo32 + 1.844674407370955e19 + (double)pdecIn->Hi32
* 1.844674407370955e19)
/ sub_1006AC0D(v2);
if ( v3 )
v4 = -v4;
*(_QWORD *)pdblOut = *(_QWORD *)&v4;
result = 0;
}
return result;
}
double __fastcall sub_1006AC0D(unsigned int a1)
{
double result; // st7@2
if ( a1 > 0x50 )
result = sub_1006ABD4((void *)a1, 10.0);
else
result = dbl_1002EF08[a1];
return result;
}
double __thiscall sub_1006ABD4(void *this, double a2)
{
unsigned int v2; // eax@1
double v3; // st6@3
double i; // st5@3
double result; // st7@9
v2 = (unsigned int)this;
if ( (signed int)this < 0 )
v2 = -(signed int)this;
v3 = 1.0;
for ( i = a2; ; i = i * i )
{
if ( v2 & 1 )
v3 = v3 * i;
v2 >>= 1;
if ( !v2 )
break;
}
if ( (signed int)this >= 0 )
result = v3;
else
result = 1.0 / v3;
return result;
}
.text:1002EF08 ; double dbl_1002EF08[]
.text:1002EF08 dbl_1002EF08 dq 1.0 ; DATA XREF: VarDecFromR4:loc_1002F23Ar
.text:1002EF08 ; VarDecFromR8:loc_1002F4BAr ...
.text:1002EF10 dd 0
.text:1002EF14 dd 40240000h, 0
.text:1002EF1C dd 40590000h, 0
.text:1002EF24 dd 408F4000h, 0
.text:1002EF2C dd 40C38800h, 0
.text:1002EF34 dd 40F86A00h, 0
.text:1002EF3C dd 412E8480h, 0
.text:1002EF44 dd 416312D0h, 0
.text:1002EF4C dd 4197D784h, 0
.text:1002EF54 dd 41CDCD65h, 20000000h, 4202A05Fh, 0E8000000h, 42374876h
.text:1002EF54 dd 0A2000000h, 426D1A94h, 0E5400000h, 42A2309Ch, 1E900000h
.text:1002EF54 dd 42D6BCC4h, 26340000h, 430C6BF5h, 37E08000h, 4341C379h
.text:1002EF54 dd 85D8A000h, 43763457h, 674EC800h, 43ABC16Dh, 60913D00h
.text:1002EF54 dd 43E158E4h, 78B58C40h, 4415AF1Dh, 0D6E2EF50h, 444B1AE4h
.text:1002EF54 dd 64DD592h, 4480F0CFh, 0C7E14AF6h, 44B52D02h, 79D99DB4h
.text:1002EF54 dd 44EA7843h, 2C280291h, 45208B2Ah, 0B7320335h, 4554ADF4h
.text:1002EF54 dd 0E4FE8402h, 4589D971h, 2F1F1281h, 45C027E7h, 0FAE6D721h
.text:1002EF54 dd 45F431E0h, 39A08CEAh, 46293E59h, 8808B024h, 465F8DEFh
.text:1002EF54 dd 0B5056E17h, 4693B8B5h, 2246C99Ch, 46C8A6E3h, 0EAD87C03h
.text:1002EF54 dd 46FED09Bh, 72C74D82h, 47334261h, 0CF7920E3h, 476812F9h
.text:1002EF54 dd 4357691Bh, 479E17B8h, 2A16A1B1h, 47D2CED3h, 0F49C4A1Dh
.text:1002EF54 dd 48078287h, 0F1C35CA5h, 483D6329h, 371A19E7h, 48725DFAh
.text:1002EF54 dd 0C4E0A061h, 48A6F578h, 0F618C879h, 48DCB2D6h, 59CF7D4Ch
.text:1002EF54 dd 4911EFC6h, 0F0435C9Eh, 49466BB7h, 0EC5433C6h, 497C06A5h
.text:1002EF54 dd 0B3B4A05Ch, 49B18427h, 0A0A1C873h, 49E5E531h, 8CA3A8Fh
.text:1002EF54 dd 4A1B5E7Eh, 0C57E649Ah, 4A511B0Eh, 76DDFDC0h, 4A8561D2h
.text:1002EF54 dd 14957D30h, 4ABABA47h, 6CDD6E3Eh, 4AF0B46Ch, 8814C9CEh
.text:1002EF54 dd 4B24E187h, 6A19FC41h, 4B5A19E9h, 0E2503DA9h, 4B905031h
.text:1002EF54 dd 5AE44D13h, 4BC4643Eh, 0F19D6057h, 4BF97D4Dh, 6E04B86Dh
.text:1002EF54 dd 4C2FDCA1h, 0E4C2F344h, 4C63E9E4h, 1DF3B015h, 4C98E45Eh
.text:1002EF54 dd 0A5709C1Bh, 4CCF1D75h, 87666191h, 4D037269h, 0E93FF9F5h
.text:1002EF54 dd 4D384F03h, 0E38FF872h, 4D6E62C4h, 0E39FB47h, 4DA2FDBBh
.text:1002EF54 dd 0D1C87A19h, 4DD7BD29h, 463A989Fh, 4E0DAC74h, 0ABE49F64h
.text:1002EF54 dd 4E428BC8h, 0D6DDC73Dh, 4E772EBAh, 8C95390Ch, 4EACFA69h
.text:1002EF54 dd 0F7DD43A7h, 4EE21C81h, 75D49491h, 4F16A3A2h, 1349B9B5h
.text:1002EF54 dd 4F4C4C8Bh, 0EC0E1411h, 4F81AFD6h