C#中将decimal转换为double时是否会出现精度丢失问题?
问题1:decimal转double是否会丢失精度?
会,存在两类触发精度丢失的场景:
- 当
decimal类型的_c有效十进制位数超过double支持的15~16位有效数字范围时,转换会触发舍入丢失精度 - 当
_c的十进制值本身无法被double(二进制浮点类型)精确表示时(比如0.1这类分母含2以外质因数的十进制小数),转换后也会是近似值,只不过大部分业务场景下只要精度要求不超过15位有效数字,误差会小到可以被默认的显示规则舍入为预期值。
你当前使用的转换计算方案,只要业务对结果的精度要求不超过15位有效数字,且数值范围在double的正常表示区间内,基本可以满足需求。
问题2:double通常在什么场景下会出现精度丢失?
主要分存储和运算两个阶段的触发场景:
- 存储阶段:存入的十进制值无法转换为分母为2的整数次幂的分数,所有这类十进制小数在
double中都是以近似值存储的,比如0.01、0.2、68.24都属于这类值 - 运算阶段:
- 两个量级差异过大的
double值做加减运算,小值会被直接舍入丢弃,比如1e17 + 1的运算结果还是1e17 - 多次迭代运算,单次的微小误差经过多次累积后会放大到不可接受的范围
- 两个近似值做减法运算时如果结果量级远小于输入值,误差会被直接放大,也就是你遇到的
68.24减0.01的场景
- 两个量级差异过大的
问题3:调试器显示a、b为精确值、转decimal也精确,直接double运算却不精确的原因
- 调试器显示
double值时做了默认舍入,不会输出double存储的完整精度值,只会输出到大多数场景下可接受的小数位数,所以你看到的68.24是舍入后的结果,不是double实际存储的近似值。 - C#中
double转decimal的规则是取double值最接近的、保留15位有效数字的十进制表示,刚好你用的68.24、0.01在15位有效数字范围内可以精确表示为你预期的十进制值,因此转decimal后可以得到精确值做十进制运算。 - 直接用
double做减法时,两个本身就带微小误差的近似值相减,误差被放大到了调试器默认舍入也无法掩盖的程度,所以会显示出68.22999999999999这类不符合预期的结果。
内容的提问来源于stack exchange,提问作者helgez
相关产品推荐
相关产品推荐

