为什么编程语言会缩小到.6?

时间:2010-01-06 16:19:15

标签: math language-agnostic floating-point rounding

如果你把一个小数放在一个必须四舍五入到最接近的10的格式,它是:1.55,它将舍入到1.5。然后1.56将转为1.6。在学校里,我记得当你达到5分时,你会知道你是四舍五入的,如果是4分或者以下,你就会知道。为什么它在Python等人中有所不同。

这是Python 2.6x的代码示例(无论最新版本是什么)

'{0:01.2f}'.format(5.555)  # This will return '5.55'

在尝试了一些提供的例子后,我意识到更令人困惑的事情:

'{0:01.1f}'.format(5.55)  # This will return '5.5'
# But then
'{0:01.1f}'.format(1.55)  # This will return '1.6'

为什么使用1.55 vs 5.55时有所不同。两者都被输入为文字(因此浮动)

7 个答案:

答案 0 :(得分:85)

首先,在大多数语言中,未修饰的常量(如“1.55”)被视为双精度值。但是,1.55并不能完全表示为双精度值,因为它没有二进制的终止表示。这会引起许多奇怪的行为,但是一种效果是当你输入1.55时,你实际上并没有得到正好在1.5和1.6之间的值。

在二进制中,十进制数1.55为:

1.10001100110011001100110011001100110011001100110011001100110011001100...

当你输入“1.55”时,这个值实际上会四舍五入到最接近的可表示的双精度值(在许多系统上......但是有例外,我会得到)。该值为:

1.1000110011001100110011001100110011001100110011001101

略微大于<1.5>;十进制,它正是:

1.5500000000000000444089209850062616169452667236328125

因此,当要求将此值四舍五入到小数位后的单个数字时,它会将向上舍入为1.6。这就是为什么大多数评论者说他们不能复制你所看到的行为的原因。

但等等,在你的系统上,“1.55”舍入 down ,而不是up。发生了什么事?

它可能是一些不同的东西,但最有可能的是你在一个平台(可能是Windows)上,默认使用x87指令进行浮点运算,它使用不同的(80位)内部格式。在80位格式中,1.55具有值:

1.100011001100110011001100110011001100110011001100110011001100110

略小于小于<1.5>;在十进制中,这个数字是:

1.54999999999999999995663191310057982263970188796520233154296875

因为它小于1.55,所以当它舍入到小数点后的一位数时,它会向向下舍入,给出你正在观察的结果“1.5”。

FWIW:在大多数编程语言中,默认的舍入模式实际上是“舍入到最接近,连接到偶数”。只是当你以十进制指定小数值时,你几乎从不会遇到一个确切的中间情况,所以外行人很难观察到这一点。但是,如果你看看“1.5”是如何四舍五入为零,你可以看到它:

>>> "%.0f" % 0.5
'0'
>>> "%.0f" % 1.5
'2'

请注意,这两个值都围绕偶数数字;两个都不是“1”。

修改后的问题中的

编辑,您似乎已切换到另一个python解释器,其中浮点在IEEE754双类型中完成,而不是x87 80位类型。因此,“1.55”轮 up ,如我的第一个例子,但“5.55”转换为以下二进制浮点值:

101.10001100110011001100110011001100110011001100110011

正是:

5.54999999999999982236431605997495353221893310546875
小数

;因为小于而不是5.55,所以它会向向下

答案 1 :(得分:5)

有很多方法来舍入数字。 You can read more about rounding on Wikipedia。 Python中使用的舍入方法是从零开始的一半,并且您描述的舍入方法或多或少相同(至少对于正数)。

答案 2 :(得分:2)

你能给出一些示例代码吗,因为这不是我在Python中看到的行为:

>>> "%.1f" % 1.54
'1.5'
>>> "%.1f" % 1.55
'1.6'
>>> "%.1f" % 1.56
'1.6'

答案 3 :(得分:2)

情况似乎并非如此。你正在使用“float”字符串格式化器,对吗?

>>> "%0.2f" % 1.55
'1.55'
>>> "%0.1f" % 1.55
'1.6'
>>> "%0.0f" % 1.55
'2'

答案 4 :(得分:2)

对于每种编程语言,舍入和截断都是不同的,因此您的问题可能与Python直接相关。

但是,rounding作为一种做法取决于您的方法。

您还应该知道,在许多编程语言中将小数转换为整数会产生与实际舍入数字不同的结果。

编辑:根据其他一些海报,似乎Python没有展示您所描述的舍入行为:

>>> "%0.2f" % 1.55 
'1.55' 
>>> "%0.1f" % 1.55 
'1.6' 
>>> "%0.0f" % 1.55 
'2' 

答案 5 :(得分:2)

我看不出你所描述的确切行为的原因。如果您的数字只是示例,那么类似的情况可以通过使用四舍五入来解释:

1.5 rounds to 2
2.5 rounds to 2
3.5 rounds to 4
4.5 rounds to 4

即。 a .5值将四舍五入到最接近的整数。这样做的原因是,从长远来看,对很多数字进行舍入甚至会出现问题。例如,如果一家银行要向一百万客户支付赎金,其中10%最终以0.5美分的价值进行四舍五入,那么如果这些价值被四舍五入,银行将支付500美元。

意外舍入的另一个原因是浮点数的精度。大多数数字无法准确表示,因此它们用最接近的可能近似值表示。当你认为你有一个1.55的数字时,你实际上可能会得到一个像1.54999这样的数字。将该数字舍入为一位小数当然会导致1.5而不是1.6。

答案 6 :(得分:0)

消除舍入问题的至少一个方面(至少在某些时候)的一种方法是进行一些预处理。单精度和双精度格式可以分别精确地表示从-2 ^ 24-1到2 ^ 24-1和-2 ^ 53-1到2 ^ 53-1的所有整数。使用实数(具有非零分数部分)可以做什么是

  1. 剥离标志并保留以供日后使用
  2. 将剩余的正数乘以10 ^(所需的小数位数)
  3. 如果您的环境的舍入模式设置为chop(舍入为零),则添加0.5
  4. 将数字四舍五入到最近的
  5. 将数字sprintf为格式为<0]的小数为0的字符串
  6. “手动”格式化字符串,根据sprintf后面的长度,所需的小数位数,小数点和符号
  7. 字符串现在应包含确切的数字
  8. 请注意,如果第3步之后的结果超出特定格式(上图)的范围,则答案将不正确。