Я вычисляю n-ный корень положительного целого числа, используя стандартный метод библиотеки pow (). Вот фрагмент из моей программы:
double x,y;
x=pow(64,(1.0/3));
int z;
printf("x=%lf\n",x);
z=(int)x;
printf("%d\n",z);
Но при поиске кубического корня из 64. X печатается как 4.000000, а z как 3. Почему так?
Может кто-нибудь предложить лучший алгоритм, для того же?
Если вы печатаете больше цифр на x
, вы увидите, в чем проблема (я выбрал 30 случайно):
double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);
Выход:
x=3.99999999...999600000000
Так что, если вы бросите x
в int
это станет 3
,
Не существует «идеального» решения. Если вы имеете дело только с целым числом, вы можете создать свою собственную корневую функцию, но если вы хотите иметь возможность использовать float, вам нужно иметь дело с проблемой точности из-за представления с плавающей запятой.
Может быть, есть некоторые библиотеки C, которые могут помочь вам с такими проблемами.
int
переопределить округляет вниз. поскольку операции с плавающей точкой неточны, расчет может быть 3.999999 …
использование round(x)
чтобы получить правильный результат.
Так как вы всегда хотите округлить вниз, Вы можете использовать оба floor
а также (int)
— но вы столкнетесь с наблюдаемой ошибкой, как только нестабильность вычислений с плавающей запятой приводит к немного меньшее значение — порядка 10-15, за double
размерные расчеты. Используйте крошечное значение эпсилона, чтобы противостоять этому.
Обратите внимание, что значение «fudge» в эпсилоне ниже будут относятся к числу значащих цифр в вашем исходном номере. Для больших чисел вам нужен меньший эпсилон.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main (void)
{
double x;
int z;
x=pow(64,(1.0/3));
printf("x=%lf\n",x);
printf("x=%.30lf\n",x);
z=(int)x;
printf("%d\n",z);
z=(int)(x+0.000000000000005);
printf("%d\n",z);
x=pow(64,(1.0/4));
printf("x=%lf\n",x);
printf("x=%.30lf\n",x);
z=(int)x;
printf("%d\n",z);
z=(int)(x+0.0000000000000005);
printf("%d\n",z);
return 1;
}
результаты для степеней 1/3 и 1/4, в
x=4.000000
x=3.999999999999999555910790149937
3
4
x=2.828427
x=2.828427124746190290949243717478
2
2
Как рассказывает @jongware The int override округляет и операции с плавающей запятой могут быть неточными.
хотя вы всегда можете сделать это, чтобы избежать этой проблемы
def invpow ( n , i):
x = pow (n ,(1/i))
if((int)pow((x+1) , i) <= n):
x += 1;
print(x)
Или вы можете написать свой собственный метод для возведения в степень с помощью Ньютон — Рафсон описанный метод Вот а также Вот
Вы также можете использовать Бинарный поиск что довольно быстро, если у вас есть правильное предположение о диапазоне
то есть (переменные высокие и низкие)
def invpow( x, n, low, high){
if(n==1)
return x;
mid=(low+high)/2;
while(low<high){
mid=(low+high)/2;
raised=pw(mid,n);
if(raised==x)
break;
if(raised>x)
high=mid;
else
low=mid;
if(low+1==high){
mid=low;
break;
}
}
return mid;
}