当前位置: 首页 > 知识库问答 >
问题:

C语言中正弦函数不工作的实现

师冥夜
2023-03-14

我试图在C中实现正弦函数,但我得到了奇怪的结果。下面是我用来计算正弦的三个函数:

#define PI 3.14159265358979323846
#define DEPTH 16

double sine(long double);
long double pow(long double, unsigned int);
unsigned int fact(unsigned int);

double sine(long double x) {
    long double i_x = x *= PI/180;
    int n = 3, d = 0, sign = -1;

    // fails past 67 degrees
    for (; d < DEPTH; n += 2, d++, sign *= -1) {
        x += pow(i_x, n) / fact(n) * sign;
    }

    return x;
}

long double pow(long double base, unsigned int exp) {
    double answer = 1;
    while (exp) {
        answer *= base;
        exp--;
    }
    return answer;
}

unsigned int fact(unsigned int n) {
    unsigned int answer = 1;
    while (n > 1) {
        answer *= n--;
    }
    return answer;
}
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

main() {
    for (int i = 0; i <= 180; i++) {
        printf("sin(%i) = %lf, %lf\n", i, sine(i), sin(i*3.14159265358979323846/180));
    }

    exit(EXIT_SUCCESS);
}
>> sin(100) = 0.987711, 0.984808
>> sin(101) = 0.986885, 0.981627
>> sin(102) = 0.987056, 0.978148
>> sin(103) = 0.988830, 0.974370
>> sin(104) = 0.993060, 0.970296
>> sin(105) = 1.000948, 0.965926
>> sin(106) = 1.014169, 0.961262
>> sin(107) = 1.035052, 0.956305
>> sin(108) = 1.066807, 0.951057
>> sin(109) = 1.113846, 0.945519
>> sin(110) = 1.182194, 0.939693
>> sin(111) = 1.280047, 0.933580
>> sin(112) = 1.418502, 0.927184
>> sin(113) = 1.612527, 0.920505
>> sin(114) = 1.882224, 0.913545
>> sin(115) = 2.254492, 0.906308
>> sin(116) = 2.765192, 0.898794
>> sin(117) = 3.461969, 0.891007
              ...
>> sin(180) = 8431648.192239, 0.000000

共有1个答案

夏侯兴怀
2023-03-14

每当for循环进行时,n增加2,因此对于dept=16,在接近循环结束时,必须计算大到30的数字的阶乘,并且使用的是unsigned int,它只能存储大到2^32=4294967296~=12!的值,这会导致阶乘函数溢出,从而给出错误的阶乘。

即使您对它使用了Long Double,并且我已经在注释中指出,MSCRT中的Long Double映射到Double(Reference),您仍然会看到一些异常,可能是从更大的角度来看,因为尽管Double可以存储像1.8e+308,但它在2^53=9007199254740992~=18!中丢失了粒度(即2^53+1存储为因此,一旦增加角度,这种行为的影响就会变得越来越大,在printf()使用的6小数精度中可以明显看出。

尽管您已经走上了正确的轨道,但您应该使用像GMP或libcrypto这样的bignum库。他们可以在不损失精度的情况下执行这些计算。

19! = 19 * 18 * ... * 2 * 1

如果我们使用double来保存阶乘,那么从23!开始,阶乘就会受到舍入的影响。它可以很容易地显示出来,因为2^74<23!<2^75,这意味着至少需要75位精度才能表示它,但是由于23!19最低有效位,其值为0,因此它需要75-19=56,这比Double提供的53位要大。

对于22!,它是51位(您可以自己计算)。

 类似资料:
  • 本文向大家介绍C语言中计算正弦的相关函数总结,包括了C语言中计算正弦的相关函数总结的使用技巧和注意事项,需要的朋友参考一下 C语言sin()函数:正弦函数 头文件:  sin() 函数用来求给定值的正弦值,其原型为: 【参数】给定的值(弧度)。 【返回值】返回-1 至1 之间的计算结果。 弧度与角度的关系为: 弧度 = 180 / π 角度 角度 = π / 180 弧度 使用 rtod( ) 函

  • 本文向大家介绍C语言中求余弦值的相关函数总结,包括了C语言中求余弦值的相关函数总结的使用技巧和注意事项,需要的朋友参考一下 C语言cos()函数:求余弦值 头文件: cos() 函数用来求余弦值,即求角的临边长度除以斜边长度的比值,其原型为:     【参数】x 为一个弧度。 【返回值】返回-1 至1 之间的计算结果。 弧度与角度的关系为: 弧度 = 180 / π 角度 角度 = π / 180

  • 1. 函数的定义 程序是由一个个函数组成的。我们之前虽然没有正式介绍函数,但是我们早已经开始使用函数了。因为离开了函数,我们的程序没有办法正常的工作。只不过我们使用的是 C 语言内置的标准函数库。 那么函数是什么? 函数是由一组语句组成完成至少一个特定任务的语句的集合。在 C 语言中,我们必须要包含一个函数,就是我们最开始介绍的 mian 函数。 2. 为什么需要函数? 函数帮助我们可以减少代码的

  • 在 Go 语言开篇中我们已经知道,Go 语言与 C 语言之间有着千丝万缕的关系,甚至被称之为 21 世纪的C语言。 所以在 Go 与 C 语言互操作方面,Go 更是提供了强大的支持。尤其是在 Go 中使用 C,你甚至可以直接在 Go 源文件中编写 C 代码,这是其他语言所无法望其项背的。 格式: 在 import "C" 之前通过单行注释或者通过多行注释编写C语言代码 在 import "C" 之

  • 主要内容:形参和实参的区别和联系如果把函数比喻成一台机器,那么参数就是原材料,返回值就是最终产品;从一定程度上讲,函数的作用就是根据不同的参数产生不同的返回值。 这一节我们先来讲解C语言函数的参数,下一节再讲解C语言函数的返回值。 C语言函数的参数会出现在两个地方,分别是函数定义处和函数调用处,这两个地方的参数是有区别的。 形参(形式参数) 在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来