Я хочу напечатать некоторые числа с плавающей запятой, чтобы они всегда записывались в десятичной форме (например, 12345000000000000000000.0
или 0.000000000000012345
, а не в научной нотации, но я бы хотел, чтобы результат имел до ~ 15,7 значащих цифр в IEEE 754 в два раза и не более.
В идеале мне нужно , чтобы в результате была получена самая короткая строка в позиционном десятичном формате, которая при преобразовании в float
все равно приводит к тому же значению.
Хорошо известно, что repr
float
записывается в научной записи, если показатель степени больше 15 или меньше -4:
>>> n = 0.000000054321654321
>>> n
5.4321654321e-08 # scientific notation
Если используется str
, результирующая строка снова находится в научной записи:
>>> str(n)
'5.4321654321e-08'
Было предложено использовать format
с флагом f
и достаточной точностью, чтобы избавиться от научной нотации:
>>> format(0.00000005, '.20f')
'0.00000005000000000000'
Это работает для этого числа, хотя у него есть некоторые дополнительные конечные нули. Но тогда тот же формат не работает для .1
, который дает десятичные цифры сверх фактической точности вычислений с плавающей точкой:
>>> format(0.1, '.20f')
'0.10000000000000000555'
И если мой номер 4.5678e-20
, использование .20f
все равно потеряет относительную точность:
>>> format(4.5678e-20, '.20f')
'0.00000000000000000005'
Таким образом эти подходы не соответствуют моим требованиям.
Это приводит к вопросу: каков самый простой и эффективный способ печати произвольного числа с плавающей запятой в десятичном формате, имеющий те же цифры, что и в repr(n)
(или str(n)
в Python 3), но всегда используя десятичный формат, а не научную запись.
То есть функция или операция, которая, например, преобразует значение с плавающей запятой 0.00000005
в строку '0.00000005'
; С 0.1
по '0.1'
; 420000000000000000.0
- '420000000000000000.0'
или 420000000000000000
и форматирует значение с плавающей точкой -4.5678e-5
как '-0.000045678'
.
После периода вознаграждения: кажется, что есть по крайней мере 2 жизнеспособных подхода, поскольку Карин продемонстрировала, что с помощью манипуляции со строками можно добиться значительного увеличения скорости по сравнению с моим первоначальным алгоритмом на Python 2.
Таким образом,
- Если важна производительность и требуется совместимость с Python 2; или если модуль
decimal
не может быть использован по какой-либо причине, то подход Карина с использованием манипуляции со строками является способом сделать это. - На Python 3 мой мой более короткий код также будет быстрее.
Поскольку я в основном занимаюсь разработкой на Python 3, я приму собственный ответ и награду Карин за награду.