为什么我在 C return 中的 sin 计算代码的值是错误的?
Why does my sin calculating code in C return the wrong value?
我想根据这个等式使用我自己的函数计算用户输入的正弦:
sin(x) = sum_(i=0)^n (-1)^i * (x^(2 i + 1)/((2 i + 1)!))
我有这段代码,根据我的理解,我所做的与等式中写的完全一样:
#include <stdio.h>
#include <math.h>
int faculty(int factor)
{
int result = 1;
if (factor > 0)
{
for (int i = 1; i <= factor; i++)
{
result = result * i;
}
}
else
{
result = 1;
}
return result;
}
double my_sin(double x, int n)
{
double my_sin = 0;
for (int j = 0; j < n ; j++)
{
double i = (double)j;
double faculty_j = (double)faculty(2*j+1);
my_sin = my_sin + (pow((-1.0), i) * (pow(x, (double)(2.0 * i + 1.0)) / faculty_j));
}
return my_sin;
}
int main()
{
int n = 0;
double x = 0;
printf("x=");
scanf("%lf", &x);
printf("n=");
scanf("%i", &n);
printf("sin(%i)=", (int)x);
printf("%lf\n", my_sin(x, n));
return 0;
}
但是,例如,当我使用 x = 8
和 n = 5
时,结果是 sin(8)=149
。我尝试调试代码一段时间了,但我不知道问题出在哪里,也不知道如何找出问题所在。
更新代码:
#include <stdio.h>
long int factorial(int factor)
{
long int result = 1;
if (factor > 0)
{
for (int i = 1; i <= factor; i++)
{
result = result * i;
}
}
else
{
result = 1;
}
return result;
}
double my_pow(double a, double b)
{
if (b == 0)
{
return 1;
}
double result = a;
double increment = a;
double i, j;
for (i = 1; i < b; i++)
{
for (j = 1; j < a; j++)
{
result += increment;
}
increment = result;
}
return result;
}
double my_sin(double x, int n)
{
double my_sin = 0;
for (int j = 0; j < n ; j++)
{
double i = (double)j;
double faculty_j = (double)factorial(2*i+1);
my_sin = my_sin + (my_pow((-1.0), i) * (my_pow(x, 2.0 * i + 1.0) / faculty_j));
}
return my_sin;
}
int main()
{
int n = 0;
double x = 0;
printf("x=");
scanf_s("%lf", &x);
printf("n=");
scanf_s("%i", &n);
printf("sin(%i)=", (int)x);
printf("%lf\n", my_sin(x, n));
return 0;
}
这里的问题不一定是你的代码。这只是您对等式的期望。我在 Wolfram Alpha 中测试了 n=5 的泰勒级数,并使用查询
从该系列中减去 sin(x)
(sum (-1)^i * x^(2i+1)/(2i+1)!, i=0 to 5) - sin(x)
查看错误。
如您所见,当 x 大约为 0 时,该级数进行了很好的近似,但是当 x 超过 3 时,误差开始变大,并且增长极快。在 x=8 时,错误的大小为 67,这显然是无用的。要获得合理的近似值,您需要使用 n=15 左右。只有五个太少了。
您在这里应该做的是利用 sin(x) = sin(x + k * 2 * PI) 的事实,其中 k 是任意整数。如果 x 是负数,您可以简单地使用 sin(x) = -sin(-x) 这一事实。我正在展示一个简单的例子来说明它是如何完成的:
double my_sin(double x, int n)
{
double my_sin = 0;
double sign = 1.0;
// sin(-x) = -sin(x)
// This does not improve accuracy. It's just to make the rest simpler
if(x<0) {
x=-x;
sign *= -1;
}
// sin(x) = sin(k*2*PI + x)
x -= 2*PI*floor(x/(2*PI));
// Continue as usual
return sign * my_sin;
}
您想尽可能接近 x=0。为了进一步改进这一点,您可以使用 sin(x) = -sin(x+PI) 这一事实,如下所示。
以上足以将所有内容保持在 [0, PI] 区间内,但实际上我们可以通过使用一些更聪明的数学来做得更好。我们可以利用 sin(x) 关于 x=PI/2 + k*PI 对称的事实。所以 sin(PI/2 -x) = sin(PI/2 + x)。利用它将使您保持在 [0, PI/2] 区间内,当您处于该区间内时,n=2 足以使误差低于 0.005。对于 n=5,误差低于 10^-7。您可以在前面的步骤之后添加:
// sin(x) = -sin(x+PI)
if(x>PI) {
x-=PI;
sign *= -1;
}
// sin(PI/2 -x) = sin(PI/2 + x)
if(x>PI/2)
x = PI - x;
但是,您的代码中存在一个错误。请记住,应该包括 case j=n,所以更改
for (int j = 0; j < n ; j++)
至
for (int j = 0; j <= n ; j++)
另一种方法是始终在参数中添加 1 来调用函数。
为了清楚起见。请记住,泰勒级数期望 x
以弧度为单位。如果你使用度数,你会得到错误的结果。
为了完整起见,这里是完整的函数以及一些不影响正确性但会影响性能和可读性的其他修复:
double my_sin(double x, int n)
{
double ret = 0;
double sign = 1.0;
if(x<0) {
x=-x;
sign *= -1;
}
x -= 2*PI*floor(x/(2*PI));
if(x>PI) {
x-=PI;
sign *= -1;
}
if(x>PI/2)
x = PI - x;
size_t denominator = 1;
double numerator = x;
int s = -1;
for (int j = 0; j <= n ; j++) {
denominator *= 2*j + 1;
s *= -1;
ret += s * numerator / denominator;
numerator *= x*x;
}
return sign*ret;
}
追求一定的精度
假设您想要 3 个正确的十进制数字。然后我们可以利用分子比分母增长慢的事实并做这样的事情:
size_t denominator = 1;
double numerator = x;
double term;
int s = -1;
int j = 0;
double tolerance = 0.001;
do {
denominator *= 2*j + 1;
j++;
s *= -1;
term = numerator / denominator;
ret += s * term;
numerator *= x*x;
} while(abs(term) > tolerance);
你的代码有很多问题:
factorial
函数使用范围有限的整数算法进行计算。对于 n > 13
和 32 位 int
或 long
. ,它会溢出未定义的行为
my_pow()
函数不正确:它不适用于负值,因此对于 my_pow(-1, ...)
. 给出了错误的结果
您还应该首先将 x
减少到 0 和 PI/2 之间的数字,然后逐步计算序列的项。
这是带有测试套件的修改版本:
#include <math.h>
#include <stdio.h>
long int factorial(int factor) {
long int result = 1;
if (factor > 0) {
for (int i = 1; i <= factor; i++) {
result = result * i;
}
} else {
result = 1;
}
return result;
}
double my_pow(double a, double b) {
if (b == 0) {
return 1;
}
double result = a;
double increment = a;
double i, j;
for (i = 1; i < b; i++) {
for (j = 1; j < a; j++) {
result += increment;
}
increment = result;
}
return result;
}
double my_sin(double x, int n) {
double my_sin = 0;
for (int j = 0; j < n; j++) {
double i = (double)j;
double faculty_j = (double)factorial(2 * i + 1);
my_sin = my_sin + (my_pow((-1.0), i) * (my_pow(x, 2.0 * i + 1.0) / faculty_j));
}
return my_sin;
}
double my_sin2(double x, int n) {
double my_sin, term, sign = 1.0;
if (x < 0) {
x = -x;
sign = -sign;
}
if (x >= 2 * M_PI) {
x = fmod(x, 2 * M_PI);
}
if (x > M_PI) {
x -= M_PI;
sign = -sign;
}
if (x > M_PI / 2) {
x = M_PI - x;
}
my_sin = term = x * sign;
for (int i = 1; i <= n; i++) {
term = -term * x * x / ((2 * i) * (2 * i + 1));
my_sin += term;
}
return my_sin;
}
int main() {
int i, n = 16, steps = 100;
double x1 = -7.0, x2 = 7.0;
#if 0
printf("n=");
scanf("%i", &n);
printf("x1=");
scanf("%lf", &x1);
printf("x2=");
scanf("%lf", &x2);
printf("steps=");
scanf("%i", &steps);
#endif
char buf1[20];
char buf2[20];
snprintf(buf1, sizeof(buf1), "my_sin(x,%d)", n);
snprintf(buf2, sizeof(buf2), "my_sin2(x,%d)", n);
printf("%17s %17s %17s %17s %17s %17s\n",
"x", "sin(x)", buf1, "error1", buf2, "error2");
for (i = 0; i <= steps; i++) {
double x = x1 + (x2 - x1) * ((double)i / steps);
double s = sin(x);
double s1 = my_sin(x, n);
double s2 = my_sin2(x, n);
printf("%17.14f %17.14f %17.14f %17.14f %17.14f %17.14f\n",
x, s, s1, s1 - s, s2, s2 - s);
}
return 0;
}
输出:
x sin(x) my_sin(x,16) error1 my_sin2(x,16) error2
-7.00000000000000 -0.65698659871879 -5.77359164449339 -5.11660504577460 -0.65698659871879 -0.00000000000000
-6.86000000000000 -0.54535677064030 -5.65811981160352 -5.11276304096322 -0.54535677064030 0.00000000000000
-6.72000000000000 -0.42305539714300 -5.54264797871365 -5.11959258157066 -0.42305539714300 -0.00000000000000
-6.58000000000000 -0.29247567242987 -5.42717614582379 -5.13470047339392 -0.29247567242987 -0.00000000000000
-6.44000000000000 -0.15617278154321 -5.31170431293392 -5.15553153139071 -0.15617278154321 -0.00000000000000
-6.30000000000000 -0.01681390048435 -5.19623248004405 -5.17941857955970 -0.01681390048435 -0.00000000000000
-6.16000000000000 0.12287399510655 -5.08076064715418 -5.20363464226073 0.12287399510655 -0.00000000000000
-6.02000000000000 0.26015749143047 -4.96528881426431 -5.22544630569478 0.26015749143047 -0.00000000000000
-5.88000000000000 0.39235022399145 -4.84981698137445 -5.24216720536590 0.39235022399145 -0.00000000000000
-5.74000000000000 0.51686544439743 -4.73434514848458 -5.25121059288201 0.51686544439743 -0.00000000000000
-5.60000000000000 0.63126663787232 -4.61887331559471 -5.25013995346703 0.63126663787232 -0.00000000000000
-5.46000000000000 0.73331520099566 -4.50340148270484 -5.23671668370050 0.73331520099566 -0.00000000000000
-5.32000000000000 0.82101424671125 -4.38792964981498 -5.20894389652622 0.82101424671125 -0.00000000000000
-5.18000000000000 0.89264767942823 -4.27245781692511 -5.16510549635334 0.89264767942823 0.00000000000000
-5.04000000000000 0.94681377559261 -4.15698598403524 -5.10379975962785 0.94681377559261 -0.00000000000000
-4.90000000000000 0.98245261262433 -4.04151415114537 -5.02396676376970 0.98245261262433 -0.00000000000000
-4.76000000000000 0.99886680949041 -3.92604231825550 -4.92490912774592 0.99886680949041 0.00000000000000
-4.62000000000000 0.99573517306225 -3.81057048536564 -4.80630565842788 0.99573517306225 0.00000000000000
-4.48000000000000 0.97311898322517 -3.69509865247577 -4.66821763570094 0.97311898322517 0.00000000000000
-4.34000000000000 0.93146079375324 -3.57962681958590 -4.51108761333914 0.93146079375324 0.00000000000000
-4.20000000000000 0.87157577241359 -3.46415498669603 -4.33573075910962 0.87157577241359 0.00000000000000
-4.06000000000000 0.79463574975740 -3.34868315380617 -4.14331890356356 0.79463574975740 0.00000000000000
-3.92000000000000 0.70214628873081 -3.23321132091630 -3.93535760964710 0.70214628873081 0.00000000000000
-3.78000000000000 0.59591722380776 -3.11773948802643 -3.71365671183419 0.59591722380776 -0.00000000000000
-3.64000000000000 0.47802724613534 -3.00226765513656 -3.48029490127191 0.47802724613534 0.00000000000000
-3.50000000000000 0.35078322768962 -2.88679582224669 -3.23757904993631 0.35078322768962 0.00000000000000
-3.36000000000000 0.21667508038738 -2.77132398935683 -2.98799906974421 0.21667508038738 0.00000000000000
-3.22000000000000 0.07832703347086 -2.65585215646696 -2.73417918993782 0.07832703347086 0.00000000000000
-3.08000000000000 -0.06155371742991 -2.54038032357709 -2.47882660614718 -0.06155371742991 0.00000000000000
-2.94000000000000 -0.20022998472177 -2.42490849068722 -2.22467850596545 -0.20022998472177 0.00000000000000
-2.80000000000000 -0.33498815015591 -2.30943665779736 -1.97444850764145 -0.33498815015590 0.00000000000000
-2.66000000000000 -0.46319126493035 -2.19396482490749 -1.73077355997714 -0.46319126493035 0.00000000000000
-2.52000000000000 -0.58233064952408 -2.07849299201762 -1.49616234249354 -0.58233064952408 0.00000000000000
-2.38000000000000 -0.69007498355694 -1.96302115912775 -1.27294617557082 -0.69007498355694 0.00000000000000
-2.24000000000000 -0.78431592508442 -1.84754932623788 -1.06323340115346 -0.78431592508442 0.00000000000000
-2.10000000000000 -0.86320936664887 -1.73207749334802 -0.86886812669914 -0.86320936664887 0.00000000000000
-1.96000000000000 -0.92521152078817 -1.61660566045815 -0.69139413966998 -0.92521152078817 0.00000000000000
-1.82000000000000 -0.96910912888046 -1.50113382756828 -0.53202469868783 -0.96910912888046 0.00000000000000
-1.68000000000000 -0.99404320219808 -1.38566199467841 -0.39161879248034 -0.99404320219808 -0.00000000000000
-1.54000000000000 -0.99952583060548 -1.27019016178855 -0.27066433118307 -0.99952583060548 0.00000000000000
-1.40000000000000 -0.98544972998846 -1.15471832889868 -0.16926859891022 -0.98544972998846 0.00000000000000
-1.26000000000000 -0.95209034159052 -1.03924649600881 -0.08715615441829 -0.95209034159052 -0.00000000000000
-1.12000000000000 -0.90010044217651 -0.92377466311894 -0.02367422094244 -0.90010044217651 0.00000000000000
-0.98000000000000 -0.83049737049197 -0.80830283022907 0.02219454026290 -0.83049737049197 -0.00000000000000
-0.84000000000000 -0.74464311997086 -0.69283099733921 0.05181212263165 -0.74464311997086 0.00000000000000
-0.70000000000000 -0.64421768723769 -0.57735916444934 0.06685852278835 -0.64421768723769 0.00000000000000
-0.56000000000000 -0.53118619792088 -0.46188733155947 0.06929886636141 -0.53118619792088 0.00000000000000
-0.42000000000000 -0.40776045305957 -0.34641549866960 0.06134495438997 -0.40776045305957 -0.00000000000000
-0.28000000000000 -0.27635564856411 -0.23094366577974 0.04541198278438 -0.27635564856411 0.00000000000000
-0.14000000000000 -0.13954311464424 -0.11547183288987 0.02407128175437 -0.13954311464424 0.00000000000000
0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000
0.14000000000000 0.13954311464424 0.11547183288987 -0.02407128175437 0.13954311464424 0.00000000000000
0.28000000000000 0.27635564856411 0.23094366577974 -0.04541198278438 0.27635564856411 0.00000000000000
0.42000000000000 0.40776045305957 0.34641549866960 -0.06134495438997 0.40776045305957 0.00000000000000
0.56000000000000 0.53118619792088 0.46188733155947 -0.06929886636141 0.53118619792088 0.00000000000000
0.70000000000000 0.64421768723769 0.57735916444934 -0.06685852278835 0.64421768723769 0.00000000000000
0.84000000000000 0.74464311997086 0.69283099733921 -0.05181212263165 0.74464311997086 0.00000000000000
0.98000000000000 0.83049737049197 0.80830283022907 -0.02219454026290 0.83049737049197 0.00000000000000
1.12000000000000 0.90010044217650 0.20895817141848 -0.69114227075803 0.90010044217650 0.00000000000000
1.26000000000000 0.95209034159052 0.23507794284579 -0.71701239874473 0.95209034159052 0.00000000000000
1.40000000000000 0.98544972998846 0.26119771427310 -0.72425201571536 0.98544972998846 0.00000000000000
1.54000000000000 0.99952583060548 0.28731748570041 -0.71220834490507 0.99952583060548 0.00000000000000
1.68000000000000 0.99404320219808 0.31343725712772 -0.68060594507036 0.99404320219808 0.00000000000000
1.82000000000000 0.96910912888046 0.33955702855503 -0.62955210032543 0.96910912888046 -0.00000000000000
1.96000000000000 0.92521152078817 0.36567679998234 -0.55953472080583 0.92521152078817 0.00000000000000
2.10000000000000 0.86320936664887 -2.81259124559189 -3.67580061224076 0.86320936664887 0.00000000000000
2.24000000000000 0.78431592508442 -3.00009732863135 -3.78441325371577 0.78431592508442 -0.00000000000000
2.38000000000000 0.69007498355694 -3.18760341167081 -3.87767839522775 0.69007498355694 -0.00000000000000
2.52000000000000 0.58233064952408 -3.37510949471027 -3.95744014423435 0.58233064952408 -0.00000000000000
2.66000000000000 0.46319126493035 -3.56261557774973 -4.02580684268007 0.46319126493035 0.00000000000000
2.80000000000000 0.33498815015591 -3.75012166078919 -4.08510981094509 0.33498815015591 -0.00000000000000
2.94000000000000 0.20022998472177 -3.93762774382865 -4.13785772855042 0.20022998472177 -0.00000000000000
3.08000000000000 0.06155371742991 -15.52969329095525 -15.59124700838516 0.06155371742991 -0.00000000000000
3.22000000000000 -0.07832703347086 -16.23558844054412 -16.15726140707325 -0.07832703347086 -0.00000000000000
3.36000000000000 -0.21667508038738 -16.94148359013299 -16.72480850974561 -0.21667508038738 -0.00000000000000
3.50000000000000 -0.35078322768962 -17.64737873972186 -17.29659551203224 -0.35078322768962 -0.00000000000000
3.64000000000000 -0.47802724613534 -18.35327388931075 -17.87524664317541 -0.47802724613534 -0.00000000000000
3.78000000000000 -0.59591722380777 -19.05916903889963 -18.46325181509186 -0.59591722380776 0.00000000000000
3.92000000000000 -0.70214628873081 -19.76506418848850 -19.06291789975770 -0.70214628873081 -0.00000000000000
4.06000000000000 -0.79463574975740 -785.98288527038937 -785.18824952063198 -0.79463574975740 -0.00000000000000
4.20000000000000 -0.87157577241359 -813.08574338316134 -812.21416761074772 -0.87157577241359 0.00000000000000
4.34000000000000 -0.93146079375324 -840.18860149593320 -839.25714070217998 -0.93146079375324 0.00000000000000
4.48000000000000 -0.97311898322517 -867.29145960870540 -866.31834062548023 -0.97311898322517 0.00000000000000
4.62000000000000 -0.99573517306225 -894.39431772147736 -893.39858254841511 -0.99573517306225 -0.00000000000000
4.76000000000000 -0.99886680949041 -921.49717583424911 -920.49830902475867 -0.99886680949041 -0.00000000000000
4.90000000000000 -0.98245261262433 -948.60003394702130 -947.61758133439696 -0.98245261262433 0.00000000000000
5.04000000000000 -0.94681377559261 -218497.22569403689704 -218496.27888026129222 -0.94681377559261 0.00000000000000
5.18000000000000 -0.89264767942823 -224566.59307442686986 -224565.70042674744036 -0.89264767942823 0.00000000000000
5.32000000000000 -0.82101424671125 -230635.96045481678448 -230635.13944057008484 -0.82101424671125 0.00000000000000
5.46000000000000 -0.73331520099566 -236705.32783520672820 -236704.59452000574674 -0.73331520099566 0.00000000000000
5.60000000000000 -0.63126663787232 -242774.69521559661371 -242774.06394895873382 -0.63126663787232 0.00000000000000
5.74000000000000 -0.51686544439743 -248844.06259598652832 -248843.54573054212960 -0.51686544439743 0.00000000000000
5.88000000000000 -0.39235022399145 -254913.42997637641383 -254913.03762615242158 -0.39235022399145 0.00000000000000
6.02000000000000 -0.26015749143047 -26739506.86298683285713 -26739506.60282934084535 -0.26015749143047 0.00000000000000
6.16000000000000 -0.12287399510655 -27361355.85980049148202 -27361355.73692649602890 -0.12287399510655 0.00000000000000
6.30000000000000 0.01681390048435 -27983204.85661410912871 -27983204.87342800945044 0.01681390048435 0.00000000000000
6.44000000000000 0.15617278154321 -28605053.85342779010534 -28605054.00960057228804 0.15617278154321 0.00000000000000
6.58000000000000 0.29247567242987 -29226902.85024143010378 -29226903.14271710067987 0.29247567242987 0.00000000000000
6.72000000000000 0.42305539714300 -29848751.84705507382751 -29848752.27011046931148 0.42305539714300 0.00000000000000
6.86000000000000 0.54535677064030 -30470600.84386872500181 -30470601.38922549411654 0.54535677064030 0.00000000000000
7.00000000000000 0.65698659871879 -31092449.84068236500025 -31092450.49766896292567 0.65698659871879 0.00000000000000
我想根据这个等式使用我自己的函数计算用户输入的正弦:
sin(x) = sum_(i=0)^n (-1)^i * (x^(2 i + 1)/((2 i + 1)!))
我有这段代码,根据我的理解,我所做的与等式中写的完全一样:
#include <stdio.h>
#include <math.h>
int faculty(int factor)
{
int result = 1;
if (factor > 0)
{
for (int i = 1; i <= factor; i++)
{
result = result * i;
}
}
else
{
result = 1;
}
return result;
}
double my_sin(double x, int n)
{
double my_sin = 0;
for (int j = 0; j < n ; j++)
{
double i = (double)j;
double faculty_j = (double)faculty(2*j+1);
my_sin = my_sin + (pow((-1.0), i) * (pow(x, (double)(2.0 * i + 1.0)) / faculty_j));
}
return my_sin;
}
int main()
{
int n = 0;
double x = 0;
printf("x=");
scanf("%lf", &x);
printf("n=");
scanf("%i", &n);
printf("sin(%i)=", (int)x);
printf("%lf\n", my_sin(x, n));
return 0;
}
但是,例如,当我使用 x = 8
和 n = 5
时,结果是 sin(8)=149
。我尝试调试代码一段时间了,但我不知道问题出在哪里,也不知道如何找出问题所在。
更新代码:
#include <stdio.h>
long int factorial(int factor)
{
long int result = 1;
if (factor > 0)
{
for (int i = 1; i <= factor; i++)
{
result = result * i;
}
}
else
{
result = 1;
}
return result;
}
double my_pow(double a, double b)
{
if (b == 0)
{
return 1;
}
double result = a;
double increment = a;
double i, j;
for (i = 1; i < b; i++)
{
for (j = 1; j < a; j++)
{
result += increment;
}
increment = result;
}
return result;
}
double my_sin(double x, int n)
{
double my_sin = 0;
for (int j = 0; j < n ; j++)
{
double i = (double)j;
double faculty_j = (double)factorial(2*i+1);
my_sin = my_sin + (my_pow((-1.0), i) * (my_pow(x, 2.0 * i + 1.0) / faculty_j));
}
return my_sin;
}
int main()
{
int n = 0;
double x = 0;
printf("x=");
scanf_s("%lf", &x);
printf("n=");
scanf_s("%i", &n);
printf("sin(%i)=", (int)x);
printf("%lf\n", my_sin(x, n));
return 0;
}
这里的问题不一定是你的代码。这只是您对等式的期望。我在 Wolfram Alpha 中测试了 n=5 的泰勒级数,并使用查询
从该系列中减去 sin(x)(sum (-1)^i * x^(2i+1)/(2i+1)!, i=0 to 5) - sin(x)
查看错误。
如您所见,当 x 大约为 0 时,该级数进行了很好的近似,但是当 x 超过 3 时,误差开始变大,并且增长极快。在 x=8 时,错误的大小为 67,这显然是无用的。要获得合理的近似值,您需要使用 n=15 左右。只有五个太少了。
您在这里应该做的是利用 sin(x) = sin(x + k * 2 * PI) 的事实,其中 k 是任意整数。如果 x 是负数,您可以简单地使用 sin(x) = -sin(-x) 这一事实。我正在展示一个简单的例子来说明它是如何完成的:
double my_sin(double x, int n)
{
double my_sin = 0;
double sign = 1.0;
// sin(-x) = -sin(x)
// This does not improve accuracy. It's just to make the rest simpler
if(x<0) {
x=-x;
sign *= -1;
}
// sin(x) = sin(k*2*PI + x)
x -= 2*PI*floor(x/(2*PI));
// Continue as usual
return sign * my_sin;
}
您想尽可能接近 x=0。为了进一步改进这一点,您可以使用 sin(x) = -sin(x+PI) 这一事实,如下所示。
以上足以将所有内容保持在 [0, PI] 区间内,但实际上我们可以通过使用一些更聪明的数学来做得更好。我们可以利用 sin(x) 关于 x=PI/2 + k*PI 对称的事实。所以 sin(PI/2 -x) = sin(PI/2 + x)。利用它将使您保持在 [0, PI/2] 区间内,当您处于该区间内时,n=2 足以使误差低于 0.005。对于 n=5,误差低于 10^-7。您可以在前面的步骤之后添加:
// sin(x) = -sin(x+PI)
if(x>PI) {
x-=PI;
sign *= -1;
}
// sin(PI/2 -x) = sin(PI/2 + x)
if(x>PI/2)
x = PI - x;
但是,您的代码中存在一个错误。请记住,应该包括 case j=n,所以更改
for (int j = 0; j < n ; j++)
至
for (int j = 0; j <= n ; j++)
另一种方法是始终在参数中添加 1 来调用函数。
为了清楚起见。请记住,泰勒级数期望 x
以弧度为单位。如果你使用度数,你会得到错误的结果。
为了完整起见,这里是完整的函数以及一些不影响正确性但会影响性能和可读性的其他修复:
double my_sin(double x, int n)
{
double ret = 0;
double sign = 1.0;
if(x<0) {
x=-x;
sign *= -1;
}
x -= 2*PI*floor(x/(2*PI));
if(x>PI) {
x-=PI;
sign *= -1;
}
if(x>PI/2)
x = PI - x;
size_t denominator = 1;
double numerator = x;
int s = -1;
for (int j = 0; j <= n ; j++) {
denominator *= 2*j + 1;
s *= -1;
ret += s * numerator / denominator;
numerator *= x*x;
}
return sign*ret;
}
追求一定的精度
假设您想要 3 个正确的十进制数字。然后我们可以利用分子比分母增长慢的事实并做这样的事情:
size_t denominator = 1;
double numerator = x;
double term;
int s = -1;
int j = 0;
double tolerance = 0.001;
do {
denominator *= 2*j + 1;
j++;
s *= -1;
term = numerator / denominator;
ret += s * term;
numerator *= x*x;
} while(abs(term) > tolerance);
你的代码有很多问题:
factorial
函数使用范围有限的整数算法进行计算。对于n > 13
和 32 位int
或long
. ,它会溢出未定义的行为
my_pow()
函数不正确:它不适用于负值,因此对于my_pow(-1, ...)
. 给出了错误的结果
您还应该首先将 x
减少到 0 和 PI/2 之间的数字,然后逐步计算序列的项。
这是带有测试套件的修改版本:
#include <math.h>
#include <stdio.h>
long int factorial(int factor) {
long int result = 1;
if (factor > 0) {
for (int i = 1; i <= factor; i++) {
result = result * i;
}
} else {
result = 1;
}
return result;
}
double my_pow(double a, double b) {
if (b == 0) {
return 1;
}
double result = a;
double increment = a;
double i, j;
for (i = 1; i < b; i++) {
for (j = 1; j < a; j++) {
result += increment;
}
increment = result;
}
return result;
}
double my_sin(double x, int n) {
double my_sin = 0;
for (int j = 0; j < n; j++) {
double i = (double)j;
double faculty_j = (double)factorial(2 * i + 1);
my_sin = my_sin + (my_pow((-1.0), i) * (my_pow(x, 2.0 * i + 1.0) / faculty_j));
}
return my_sin;
}
double my_sin2(double x, int n) {
double my_sin, term, sign = 1.0;
if (x < 0) {
x = -x;
sign = -sign;
}
if (x >= 2 * M_PI) {
x = fmod(x, 2 * M_PI);
}
if (x > M_PI) {
x -= M_PI;
sign = -sign;
}
if (x > M_PI / 2) {
x = M_PI - x;
}
my_sin = term = x * sign;
for (int i = 1; i <= n; i++) {
term = -term * x * x / ((2 * i) * (2 * i + 1));
my_sin += term;
}
return my_sin;
}
int main() {
int i, n = 16, steps = 100;
double x1 = -7.0, x2 = 7.0;
#if 0
printf("n=");
scanf("%i", &n);
printf("x1=");
scanf("%lf", &x1);
printf("x2=");
scanf("%lf", &x2);
printf("steps=");
scanf("%i", &steps);
#endif
char buf1[20];
char buf2[20];
snprintf(buf1, sizeof(buf1), "my_sin(x,%d)", n);
snprintf(buf2, sizeof(buf2), "my_sin2(x,%d)", n);
printf("%17s %17s %17s %17s %17s %17s\n",
"x", "sin(x)", buf1, "error1", buf2, "error2");
for (i = 0; i <= steps; i++) {
double x = x1 + (x2 - x1) * ((double)i / steps);
double s = sin(x);
double s1 = my_sin(x, n);
double s2 = my_sin2(x, n);
printf("%17.14f %17.14f %17.14f %17.14f %17.14f %17.14f\n",
x, s, s1, s1 - s, s2, s2 - s);
}
return 0;
}
输出:
x sin(x) my_sin(x,16) error1 my_sin2(x,16) error2 -7.00000000000000 -0.65698659871879 -5.77359164449339 -5.11660504577460 -0.65698659871879 -0.00000000000000 -6.86000000000000 -0.54535677064030 -5.65811981160352 -5.11276304096322 -0.54535677064030 0.00000000000000 -6.72000000000000 -0.42305539714300 -5.54264797871365 -5.11959258157066 -0.42305539714300 -0.00000000000000 -6.58000000000000 -0.29247567242987 -5.42717614582379 -5.13470047339392 -0.29247567242987 -0.00000000000000 -6.44000000000000 -0.15617278154321 -5.31170431293392 -5.15553153139071 -0.15617278154321 -0.00000000000000 -6.30000000000000 -0.01681390048435 -5.19623248004405 -5.17941857955970 -0.01681390048435 -0.00000000000000 -6.16000000000000 0.12287399510655 -5.08076064715418 -5.20363464226073 0.12287399510655 -0.00000000000000 -6.02000000000000 0.26015749143047 -4.96528881426431 -5.22544630569478 0.26015749143047 -0.00000000000000 -5.88000000000000 0.39235022399145 -4.84981698137445 -5.24216720536590 0.39235022399145 -0.00000000000000 -5.74000000000000 0.51686544439743 -4.73434514848458 -5.25121059288201 0.51686544439743 -0.00000000000000 -5.60000000000000 0.63126663787232 -4.61887331559471 -5.25013995346703 0.63126663787232 -0.00000000000000 -5.46000000000000 0.73331520099566 -4.50340148270484 -5.23671668370050 0.73331520099566 -0.00000000000000 -5.32000000000000 0.82101424671125 -4.38792964981498 -5.20894389652622 0.82101424671125 -0.00000000000000 -5.18000000000000 0.89264767942823 -4.27245781692511 -5.16510549635334 0.89264767942823 0.00000000000000 -5.04000000000000 0.94681377559261 -4.15698598403524 -5.10379975962785 0.94681377559261 -0.00000000000000 -4.90000000000000 0.98245261262433 -4.04151415114537 -5.02396676376970 0.98245261262433 -0.00000000000000 -4.76000000000000 0.99886680949041 -3.92604231825550 -4.92490912774592 0.99886680949041 0.00000000000000 -4.62000000000000 0.99573517306225 -3.81057048536564 -4.80630565842788 0.99573517306225 0.00000000000000 -4.48000000000000 0.97311898322517 -3.69509865247577 -4.66821763570094 0.97311898322517 0.00000000000000 -4.34000000000000 0.93146079375324 -3.57962681958590 -4.51108761333914 0.93146079375324 0.00000000000000 -4.20000000000000 0.87157577241359 -3.46415498669603 -4.33573075910962 0.87157577241359 0.00000000000000 -4.06000000000000 0.79463574975740 -3.34868315380617 -4.14331890356356 0.79463574975740 0.00000000000000 -3.92000000000000 0.70214628873081 -3.23321132091630 -3.93535760964710 0.70214628873081 0.00000000000000 -3.78000000000000 0.59591722380776 -3.11773948802643 -3.71365671183419 0.59591722380776 -0.00000000000000 -3.64000000000000 0.47802724613534 -3.00226765513656 -3.48029490127191 0.47802724613534 0.00000000000000 -3.50000000000000 0.35078322768962 -2.88679582224669 -3.23757904993631 0.35078322768962 0.00000000000000 -3.36000000000000 0.21667508038738 -2.77132398935683 -2.98799906974421 0.21667508038738 0.00000000000000 -3.22000000000000 0.07832703347086 -2.65585215646696 -2.73417918993782 0.07832703347086 0.00000000000000 -3.08000000000000 -0.06155371742991 -2.54038032357709 -2.47882660614718 -0.06155371742991 0.00000000000000 -2.94000000000000 -0.20022998472177 -2.42490849068722 -2.22467850596545 -0.20022998472177 0.00000000000000 -2.80000000000000 -0.33498815015591 -2.30943665779736 -1.97444850764145 -0.33498815015590 0.00000000000000 -2.66000000000000 -0.46319126493035 -2.19396482490749 -1.73077355997714 -0.46319126493035 0.00000000000000 -2.52000000000000 -0.58233064952408 -2.07849299201762 -1.49616234249354 -0.58233064952408 0.00000000000000 -2.38000000000000 -0.69007498355694 -1.96302115912775 -1.27294617557082 -0.69007498355694 0.00000000000000 -2.24000000000000 -0.78431592508442 -1.84754932623788 -1.06323340115346 -0.78431592508442 0.00000000000000 -2.10000000000000 -0.86320936664887 -1.73207749334802 -0.86886812669914 -0.86320936664887 0.00000000000000 -1.96000000000000 -0.92521152078817 -1.61660566045815 -0.69139413966998 -0.92521152078817 0.00000000000000 -1.82000000000000 -0.96910912888046 -1.50113382756828 -0.53202469868783 -0.96910912888046 0.00000000000000 -1.68000000000000 -0.99404320219808 -1.38566199467841 -0.39161879248034 -0.99404320219808 -0.00000000000000 -1.54000000000000 -0.99952583060548 -1.27019016178855 -0.27066433118307 -0.99952583060548 0.00000000000000 -1.40000000000000 -0.98544972998846 -1.15471832889868 -0.16926859891022 -0.98544972998846 0.00000000000000 -1.26000000000000 -0.95209034159052 -1.03924649600881 -0.08715615441829 -0.95209034159052 -0.00000000000000 -1.12000000000000 -0.90010044217651 -0.92377466311894 -0.02367422094244 -0.90010044217651 0.00000000000000 -0.98000000000000 -0.83049737049197 -0.80830283022907 0.02219454026290 -0.83049737049197 -0.00000000000000 -0.84000000000000 -0.74464311997086 -0.69283099733921 0.05181212263165 -0.74464311997086 0.00000000000000 -0.70000000000000 -0.64421768723769 -0.57735916444934 0.06685852278835 -0.64421768723769 0.00000000000000 -0.56000000000000 -0.53118619792088 -0.46188733155947 0.06929886636141 -0.53118619792088 0.00000000000000 -0.42000000000000 -0.40776045305957 -0.34641549866960 0.06134495438997 -0.40776045305957 -0.00000000000000 -0.28000000000000 -0.27635564856411 -0.23094366577974 0.04541198278438 -0.27635564856411 0.00000000000000 -0.14000000000000 -0.13954311464424 -0.11547183288987 0.02407128175437 -0.13954311464424 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.00000000000000 0.14000000000000 0.13954311464424 0.11547183288987 -0.02407128175437 0.13954311464424 0.00000000000000 0.28000000000000 0.27635564856411 0.23094366577974 -0.04541198278438 0.27635564856411 0.00000000000000 0.42000000000000 0.40776045305957 0.34641549866960 -0.06134495438997 0.40776045305957 0.00000000000000 0.56000000000000 0.53118619792088 0.46188733155947 -0.06929886636141 0.53118619792088 0.00000000000000 0.70000000000000 0.64421768723769 0.57735916444934 -0.06685852278835 0.64421768723769 0.00000000000000 0.84000000000000 0.74464311997086 0.69283099733921 -0.05181212263165 0.74464311997086 0.00000000000000 0.98000000000000 0.83049737049197 0.80830283022907 -0.02219454026290 0.83049737049197 0.00000000000000 1.12000000000000 0.90010044217650 0.20895817141848 -0.69114227075803 0.90010044217650 0.00000000000000 1.26000000000000 0.95209034159052 0.23507794284579 -0.71701239874473 0.95209034159052 0.00000000000000 1.40000000000000 0.98544972998846 0.26119771427310 -0.72425201571536 0.98544972998846 0.00000000000000 1.54000000000000 0.99952583060548 0.28731748570041 -0.71220834490507 0.99952583060548 0.00000000000000 1.68000000000000 0.99404320219808 0.31343725712772 -0.68060594507036 0.99404320219808 0.00000000000000 1.82000000000000 0.96910912888046 0.33955702855503 -0.62955210032543 0.96910912888046 -0.00000000000000 1.96000000000000 0.92521152078817 0.36567679998234 -0.55953472080583 0.92521152078817 0.00000000000000 2.10000000000000 0.86320936664887 -2.81259124559189 -3.67580061224076 0.86320936664887 0.00000000000000 2.24000000000000 0.78431592508442 -3.00009732863135 -3.78441325371577 0.78431592508442 -0.00000000000000 2.38000000000000 0.69007498355694 -3.18760341167081 -3.87767839522775 0.69007498355694 -0.00000000000000 2.52000000000000 0.58233064952408 -3.37510949471027 -3.95744014423435 0.58233064952408 -0.00000000000000 2.66000000000000 0.46319126493035 -3.56261557774973 -4.02580684268007 0.46319126493035 0.00000000000000 2.80000000000000 0.33498815015591 -3.75012166078919 -4.08510981094509 0.33498815015591 -0.00000000000000 2.94000000000000 0.20022998472177 -3.93762774382865 -4.13785772855042 0.20022998472177 -0.00000000000000 3.08000000000000 0.06155371742991 -15.52969329095525 -15.59124700838516 0.06155371742991 -0.00000000000000 3.22000000000000 -0.07832703347086 -16.23558844054412 -16.15726140707325 -0.07832703347086 -0.00000000000000 3.36000000000000 -0.21667508038738 -16.94148359013299 -16.72480850974561 -0.21667508038738 -0.00000000000000 3.50000000000000 -0.35078322768962 -17.64737873972186 -17.29659551203224 -0.35078322768962 -0.00000000000000 3.64000000000000 -0.47802724613534 -18.35327388931075 -17.87524664317541 -0.47802724613534 -0.00000000000000 3.78000000000000 -0.59591722380777 -19.05916903889963 -18.46325181509186 -0.59591722380776 0.00000000000000 3.92000000000000 -0.70214628873081 -19.76506418848850 -19.06291789975770 -0.70214628873081 -0.00000000000000 4.06000000000000 -0.79463574975740 -785.98288527038937 -785.18824952063198 -0.79463574975740 -0.00000000000000 4.20000000000000 -0.87157577241359 -813.08574338316134 -812.21416761074772 -0.87157577241359 0.00000000000000 4.34000000000000 -0.93146079375324 -840.18860149593320 -839.25714070217998 -0.93146079375324 0.00000000000000 4.48000000000000 -0.97311898322517 -867.29145960870540 -866.31834062548023 -0.97311898322517 0.00000000000000 4.62000000000000 -0.99573517306225 -894.39431772147736 -893.39858254841511 -0.99573517306225 -0.00000000000000 4.76000000000000 -0.99886680949041 -921.49717583424911 -920.49830902475867 -0.99886680949041 -0.00000000000000 4.90000000000000 -0.98245261262433 -948.60003394702130 -947.61758133439696 -0.98245261262433 0.00000000000000 5.04000000000000 -0.94681377559261 -218497.22569403689704 -218496.27888026129222 -0.94681377559261 0.00000000000000 5.18000000000000 -0.89264767942823 -224566.59307442686986 -224565.70042674744036 -0.89264767942823 0.00000000000000 5.32000000000000 -0.82101424671125 -230635.96045481678448 -230635.13944057008484 -0.82101424671125 0.00000000000000 5.46000000000000 -0.73331520099566 -236705.32783520672820 -236704.59452000574674 -0.73331520099566 0.00000000000000 5.60000000000000 -0.63126663787232 -242774.69521559661371 -242774.06394895873382 -0.63126663787232 0.00000000000000 5.74000000000000 -0.51686544439743 -248844.06259598652832 -248843.54573054212960 -0.51686544439743 0.00000000000000 5.88000000000000 -0.39235022399145 -254913.42997637641383 -254913.03762615242158 -0.39235022399145 0.00000000000000 6.02000000000000 -0.26015749143047 -26739506.86298683285713 -26739506.60282934084535 -0.26015749143047 0.00000000000000 6.16000000000000 -0.12287399510655 -27361355.85980049148202 -27361355.73692649602890 -0.12287399510655 0.00000000000000 6.30000000000000 0.01681390048435 -27983204.85661410912871 -27983204.87342800945044 0.01681390048435 0.00000000000000 6.44000000000000 0.15617278154321 -28605053.85342779010534 -28605054.00960057228804 0.15617278154321 0.00000000000000 6.58000000000000 0.29247567242987 -29226902.85024143010378 -29226903.14271710067987 0.29247567242987 0.00000000000000 6.72000000000000 0.42305539714300 -29848751.84705507382751 -29848752.27011046931148 0.42305539714300 0.00000000000000 6.86000000000000 0.54535677064030 -30470600.84386872500181 -30470601.38922549411654 0.54535677064030 0.00000000000000 7.00000000000000 0.65698659871879 -31092449.84068236500025 -31092450.49766896292567 0.65698659871879 0.00000000000000