不同计算工具的不同结果

各位读者可能知道,不同品牌或者不同型号的计算器算法可能不同,甚至(看起来显示精度相同的计算器)精度实际上也是不同的。如果计算器没错误的话,应该是处理(通常是对于二进制而言的)数位过多的数据,尤其是无限小数,尤其是输入有理数返回无理数的计算时会产生这种区别,不过功能复杂的科学计算器会被设计成储存的精度比显示的高的效果,比如一个十位有效数字的计算器显示出了 4.810477381 的结果,此时其内部存储的结果会是 4.810477380965 甚至更高精度(通常的计算器应该是二进制运算和存储吧,此处用十进制说明),而显示出来的结果都会比较稳妥,两种计算器看不出差异(差异可能存在于没显示的部分)。但是继续计算,比如某种不收敛的迭代运算就可能把这种差异放大到可见的程度,这也是用简单的工具产生蝴蝶效应的一个实验。

为了追求结果的稳妥,(我认为)设计计算器的时候可以用此理由拒绝一些计算,比如[latex]\sin(10^9)[/latex](MS office Excel 2007 会拒绝此计算),虽然可以肯定这个结果不会超过什么浮点数范围(与之相比阶乘、幂等运算就会很容易超过什么范围),1 000 000 000 也不是什么大得处理不了的数。也就是这里,我发现有的时候这些计算工具确实会产生可见的差错,虽然之前也注意到过,现在需要一定精度的计算时开始觉得这种差错不可忽视,是影响到这种使用的程度(还好发现了,要是不知此情况而认为显示出的数字都是准确的那就不好了)。

并不使用迭代或者复杂的运算,下面我记录一下一些计算工具简单内置的常用函数,以Mathematica为准,红色的数字表示有误的部分,正确四舍五入不算有误用绿色标记,而正确的截断但不是正确的四舍五入用蓝色标记,仅对最后一位使用。
Mathematica 简写作 MAT,用 N[expr,50] 给出50位有效数字;MS office Excel 2007 简写作 E07;Win7 自带计算器简写作 7CA;Javascript 简写作 JAS。

首先是[latex]\sin 1[/latex]:
MAT: 0.84147098480789650665250232163029899962256306079837
E07: 0.841470984807897
7CA: 0.8414709848078965066525023216303
JAS: 0.8414709848078965

[latex]\sin 1000[/latex]:
MAT: 0.82687954053200256025588742910921814121272496784779
E07: 0.826879540532003
7CA: 0.82687954053200256025588742910922
JAS: 0.8268795405320025

是不是好像没多大错?接下来就出现了

