我正在尝试在 C# 中计算 4203708359 弧度的余弦:
var x = (double)4203708359;
var c = Math.Cos(x);
Run Code Online (Sandbox Code Playgroud)
(4203708359可以用双精度精确表示。)
我越来越
c = -0.57977754519440394
Run Code Online (Sandbox Code Playgroud)
Windows 的计算器给出
c = -0.579777545198813380788467070278
Run Code Online (Sandbox Code Playgroud)
Linux 上的PHPcos(double)函数(内部仅使用cos(double)C 标准库)给出:
c = -0.57977754519881
Run Code Online (Sandbox Code Playgroud)
cos(double)使用 Visual Studio 2017 编译的简单 C 程序中的C函数给出
c = -0.57977754519881342
Run Code Online (Sandbox Code Playgroud)
Math.cos()以下是C# 中的定义:https: //github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Math.cs#L57-L58
它似乎是一个内置函数。我(还)没有深入研究 C# 编译器来检查其有效编译的内容,但这可能是下一步。
同时:
为什么我的 C# 示例中的精度这么差,我该怎么办?
难道只是因为 C# 编译器中的余弦实现无法很好地处理大整数输入吗?
编辑 1:Wolfram Mathematica 11.0:
In[1] := N[Cos[4203708359], 50]
Out[1] := -0.57977754519881338078846707027800171954257546099993
Run Code Online (Sandbox Code Playgroud)
编辑2:我确实需要这种级别的精度,并且我已经准备好为了获得它而走很远。如果存在一个支持余弦的好库(到目前为止我的努力还没有实现),我很乐意使用任意精度库。
编辑3:我在 coreclr 的问题跟踪器上发布了问题: https: //github.com/dotnet/coreclr/issues/12737
我想我可能知道答案。我很确定 sin/cos 库不会采用任意大的数字并计算它们的 sin/cos - 相反,它们会将它们减少到较低的数字(0-2xpi 之间?)并在那里计算它们。我的意思是,cos(x) = cos(x + 2xpi) = cos(x + 4xpi) = ...
问题是,程序如何减少你的 10 位数字呢?实际上,它应该计算出需要乘以多少次 (2xpi) 才能得到略低于您的数字的值,然后将其减去。就您而言,大约是 6.7 亿。
因此,它将 (2xpi) 乘以这个 9 位数的值 - 因此它实际上失去了数学库版本的 pi 的 9 位数的重要性。
我最终编写了一个小函数来测试发生了什么:
private double reduceDown(double start)
{
decimal startDec = (decimal)start;
decimal pi = decimal.Parse("3.1415926535897932384626433832795");
decimal tau = pi * 2;
int num = (int)(startDec / tau);
decimal x = startDec - (num * tau);
double retVal;
double.TryParse(x.ToString(), out retVal);
return retVal;
//return start - (num * tau);
}
Run Code Online (Sandbox Code Playgroud)
所有这一切都是使用十进制数据类型作为减少值的一种方式,而不会丢失 pi 的精度数字 - 它仍然返回双精度。当我通过修改您的代码来调用它时:
var x = (double)4203708359;
var c = Math.Cos(x);
double y = reduceDown(x);
double c2 = Math.Cos(y);
MessageBox.Show(c.ToString() + Environment.NewLine + c2);
return;
Run Code Online (Sandbox Code Playgroud)
……果然,第二个是准确的。
所以我的建议是 - 如果你真的需要那么高的弧度,并且你真的需要精度?执行类似上面的函数的操作,并以不丢失精度的方式减少最终的数字。
| 归档时间: |
|
| 查看次数: |
812 次 |
| 最近记录: |