Как проверить десятичную точность по умолчанию при преобразовании float в str?

При преобразовании float в str я могу указать количество десятичных точек, которые я хочу отобразить

'%.6f' % 0.1
> '0.100000'
'%.6f' % .12345678901234567890
> '0.123457'

Но при простом вызове str на float в python 2.7, по умолчанию он равен 12 десятичным точкам max

str(0.1)
>'0.1'
str(.12345678901234567890)
>'0.123456789012'

Где это максимальное количество десятичных точек, определенных/задокументированных? Могу ли я программно получить этот номер?

Ответы

Ответ 1

Количество отображаемых десятичных знаков будет сильно отличаться, и не будет способа предсказать, сколько из них будет отображаться в чистом Python. Некоторые библиотеки, такие как numpy позволяют устанавливать точность вывода.

Это просто из-за ограничений представления float.

В соответствующих частях ссылки рассказывается о том, как Python выбирает отображение поплавков.

Python только печатает десятичное приближение к истинному десятичному значению двоичного приближения, хранящегося на машине

Python сохраняет количество цифр, управляемых, показывая округленное значение

Теперь есть возможность перекрытия:

Интересно, что существует много разных десятичных чисел, которые имеют одну и ту же ближайшую приближенную двоичную долю

Метод выбора десятичных значений для отображения был изменен в Python 3.1 (Но последнее предложение подразумевает, что это может быть деталь реализации).

Например, числа 0,1 и 0,10000000000000001 оба приближаются к 3602879701896397/2 ** 55. Поскольку все эти десятичные значения имеют одинаковое приближение, любой из них может отображаться при сохранении инвариантного eval (repr (x)) = = x

Исторически, подсказка Python и встроенная функция repr() выбрали бы одну из 17 значащих цифр, 0.10000000000000001. Начиная с Python 3.1, Python (в большинстве систем) теперь может выбрать самый короткий из них и просто отобразить 0,1.

Ответ 2

Я не считаю, что это существует в спецификации языка python. Однако реализация cpython указывает его. Функция float_repr(), которая превращает float в строку, в конечном итоге вызывает вспомогательную функцию с форматом 'r', которая в конечном итоге вызывает функцию утилиты, которая жестко кодирует формат до того, что сводится к format(float, '.16g'), Этот код можно увидеть здесь. Обратите внимание, что это для python3.6.

>>> import math
>>> str(math.pi*4)
12.5663706144

давая максимальное число значащих цифр (как до, так и после десятичной) в 16. Похоже, что в реализации python2.7 это значение было жестко запрограммировано на .12g. Что касается того, почему это произошло (и несколько недостает документации, можно найти здесь.)

Поэтому, если вы пытаетесь получить, как долго число будет отформатировано при печати, просто получите его длину с .12g.

def len_when_displayed(n):
     return len(format(n, '.12g'))

Ответ 3

Ну, если вы ищете чистый способ выполнения python, вы всегда можете использовать что-то вроде:

len(str(.12345678901234567890).split('.')[1])
>>>> 12

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

Как вы сказали, всегда кажется, что 12 даже при кормлении больших плавающих очков.


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

def max_floating_point():
    counter = 0
    current_length = 0
    str_rep = '.1'
    while(counter <= current_length):
        str_rep += '1'
        current_length = len(str(float(str_rep)).split('.')[1])
        counter += 1

    return current_length

Это вернет вам представление максимальной длины в вашей текущей системе,

print max_floating_point()
>>>> 12

Ответ 4

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

>>> str(.123456789123456789123456789)
'0.12345678912345678'
>>> str(.111111111111111111111111111)
'0.1111111111111111'

Вы можете выбрать этот код, который реально имитирует вашу реальную ситуацию:

import random
maxdec=max(map(lambda x:len(str(x)),filter(lambda x:x>.1,[random.random() for i in range(99)])))-2

Здесь мы тестируем длину ~ 90 случайных чисел в (.1,1) открытом интервале после преобразования (и выведем 0. слева, следовательно -2). Python 2.7.5 на 64-битном Linux дает мне 12, а Python 3.4.8 и 3.6.6 дают мне 17.