Доступна ли произвольная точность с плавающей запятой?
Просто ради удовольствия и потому, что это было действительно легко, я написал короткую программу для генерации прививочных чисел, но из-за проблем с точностью с плавающей запятой в ней не удается найти некоторые из более крупных примеров.
defisGrafting(a): for i in xrange(1, int(ceil(log10(a))) + 2): if a == floor((sqrt(a) * 10**(i-1)) % 10**int(ceil(log10(a)))): return1
a = 0 while(1): if (isGrafting(a)): print"%d %.15f" % (a, sqrt(a)) a += 1
В этом коде отсутствует по крайней мере одно известное число прививки. 9999999998 => 99999.99998999999999949999999994999999999374999999912... Кажется, что после умножения на 10**5 снижается дополнительная точность.
Итак, я написал короткую программу на C ++, чтобы посмотреть, был ли это мой процессор, усекающий число с плавающей запятой, или python каким-то образом.
Похоже, что я сильно превышаю пределы точности с плавающей запятой, и центральный процессор отключает оставшиеся биты, потому что он думает, что оставшаяся разница - это ошибка с плавающей запятой. Есть ли способ обойти это в Python? Или мне нужно перейти на C и использовать GMP или что-то в этом роде?
Переведено автоматически
Ответ 1
В стандартной библиотеке decimal модуль может быть тем, что вы ищете. Кроме того, я обнаружил, что mpmath весьма полезен. В документации также есть много отличных примеров (к сожалению, на моем офисном компьютере не mpmath установлено; в противном случае я бы проверил несколько примеров и опубликовал их).
Однако есть одно предостережение по поводу decimal модуля. Модуль содержит несколько встроенных функций для простых математических операций (например, sqrt), но результаты этих функций не всегда могут соответствовать соответствующей функции в math или других модулях с более высокой точностью (хотя они могут быть более точными). Например,
from decimal import * import math
getcontext().prec = 30 num = Decimal(1) / Decimal(7)
math.sqrt: 0.37796447300922719758631274089566431939601898193359375 decimal.sqrt: 0.377964473009227227214516536234 actual value: 0.3779644730092272272145165362341800608157513118689214
что, как указано, не совсем то, что вы ожидаете, и вы можете видеть, что чем выше точность, тем меньше совпадают результаты. Обратите внимание, что decimal модуль действительно обладает большей точностью в этом примере, поскольку он более точно соответствует фактическому значению.
Ответ 2
Для этой конкретной проблемы decimal - отличный способ, потому что он хранит десятичные цифры в виде кортежей!
Поскольку вы ищете свойство, которое наиболее естественно выражается в десятичной системе счисления, немного глупо использовать двоичное представление. На странице Википедии, на которую вы ссылаетесь, не указано, сколько "непрививаемых цифр" может появиться до начала "прививаемых цифр", поэтому это позволяет вам указать:
>>> defisGrafting(dec, max_offset=5): ... dec_digits = dec.as_tuple().digits ... sqrt_digits = dec.sqrt().as_tuple().digits ... windows = [sqrt_digits[o:o + len(dec_digits)] for o inrange(max_offset)] ... return dec_digits in windows ... >>> isGrafting(decimal.Decimal(9999999998)) True >>> isGrafting(decimal.Decimal(77)) True
Я думаю, есть большая вероятность, что результат Decimal.sqrt() будет более точным, по крайней мере, для этого, чем результат math.sqrt() из-за преобразования двоичного представления в десятичное. Рассмотрим следующее, например:
Вы можете попробовать использовать Decimal вместо floatingpoint .
Ответ 4
В Python нет встроенных плавающих значений произвольной точности, но есть пакеты Python сторонних производителей, которые используют GMP: gmpy и PyGMP.