杂记 › 技术笔记 › sin(π) 算出 0.0548 而不是 0:角度制、弧度制和计算器的优先级

sin(π) 算出 0.0548 而不是 0:角度制、弧度制和计算器的优先级

上周帮一个读工科的朋友核对实验报告。他要算 sin(pi),屏幕上是 0.0548036651488,标准答案写 0,他来回按了几遍,说这东西算错了。我把同一串字符在两种模式下各跑一遍,结论当场翻过来:那个数不是噪声,是他把 π 当成角度喂了进去;换成弧度,屏幕换成 1.224647e-16,这才是「理论上等于 0」那条式子的双精度真身。模式、语法、浮点表示,混在了同一次按键里。

先把三件事拆开

模式决定括号里那个数按什么单位读:角度制下先乘 π/180 再进函数,弧度制下原样进去。语法决定计算顺序:幂右结合,阶乘与百分号是后缀,一元负号排在幂之后,与单位无关。表示决定结果为什么不会正好是 0:双精度存不下 π,也存不下 0.1,于是 1.224647e-16 与 0.30000000000000004441 这类尾巴必然出现。

同一个表达式,两列分开看

下表是同一串输入在两种模式下的结果,raw 是双精度原始值,shown 是屏幕那行数:

表达式模式rawshown
sin(pi)DEG0.0548036651487895307140.0548036651488
sin(pi)RAD1.2246467991473532072e-161.224647e-16
cos(pi)DEG0.998497149863863842080.998497149864
sin(30)DEG0.499999999999999944490.5
sin(30)RAD-0.98803162409286182655-0.988031624093
0.1+0.2四则0.300000000000000044410.3

cos(pi) 在角度制下 shown 是 0.998497149864:它算的是 3.14159265359 这个角度的余弦,跟 180 度的余弦不是同一个问题。sin(30) 两行差得更远,一个读成 30 度,一个读成 30 弧度。

语法:三个容易被当成 bug 的结论

这块跟模式无关,纯粹是解析顺序。2^3^2 的 shown 是 512:幂右结合,先算完 3^2 那一支再拿 2 去乘方,从左往右读得到的 64 不是它的口径。2^3! = 64,后缀的 ! 比幂更紧。-2^2 = -4,一元负号排在幂之后,跟数学里把 −x² 读成 −(x²) 是同一条规矩。2+3*4 = 14 对 (2+3)*4 = 20,sin30+1 在角度制下 = 1.5,无括号的函数只吃紧跟的那个数。

数字清单:上限与边界

  • 阶乘只接受非负整数,最大到 170!:shown=7.257416e+306,raw=7.2574156153079940454e+306。再往上一个整数,页面不返回数字,只给超出范围的说明;双精度能显示的上限是 1.797693e+308。
  • 精确整数上限是 9007199254740991,即 2^53-1;到 1e21 这个量级,1e21+1-1e21 得 0,那个加进去的 1 已经被吃掉。
  • 百分号是后缀运算,读作除以 100:200*(1+10%) 的 shown 是 220、raw 是 220.00000000000002842;(1+10%)^12-1 = 2.13842837672,跟把 10% 乘 12 是两条路。
  • 千分位逗号与科学计数法都吃:1,000/8 = 125、1000*(1+4.7%)^7 = 1379.19848604。逗号只用于分组,站错位置直接报错。
  • 常数与函数:pi = 3.14159265359、degrees(pi/3) = 60、log2(1024) = 10、log(8)/log(2) = 3。

一整列中间值怎么核

那天要核对的不是一道题,是一整列中间值,逐个按再逐个抄,抄错的风险比算错还大。我用的是 科学计算器:幂、阶乘、百分号、取余、隐式乘法能混写,一行一式粘进去一起算;原始值与显示值分两行给,模式标着 DEG 还是 RAD,Ans 引用上一次结果,最近 20 条算式留成历史。角度制与弧度制可切换,除零、负数开方、超范围阶乘都会说明原因,表达式只在浏览器本地算完。求值走自写的词法分析与调度场算法,全程不调用 eval,所以我敢把别人一整列算式贴进去。

想把某个常数换成别的进制看一眼,用 进制转换器;那道题本来就该拿分数做四则、不该先看小数尾巴的时候,交给 分数计算器。

Q:DEG 和 RAD 到底什么时候用哪个?

看括号里那个数的单位。题目写清是度数的用角度制,sin(30) 给 0.5;表达式里出现 pi,或者在验恒等式的切弧度,sin(pi) 落到 1.224647e-16 这个量级才对得上。degrees、radians 不受开关影响,radians(180) 始终是 3.14159265359。

Q:为什么不显示完整小数?

显示行按有效数字归一过,自动口径是 12 位,要看真实值就对照原始行。0.1+0.2 的 shown 是 0.3,raw 是 0.30000000000000004441;sqrt(2)*sqrt(8) 显示 4,原始值是 4.0000000000000008882。那是表示误差,不是这一次按错了。

Q:171! 为什么没有结果?

它落在双精度能表示的范围之外,页面给的是超范围说明而不是一个数。要整数比值就在溢出前先相消:12!/(5!*7!) = 792、5!+3! = 126,比把阶乘单独摊开算安全。

Q:能不能给变量赋值、把中间量存下来?

没有变量,也没有自定义函数:字母只认已登记的函数名与常数,其余会报错并指出位置。中间量走 Ans 或 MS / MR / MC。不支持多参数函数,换底写 log(8)/log(2) = 3;求和、连乘那类记号也不认。

回到我朋友那句「是不是算错了」。我的顺序是:先看模式那栏写的是 DEG 还是 RAD,它决定 pi 读成 3.14159265359 度还是弧度;再看语法,幂、阶乘、一元负号最容易跟手算的读法岔开;最后才看尾巴,raw 的位数决定你看到的 0.3 是不是严格成立。这样 sin(pi) 显示 0.0548036651488 是单位问题,显示 1.224647e-16 才是表示问题:前者只有换模式才有意义,后者该设容差判断,不该期待一个 0。

📎 相关文章

同一批投放链接为什么跑出两行数据?UTM 五个参数、大小写与一次百分号编码 2026-10-21 JWT 那三段字符串里到底写了什么?header、payload 与 exp 的真实读法 2026-10-21 网址里哪一段会到服务器?六段拆分与 %20、+、二次编码 2026-10-19 身份证最后一位为什么是 X?前 17 位加权取模算出的校验位 2026-10-19 子网掩码写成 /22 能带多少台设备?主机位、网络地址与广播地址 2026-10-19