Превосходная разница при печати Python и С++ удваивается

В настоящее время я удивляюсь этому:

С++ 11

#include <iostream>
#include <iomanip>
#include <limits>

int main()
{
  double d = 1.305195828773568;
  std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << d << std::endl;
  // Prints  1.3051958287735681
}

Python

>>> repr(1.305195828773568)
'1.305195828773568'

Что происходит, почему дополнительный 1 в С++?

До сих пор я думал, что С++ и Python используют один и тот же 64-битный IEEE-дубликат под капотом; обе функции форматирования должны печатать полную точность.

Ответы

Ответ 1

вы можете заставить python также напечатать 1 (и еще многие из следующих цифр):

print('{:.16f}'.format(1.305195828773568))
# -> 1.3051958287735681

из https://docs.python.org/2/tutorial/floatingpoint.html:

>>> 7205759403792794 * 10**30 // 2**56
100000000000000005551115123125L

В версиях до Python 2.7 и Python 3.1 Python округлил это значение до 17 значащих цифр, давая "0,10000000000000001. В текущие версии, Python отображает значение на основе кратчайшего десятичная дробь, которая правильно вернется к истинному двоичному значению, в результате просто в 0.1.

"распечатать полную точность" сложно: какая полная точность? представление поплавков двоично; только доли степеней 2 могут быть представлены точно (до полной точности); большинство десятичных дробей не могут быть представлены точно в базе 2.

но float в памяти будет одинаковым для python и С++; это просто строковое представление, которое отличается.

Ответ 2

Когда формат заканчивается с использованием нотации с фиксированной точкой, precision() указывает количество дробных цифр. Поскольку в вашем примере есть дополнительные дробные цифры, создается еще один, чем те, которые могут быть безопасно представлены.

При использовании научной нотации общее число цифр подсчитывается, и вы получите те же цифры, что и оригинал (плюс показатель, конечно). Параметры C и С++ для форматирования чисел с плавающей запятой на самом деле довольно плохи. В частности, нет опции, которая позволяет форматеру принимать правильное количество цифр, хотя базовый алгоритм может фактически определить их.

Ответ 3

Взято из ответа на этот вопрос:

Плавающая точка IEEE 754 выполняется в двоичном формате. Нет точного преобразования из заданного количества бит в заданное число десятичных цифр. 3 бита могут содержать значения от 0 до 7, а 4 бита могут содержать значения от 0 до 15. Значение от 0 до 9 принимает примерно 3,5 бита, но это также не точно.

Число двойной точности IEEE 754 занимает 64 бита. Из них 52 бит посвящены значению (остальные - знаковый бит и показатель степени). Поскольку значение (обычно) нормализуется, подразумевается 53-й бит.

Теперь, учитывая 53 бит и примерно 3,5 бит на цифру, простое деление дает нам 15.1429 цифр точности. Но помните, что 3,5 бит на десятичную цифру - это всего лишь приближение, а не вполне точный ответ.

Этот странный .1429 после того, как вы указали 15 цифр, вероятно, является виновником добавленного 1.

Для чего это стоит, Python написал это на своем сайте:

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