C ++ `digits10` равно 6 для IEEE с плавающей запятой, но первое не представимое целое число уже имеет 8 цифр?

C ++ ‘s std::numeric_limits<float>::digits10, описывается на cppref как таковой:

Значение std::numeric_limits<T>::digits10 это число из 10 цифр с основанием, которое может быть представлено типом T без изменений, то есть любое число с таким количеством десятичных цифр может быть преобразовано в значение типа T и обратно в десятичную форму без изменения из-за округления или переполнение.

Аналогичное описание существует для двоюродного брата FLT_DIG.

Значение дано:

float     FLT_DIG /* 6 for IEEE float */

тем не мение, это показано здесь на С.О. что все целые числа до 16,777,216 (224) точно представимы в 32-битном типе IEEE с плавающей точкой. И если я могу посчитать, это число 8 цифры, поэтому значение для digits10 должно быть на самом деле 7, сейчас не так ли?

Скорее всего, я что-то неправильно понимаю digits10 здесь, так что же это на самом деле скажи мне?


Практическая применимость:

Меня спросили, можем ли мы сохранить все числа из 0.0086,400.00 точно в 32-битном IEEE поплавке.

Теперь я очень уверен, что мы могли бы хранить все номера из 08,640,000 в 32-разрядном формате с плавающей запятой IEEE, но сохраняется ли это для того же «целочисленного» диапазона, смещенного на 2 цифры влево?

3

Решение

(Ограничив этот ответ IEEE754 float).

8.589973e9 а также 8.589974e9 обе карты в 8589973504, Это контрпример к утверждению, что седьмая значащая цифра сохраняется.

Так как на шестом значимом рисунке такого контрпримера не существует, std::numeric_limits<float>::digits10 а также FLT_DIG 6

Действительно целые числа могут быть представлены в точности до 24го сила 2. (16,777,216 а также 16,777,217 обе карты в 16,777,216). Это потому что float имеет 24 бит мантисса.

8

Другие решения

Поскольку другой ответ и комментарий устанавливает, digits10 охватывает все «диапазоны показателей», то есть 1234567 а также для 1.234567 а также 12345670000 — и это касается только 6 цифры!

Пример счетчика для 7 цифр:

  • 8.589,973 e9 против 8.589,974 e9 (из примера cppref)
2

Другая точка зрения:

Рассмотрим между каждой парой степеней-2, а float лайк Бинарный IEEE кодирует 223 Значения распределены линейно.


Пример: между 20 и 21 или 1,0 и 2,0,

Разница между float значения 1,0 / 223 или 10.192e-06.

Написано в текстовой форме «1.dddddd», 7-значное число, цифры имеют разницу 1.000e-06.

Таким образом, для каждого шага десятичного числа текста, есть около 10,2 float,
Нет проблем с кодированием этих 7 цифр.
В этом диапазоне также нет проблем с кодированием 8 цифр.


Пример: между 223 и 224 или 8 388 608,0 и 16 777 216,0.

Разница между float значения 223/ 223 или 1.0.

Числа около нижнего конца написаны в текстовой форме «8or9.dddddd * 106«, 7 значных цифр, имеют разницу 1,0.

Нет проблем с кодированием этих 7 цифр.


Пример: между 233 и 234 или 8 589 934 592,0 и 17 179 869 184,0,

Разница между float значения 233/ 223 или 1024,0.

Числа около нижнего конца написаны в текстовой форме «8or9.dddddd * 109«, 7 значных цифр, имеют разность 1,000.0.

Теперь у нас есть проблема. Начиная с 8 589 934 592,0, то следующие 1024 числа в текстовой форме имеют только 1000 различных float кодирование.


7 цифр в форме d.dddddd * 10Экспо слишком много комбинаций для уникального кодирования с использованием float,

1

Иногда достаточно легко найти контрпримеры.

#include <stdio.h>
#include <string.h>

int main(void) {
int p6 = 1e6;
int p7 = 1e7;
for (int expo = 0; expo < 29; expo++) {
for (int frac = p6; frac < p7; frac++) {
char s[30];
sprintf(s, "%d.%06de%+03d", frac / p6, frac % p6, expo);
float f = atof(s);
char t[30];
sprintf(t, "%.6e", f);
if (strcmp(s, t)) {
printf("<%s> %.10e <%s>\n", s, f, t);
break;
}
}
}
puts("Done");
}

Выход

<8.589973e+09> 8.5899735040e+09 <8.589974e+09>
<8.796103e+12> 8.7961035080e+12 <8.796104e+12>
<9.007203e+15> 9.0072024760e+15 <9.007202e+15>
<9.223377e+18> 9.2233775344e+18 <9.223378e+18>
<9.444738e+21> 9.4447374693e+21 <9.444737e+21>
<9.671414e+24> 9.6714134744e+24 <9.671413e+24>
<9.903522e+27> 9.9035214949e+27 <9.903521e+27>
<1.000000e+28> 9.9999994421e+27 <9.999999e+27>  This is an interesting one
1
По вопросам рекламы [email protected]