如何修复数学函数

时间:2015-10-14 14:20:38

标签: c# .net

http://ideone.com/XjMJBa

using System;

public class Test
{
    public static void Main()
    {
        Console.WriteLine(Math.Cos(1e27));
    }
}

从某个值Math.Cos开始,Math.Sin开始在[-1,+ 1]段内返回其参数而不是值。例如,上面的输出是

1E+27

为什么会这样,是否有可能解决这种问题?

4 个答案:

答案 0 :(得分:4)

三角函数函数(<javac encoding="iso-8859-1" ...> Sin等)周期为 2 pi Cos)。但是,由于2 * Math.PIMath.PI,因此仅 16-17正确的数字,您无法通过天真计算double(我们至少需要 27位):

1e27

要执行此任务,您需要先获得适当的 Double result = Math.Cos(1e27); // totally wrong. 值,例如从这里

http://www.piday.org/million/

我们也必须与pi合作:

BigInteger

最后,实际结果是

  

-0.695977596990354

注意,天真的 C ++计算(取自 Qwertiy 评论, int exponent = 27; const String piString = "314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054"; BigInteger pi2 = BigInteger.Parse(piString) * 2; int scale = piString.Length - 1; // 2 * pi is not that big integer, it's 6.28... BigInteger argument = BigInteger.Pow(10, exponent + scale); // Now let's compute the double value (fraction) that's reminder of 1e27 % (2 * PI) String remainder = (argument % pi2) .ToString() .PadLeft(piString.Length, '0') .Insert(1, "."); // we can have x.xxx, 0.xxx, 0.0xxx etc. remainders Double fraction = Double.Parse("0." + remainder.Substring(0, 20), CultureInfo.InvariantCulture); // and now, finally Double result = Math.Cos(fraction); )是完全错误的,因为即使是C ++ 0.849247也没有t支持double 27位数。

答案 1 :(得分:2)

来自MSDN documentation

  

角度a必须是弧度。乘以Math.PI / 180将度数转换为弧度。

     

可接受的范围大约为-9223372036854775295   至大约9223372036854775295.对于此之外的值   范围,Sin方法返回一个不变的而不是抛出一个   异常。

答案 2 :(得分:0)

&#34;角度d必须是弧度。乘以Math.PI / 180将度数转换为弧度。 可接受的d值范围从大约-9223372036854775295到大约9223372036854775295.对于超出此范围的值,Cos方法返回d而不是抛出异常。&#34;

参考 - &gt; https://msdn.microsoft.com/en-us/library/system.math.cos(v=vs.110).aspx

答案 3 :(得分:0)

这里的问题是Sin,Cos计算的数学和表示存储信息的可用位数,实际值。

要计算Cos函数,例如您在此处所要求的,您需要计算:

Cos(x) = 1 - x*x/2! + x*x*x*x/4! - x*x*x*x*x*x/6! + ...

如果您的号码在左侧(负)或右侧(正)限制用于存储号码的数据类型的边界,那么您可以快速解决问题,因为如果您接近此限制,那么计算x ^ 2, x ^ 4,x ^ 6在数据类型限制之外非常快......

当然,有一些方法可以选择一些不那么暴力的算法来计算Sin / Cos,但是有一些限制。

这里的第二件事是,在更长的时间内,数学计算要归功于这样的行为容易且容易出错。如果方法不介意计算结果,那么它应该以一个例外结束,以提供失败的信息。我看到了许多算法,(有些是我的:)),这些细节被忽略了,产生了神奇的结果,最终得到了NaN或类似的东西,返回相同的值。在复杂算法中使用数字,限制等来捕获这些数学错误非常困难......