Странное поведение функции pow
Во время выполнения следующих строк кода:
int i,a;
for(i=0;i<=4;i++)
{
a=pow(10,i);
printf("%d\t",a);
}
Я был удивлен, увидев результат, он выходит 1
10
99
1000
9999
вместо 1
10
100
1000
10000
,
В чем может быть причина?
Заметка
Если вы думаете, что это погрешность с плавающей запятой, что в приведенном выше цикле для i = 2
, значения хранятся в переменной a
является 99
,
Но если вы напишите вместо
a=pow(10,2);
теперь значение выходит 100
, Как это возможно?
5 ответов
Я даже не могу произнести c, но я могу сказать вам, почему.
Вы установили a
быть int
, pow()
генерирует число с плавающей запятой, которое в НЕКОТОРЫХ случаях может быть на волосок меньше 100 или 10000 (как мы видим здесь).
Затем вы складываете это в целое число, которое ОБРАЩАЕТСЯ в целое число. Таким образом, вы потеряете эту дробную часть. К сожалению. Если вы действительно нуждались в целочисленном результате, раунд может быть лучшим способом сделать эту операцию.
Будьте осторожны даже там, так как для достаточно больших полномочий ошибка может быть достаточно большой, чтобы вызвать сбой, что даст вам то, чего вы не ожидаете. Помните, что числа с плавающей запятой несут только такую большую точность.
Функция pow()
возвращает double
, Вы назначаете это переменной a
типа int
, Это не "округляет" значение с плавающей запятой, оно усекает его. Так pow()
возвращает что-то вроде 99.99999... за 10^2, а потом вы просто отбрасываете часть.9999... Лучше сказать a = round(pow(10, i))
,
Это связано с неточностью с плавающей запятой. Хотя вы проходите вint
s они неявно преобразуются в тип с плавающей запятой, так какpow
Функция определена только для параметров с плавающей запятой.
Никто не объяснил, как на самом деле сделать это правильно - вместо pow
Функция, просто есть переменная, которая отслеживает текущую мощность:
int i, a, power;
for (i = 0, a = 1; i <= 4; i++, a *= 10) {
printf("%d\t",a);
}
Это продолжающееся умножение на десять гарантированно даст вам правильный ответ, и вполне нормально (и намного лучше, чем pow, даже если бы он давал правильные результаты) для задач, таких как преобразование десятичных строк в целые числа.
Математически целочисленная степень целого числа является целым числом.
В хорошем качестве pow()
рутина этот конкретный расчет не должен приводить к ошибкам округления. Я запустил ваш код на Eclipse/Microsoft C и получил следующий вывод:
1 10 100 1000 10000
Этот тест НЕ показывает, использует ли Microsoft числа с плавающей запятой и округления, или они определяют тип ваших чисел и выбирают подходящий метод.
Итак, я запустил следующий код:
#include <stdio.h>
#include <math.h>
main ()
{
double i,a;
for(i=0.0; i <= 4.0 ;i++)
{
a=pow(10,i);
printf("%lf\t",a);
}
}
И получил следующий вывод:
1.000000 10.000000 100.000000 1000.000000 10000.000000