c# – 在15位数之后没有舍入的双倍到十进制

c# – 在15位数之后没有舍入的双倍到十进制,第1张

概述将“高”精度Double转换为Decimal时,由于Rounding,我将使用Convert.ToDecimal或转换为(Decimal)而失去精度. 示例: double d = -0.99999999999999956d;decimal result = Convert.ToDecimal(d); // Result = -1decimal result = (Decimal)(d); / 将“高”精度Double转换为Decimal时,由于Rounding,我将使用Convert.ToDecimal或转换为(Decimal)而失去精度.

示例:

double d = -0.99999999999999956d;decimal result = Convert.ToDecimal(d); // Result = -1decimal 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)精确地转换为十进制.

对于-1.0和1.0之间的源双d:

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;

Test it on ideone.com.

注意, *** 作d – =是精确的,即使C#以高于double的精度计算二进制浮点运算(它允许自己这样做).

这比从double到string的转换便宜,并且在结果中提供了一些额外的精度数字(对于上述四个if-then-elses,精度为4位).

备注:如果C#不允许自己以更高的精度进行浮点计算,那么一个好的技巧就是使用Dekker拆分将d分成两个值d1和d2,将每个值精确地转换为十进制.唉,Dekker分裂仅适用于对IEEE 754乘法和加法的严格解释.

另一个想法是使用C#的frexp版本来获得d的有效数和指数e,并计算(十进制)((长)(s * 4503599627370496.0d))*<然而,在Decimal>中计算2 ^ e.

总结

以上是内存溢出为你收集整理的c# – 在15位数之后没有舍入的双倍到十进制全部内容,希望文章能够帮你解决c# – 在15位数之后没有舍入的双倍到十进制所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/1243489.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存