Странное поведение Python в то время как цикл с <сравнение - PullRequest
1 голос
/ 18 января 2012

Я запутался с этим фрагментом кода:

t=0
while  t<5:  #currently loop runs for 10 seconds
    print "in loop",t
    if (t<5):
        print "true"
    t=t+0.01

печатает в последнем цикле цикла:

in loop 5.0 
true

Теперь, если верно, что t = 5.0 на последнем проходе цикла, не должно ли быть выполнено условие, что t <5 в операторе if не будет выполнено? И, кроме того, разве он не должен проходить через цикл при t = 5, поскольку он также должен был выполнить условие while? </p>

Ответы [ 6 ]

3 голосов
/ 18 января 2012

5 не обязательно 5:

t=0
while  t<5:  #currently loop runs for 10 seconds
    print "in loop",t, repr(t)
    if (t<5):
        print "true"
    t=t+0.1

производит

in loop 0 0
true
in loop 0.1 0.1
true
in loop 0.2 0.2
true
in loop 0.3 0.30000000000000004

[...]

in loop 4.8 4.799999999999999
true
in loop 4.9 4.899999999999999
true
in loop 5.0 4.999999999999998
true

0.1 не может быть точно представленов двоичном формате.

[Ах, я только что заметил, что я использовал 0,1 вместо 0,01, как вы сделали.Ну, это та же проблема.]

Две ссылки "как работает плавающая точка": классическая и более мягкая .

1 голос
/ 18 января 2012

Значение t на последней итерации цикла близко к, но чуть меньше 5.0. Невозможно точно представить 0,01 в двоичном виде, поэтому при каждом добавлении 0,01 к t появляется небольшая ошибка. Python считает результат достаточно близким к 5,0, чтобы напечатать «5,0», но на самом деле это не совсем 5,0.

Чтобы заставить его работать так, как вы ожидаете, используйте Decimal, который не страдает от этих ошибок округления.

from decimal import Decimal
t=Decimal("0")
while  t<5:
    print "in loop",t
    if (t<5):
        print "true"
    t=t+Decimal("0.01")
1 голос
/ 18 января 2012

Это потому, что значения округлены для печати.Это абсолютно то, что можно ожидать.

Если вам нужно избежать этого поведения, то либо отформатируйте выходные данные по-другому, либо используйте соответствующую дельту для проверки, например, 5.0 - t < delta

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

Если это недопустимо в вашем приложении, альтернативой является использованиедесятичный класс, который использует десятичное представление внутри.

0 голосов
/ 18 января 2012

Еще один способ взглянуть на это состоит в том, что 0.1 в двоичном виде аналогичен 1/3 в базе 10 (то есть 0.333333). Он не может быть представлен конечным числом цифр. Когда вы набираете 0.1, Python преобразует его в двоичный файл, но (очевидно) делает это, используя конечное число битов, и, следовательно, это не точно 0.1. Итак, в основном, что здесь происходит, с гипотетическим компьютером, который работает в базе 10:

count = 0
while count != 1:
    count += 0.33333333333

Конечно, количество никогда точно не будет 1, и цикл while будет продолжать работать.

0 голосов
/ 18 января 2012

Исходя из рекомендации Марцина об использовании дельты, вот работоспособное решение:

>>> step = 0.01
>>> t = 4.9
>>> while 5.0 - t > step:
        print 'in loop', t
        t += step


in loop 4.9
in loop 4.91
in loop 4.92
in loop 4.93
in loop 4.94
in loop 4.95
in loop 4.96
in loop 4.97
in loop 4.98
in loop 4.99
0 голосов
/ 18 января 2012

Проблема в точности ошибки. Если вы измените это на:

t=0
while  t<5:  #currently loop runs for 10 seconds
    print "in loop",repr(t)
    if (t<5):
        print "true"
    t=t+0.01

вы увидите, что последний раз через цикл t на самом деле что-то вроде 4.999999999999938.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...