Math.round 错误 - 该怎么办? [英] Math.round bug - what to do?

查看:63
本文介绍了Math.round 错误 - 该怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Math.Round(8.075, 2, MidpointRounding.AwayFromZero) 返回 8.07,但它应该返回 8.08.奇怪的是,7.075 工作正常,但 9.075 也返回 9.07

Math.Round(8.075, 2, MidpointRounding.AwayFromZero) returns 8.07, though it should return 8.08. Mysteriously enough, 7.075 is working fine, but 9.075 also returns 9.07!

怎么办?有人知道没有这种错误的舍入方法吗?

What to do? Does anybody know a rounding method without such bugs?

推荐答案

如果你像人类一样用 10 根手指数数,精确表达十进制值 8.075 就没有任何问题:

If you count with 10 fingers, like humans do, you don't have any trouble expressing the decimal value 8.075 precisely:

  8.075 = 8 x 10^1 + 0 x 10^0 + 7 x 10^-1 + 5 x 10^-2

但是计算机是用 2 个手指计算的,它们需要用 2 的幂来表示该值:

But computers count with 2 fingers, they need to express that value in powers of 2:

  8.075 = 1 x 2^3  + 0 x 2^2  + 0 x 2^1  + 0 x 2^0  + 0 x 2^-1 + 0 x 2^-2 + 0 x 2^-3 + 
          1 x 2^-4 + 0 x 2^-5 + 0 x 2^-6 + 1 x 2^-7 + 1 x 2^-8 + 0 x 2^-9 + 0 x 2^-10 +
          1 x 2^-11 + ...

我放弃了打字时手指抽筋的问题,但重点是,无论您添加多少次 2 的幂,您都永远不会得到正好 8.075m.与人类永远无法精确地写出 10/3 的结果类似的问题,它在分数中有无限数量的数字.只有用 6 根手指数数才能准确写出该表达式的结果.

I gave up with finger cramp typing the terms but the point is that no matter how many powers of 2 you add, you'll never get exactly 8.075m. A similar problem to how humans can never write the result of 10 / 3 precisely, it has an infinite number of digits in the fraction. You can only write the result of that expression accurately when you count with 6 fingers.

处理器当然没有足够的存储空间来存储无限数量的位来表示一个值.所以他们必须截断数字序列,double类型的值可以存储53位.

A processor of course doesn't have enough storage to store an infinite number of bits to represent a value. So they must truncate the digit sequence, a value of type double can store 53 bits.

因此,十进制值 8.075 在存储在处理器中时会四舍五入.转换回十进制的 53 位序列是值 ~8.074999999999999289.然后,正如预期的那样,您的代码会四舍五入为 8.07.

As a result, the decimal value 8.075 gets rounded when it is stored in the processor. The sequence of 53 bits, converted back to decimal, is the value ~8.074999999999999289. Which then, as expected, gets rounded to 8.07 by your code.

如果您想要 10 指的数学结果,您需要使用以 10 为基数存储数字的数据类型.这就是 .NET 中的 System.Decimal 类型.修复:

If you want 10 finger math results, you'll need to use a data type that stores numbers in base 10. That's the System.Decimal type in .NET. Fix:

decimal result = Math.Round(8.075m, 2, MidpointRounding.AwayFromZero)

注意代码段中 8.075m 字面量中字母 m 的用法,这是一个十进制类型的字面量.其中选择了用 10 个手指计数的 Math.Round() 重载,之前您使用了使用 System.Double 的重载,即 2 手指版本.

Note the usage of the letter m in the 8.075m literal in the snippet, a literal of type decimal. Which selects the Math.Round() overload that counts with 10 fingers, previously you used the overload that uses System.Double, the 2 finger version.

请注意,使用 System.Decimal 进行计算有一个明显的缺点,它.比使用 System.Double 计算要慢得多,后者是处理器直接支持的值类型.十进制数学是在软件中完成的,而不是硬件加速.

Do note that there's a significant disadvantage to calculating with System.Decimal, it is slow. Much, much slower than calculating with System.Double, a value type that's directly supported by the processor. Decimal math is done in software and is not hardware accelerated.

这篇关于Math.round 错误 - 该怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