Ste*_*uhr 7 c# precision double decimal
将"高"精度Double转换为Decimal时,由于Rounding,我将使用Convert.ToDecimal或转换为(Decimal)而失去精度.
示例:
double d = -0.99999999999999956d;
decimal result = Convert.ToDecimal(d); // Result = -1
decimal result = (Decimal)(d); // Result = -1
Convert.ToDecimal(double)返回的Decimal值最多包含15位有效数字.如果value参数包含超过15个有效数字,则使用舍入舍入为最接近的数字.
所以为了保持我的精度,我必须将我的double转换为String然后调用Convert.ToDecimal(String):
decimal result = System.Convert.ToDecimal(d.ToString("G20")); // Result = -0.99999999999999956d
这个方法是有效的,但是我想避免使用String变量来将Double转换为Decimal而不用15位后的舍入?
一种可能的解决方案是分解d为 n 个双精度数的精确总和,其中最后一个很小,包含转换为十进制时所需的所有尾随有效数字,而第一个 (n-1) 则精确转换为十进制。
d对于-1.0 和 1.0 之间的源双精度数:
    decimal t = 0M;
    bool b = d < 0;
    if (b) d = -d;
    if (d >= 0.5) { d -= 0.5; t = 0.5M; }
    if (d >= 0.25) { d -= 0.25; t += 0.25M; }
    if (d >= 0.125) { d -= 0.125; t += 0.125M; }
    if (d >= 0.0625) { d -= 0.0625; t += 0.0625M; }
    t += Convert.ToDecimal(d);
    if (b) t = -t;
请注意,即使 C# 以比(它允许自己执行的)d -=更高的精度计算二进制浮点运算,这些运算也是精确的。double
这比从字符串到字符串的转换更便宜double,并且在结果中提供了一些额外的精度位数(上述四个 if-then-else 的精度为四位)。
备注:如果 C# 不允许自己以更高的精度进行浮点计算,一个好技巧是使用 Dekker 拆分来拆分d为两个值d1,d2并将每个值精确地转换为十进制。唉,Dekker 分裂仅适用于 IEEE 754 乘法和加法的严格解释。
另一个想法是使用 C# 版本的frexp来获取 的有效数s和指数e,d并计算(Decimal)((long) (s * 4503599627370496.0d)) * <however one computes 2^e in Decimal>。