浮点运算:求和与乘法的误差 [英] Floating point arithmetic: summation versus multiplication of error

查看:197
本文介绍了浮点运算:求和与乘法的误差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解这个简单例子背后的浮点运算。两个代码在理论上算术上是等价的,但显然一系列的加法比单纯的乘法增加了更多的误差。

  s = 0.0 
在范围内(10):
s + = 0.1
印刷品
print('%。30f'%s)

0.9999999999999999
0.999999999999999888977697537484

但是:

$ $ $ code $ s = 0.1
s * = 10
print(s)
print('%。30f'%s)
1.0
1.000000000000000000000000000000

我想了解幕后发生了什么。



据我所知,小数点的二进制表示形式从来都不准确,这可以通过以下方式来验证:

$ p $ print(0.1)
print('%。30f'%0.1)
0.1
0.100000000000000005551115123126

所以在一系列总和中,余数 5.55e-18 不断加在变量上,并且非常快地增长。然而,当乘法时,我预计同样的余数也会乘以,并且会增长,但是这不会发生。这是为什么?转换为二进制之前的任何优化?

解决方案

它只是如何结果四舍五入(内部,二进制) 。 0.1 转换成



0.1000000000000000055511151231257827021181583404541015625





0.0001100110011001100110011001100110011001100110011001101 二进制



将其乘以10 (1010二进制),你得到
$ b $ pre $ $ c $ 1.00000000000000000000000000000000000000000000000000
code pre >

55个有效位;四舍五入到53位,它等于1.0。

加上0.1十倍,你会经历一系列的舍入(你假设错误保持加起来的变量并且很快就会增长是错误的 - 为什么要加0.1减10小于1.0呢?)。如果您在每次迭代后打印完整的十进制值,您应该看到

  0.1000000000000000055511151231257827021181583404541015625 
0.200000000000000011102230246251565404236316680908203125
0.3000000000000000444089209850062616169452667236328125
0.40000000000000002220446049250313080847263336181640625
0.5
0.59999999999999997779553950749686919152736663818359375
0.6999999999999999555910790149937383830547332763671875
0.79999999999999993338661852249060757458209991455078125
0.899999999999999911182158029987476766109466552734375
0.99999999999999988897769753748434595763683319091796875


0.1 + 0.0001100110011001100110011001100110011001100110011001101 $ b $ p
$ b $ p

$ $ $ $ $ $ $ 0.1001100110011001100110011001100110011001100110011001101

即55位;四舍五入到53位它是

pre $ code 0.10011001100110011001100110011001100110011001100110011
$ / code>

其中小数点是

0.59999999999999997779553950749686919152736663818359375

小于0.6,尽管你可能预料会更大。


I'm trying to understand the floating point arithmetic behind this simple example. Both codes are arithmetically equivalent in theory, but obviously a series of additions adds more error than a simple multiplication.

s=0.0
for i in range(10):
    s += 0.1
print(s)
print('%.30f' % s)

0.9999999999999999
0.999999999999999888977697537484

but:

s=0.1
s *= 10
print(s)
print('%.30f' % s)
1.0
1.000000000000000000000000000000

I would like to understand what is going on behind the scenes.

I understand that the binary representation of the decimal 0.1 is never accurate, and that can be verified by:

print(0.1)
print('%.30f' % 0.1)
0.1
0.100000000000000005551115123126

So in a sequence of summations, that remainder 5.55e-18 keeps adding up to the variable and very quickly it grows.

However, when multiplying, I'd expect that the same remainder is also multiplied and it would grow, but that doesn't happen. Why is that? Any sort of optimisation before converting to binary?

解决方案

It just has to do with how results are rounded (internally, in binary). 0.1 converts to

0.1000000000000000055511151231257827021181583404541015625

which is

0.0001100110011001100110011001100110011001100110011001101 in binary.

Multiply that by 10 (1010 in binary) and you get

1.000000000000000000000000000000000000000000000000000001

That is 55 significant bits; rounded to 53 bits it equals 1.0.

Add 0.1 ten times and you'll go through a sequence of roundings (your assumption that the error "keeps adding up to the variable and very quickly it grows" is wrong -- why would adding 0.1 ten times be less than 1.0 then?). If you print the full decimal values after each iteration and you should see

0.1000000000000000055511151231257827021181583404541015625
0.200000000000000011102230246251565404236316680908203125
0.3000000000000000444089209850062616169452667236328125
0.40000000000000002220446049250313080847263336181640625
0.5
0.59999999999999997779553950749686919152736663818359375
0.6999999999999999555910790149937383830547332763671875
0.79999999999999993338661852249060757458209991455078125
0.899999999999999911182158029987476766109466552734375
0.99999999999999988897769753748434595763683319091796875

Look at what happens between 0.5 and 0.6, for example. Add the internal binary values for 0.5 and 0.1

0.1 + 0.0001100110011001100110011001100110011001100110011001101

The answer is

0.1001100110011001100110011001100110011001100110011001101

That is 55 bits; rounded to 53 bits it's

0.10011001100110011001100110011001100110011001100110011

which in decimal is

0.59999999999999997779553950749686919152736663818359375

which is less than 0.6, though you might have expected it to be greater.

这篇关于浮点运算:求和与乘法的误差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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