Может кто-нибудь объяснить это поведение с плавающей точкой? - PullRequest
4 голосов
/ 25 марта 2011

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

Я полагаю, что это сводится к этому (запуск 64-битного Python):

>>> sys.maxint
9223372036854775807
>>> float(sys.maxint)
9.2233720368547758e+18

Python использует представление IEEE 754 с плавающей точкой, которое фактически имеет 53 бита для значащего.Однако, насколько я понимаю, значимое в приведенном выше примере потребует 57 бит (56, если вы опустите подразумеваемое начальное значение 1) для представления.Может кто-нибудь объяснить это несоответствие?

Ответы [ 3 ]

6 голосов
/ 25 марта 2011

Возможно, следующее поможет прояснить ситуацию:

>>> hex(int(float(sys.maxint)))
'0x8000000000000000L'

Это показывает, что float(sys.maxint) на самом деле является степенью 2. Следовательно, в двоичном коде его мантисса точно равна 1.В IEEE 754 подразумевается ведущий 1., поэтому в машинном представлении мантисса этого числа состоит из всех нулевых битов.

Фактически, битовая комбинация IEEE, представляющая это число, выглядит следующим образом:

0x43E0000000000000

Заметьте, что только первые три полубайта (знак и показатель степени) отличны от нуля.Значение и состоит исключительно из нулей.Таким образом, для представления не требуется 56 (и даже 53) битов.

2 голосов
/ 25 марта 2011

Вы не правы. Требуется 1 бит.

>>> (9.2233720368547758e+18).hex()
'0x1.0000000000000p+63'
1 голос
/ 10 апреля 2011

Когда вы конвертируете sys.maxint в число с плавающей запятой или в двойное число, результат в точности равен 0x1p63, потому чтозначение содержит только 24 или 53 бита (включая неявный бит), поэтому завершающие биты вызывают округление в большую сторону. (sys.maxint равен 2 ^ 63 - 1, а при округлении получается 2 ^ 63.)

Затем, когда вы печатаете это число, некоторые подпрограммы форматируют его как десятичное число. Для этого он рассчитывает цифры для представления 2 ^ 63. Тот факт, что он способен печатать 9.2233720368547758e + 18, не означает, что исходное число содержит биты, которые отличают его от 9.2233720368547759e + 18. Это просто означает, что биты в нем действительно представляют 9,2233720368547758e + 18 (приблизительно). Фактически, следующее представимое число с плавающей точкой с двойной точностью - 9223372036854777856 (приблизительно 9,2233720368547778e + 18), что равно 2 ^ 63 + 2048. Таким образом, младшие 11 битов этих целых чисел отсутствуют в двойном. Форматер просто отображает число, как будто эти биты равны нулю.

...