C 中正弦函数的实现不起作用

2024-03-13

我尝试用 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);
}

直至 67 度,其计算结果与内置函数相同。不过,当它超过 67 时,它通常会偏离实际值越来越远。

这是一个示例输出:

>> 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

有谁知道为什么会发生这种情况?我正在 Windows 7 上使用 Visual Studio 2017,如果这提供了任何有用的信息。


每次你的for loop进步,n增加了2因此对于DEPTH = 16,在循环结束时,您必须计算大到的数字的阶乘30你正在使用unsigned int只能存储大小为2^32 = 4294967296 ~= 12!这会导致阶乘函数溢出,从而给出错误的阶乘。

即使你用过long double为此,我已经在评论中指出long double在 MSCRT 中映射到double (参考 https://msdn.microsoft.com/en-us/library/9cx8xs15.aspx)你仍然会在更大的角度看到一些异常,因为尽管double可以存储大到的值1.8E+308但它失去了它的粒度2^53 = 9007199254740992 ~= 18! (i.e. 2^53 + 1存储为double等于2^53)。因此,一旦角度上升,这种行为的影响就会变得越来越大,以至于在您使用的 6 位小数精度中很明显printf().

虽然你走在正确的轨道上,但你应该使用像这样的bignum库GMP or 加密库。他们可以在不损失精度的情况下执行这些计算。

顺便说一句,由于您正在 Windows 7 上进行开发,这意味着您要么使用 x86,要么使用 x86-64。在这些平台上,x87 能够执行 80 位的扩展精度(根据 754 标准)操作,但我不知道编译器内在函数可以为您提供这种功能,而无需求助于汇编代码。

我还想请您注意范围缩小技术。虽然我仍然建议使用 bignum libs,如果你擅长两者之间0 and 90度(0 and 45如果我要更严格的话),你可以计算sine()所有其他角度都可以通过简单的三角恒等式.

UPDATE:

实际上我会纠正自己的使用double阶乘计算中的 s。编写了一个简单的程序后,我验证了当我使用double存储阶乘,即使我高于18。经过一番思考后,我意识到在这种情况下阶乘,情况与double的粒度稍微复杂一些。我举个例子让你明白:

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

在这个数字中18, 16, 14, ... , 2都是的倍数2并且由于乘以2相当于二进制表示中的左移,所有低位都在19!已经0因此当double的舍入开始为integers比...更棒2^53,这些阶乘不受影响。您可以计算二进制表示中最低有效零的数量19!通过计算216. (for 20!, it is 18)

我要上去1.8e+308并检查所有阶乘是否不受影响。我会向您通报最新结果。

更新2:

如果我们使用doubles 保存阶乘,它们受到四舍五入的影响23!向前。它可以很容易地显示出来,因为2^74 < 23! < 2^75这意味着至少需要 75 位精度来表示它,但由于23! has 19最低有效位的值为0,所以需要75 - 19 = 56它大于53位提供者double.

For 22!, it is 51位(您可以自己计算)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中正弦函数的实现不起作用 的相关文章

随机推荐

  • Android:在 Flickr 上上传图片

    我必须制作一个 Android 应用程序来将图片从手机上传到 Flickr 我开始读书API Flickr 文档 http www flickr com services api 但仍然想了解如何进行身份验证以及如何上传 我也在这里阅读了类
  • MyBatis - jdbcTypeForNull Oracle

    我将 MyBatis 与 Oracle 11g R2 数据库结合使用 我正在使用 MyBatis 3 3 和 ojdbc6 12 1 0 2 我的问题是每当我尝试插入一个空对象时我都会得到以下信息 org springframework j
  • os.mknod() 在 MacOS 上失败?

    Is os mknod Mac 上的特权调用 总是失败 不允许操作 In 1 import os In 2 os mknod tmp test123 OSError Traceback most recent call last
  • 为什么 vscode 保存 java 文件时遇到问题?我应该检查哪个设置?

    在 vs code 中 我按 Ctr N 然后按 Ctr Shift S 这是 另存为 选项的排序方式 当我尝试将文件另存为 java 时 它会自动保存为类文件 当然 当我尝试不使用排序器保存文件时也会发生这种情况 因此创建 java 文件
  • Kotlin 的可空性和 LiveData

    我想将 LiveData 与 Kotlin 一起使用 并且值不应为空 你如何处理这个问题 也许是 LiveData 的包装 在这里寻找好的模式 举个例子 class NetworkDefinitionProvider MutableLive
  • 自定义 jQuery UI 1.8 中的自动完成显示

    我正在尝试自定义 JQuery 1 8 中自动完成元素的外观 我使用了来自的示例JQuery UI 网站 http jqueryui com autocomplete custom data term autocomplete source
  • 如何保存和使用应用程序的窗口大小?

    使用 NET 4 在关闭时保存应用程序的窗口大小和位置并在下次运行时使用这些值启动应用程序的窗口的最佳方法是什么 我不想接触任何类型的注册表 但不知道是否有某种 app config 类似于 ASP NET 应用程序的 web config
  • 获得使用 FTP-WinSCP 处理我的 Amazon EC2 Ubuntu 服务器上的文件的权限

    我在 Amazon 上有一个 Ubuntu 服务器 我安装了使用它的所有内容 php mysql phpmyadmin apache 问题是我无法使用 FTP 移动或编辑文件 我收到错误消息 Permission denied Error
  • 如何在Backbone.js中使用groupBy对集合进行分组?

    示例集合 仅显示模型 name Bob date Thu Mar 29 2012 name James date Fri Mar 30 2012 name Dylan date Fri Mar 30 2012 name Stanley da
  • D3 鼠标事件——单击和拖动结束

    在 D3 中 如果您定义了这样的拖动函数 var drag d3 behavior drag on drag function alert drag on dragend function alert dragEnd 您确实不能执行以下操作
  • 如何在Android中的地图视图中获取3D建筑视图?

    我使用了地图设置 googleMap setBuildingsEnabled true 但这不起作用 大约一个月前 它运行良好 附上屏幕截图以供参考 这是我一个月前得到的观点 现在地图显示 2D 视图 None
  • 在 Android TV 模拟器上运行时缺少 MainActivity 错误

    我创建了一个示例 Android TV 应用程序用于测试目的 我按照以下文档进行操作 https developer android com training tv start start https developer android c
  • Netbeans + 德比 + 休眠

    我正在跟进http netbeans org kb docs java hibernate java se html http netbeans org kb docs java hibernate java se html学习在 Netb
  • 一次从目录导入所有模块 [NODE]

    MyApp main js modules a js b js c js d js e js 在我的 NodeJS 应用程序中 如何一次性导入 main js 文件中的所有自定义模块 a b c d e 我有一长串模块 我不想单独导入它们
  • JAX-WS 从 jar 加载 WSDL

    我正在编写一个胖客户端 它使用 SOAP 服务来实现某些功能 错误报告等 我的 JAX WS 工作正常 但默认情况下 至少在 netbeans 中 它会在每次初始化服务时从远程服务器获取 WSDL 我希望这有助于提供一些版本控制支持等 但这
  • SQL Select 语句中的动态列,保留“未定义”值

    这是基于我之前的问题的一个新问题 该问题被标记为问题的 重复 mySQL 使用三个表中的数据和列创建新表 https stackoverflow com questions 26665499 mysql create a new table
  • 使用 React 定期运行 fetch

    我有一个包含不同反应组件的网格 所有组件都是独立的 因为它们获取自己的数据并显示它 我想以某种方式让它们每 15 分钟自动重新获取和更新一次 我的第一个想法是 HOC 但是随着更新的钩子和功能组件的出现 我尝试了一些使用钩子的东西 所以我已
  • 何时抑制 PHP 中的错误

    我有一些可能已定义或未定义的变量 isLoggedIn布尔值 我正在尝试清除错误消息 我想知道是否有任何理由不应该使用错误抑制运算符 if isLoggedIn 或者我是否应该首先检查变量是否存在 if isset isLoggedIn a
  • javafx.scene.control.TableColumn 无法转换为 javafx.scene.control.TableColumn$CellDataFeatures

    我在填充 javafx tableview 时遇到问题 我目前正在开发一个基于 GUI 的事件管理工具 适用于大学 并且我一直在尝试填充 Tableview 列表 该列表应该位于边框窗格布局的中心 这是我的代码 它很长的想法 它的主窗口函数
  • C 中正弦函数的实现不起作用

    我尝试用 C 语言实现正弦函数 但得到了奇怪的结果 以下是我用来计算正弦的三个函数 define PI 3 14159265358979323846 define DEPTH 16 double sine long double long