Почему некоторые очень близкие плавающие числа вызывают такое расхождение в этом коде Python с 3.4.x по крайней мере до версии 3.6.6? - PullRequest
1 голос
/ 29 марта 2019

Когда я выполняю этот код, он генерирует арифметическую дивергенцию или нет с очень близкими числами с плавающей запятой, это происходит, когда числа имеют вид 2 ** np / q может дать приемлемый результат и иногда очень быструю дивергенцию.Я прочитал некоторую документацию по арифметике с плавающей точкой, но я думаю, что дело не в этом, а где?Если у кого-то есть идея, я буду очень рад разобраться в этом вопросе ...

Я попытался выполнить код на Python 3.4.5 (32 бита), и я попробовал его в Интернете с repl.it ибрелок здесь url [https://trinket.io/python3/d3f3655168] результаты были похожи.

#this code illustrates arithmetical divergence with floating point numbers
# on Python 3.4 an 3.6.6

def ErrL(r):
    s=1
    L=[]
    for k in range(10):
        s=s*(r+1)-r
        L.append(s)
    return L

print(ErrL(2**11-2/3.0)) # this number generate a fast divergence in loop for
#[0.9999999999997726, 0.9999999995341113, 0.9999990457047261, 0.9980452851802966, -3.003907522359441, -8200.33724163292, -16799071.44994476, -34410100067.30351, -70483354973240.67, -1.4437340543685667e+17]

print(ErrL(2**12-1/3.0)) # this number generate a fast divergence in loop for
#[0.9999999999995453, 0.9999999981369001, 0.9999923674999991, 0.968732191662184, -127.09378815725313, -524756.5521508802, -2149756770.9781055, -8806836909202.637, -3.607867520470422e+16, -1.4780230608860496e+20]

print(ErrL(2**12-1/10.0)) # this number generate a fast divergence in loop for
#[0.9999999999995453, 0.9999999981369001, 0.9999923670652606, 0.9687286296662023, -127.11567712053602, -524876.117595124, -2150369062.0754633, -8809847014512.865, -3.609306223376185e+16, -1.478696666654989e+20]

print(ErrL(2**12-1/9.0)) # no problem here
#[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]

print(ErrL(2**12-1/11.0)) # no problem here
#[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]

То, что я ожидаю, это, очевидно, вектор из десяти!

Ответы [ 2 ]

2 голосов
/ 29 марта 2019

При выполнении этого кода с Python 2, / между целыми числами означает целочисленное деление (которое теперь называется // в Python 3).

Таким образом, в этом случае, 2/3, 1/3 и так далее равны 0, и вы получите ErrL(2**11), ..., который всегда будет равен 1.

В Python 3 2/3 - это число с плавающей точкой, а не 0,что объясняет, почему вы получаете разные результаты.

1 голос
/ 29 марта 2019

Причиной, по которой расхождение очень быстро, является математика.Если вы напишите f(s) = (r+1) * s - r, станет очевидно, что производная является константой r+1.Согласно википедии 64 бита числа с плавающей запятой в представлении IEE 754 имеют мантиссу в 53 бита.При r, близком к 2**11, ошибка в последнем бите потребует, чтобы менее 5 шагов стали близкими к 1. А с числами, близкими к 2 **12, она взорвется на 5-й итерации, что и получается.

Фу, математика, которую я выучил 40 лет назад, до сих пор не сломана ...

...