Двойная точность - десятичные разряды - PullRequest
36 голосов
/ 03 апреля 2012

Из того, что я прочитал, значение типа данных double имеет приблизительную точность 15 десятичных знаков.Однако, когда я использую число, десятичное представление которого повторяется, такое как 1.0 / 7.0, я нахожу, что переменная содержит значение 0.14285714285714285 - 17 мест (через отладчик).

Я хотел бы знатьпочему он представлен как 17 мест внутри и почему точность 15 всегда записывается в ~ 15?

Ответы [ 7 ]

35 голосов
/ 03 апреля 2012

Двойной IEEE имеет 53 значащих бита (это значение DBL_MANT_DIG в <cfloat>).Это примерно 15,95 десятичных цифр (log10 (2 53 ));реализация устанавливает DBL_DIG на 15, а не на 16, потому что оно должно округляться.Таким образом, у вас есть почти дополнительная десятичная цифра точности (помимо того, что подразумевается DBL_DIG==15) из-за этого.

Функция nextafter() вычисляет ближайшее представимое число для данного числа;его можно использовать, чтобы показать, насколько точным является данное число.

Эта программа:

#include <cstdio>
#include <cfloat>
#include <cmath>

int main() {
    double x = 1.0/7.0;
    printf("FLT_RADIX = %d\n", FLT_RADIX);
    printf("DBL_DIG = %d\n", DBL_DIG);
    printf("DBL_MANT_DIG = %d\n", DBL_MANT_DIG);
    printf("%.17g\n%.17g\n%.17g\n", nextafter(x, 0.0), x, nextafter(x, 1.0));
}

выдает мне вывод в моей системе:

FLT_RADIX = 2
DBL_DIG = 15
DBL_MANT_DIG = 53
0.14285714285714282
0.14285714285714285
0.14285714285714288

(Вы можете заменить %.17g, скажем, %.64g, чтобы увидеть больше цифр, ни одна из которых не является значимой.)

Как видите, последняя отображаемая десятичная цифра изменяется на 3 с каждым последующим значением.Тот факт, что последняя отображаемая цифра 1.0/7.0 (5) соответствует математическому значению, в значительной степени совпадает;это была удачная догадка.И правильная округленная цифра - 6, а не 5.Замена 1.0/7.0 на 1.0/3.0 дает следующий вывод:

FLT_RADIX = 2
DBL_DIG = 15
DBL_MANT_DIG = 53
0.33333333333333326
0.33333333333333331
0.33333333333333337

, который показывает примерно 16 десятичных цифр точности, как и следовало ожидать.

15 голосов
/ 03 апреля 2012

На самом деле это 53 двоичных разряда, что переводит в 15 устойчивых десятичных знаков, а это означает, что если вы округлите начало с числом с 15 десятичными разрядами, преобразуйте его в double, а затем округлите обратно doubleдо 15 знаков после запятой вы получите тот же номер.Чтобы однозначно представить double, вам нужно 17 десятичных знаков (это означает, что для каждого числа с 17 десятичными знаками есть уникальный ближайший double), поэтому 17 мест отображаются, но не все 17-значные числа отображаются на разныеdouble значений (как в примерах в других ответах).

12 голосов
/ 03 апреля 2012

Десятичное представление чисел с плавающей запятой довольно странно. Если у вас есть число с 15 десятичными разрядами, и вы конвертируете его в double, а затем распечатаете его точно с 15 десятичными разрядами, вы должны получить такое же число. С другой стороны, если вы распечатаете произвольный double с 15 десятичными разрядами и преобразуете его обратно в double, вы не обязательно получите то же значение обратно - вам потребуется 17 десятичный места для этого. И ни 15, ни 17 десятичных знаков недостаточно для точного отображения точного десятичного эквивалента произвольного double. В общем, вам нужно более 100 знаков после запятой , чтобы сделать это точно.

См. на странице Википедии о двойной точности и этой статье о точности с плавающей точкой .

7 голосов
/ 03 апреля 2012

Двойной тип точно содержит 53 двоичных знака, что составляет ~ 15,9545898 десятичных знаков. Отладчик может показывать столько цифр, сколько пожелает, чтобы быть более точным по отношению к двоичному значению. Или может потребоваться меньше цифр и двоичного числа, например, 0,1 занимает 1 цифру в базе 10, но бесконечно в базе 2.

Это странно, поэтому я покажу крайний пример. Если мы создаем сверхпростое значение с плавающей запятой, которое содержит только 3 двоичные цифры точности, и не содержит ни мантиссы, ни знака (поэтому диапазон равен 0–0,875), наши варианты:

binary - decimal
000    - 0.000
001    - 0.125
010    - 0.250
011    - 0.375
100    - 0.500
101    - 0.625
110    - 0.750
111    - 0.875

Но если вы сделаете цифры, этот формат будет точен только до 0,903089987 десятичных цифр. Даже 1 цифра не является точной. Как легко видеть, поскольку нет значения, начинающегося с 0.4?? или 0.9??, и, тем не менее, для отображения полной точности нам требуется 3 десятичных знака.

tl; dr: отладчик показывает вам значение переменной с плавающей запятой с некоторой произвольной точностью (19 цифр в вашем случае), которая не обязательно коррелирует с точностью Формат с плавающей запятой (17 цифр в вашем случае).

4 голосов
/ 03 апреля 2012

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

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

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

Многие (большинство?) Отладчики фактически смотрят содержимое всего регистра.На x86 это 80-битное число.Модуль с плавающей запятой x86 обычно настраивается для выполнения вычислений с 64-битной точностью - но внутри он фактически использует пару «защитных битов», что в основном означает, что он выполняет вычисления с несколькими дополнительными битами точности, поэтомуон может правильно округлить последний.Когда отладчик просматривает весь регистр, он обычно находит хотя бы одну дополнительную цифру, которая достаточно точна - хотя, так как эта цифра не будет иметь защитных битов, она может быть неправильно округлена.

3 голосов
/ 03 апреля 2012

Это потому, что он конвертируется из двоичного представления.Тот факт, что он напечатал все эти десятичные цифры, не означает, что он может представлять все десятичные значения с такой точностью.Возьмем, к примеру, это в Python:

>>> 0.14285714285714285
0.14285714285714285
>>> 0.14285714285714286
0.14285714285714285

Обратите внимание, как я изменил последнюю цифру, но она все равно напечатала тот же номер.

1 голос
/ 10 июня 2012

В большинстве случаев, когда используются значения double, расчеты будут иметь определенную степень неопределенности.Разница между 1.33333333333333300 и 1.33333333333333399 может быть меньше, чем неопределенность, которая существует в расчетах.Отображение значения «2/3 + 2/3» как «1.33333333333333» может быть более значимым, чем отображение «1.33333333333333319», поскольку последнее отображение подразумевает уровень точности, которого на самом деле не существует.

Однако в отладчике важно однозначно указать значение, содержащееся в переменной , включая, по существу, бессмысленные биты точности .Было бы очень странно, если бы отладчик отображал две переменные, содержащие значение «1.333333333333333», когда одна из них фактически имела значение 1.33333333333333319, а другая - 1.33333333333333294 (это означает, что, хотя они выглядели одинаково, они не были равны).Дополнительная точность, отображаемая отладчиком, не способна представить численно правильный результат вычисления, но указывает, как код будет интерпретировать значения, содержащиеся в переменных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...