[latex]\sin 1000000[/latex]:
MAT: -0.34999350217129295211765248678077146906140660532872
E07: -0.349993502171308
7CA: -0.34999350217129295211765248678077
JAS: -0.34999350217129177
[latex]\sin 10000000[/latex]:
MAT: 0.42054779319078249129850658974094559516717524753080
E07: 0.420547793190927
7CA: 0.42054779319078249129850658974095
JAS: 0.4205477931907708
[latex]\sin 100000000[/latex]:
MAT: 0.93163902710972600802751665361204297047290183852754
E07: 0.931639027110306
7CA: 0.93163902710972600802751665361204
JAS: 0.9316390271096793
[latex]\sin 1000000000[/latex]:
MAT: 0.54584344944869956424438727089751452899502293026289
E07: 错误(#NUM!)
7CA: 0.54584344944869956424438727089751
JAS: 0.5458434494497783

已经差了很多位,难怪不计算了,只能欢送Excel出局。而Javascript还在强撑……

[latex]\sin 1 000 000 000 000[/latex]:
MAT: -0.61123870237688949819202041532463056649624170559342
7CA: -0.61123870237688949819202041532463
JAS: -0.6112387013579699

[latex]\sin 1 000 000 000 000 000[/latex]:
MAT: 0.85827279317023583552388639084840664660020340822073
7CA: 0.8582727931702358355238863908484
JAS: 0.8582721324763734

[latex]\sin 1 000 000 000 000 000 000[/latex]:
MAT: -0.99296932074040507620955301726363027085998456867821
7CA: -0.99296932074040507620955301726123
JAS: -0.9928161040530035

[latex]\sin 1 000 000 000 000 000 000 000[/latex]:
MAT: -0.66712017707180484696519575812617624868948413154158
7CA: -0.66712017707180484696519575812618
JAS: 错误(0.8332490480535)

到这里Javascript终于放弃治疗了,而Win7计算器不知道什么原因有一些波动,还是能坚持的

[latex]\sin 1 000 000 000 000 000 000 000 000[/latex]:
MAT: -0.99647222910258325837583592426218489772581924687542
7CA: -0.99647222910258325837583592426218
JAS: 错误(-0.03732302703363715)

[latex]\sin 1 000 000 000 000 000 000 000 000 000[/latex]:
MAT: 0.71806349613911766607951565214634705272349173786033
7CA: 0.71806349613911766607951565213469
JAS: 错误(-0.522716546307594)

[latex]\sin 100 000 000 000 000 000 000 000 000 000[/latex]:
MAT: 0.99995928459840576572350091279747916876501995785707
7CA: 0.99995928459840576572350091279748
JAS: 错误(0.41420674441457567)

[latex]\sin 1 000 000 000 000 000 000 000 000 000 000[/latex]:
MAT: -0.090116901912138058030386428952987330274396332993043
7CA: -0.09011690191213805803038642895299
JAS: 错误(-0.7562627303335765)

[latex]\sin 10 000 000 000 000 000 000 000 000 000 000[/latex]:
MAT: 0.78481232612639561633855654446698060211871509432318
7CA: 0.78481232612639561633855654446698
JAS: 错误(-0.8862734160108359)

32位十进制数就是Win7计算器输入的极限了,也就到此为止了,看来在Sin函数上这个自带计算器还是挺准确的,就是不知道为什么有时候会错那么三位……
(未完)

2 评论

  1. .NET with double-precision floating point

    Microsoft (R) Visual C# Interactive 2.8.3.62923
    > Console.WriteLine(string.Join(“\n”, Enumerable.Range(0, 33).Select(x => Math.Pow(10, x)).Select(x => $”{x:E}, {Math.Sin(x):F32}”)));
    1.000000E+000, 0.84147098480789700000000000000000
    1.000000E+001, -0.54402111088937000000000000000000
    1.000000E+002, -0.50636564110975900000000000000000
    1.000000E+003, 0.82687954053200300000000000000000
    1.000000E+004, -0.30561438888825200000000000000000
    1.000000E+005, 0.03574879797201640000000000000000
    1.000000E+006, -0.34999350217129200000000000000000
    1.000000E+007, 0.42054779319077100000000000000000
    1.000000E+008, 0.93163902710967900000000000000000
    1.000000E+009, 0.54584344944977800000000000000000
    1.000000E+010, -0.48750602507627000000000000000000
    1.000000E+011, 0.92869366054433500000000000000000
    1.000000E+012, -0.61123870135797000000000000000000
    1.000000E+013, -0.28888528249228400000000000000000
    1.000000E+014, -0.20940843338350000000000000000000
    1.000000E+015, 0.85827213247637300000000000000000
    1.000000E+016, 0.77967994516106700000000000000000
    1.000000E+017, -0.46464410893576400000000000000000
    1.000000E+018, -0.99281610405300300000000000000000
    1.000000E+019, 10000000000000000000.00000000000000000000000000000000
    1.000000E+020, 100000000000000000000.00000000000000000000000000000000
    1.000000E+021, 1000000000000000000000.00000000000000000000000000000000
    1.000000E+022, 10000000000000000000000.00000000000000000000000000000000
    1.000000E+023, 100000000000000000000000.00000000000000000000000000000000
    1.000000E+024, 1000000000000000000000000.00000000000000000000000000000000
    1.000000E+025, 10000000000000000000000000.00000000000000000000000000000000
    1.000000E+026, 100000000000000000000000000.00000000000000000000000000000000
    1.000000E+027, 1000000000000000000000000000.00000000000000000000000000000000
    1.000000E+028, 10000000000000000000000000000.00000000000000000000000000000000
    1.000000E+029, 100000000000000000000000000000.00000000000000000000000000000000
    1.000000E+030, 1000000000000000000000000000000.00000000000000000000000000000000
    1.000000E+031, 10000000000000000000000000000000.00000000000000000000000000000000
    1.000000E+032, 100000000000000000000000000000000.00000000000000000000000000000000

  2. .NET 4.7.2 with custom 128 bit* floating point number and DecimalMath**
    * https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal
    ** https://github.com/nathanpjones/DecimalMath

    using System;
    using System.Linq;
    using DecimalMath;

    namespace Math
    {
    public static class Program
    {
    public static void Main(string[] args)
    {
    Console.WriteLine(string.Join(“\n”,
    Enumerable.Range(0, 33)
    .Select(x =>
    {
    try
    {
    return DecimalEx.Pow(10, x);
    }
    catch
    {
    return decimal.MinValue;
    }
    })
    .Where(x => x != decimal.MinValue)
    .Select(x => $”{x:E}, {DecimalEx.Sin(x):F32}”)));
    }
    }
    }

    1.000000E+000, 0.84147098480789650665250232160000
    1.000000E+001, -0.54402111088936981340474766160000
    1.000000E+002, -0.50636564110975879365655761210000
    1.000000E+003, 0.82687954053200256025588742550000
    1.000000E+004, -0.30561438888825214136090997340000
    1.000000E+005, 0.03574879797201650931647115250000
    1.000000E+006, -0.34999350217129295211765859650000
    1.000000E+007, 0.42054779319078249129856578410000
    1.000000E+008, 0.93163902710972600802775374170000
    1.000000E+009, 0.54584344944869956423892053080000
    1.000000E+010, -0.48750602508751069158476041130000
    1.000000E+011, 0.92869366049659195261526994760000
    1.000000E+012, -0.61123870237688950335576005110000
    1.000000E+013, -0.28888529481752518472535062190000
    1.000000E+014, -0.20940830749645166471707467460000
    1.000000E+015, 0.85827279317023918382286483660000
    1.000000E+016, 0.77968800660701960417009046790000
    1.000000E+017, -0.46453010483479492006737214180000
    1.000000E+018, -0.99296932074117738651798387510000
    1.000000E+019, -0.92706316602418994263918560570000
    1.000000E+020, -0.64525128576422833794977815940000
    1.000000E+021, -0.66712018193218311739261037760000
    1.000000E+022, -0.85220088390399346965318055740000
    1.000000E+023, 0.70114110506812440322958476730000
    1.000000E+024, -0.99647277663253681380528875440000
    1.000000E+025, -0.74474630966666046004466622840000
    1.000000E+026, 0.85379499787383168303760516060000
    1.000000E+027, 0.72258904093869587186479879880000
    1.000000E+028, -0.97558623128605030830045950560000

发表回复

您的电子邮箱地址不会被公开。