2017-02-08 30 views
0

Итак, до 10000 единиц будет добавлено значение 1/10000 10000 раз. Логически это дает 10001. Однако из-за размытия это не происходит, что связано с ограничениями хранения. Результат 10000.999999992928. Я нахожусь там, где происходит размывание, который находится во втором дополнения:Арифметика машины и смазывание: добавление большого небольшого числа

1: 10000.0001 
2: 10000.000199999999 
3: 10000.000299999998 
4: 10000.000399999997 
etc... 

Однако, захватывая, почему произошло размытие, где борьба лежит. Я написал код для создания плавающей точки двоичных чисел, чтобы увидеть, произошли ли здесь размазывании

So 10000 = 10011100010000 or 1.001110001*10**13 while 

0.0001= 0.00000000000001101001 or 

1.1010001101101110001011101011000111000100001100101101*2**(-14) 

then 10000.0001 = 10011100010000.00000000000001101001 

Теперь размазывание происходит в следующем добавлении. Это имеет отношение к размеру мантиссы? Почему это происходит только на этом этапе? Просто интересно знать. Сначала я собираюсь добавить все 1/10000, а затем добавить его в 10000, чтобы избежать smaering.

+0

Возможно, вам лучше найти хорошее общее руководство по представлениям с плавающей точкой. Я бы рекомендовал [* Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] Дэвида Голдберга] (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html), или, для более мягкой езды, [* Плавучий путеводитель * Веб-сайт] (http://floating-point-gui.de/). –

ответ

0

Небольшой «размытию» ошибка для одного дополнения может быть вычислен точно так, как

a=10000; b=0.0001 
err = ((a+b)-a)-b 
print "err=",err 

>>> err= -7.07223084891e-13 

округления погрешность дополнения имеет размера (abs(a)+abs(b))*mu/2 или вокруг 1e4 * 1e-16 = 1e-12, который прекрасно подходит вычисленный результату. В целом вам также нужно проверить выражение ((a+b)-b)-a, но один из них всегда равен нулю, здесь последний.

И действительно, эта одношаговая ошибка, накопленная на всех этапах, уже дает наблюдаемый результат, вторичные ошибки, связанные с медленным увеличением суммы в качестве первого члена в каждом добавлении, оказывающего гораздо более низкое воздействие.

print err*10000 
>>> -7.072230848908026e-09 
print 10001+err*10000 
>>> 10000.999999992928 
0

Основная проблема заключается в том, что 1/10000 т.е. 0.0001 не может быть закодирован именно в качестве значения машины поплавка (см стандарт IEEE 754), так как 10000 не является степенью 2. Также 1/10 = 0.1 не может быть закодирован как машины поплавка, так что вы будете испытывать phanomena как 0.1 + 0.1 + 0.1 > 0.3.

При вычислении с двойной точностью (64 бит) имеет место следующее:

1.0001 - 1 < 0.0001 
10000.0001 + 9999*0.0001 == 10001 

Так что я предполагаю, что вы вычисления с одинарной точностью (32 бит)?