Странная ошибка добавления Python

Возможный дубликат:
python - проблемы с десятичными разрядами с числами с плавающей запятой
Странность равенства чисел с плавающей запятой в Python

В приведенном ниже коде у меня есть переменная percentage, которая является плавающей. Я настроил его так, что если number достигнет 10,000, percentage, предположительно, вырастет на .01.

# Tries to find a number that when squared and 5%'ed is still a square.

import math

print("Script has started:\n")

percentage = .1
number = 1
while number != -1:
    number = number + 1
    num_powered = number ** 2
    num_5per = num_powered * percentage
    num_5per_sqrt = math.sqrt(num_5per)
    num_list = list(str(num_5per_sqrt))
    dot_location = num_list.index(".")
    not_zero = 0
    for x in num_list[dot_location + 1:]:
        if x != "0":
            not_zero = 1
            break
    if not_zero == 0:
        print("*********************************")
        print("Map :",number)
        print("Safe-Area :",num_5per_sqrt)
        print("Percentage :",percentage)
        print("*********************************")
        input()

    if number > 10000:
              number = 0
              percentage = percentage + .01
              print(percentage)

Вывод:

0.11
0.12
0.13
0.14
0.15000000000000002  # Here is where it goes crazy
0.16000000000000003

person RandomPhobia    schedule 08.08.2012    source источник
comment
Это невероятно часто. Числа с плавающей запятой в компьютере имеют основание 2, и они не могут точно представить многие числа, которые являются естественными в базе 10.   -  person Mark Ransom    schedule 09.08.2012
comment
Это НЕ ошибка. Это следствие того, как работают переменные с плавающей запятой. См. docs.oracle.com/cd/E19957-01/806 -3568 / ncg_goldberg.html. Голосование закрыть как дублирующее.   -  person Chinmay Kanchi    schedule 09.08.2012
comment
о, я вижу, спасибо, потом извини, что погуглил, но не видел дубликата.   -  person RandomPhobia    schedule 09.08.2012
comment
Это недоразумение настолько распространено, что на самом деле упоминается не только в вики-странице stackoverflow по плавающей запятой, но также и в Википедия.   -  person phihag    schedule 09.08.2012


Ответы (4)


Из документации Python

Обратите внимание, что это заложено в самой природе двоичных чисел с плавающей запятой: это не ошибка в Python, и это также не ошибка в вашем коде (выделено мной). Вы увидите одно и то же на всех языках, поддерживающих арифметику с плавающей запятой вашего оборудования (хотя некоторые языки могут не отображать разницу по умолчанию или во всех режимах вывода)

Вероятно, вам следует использовать модуль decimal.

person supervacuo    schedule 08.08.2012
comment
Эта ссылка - невероятно хорошее объяснение феномена, я никогда его раньше не видел. Я предлагаю всем, кто все еще не понимает, прочитать его полностью. - person Mark Ransom; 09.08.2012

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

Вы можете решить свою проблему несколькими способами.

  • Согласитесь, что результаты не совсем точны, или
  • Умножьте все на 100 и работайте с целыми числами или
  • Используйте тип Decimal.

Пример:

from decimal import Decimal
percentage = Decimal('0.1')
step = Decimal('0.01')
percentage += step
person Mark Byers    schedule 08.08.2012
comment
+1 за список распространенных способов решения этой проблемы. - person Steven Rumbalski; 09.08.2012

Поплавки не обладают бесконечной точностью, и поэтому вы получаете такое странное поведение.

Лучшим решением было бы сохранить ваш процент в виде целого числа, представляющего десятые доли процента, с увеличением на единицу.

e.g.:

percent_as_integer += 1

вместо

percent_as_float += 0.01

Если вы хотите отобразить процент, просто выполните:

print "%d.%02d" % divmod(percent_as_integer, 100)

РЕДАКТИРОВАТЬ: На самом деле, использование десятичного модуля вместо этого, как было предложено в другом ответе, вероятно, является лучшим, более питоническим решением.

person Gordon Bailey    schedule 08.08.2012

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

Если вам нужно точное представление десятичных чисел (например, для бухгалтерского учета и бизнес-приложений), вы должны использовать decimal тип, а не с плавающей точкой. Вы также можете использовать модуль cdecimal, который представляет собой высокопроизводительную реализацию десятичного типа. .

Обновление: начиная с Python v3.3, встроенный десятичный модуль реализован на C.

person Mohammad Alhashash    schedule 08.08.2012