Почему double в C печатает меньше десятичных цифр, чем C ++? - PullRequest
0 голосов
/ 05 октября 2018

У меня есть этот код в C, где я объявил 0.1 как double.

#include <stdio.h> 
int main() {
    double a = 0.1;

    printf("a is %0.56f\n", a);
    return 0;
}

Это то, что он печатает, a is 0.10000000000000001000000000000000000000000000000000000000

Тот же код в C ++,

#include <iostream>
using namespace std;
int main() {
    double a = 0.1;

    printf("a is %0.56f\n", a);
    return 0;
}

Это то, что печатается, a is 0.1000000000000000055511151231257827021181583404541015625

В чем разница?Когда я читаю оба выделены 8 байтов?Как C ++ печатает больше чисел в десятичных разрядах?

Кроме того, как он может идти до 55 знаков после запятой?IEEE 754 имеет только 52 бита для дробного числа, с помощью которого мы можем получить 15 десятичных знаков точности.Хранится в двоичном виде.Как получается, что его десятичная интерпретация хранит больше?

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

С MinGW g ++ (и gcc) 7.3.0 ваши результаты воспроизводятся точно.

Это довольно странный случай неопределенного поведения.

Неопределенное поведение связано с использованием printf без включения соответствующего заголовка ¹ нарушение «должен» в

C ++ 17 § 20.5.2.2

Единица перевода должна включать заголовоктолько вне какого-либо объявления или определения и должен включать лексический заголовок перед первой ссылкой в ​​этом блоке перевода на любую из сущностей, объявленных в этом заголовке.Диагностика не требуется.

В коде C ++ измените <iostream> на <stdio.h>, чтобы получить действительный код C ++ , и вы получите тот же результат, что и с программой C.


Почему код C ++ даже компилируется?

Ну, в отличие от C, в C ++ стандартный библиотечный заголовок допускается перетаскивать в любой другой заголовок.И, очевидно, с g ++ заголовок <iostream> тянется в некотором объявлении printf.Только не совсем правильный.

Подробности: С MinGW g ++ 7.3.0 объявление / определение printf зависит от символа макроса __USE_MINGW_ANSI_STDIO.По умолчанию <stdio.h> объявляет printf.Но когда __USE_MINGW_ANSI_STDIO определено как логическое истина, <stdio.h> предоставляет определяющее определение printf, которое вызывает __mingw_vprintf.И, как это бывает, заголовок <cstdio> определяет (через косвенное включение) __USE_MINGW_ANSI_STDIO перед включением <stdio.h>.

В <_mingw.h> есть комментарий: «Обратите внимание, что мы включаем его также для _GNU_SOURCE вC ++, но не для случая C. ".

В C ++ с соответствующими версиями этого компилятора фактически существует разница между включением <stdio.h> и использованием printf или включением <cstdio>, говоря using std::printf; и с использованием printf.


Относительно

Кроме того, как оно может идти до 55 знаков после запятой?IEEE 754 имеет только 52 бита для дробного числа, с помощью которого мы можем получить 15 десятичных знаков точности.Хранится в двоичном виде.Почему его десятичная интерпретация хранит больше?

... это просто десятичная дробь представление , что длиннее.Цифры, превышающие точность внутреннего представления, около 15 цифр для 64-битного IEEE 754, по сути являются мусором, но их можно использовать для точного восстановления исходных битов.В какой-то момент они станут всеми нулями, и эта точка будет достигнута для последней цифры в выводе вашей программы на C ++.


1 Благодаря Dietrich Epp для нахождения этой цитаты стандартов.

0 голосов
/ 05 октября 2018

Мне кажется, что в обоих случаях печатаются 56 десятичных цифр, поэтому вопрос технически основан на ошибочной предпосылке.

Я также вижу, что оба числа равны 0.1 с точностью до 52 бит,так что оба верны.

Это приводит к вашему последнему вопросу: «Как получается, что его десятичная интерпретация хранит больше?».Он не хранит больше десятичных знаков.double не хранит десятичные дроби.Он хранит биты.Десятичные числа генерируются.

...