Подтвердить что ты не робот

Двойная точность - десятичные разряды

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

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

4b9b3361

Ответ 1

У IEEE double есть 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 десятичных цифр точности, как и следовало ожидать.

Ответ 2

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

Ответ 3

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

Смотрите страницу Wikipedia для двойной точности и эту статью статью о плавающих Точечная точность.

Ответ 4

Двойная метка содержит 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 десятичных цифр. Даже четность не является точной. Как легко видеть, поскольку нет значения, которое начинается с 0.4?? и 0.9??, но для полной точности мы требуем 3 десятичных разряда.

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

Ответ 5

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

>>> 0.14285714285714285
0.14285714285714285
>>> 0.14285714285714286
0.14285714285714285

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

Ответ 6

Плавающая точка 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 бит, но внутри он фактически использует пару "защитных бит", что в основном означает внутреннее вычисление с несколькими дополнительными битами точности, поэтому он может округлить последнее правильно. Когда отладчик смотрит на весь регистр, он обычно найдет хотя бы одну дополнительную цифру, которая достаточно точна - хотя, поскольку эта цифра не будет иметь никаких защитных бит, она может быть не закруглена правильно.

Ответ 7

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

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