Является ли наиболее значительная десятичная цифра точностью, которая может быть преобразована в двоичную и обратно в десятичную без потери значимости 6 или 7.225?
Я встретил две различные формулы точности для чисел с плавающей запятой.
⌊ (N-1) log 10 (2) ⌋ = 6 десятичных цифр (Single-precision)
и
N log 10 (2) & асимп. 7.225 десятичных цифр (Single-precision)
Где N = 24 Значительные биты (Single-precision)
Первая формула находится в верхней части страницы 4 " IEEE Standard 754 для двоичной арифметики с плавающей запятой", написанной профессором W Кахан.
Вторая формула найдена в статье Википедии " Формат с плавающей запятой с одинарной точностью в разделе IEEE 754 с двойной точностью, точечный формат: binary32.
По первой формуле профессор В. Кахан говорит
Если десятичная строка с не более 6 sig. dec. преобразуется в Single, а затем преобразуется обратно в одно и то же число sig. Декабре, то окончательная строка должна соответствовать оригиналу.
Для второй формулы, Wikipedia говорит
... общая точность 24 бита (эквивалентно log 10 (2 24) ≈ 7.225 десятичных цифр).
Результаты обеих формул (6 и 7,225 десятичных цифр) различны, и я ожидал, что они будут одинаковыми, поскольку я предположил, что они оба предназначены для представления наиболее значимых десятичных цифр, которые могут быть преобразованы в двоичные и с плавающей запятой затем преобразуется обратно в десятичное с тем же числом значащих десятичных цифр, с которого он начинался.
Почему эти два числа отличаются друг от друга, и какова самая значимая десятичная цифра, которая может быть преобразована в двоичную и обратно в десятичную без потери значимости?
Ответы
Ответ 1
какова самая значительная точность десятичных цифр, которая может быть преобразован в двоичный и обратно в десятичный без потери значимости?
Самая значительная точность десятичных цифр, которая может быть преобразована в двоичную и обратно в десятичную без потери значимости (для чисел с плавающей запятой с одинарной точностью или 24 бита), составляет 6 десятичных цифр.
Почему эти два числа отличаются...
Числа 6 и 7.225 отличаются друг от друга, потому что они определяют две разные вещи. 6 - это самые десятичные цифры, которые могут быть округлены. 7.225 - приблизительное число десятичных цифр для 24-битного двоичного целого числа, поскольку 24-битовое двоичное целое число может иметь 7 или 8 десятичных цифр в зависимости от его конкретного значения.
7.225 было найдено с использованием специальной бинарной целочисленной формулы.
d spec= b & middot; log 10 (2) (д <суб > спецификациисуб >= конкретные десятичные цифры, b = бит)
Однако то, что вам обычно нужно знать, - это минимальные и максимальные десятичные цифры для битового целого числа. Следующие формулы используются для нахождения минимальных и максимальных десятичных цифр (7 и 8 соответственно для 24 бит) определенного двоичного целого.
d min= ⌈ (b-1) & middot; log 10 (2) ⌉ д <суб > минсуб >= минимальные десятичные числа, b = бит, ⌈x⌉ = наименьшее целое ≥ x)
d max= ⌈b & middot; log 10 (2) ⌉ (д <суб > макссуб >= максимальные десятичные числа, b = бит, ⌈x⌉ = наименьшее целое ≥ x)
Чтобы узнать больше о том, как эти формулы получены, прочитайте Число десятичных цифр в двоичном целой, написанное Риком Риганом.
Все это хорошо и хорошо, но вы можете спросить: почему 6 десятичных цифр для конверсии в оба конца, если вы говорите, что диапазон десятичных цифр для 24-битного номера равен 7-8?
Ответ - потому что приведенные выше формулы работают только для целых, а не чисел с плавающей запятой!
Каждое десятичное целое имеет точное значение в двоичном формате. Однако то же самое нельзя сказать для каждого десятичного числа с плавающей запятой. Возьмите .1
, например. .1
в двоичном выражении - это число 0.000110011001100...
, которое является повторяющимся или повторяющимся двоичным. Это может привести к ошибке округления.
Кроме того, для представления десятичного числа с плавающей запятой требуется еще один бит, чем для десятичного целого числа, равного значению. Это связано с тем, что числа с плавающей запятой более точны, чем ближе они к 0, так и менее точные, чем дальше от 0. Из-за этого многие числа с плавающей запятой приближаются к минимальному и максимальному значениям (e min= -126 и e max= +127 для одиночной точности) теряют 1 бит точности из-за ошибки округления. Чтобы увидеть это визуально, посмотрите Что каждый программист должен знать о плавающей запятой, часть 1, написанной Джошем Хаберманом.
Кроме того, есть, по крайней мере, 784,757
положительные семизначные десятичные числа, которые не могут сохранить свое первоначальное значение после конверсии в оба конца. Примером такого числа, которое не может выжить в обратном направлении, является 8.589973e9
. Это наименьшее положительное число, которое не сохраняет свое первоначальное значение.
Здесь формула, которую вы должны использовать для точности чисел с плавающей запятой, которая даст вам 6 десятичных цифр для конверсии в оба конца.
d max= ⌊ (b-1) · log 10 (2) ⌋ (d <югу > тахсуб >= максимальные десятичные числа, b = бит, ⌊x⌋ = наибольшее целое число ≤ x)
Чтобы узнать больше о том, как получается эта формула, прочитайте Количество цифр, необходимых для конверсий в течение тура, также написанное Риком Риганом. Рик отлично справляется с выводом формул со ссылками на строгие доказательства.
В результате вы можете использовать приведенные выше формулы конструктивным образом; если вы понимаете, как они работают, вы можете применить их к любому языку программирования, который использует типы данных с плавающей точкой. Все, что вам нужно знать, это количество значимых бит, которые имеют ваш тип данных с плавающей точкой, и вы можете найти их соответствующее количество десятичных цифр, на которые вы можете рассчитывать, чтобы не потерять значимость после конверсии в оба конца.
18 июня 2017 года. Обновление:. Я хочу добавить ссылку на новую статью Рика Ригана, которая идет более подробно и, на мой взгляд, лучше отвечает на этот вопрос, чем любой предоставленный здесь ответ. Его статья " Десятичная точность двоичных чисел с плавающей запятой" и может быть найдена на его веб-сайте www.exploringbinary.com.
Ответ 2
Это говорят о двух немного разных вещах.
Цифры 7.225 1 - это точность, с которой число может храниться внутри. Например, если вы сделали вычисление с номером двойной точности (так что вы начинали с чего-то вроде 15 цифр точности), то округлили его до одного номера точности, точность, которую вы бы оставили в этой точке, была бы приблизительно 7 цифр.
6 цифр говорят о точности, которая может поддерживаться путем конвертации в оба конца из строки десятичных цифр, в число с плавающей запятой, а затем обратно в другую строку десятичных цифр.
Итак, допустим, что я начинаю с числа вроде 1.23456789
в виде строки, а затем конвертируем его в float32, а затем преобразуем результат обратно в строку. Когда я это сделал, я могу ожидать, что 6 цифр будут точно соответствовать. Седьмая цифра может быть округлена, поэтому я не могу ожидать, что она будет соответствовать (хотя она, вероятно, будет +/- 1 исходной строки.
Например, рассмотрим следующий код:
#include <iostream>
#include <iomanip>
int main() {
double init = 987.23456789;
for (int i = 0; i < 100; i++) {
float f = init + i / 100.0;
std::cout << std::setprecision(10) << std::setw(20) << f;
}
}
Это создает таблицу, подобную следующей:
987.2345581 987.2445679 987.2545776 987.2645874
987.2745972 987.2845459 987.2945557 987.3045654
987.3145752 987.324585 987.3345947 987.3445435
987.3545532 987.364563 987.3745728 987.3845825
987.3945923 987.404541 987.4145508 987.4245605
987.4345703 987.4445801 987.4545898 987.4645386
987.4745483 987.4845581 987.4945679 987.5045776
987.5145874 987.5245972 987.5345459 987.5445557
987.5545654 987.5645752 987.574585 987.5845947
987.5945435 987.6045532 987.614563 987.6245728
987.6345825 987.6445923 987.654541 987.6645508
987.6745605 987.6845703 987.6945801 987.7045898
987.7145386 987.7245483 987.7345581 987.7445679
987.7545776 987.7645874 987.7745972 987.7845459
987.7945557 987.8045654 987.8145752 987.824585
987.8345947 987.8445435 987.8545532 987.864563
987.8745728 987.8845825 987.8945923 987.904541
987.9145508 987.9245605 987.9345703 987.9445801
987.9545898 987.9645386 987.9745483 987.9845581
987.9945679 988.0045776 988.0145874 988.0245972
988.0345459 988.0445557 988.0545654 988.0645752
988.074585 988.0845947 988.0945435 988.1045532
988.114563 988.1245728 988.1345825 988.1445923
988.154541 988.1645508 988.1745605 988.1845703
988.1945801 988.2045898 988.2145386 988.2245483
Если мы рассмотрим это, мы увидим, что первые шесть значащих цифр всегда следуют за рисунком точно (т.е. каждый результат точно равен 0,01 больше, чем его предшественник). Как мы видим в исходном double
, значение фактически равно 98x.xx456, но когда мы конвертируем float с одной точностью в десятичную, мы можем видеть, что цифра 7 th часто не будет вернемся правильно - поскольку последующая цифра больше 5, она должна округлить до 98x.xx46, но некоторые из значений не будут (например, от второго до последнего элемента в первом столбце 988.154541
, который будет округлен, а не вверх, поэтому мы получим 98x.xx45 вместо 46
. Таким образом, даже если значение (как хранится) точно соответствует 7 цифрам (плюс немного), к тому времени мы округляем значение через преобразование в десятичную и обратно, мы не можем больше зависеть от этой седьмой цифры (даже если есть достаточная точность, что она будет намного чаще, чем нет).
1. В основном это означает 7 цифр, а цифра 8 th будет немного более точной, чем ничего, но не очень много - например, если мы переводим из двойника 1.2345678
, цифры точности .225
означают, что последняя цифра будет иметь около +/-.775 от того, что началось там (тогда как без .225
цифр точности было бы в основном +/- 1 того, что было начато там).
Ответ 3
Имейте в виду, что они являются одними и теми же формулами. Помните свою личную школьную математическую книгу:
Log(x^y) == y * Log(x)
Это помогает фактически вычислить значения для N = 24 с вашим калькулятором:
Kahan's: 23 * Log(2) = 6.924
Wikipedia's: Log(2^24) = 7.225
Кахан был вынужден урезать 6.924 до 6 цифр из-за floor(), bummer. Единственное фактическое различие заключается в том, что Кахан использовал 1 меньшую точность.
Довольно трудно догадаться, почему профессор мог полагаться на старые заметки. Написано перед IEEE-754 и не учитывает, что 24-й бит точности предоставляется бесплатно. Формат использует трюк, самый старший бит значения с плавающей запятой, который не равен 0, всегда 1. Поэтому его не нужно хранить. Процессор добавляет его обратно, прежде чем он выполнит вычисление. Превращение 23 бит сохраненной точности в 24 эффективной точности.
Или он принял во внимание, что преобразование из десятичной строки в двоичное значение с плавающей запятой порождает ошибку. Многие хорошие округлые десятичные значения, например 0,1, не могут быть полностью преобразованы в двоичные. Он имеет бесконечное количество цифр, равно как и 1/3 в десятичной форме. Тем не менее, он генерирует результат, который отключается на +/- 0,5 бит, достигаемый простым округлением. Таким образом, результат будет точным до 23.5 * Log (2) = 7.074 десятичных цифр. Если он предположил, что процедура преобразования является неуклюжей и не имеет правильного раунда, результат может быть отключен на +/- 1 бит и N-1 является подходящим. Они не неуклюжи.
Или он думал, как типичный ученый или (не дай бог) бухгалтер, и хочет, чтобы результат вычисления преобразовывался обратно в десятичный. Например, вы получите, когда вы тривиально ищете семизначное десятичное число, чья конверсия назад и вперед не дает такого же числа. Да, это добавляет еще одну ошибку +/- 0,5 бит, суммируя до 1 бит общей ошибки.
Но никогда, никогда не делайте эту ошибку, вы всегда должны включать любые ошибки, которые вы получаете от манипуляции с числом в расчете. Некоторые из них очень быстро теряют значимые цифры, в частности, вычитание очень опасно.