为何C#中Math.Round对72.6d与82.6d的IEEE754舍入结果不同?
为何Math.Round对72.6d和82.6d的舍入结果不一致?
先看问题代码:
double x = Math.Round(72.6d, 2, MidpointRounding.ToZero); double y = Math.Round(82.6d, 2, MidpointRounding.ToZero);
执行后x的值为72.59,y的值为82.6,核心原因是double类型的二进制浮点精度特性:
根本原因
十进制小数无法被二进制浮点精确表示
double是基于IEEE754标准的双精度二进制浮点数,它无法精确存储所有十进制小数。比如十进制的0.6,转换为二进制是无限循环的小数,因此72.6d和82.6d在内存中存储的都是最接近的近似值,而非精确的72.6或82.6。两个值的近似方向不同
实际存储时:
72.6d的真实值略小于十进制的72.6,具体为72.5999999999999943...82.6d的真实值略大于十进制的82.6,具体为82.6000000000000085...
当使用MidpointRounding.ToZero(向零截断保留两位小数)时:
- 对
72.599999...截断到两位小数,实际取前两位有效小数部分,得到72.59 - 对
82.600000...截断到两位小数,前两位有效小数部分是60,因此得到82.6
你看到IEEE754转换器显示两者小数部分相同,是因为转换器通常会对存储值进行四舍五入后显示,没有展示出底层的细微差异。
修复方案的原理
你使用的(double)Math.Round(Convert.ToDecimal(72.6d), 2, MidpointRounding.ToZero)之所以有效,是因为:
decimal类型是十进制浮点类型,能精确表示十进制小数。Convert.ToDecimal(72.6d)会把double的近似值转换为精确的十进制72.6- 基于精确的十进制值执行Round操作,自然能得到符合预期的结果
内容的提问来源于stack exchange,提问作者Paul M
相关产品推荐
相关产品推荐

