Я недавно написал некоторый код, подобный этому:
// Calculate a ^ b
unsigned int result = 1;
for (unsigned int i = 0; i < b; i++) {
result *= a;
}
Я получил комментарий, что я должен был использовать pow
из math.h
, и я был готов указать на плавающую точку проблемы точности, потому что pow
возвращает double
. Я даже нашел существующий вопрос переполнения стека , который иллюстрирует проблему. За исключением случаев, когда я пытался запустить код из этого другого вопроса, он "работал" просто отлично (то есть нет проблем, связанных с ошибкой 1).
Вот код, который я тестировал :
#include <math.h>
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int result;
for (unsigned int b = 1; b <= 9; b++) {
result = (unsigned int)pow(a, b);
printf("%u\n", result);
}
return 0;
}
А вот как я собираю и запускаю его (на Ubuntu 18.04.3 с G CC версия 7.4.0):
$ gcc -O3 -std=c99 -Wall -Wextra -Werror -Wpedantic -pedantic-errors -o pow_test pow_test.c -lm
$ ./pow_test
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
Так почему (unsigned int)pow(a, b)
работа? Я предполагаю, что компилятор делает некоторые маги c, чтобы предотвратить нормальные проблемы с плавающей точкой? Что он делает и почему? Похоже, плохая идея поощрять игнорирование этих проблем, если не все компиляторы делают это. И если все современные компиляторы делают делают это, разве это не проблема, о которой вам нужно беспокоиться больше?
Я также видел, как люди предлагают что-то вроде (unsigned int)(pow(a, b) + 0.1)
, чтобы избежать отключения. По 1 вопросу. Каковы преимущества / недостатки этого по сравнению с моим решением с l oop?