Функция ceil() не возвращает ожидаемое значение

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

int(ceil(A*B))

Вот несколько примеров, иллюстрирующих проблему:

int(ceil(1.01*100)) = 101
int(ceil(1.02*100)) = 102
int(ceil(1.03*100)) = 103
int(ceil(1.04*100)) = 104
int(ceil(1.05*100)) = 105
int(ceil(1.06*100)) = 106
int(ceil(1.07*100)) = 107
int(ceil(1.08*100)) = 108
int(ceil(1.09*100)) = 110 ***
int(ceil(1.10*100)) = 111 ***
int(ceil(1.11*100)) = 112 ***
int(ceil(1.12*100)) = 113 ***
int(ceil(1.13*100)) = 113

Я понимаю, что это связано с выполнением вычисления с плавающей запятой...

1.09*100 = 109.000000.... > 109

Я понятия не имею, как надежно поймать эту ошибку

Хотя у меня есть несколько "сырых" методов, таких как описанный ниже, я не считаю это достаточно надежным решением

int(ceil((1.09*100)-0.00000001)) = 109

2 ответа

Решение

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

  • два числа x и y должны рассматриваться как равные, если | x - y | < ε
  • наибольшее целое число уступает х floor(x + ε)
  • наименьшее целое число больше, чем х ceil(x - ε)

Таким образом, предложенное вами решение является хорошим, если у вас есть способ узнать, что является хорошим значением для ε. Если вы пишете модуль, вы должны разрешить пользователям указывать его.

Вы правы, проблема заключается в ограниченной точности числа с плавающей точкой.

decimal Модуль твой друг:

from decimal import Decimal
from math import ceil

print int(ceil(Decimal("1.10") * 100))

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

Другие вопросы по тегам