Неправильный ответ при расчете n-го корня числа в cpp

Я вычисляю 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. Почему так?

Может кто-нибудь предложить лучший алгоритм, для того же?

0

Решение

Если вы печатаете больше цифр на x, вы увидите, в чем проблема (я выбрал 30 случайно):

double x ;
x = pow(64, 1.0/3);
printf("x=%.30lf\n",x);

Выход:

x=3.99999999...999600000000

Так что, если вы бросите x в int это станет 3,

Не существует «идеального» решения. Если вы имеете дело только с целым числом, вы можете создать свою собственную корневую функцию, но если вы хотите иметь возможность использовать float, вам нужно иметь дело с проблемой точности из-за представления с плавающей запятой.

Может быть, есть некоторые библиотеки C, которые могут помочь вам с такими проблемами.

2

Другие решения

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
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;
}
0
По вопросам рекламы [email protected]