1

经过进一步调查,这一切都归结为:

(decimal)((object)my_4_decimal_place_double_value_20.9032)

施法两次后变为20.903199999999998


Math.Round(...)我有一个双精度值,通过值为 20.9032四舍五入到小数点后 4 位

在我的开发环境中,它按原样显示。

但在发布环境中,显示为 20.903199999999998

之后没有任何操作,Math.Round(...)但该值已被复制并分配。

这怎么可能发生?

更新: 数据不是从数据库加载的。

返回值 fromMath.Round()分配给原始双变量。

如果此信息有帮助,Release 和 dev 是相同的架构。

4

2 回答 2

2

IEEE754 双精度浮点数不能表示 20.9032。最准确的表示是 2.09031999999999982264853315428E1,这就是您在输出中看到的。

不要用 round 格式化数字,而是使用 double.ToString(string formatString) 方法的字符串格式。

请参阅Double.ToString Method (String) 的msdn 文档

Release 和 Debug 构建之间的区别可能是针对发布构建完成的一些优化,但在我看来这是详细的方法。在我看来,核心问题是您尝试使用数学运算格式化文本输出。对不起,但我不知道具体是什么造成了不同的行为。

于 2013-08-06T07:40:59.043 回答
2

根据 CLR ECMA 规范:

浮点数(静态、数组元素和类的字段)的存储位置是固定大小的。支持的存储大小为 float32 和 float64。在其他任何地方(在评估堆栈上,作为参数、作为返回类型和作为局部变量)浮点数都使用内部浮点类型表示。在每个这样的例子中,变量或表达式的名义类型是 R4 或 R8,但它的值可以在内部用额外的范围和/或精度表示。内部浮点表示的大小取决于实现,可以变化,并且应具有至少与所表示的变量或表达式一样大的精度。从存储加载这些类型时,执行从 float32 或 float64 到内部表示的隐式扩展转换。内部表示通常是硬件的本机大小,或者是有效执行操作所需的大小。

翻译一下,生成的 IL 将是相同的(除了调试模式在某些地方插入 nop 以确保断点是可能的,它也可能故意维护一个释放模式认为不必要的临时变量。)......但 JITter 不那么激进在处理标记为调试的程序集时。发布版本倾向于将更多的浮点值移动到 80 位寄存器中;调试版本倾向于直接从 64 位内存存储中读取。

如果您想要“精确”的浮点数打印,请使用string.Substring(...)而不是Math.Round

于 2013-08-06T07:22:16.973 回答