процесс отображения литерала с плавающей запятой в его двоичное представление - PullRequest
2 голосов
/ 14 января 2020

Рассмотрим точные значения с плавающей запятой около 0,3

1) 0.2999999523162841796875
2) 0.2999999821186065673828125
3) 0.300000011920928955078125
4) 0.3000000417232513427734375
5) 0.30000007152557373046875

Когда мы пишем следующий код на C ++

auto x = 0.30f

, компилятор должен проанализировать токен 0.30f и сделать x типа float со значением 0.300000011920928955078125. (вариант 3 выше)

Мне любопытно, как компиляторы достигают этого значения, а не значений вокруг него. Одна теория состоит в том, что они вызывают функцию strtof, чтобы получить число с плавающей точкой. Здесь - реализация strtof (в основном она проходит через каждый символ строки, умножается на степень 10 и вычисляет местоположение десятичной дроби). Мне не очевидно, почему этот метод даст вариант 3, а не вариант 4 или 5.

Ответы [ 2 ]

3 голосов
/ 14 января 2020

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

Действительно; они используют функцию, сравнимую с strtof. Есть компиляторы с открытым исходным кодом. Вы можете посмотреть, как они разбирают литералы. Здесь - это реализация из G CC. Это слишком большой, чтобы скопировать здесь. Он использует библиотеку GNU MPFR (с плавающей запятой с множественной точностью).

Документ IEEE-754 определяет, как это преобразование должно вести себя в системах, соответствующих стандарту IEEE-754, в разделе под названием 5.12. Подробности преобразования между плавающими точечные данные и внешние последовательности символов . Помимо функций преобразования это также относится к преобразованиям времени перевода, таким как преобразования литералов с плавающей запятой.

0 голосов
/ 14 января 2020

почему вас это волнует?

IEEE определяет число с плавающей запятой как 23-битное значение, что составляет около 7 десятичных знаков. Таким образом, двоичное представление «0.3» равно 0.3000000 +/- precision_loss (поскольку само значение 0.3 не является двоичным представлением), где Precision_loss меньше 0,0000001.

Кроме того, в зависимости от того, как вы получите «0,3», двоичный файл Представление одного и того же десятичного числа может быть различным. Например:

    float n = 0.3;
    cout << std::fixed << std::setprecision(25) << n << endl;
    float n1 = 0.1;
    cout << std::fixed << std::setprecision(25) << n1 + 0.1 + 0.1 << endl;

дает следующий вывод:

0.3000000119209289550781250
0.3000000014901161304869959

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

...