#c #math
#c #математика
Вопрос:
Я знаю, что в sin
есть math.h
функция, но я хочу создать эту функцию самостоятельно, просто для развлечения. Я создал sin
функцию, основанную на расширении функции синуса по Маклуарину.
Я написал степенную функцию и факториальную функцию, они корректно работают с main
, но они не работают в sin
функции.
Вот мой код:
int main()
{
int i;
double y;
printf("nnPlease enter a value to find corresponding sin valuen");
scanf("%d",amp;i);
y=sin(i);
printf("nYour value isn %f",y);
return 0;
}
double sin(int z)
{
int i=1;
double value,val2,val3,sum=0;
for(i=1;i<33;i =2)
{
val2=power(z,i);
val3=factorial(i);
value=val2/val3;
if(((i-1)/2)%2!=0){
sum=sum-value; //((power(x,i))/factorial(i));
}else
{
sum=sum value;
}
}
printf("n%fn",sum);
return sum;
}
int factorial(int x)
{
int i,sum=1;
for(i=1;i<=x;i )
{
sum = sum*i;
}
return sum;
}
int power(int x,int y)
{
unsigned long long int i,sum=1;
for(i=1;i<=y;i )
{
sum=sum*x;
}
return sum;
}
Комментарии:
1. Помимо переполнений, использование целых чисел приведет к усечению десятичных знаков. О, и вы объявляете функции перед их вызовом? У вас есть прототипы функций где-нибудь над
main
функцией?2. какова цель этого условия if
if(((i-1)/2)%2!=0)
?3. @ARBY это для
-
значения в последовательности типа sum-x ^ 3/3!
Ответ №1:
Формула ожидает значения в радианах, но вы используете целые числа, поэтому я предполагаю, что вы присваиваете ей градусы. Это приведет к тому, что формула выдаст неправильные значения.
Также вы используете int
s в качестве возвращаемых значений из factorial()
и power()
, которые будут вызывать переполнения. Если у вас 32-битная машина, даже присвоение 2 вашей формуле приведет к переполнению, поскольку int
может доходить только до 2 ^ 31-1, а вы пытаетесь получить 2 ^ 33.
Также, если ваш компилятор не жалуется на то, что вы возвращаете unsigned long long int
из функции, которая имеет int
в качестве возвращаемого типа, пожалуйста, увеличьте уровень предупреждения.
Ответ №2:
int factorial()
переполняется довольно быстро. 13!
не вписывается в 32-разрядное целое число. 21!
не вписывается в 64-разрядное целое число.
int power()
кажется совершенно неправильным. Почему вы ожидаете, что аргумент x
будет int
? Кстати, она также быстро переполняется.
(Почти) правильный способ вычисления ряда Маклорена — это выразить следующий член из предыдущего:
term = (-1) * term * (x*x) / ((n 1)*(n 2));
sum = term;
n = 2;
Это должно работать, но может привести к числовой нестабильности с большими x
. Расписание Хорнера — это окончательный ответ.
Ответ №3:
Если вы посмотрите на стандартные математические библиотеки, такие как fdlibm, все они выполняют сокращение аргументов. Серия Маклуарина лучше всего работает при малых значениях x . Таким образом, для больших x вы хотите поместить x в небольшой диапазон. Работаем в радианах, если мы можем найти y между -pi / 2 и pi / 2 такими, что x = y 2 k pi. Или x = pi — y 2 k pi.
Это поможет поместить y в небольшой диапазон и означает, что вам потребуется меньше членов ряда для вычисления.
Ответ №4:
Как уже заявляли другие, вычислять часть power
и factorial
в их собственной функции — плохая идея, поскольку она будет переполняться даже при довольно малых значениях.
Вы можете попробовать объединить вычисления так, чтобы у вас были multiplication
и a divide
в каждом цикле.
Вот так:
#include <stdio.h>
// This function returns the contribution from the k'th element
double kth_contribution(double x, int k)
{
int i;
int s = -1.0;
double d = 1.0;
if (k < 0) return 0;
if (k == 1) return x;
if (k % 2 == 0) return 0;
if ((k-1) % 4 == 0) s = 1.0;
for (i=1; i<=k; i)
{
d = d * x / i;
}
d = s * d;
return d;
}
int main(void) {
int k;
int x = 1.0;
for (k=0; k<33; k)
{
printf("k=%d: %0.80fn", k, kth_contribution(1.0, k));
}
return 0;
}
Вывод:
k=0: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=1: 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=2: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=3: -0.16666666666666665741480812812369549646973609924316406250000000000000000000000000
k=4: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=5: 0.00833333333333333321768510160154619370587170124053955078125000000000000000000000
k=6: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=7: -0.00019841269841269841252631711547849135968135669827461242675781250000000000000000
k=8: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=9: 0.00000275573192239858925109505932704578867742384318262338638305664062500000000000
k=10: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=11: -0.00000002505210838544172022386617932135366437762513669440522789955139160156250000
k=12: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=13: 0.00000000016059043836821615925802332523156679827680548555690620560199022293090820
k=14: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=15: -0.00000000000076471637318198174152558028953378813433183758263567142421379685401917
k=16: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000
k=17: 0.00000000000000281145725434552099254097088490189675684814327692728763707918915316
....
Теперь вам просто нужно сложить все вклады вместе.