相等十进制值转浮点数后不匹配,单元测试失败原因咨询
问题原因解析
这个测试失败的核心原因在于二进制浮点数的固有局限性,以及rust_decimal内部存储与转换的细节,具体分为三点:
1. 十进制1.539无法被二进制浮点数精确表示
f64是基于二进制的浮点类型,仅能精确表示分母为2的幂的分数(比如0.5=1/2、0.25=1/4)。而1.539的分数形式是1539/1000,分母1000包含因子5³,无法被2的幂整除,因此转成f64时只能存储最接近它的二进制近似值,而非精确值。
2. 数值相等的Decimal实例,内部存储精度可能不同
虽然assert_eq!(dec!(1.539), total2)通过了,但rust_decimal的相等判断是基于数值等价,而非内部存储的完全一致:
total1是通过val1 * coef + val2直接计算得到的,内部存储为1539 × 10^-3(精确的十进制1.539)。total2是先将total1_f(total1的f64近似值)转回Decimal,再经过/coef * coef运算得到的。这个过程中,Decimal可能会以更高精度存储数值(比如带有更多尾零,或存储为与1539 ×10^-3等价但缩放因子不同的形式)。
3. 不同的Decimal内部表示,转f64时会产生不同的二进制近似
当把这两个数值等价的Decimal转成f64时,由于内部存储的数字位数和缩放因子不同,转换过程中的舍入计算会产生细微差异:
- 对于
total1(1539 ×10^-3),转换是计算1539 ÷ 1000的二进制近似。 - 对于
total2(比如可能是1539000000000000 ×10^-16),转换是计算1539000000000000 ÷ 10^16的二进制近似。
这两个计算的结果在二进制浮点数中会有极细微的比特模式差异,最终导致assert_eq!(total1_f, total2_f)失败。
内容的提问来源于stack exchange,提问作者andigor
相关产品推荐
相关产品推荐

