C: ошибка преобразования double в int в gcc 6.3.0 - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть следующая программа на c, и в некоторых случаях, когда я ее запускаю, вывод отличается в зависимости от компилятора и платформы.Я понимаю, что преобразование double в int может вызвать проблемы.

Вот код:

//Compiler version gcc 6.3.0
#include <stdio.h>
#include <math.h>

int main(void){
    double d = 2;
    printf("%.20lf\n", pow(10, d));
    printf("%d\n", (int)pow(10, d));
    printf("%d\n", (int)pow(10, 2));
}

100 - ожидаемое значение, но выражение

    printf("%d\n", (int)pow(10, d));

имеет99 в качестве вывода, когда я использую и gcc 6.3.0, и Windows 10 x64, но не в других случаях.

Вот некоторые результаты:

//gcc 6.3.0 (Sublime Text 3) in Windows 10 x64
100.00000000000000000000
99 ->this is the problem
100

//gcc 6.3.0 in Android (using Dcoder app)
100.00000000000000000000
100
100

//MSVC(VS 2017 x86) in Windows 10 x64
100.00000000000000000000
100
100

Я также протестировал некоторые онлайн-gcc (6.3.0) компиляторы, но все выходы были 100.

Спасибо за помощь.

1 Ответ

0 голосов
/ 03 февраля 2019

Некоторые реализации pow возвращают значения, отличные от 100 для pow(10, 2).Например, 99.9999999999999857891452847979962825775146484375 могут быть возвращены.Когда это double значение преобразуется в int, результат равен 99.

Это проблема качества реализации pow.Хорошие pow реализации возвращают точные результаты, когда возможны точные результаты.

Кроме того, я подозреваю, что printf("%.20lf\n", pow(10, d)) неправильно форматирует в реализации Windows - возможно, это внутреннее округление до примерно 15 значащих десятичных цифрперед форматированием его до 20 цифр для вывода.Вы можете проверить это, напечатав printf("%.20g\n", pow(10, d)-100).Это вычтет 100 из pow(10, d) в double арифметике.Если он показывает ненулевой вывод, вы знаете, что pow(10, d) не был точно 100, поэтому printf("%.20lf\n", pow(10, d)) показал неверный результат.

Обратите внимание, что pow - сложная функция, которую трудно реализовать хорошо.Только ограниченное число случаев имеет точные результаты, поэтому большинство результатов обязательно являются неточными.Однако даже в этих случаях получить результат, который правильно округлен - с учетом ближайшего представимого значения - сложно.Насколько мне известно, никто не реализовал pow с таким качеством.Большинство реализаций pow допускают некоторые дополнительные ошибки, и поэтому вам не следует полагаться на pow для правильного округления.Однако возможно реализовать pow, чтобы в случаях, когда возможны точные результаты, действительно возвращались точные результаты, и некоторые реализации достигают этого.

...