C# C中Math.Sin()和Math.Cos()的准确性#
我对CLR中内在触发器函数的不精确性感到非常恼火。众所周知C# C中Math.Sin()和Math.Cos()的准确性#,c#,clr,trigonometry,C#,Clr,Trigonometry,我对CLR中内在触发器函数的不精确性感到非常恼火。众所周知 Math.Sin(Math.PI)=0.00000000000000012246063538223773 而不是0。类似的情况也发生在Math.Cos(Math.PI/2)上 但是当我在做一系列的计算时,在特殊情况下,我会评估 Math.Sin(Math.PI/2+x)-Math.Cos(x) 对于x=0.2,结果是零,但是对于x=0.1,结果不是零(试试看)。另一个问题是,当参数是一个大数字时,不准确度会相应地增大 因此,我想知道
Math.Sin(Math.PI)=0.00000000000000012246063538223773
而不是0。类似的情况也发生在Math.Cos(Math.PI/2)
上
但是当我在做一系列的计算时,在特殊情况下,我会评估
Math.Sin(Math.PI/2+x)-Math.Cos(x)
对于x=0.2,结果是零,但是对于x=0.1,结果不是零(试试看)。另一个问题是,当参数是一个大数字时,不准确度会相应地增大
因此,我想知道是否有人用C#编写了一些更好的trig函数表示,以便与世界共享。CLR是否调用实现CORDIC或类似功能的标准C数学库?链接:这与三角函数的精度无关,而与CLS型系统有关。根据文档,a的精度为15-16位(这正是您得到的),因此您无法对这种类型更精确。因此,如果您想要更高的精度,您需要创建一个能够存储它的新类型 还要注意,您永远不应该编写这样的代码:
double d = CalcFromSomewhere();
if (d == 0)
{
DoSomething();
}
你应该改为:
double d = CalcFromSomewhere();
double epsilon = 1e-5; // define the precision you are working with
if (Math.Abs(d) < epsilon)
{
DoSomething();
}
double d=calcfromsomeone();
双ε=1e-5;//定义正在使用的精度
if(数学绝对值(d)
这是浮点精度的结果。可以得到一定数量的有效数字,任何不能精确表示的都是近似值。例如,pi不是一个有理数,因此不可能得到精确的表示。因为不能得到π的精确值,所以不能得到包括π在内的数字的精确正弦和余弦(大多数情况下也不能得到正弦和余弦的精确值)
最好的中间解释是。如果你不想深入这一点,只要记住浮点数通常是近似值,而浮点数计算就像是在地面上移动一堆沙子:无论你用它们做什么,你都会损失一点沙子,拾起一点灰尘
如果你想要精确的表示,你需要找到一个符号代数系统。我听到了。我对除法的不准确感到非常恼火。前几天我做了:
Console.WriteLine(1.0 / 3.0);
我得到了0.333,而不是正确的答案0.333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
也许现在你明白问题所在了Math.Pi不等于Pi任何大于1.0/3.0的值都等于三分之一。它们都与真值相差几百万亿次,因此使用Math.Pi或1.0/3.0执行的任何计算也会相差几百万亿次,包括正弦
如果你不喜欢近似算法是近似的,那么就不要使用近似算法。使用精确的算术。当我需要精确的算术时,我用滑铁卢枫树;也许你应该买一份。你需要使用任意精度的十进制库。(.Net 4.0有一个,但不是小数) 有几种流行的:
const double π=Math.PI;
const double π2=Math.PI/2;
const double π4=Math.PI/4;
public static double Sin(double x)
{
if (x==0) { return 0; }
if (x<0) { return -Sin(-x); }
if (x>π) { return -Sin(x-π); }
if (x>π4) { return Cos(π2-x); }
double x2=x*x;
return x*(x2/6*(x2/20*(x2/42*(x2/72*(x2/110*(x2/156-1)+1)-1)+1)-1)+1);
}
public static double Cos(double x)
{
if (x==0) { return 1; }
if (x<0) { return Cos(-x); }
if (x>π) { return -Cos(x-π); }
if (x>π4) { return Sin(π2-x); }
double x2=x*x;
return x2/2*(x2/12*(x2/30*(x2/56*(x2/90*(x2/132-1)+1)-1)+1)-1)+1;
}
constdoubleπ=Math.PI;
常数双π2=Math.PI/2;
常数双π4=Math.PI/4;
公共静态双Sin(双x)
{
如果(x==0){返回0;}
if(xπ){return-Sin(xπ);}
如果(x>π4){返回Cos(π2-x);}
双x2=x*x;
返回x*(x2/6*(x2/20*(x2/42*(x2/72*(x2/110*(x2/156-1)+1)-1)+1);
}
公共静态双Cos(双x)
{
如果(x==0){返回1;}
if(xπ){return-Cos(xπ);}
如果(x>π4){返回Sin(π2-x);}
双x2=x*x;
返回x2/2*(x2/12*(x2/30*(x2/56*(x2/90*(x2/132-1)+1)-1)+1;
}
典型错误为1e-16
和wors
public static double Sin(double d) {
d = d % (2 * Math.PI); // Math.Sin calculates wrong results for values larger than 1e6
if (d == 0 || d == Math.PI || d == -Math.PI) {
return 0.0;
}
else {
return Math.Sin(d);
}
}
public static double Cos(double d) {
d = d % (2 * Math.PI); // Math.Cos calculates wrong results for values larger than 1e6
double multipleOfPi = d / Math.PI; // avoid calling the expensive modulo function twice
if (multipleOfPi == 0.5 || multipleOfPi == -0.5 || multipleOfPi == 1.5 || multipleOfPi == -1.5) {
return 0.0;
}
else {
return Math.Cos(d);
}
}