科学计算器

自写表达式解析,支持函数、常量、括号历史与精度提示。

这一页的计算器没有借用任何数学库,也没有把输入交给 eval 或 new Function:词法(normalize + tokenize)、语法(parse,产出一棵可读写的 AST)与求值(evalNode)三段都是自写的纯函数,表达式全程只是数据。输入先做一轮只认同义写法的归一化——× · 换成 *、÷ 换成 /、全角减号与括号、逗号、π、√、²、³ 分别换成对应写法,标识符统一转小写,所以 sin、SIN、nCr 与 ncr 是同一个名字。函数表里有 38 个名字(三角与反三角、双曲与反双曲、ln/log/log2/log10/logb、exp/pow、sqrt/cbrt/root、abs/sgn/floor/ceil/round/trunc、min/max/hypot、mod/rem、gcd/lcm、nCr/nPr),常量 4 个:pi、e、tau、phi。

数值口径是双轨的:一个字面量只要不带小数点也不带指数,它就先进 BigInt,两个整数操作数之间的 + - * ** //(非负指数) % ! 以及能整除的 / 全程走精确整数轨道;一旦出现小数点、指数写法、超越函数或百分比,该子表达式就整体退化为 IEEE-754 double,结果行会写明这次用的是哪条轨道。精度上不藏东西:浮点结果按 12 位有效数字圆整后显示,只要这个圆整值和大模型里存的 double 不是同一个数,页面就用 DataView 把 52 位尾数拆出来、做精确的十进制展开一并贴出。绝对值超过 2^53−1(9007199254740991)会标出十进制位数并说明 double 存整数只能精确到这里,1e17+1 那个 +1 就是这么被吃掉的。除以零按错误处理而不是给 ±Infinity,所有异常都带名字。病态输入有守卫,宁可报错也不卡住标签页:单条表达式 500 字符、1200 个词法单元、嵌套 64 层、结果 20000 位、阶乘参数 2000、指数 20000、历史 50 条。没有复制按钮、没有收藏、不写存储,也不发起任何请求。

科学计算器怎么用

  • 两种输入方式:直接用键盘写表达式再按 Enter,或点左栏键位区(6 列 × 5 行、共 30 键):第一行 AC、(、)、⌫、^、!,其余四行是数字与小数点、÷ × − + // %、以及 π、e、tau、phi、sin(、cos(、√(。点键只往输入框里插字符(√( 插的是 sqrt(、^ 插 **、÷ × − 插 / * -),所以光标位置和括号都能手改;键位区没有 tan( 与 log( 这类键,要就打自己字。输入框的 maxlength 就是解析器的 500 字符上限,第 501 个字符敲不进去;即使绕过输入框直接喂长串,词法阶段也报 too-long 而不是慢慢算。
  • DEG / RAD 只管三角:这个开关(标作「角度 DEG」「弧度 RAD」,旁边一行小字写明「只管三角函数入参 / 反三角出参」)影响 sin/cos/tan 的入参单位与 asin/acos/atan/atan2 的出参单位:sin(30) 在 DEG 是 0.5、在 RAD 是 -0.988031624093;acos(0.5) 在 DEG 给 60、在 RAD 给 1.0471975512。切换时如果输入框里有内容会马上重算,结果下方最后一行也会写明当前单位与所用的数值轨道。双曲函数 sinh/cosh/tanh 不受这个开关影响。
  • 逐行读懂结果区:大字行是显示值(整数轨给完整十进制,浮点轨给 12 位有效数字)。它下面那叠小字最多 196px 高、超出自己滚,依次是:表达式规范化(AST 回写的写法,按优先级补最少括号,可原样再算一遍验证语义没变)、十进制位数、整数结果附带的一行十六进制/八进制/二进制读数(真要进制换算请用进位转换页,这里只作一行补充)、触发过的「提示:」行(2^53−1 标注、百分比换算式、双精度真实展开),最后一行是「角度单位 + 运算轨道」。完整语法树的 JSON 不在这里,在右栏「解析树」的「AST(JSON)」折叠里。求值失败时大字行显示「错误」、错误名与修法出现在页面顶部提示条、小字清空、解析树的 meta 变成「失败」。所有异常都带名字:div-zero、sqrt-negative、log-domain、asin-domain、acos-domain、acosh-domain、atanh-domain、tan-undefined、factorial-domain、root-degree、int-required、complex-result、overflow,语法侧有 unbalanced-parens、trailing-operator、empty-expression、bad-arity、bad-number、bad-char,以及带「最接近名字」建议(编辑距离)的 unknown-func 与 unknown-identifier。
  • 优先级与隐式乘法:词法之后是一张固定优先级表(高到下):后缀 ! 与后缀 % 最紧、贴在最靠近的因子上;然后是 **(^ 是它的同义写法,右结合);再是一元负号与正号,它结合得比 ** 松;然后是 * / // % 与隐式乘法同级、左结合;最后是 + -。这张表直接决定了几个容易被各家实现分叉的结果:-3**2 = -9(是 3**2 取负,不是 (-3)**2)、2**3**2 = 2**(3**2) = 512(左结合才会是 64)、2**3! = 2**(3!) = 64。隐式乘法让 2pi、3(4+1)、(1+2)(3+4) 直接相乘,但歧义也一并摆出来:它与 * 同级左结合,所以 1/2pi 读作 (1/2)·π 而不是 1/(2π),2 3 读作 2×3=6——想改变含义请写括号。
  • 两栏版面与三张 pane:界面是左右两栏。左栏固定 380px,从上到下依次是:大字显示屏、结果下方那叠逐行说明(最多 196px 高、超出自己滚动)、表达式输入框、6 列 × 5 行共 30 个键的键位区加一条通栏「= 计算」、DEG/RAD 分段开关(标作「角度 DEG」「弧度 RAD」)、以及键盘下方那一行常驻速查(`速查:200+10% = 220 · -3**2 = -9 · 2**3**2 = 512 · 1/2pi = (1/2)·π · 5!! = (5!)!`)。右栏三张 pane:历史(标题写「点一条回填到输入框」,右上角给条数 `n / 50` 与「清空」「下载 .txt」两个按钮,列表最多 236px 高)、运算规则(六条折叠,meta 写「6 条 · 与实现同源」,其中「百分比、取模与 mod/rem」默认收起;六条折叠的正文都直接从解析器口径抄写,不是另编一份)、解析树(「AST(JSON)」折叠,meta 从「未计算」变成「N 字符」)。窄到 680px 以下并成一栏,键位区改用等宽弹性列以免溢出。Enter 或「= 计算」求值,↑ ↓ 在历史里回捞,点历史条目把表达式回填输入框,DEG/RAD 切换会立刻重算当前输入。

常见问题

为什么不干脆用 eval 算表达式?

三个理由,缺一不可。安全上:eval / new Function 会把用户粘贴的字符串当成代码执行,这一页要求「输入只是数据」,所以词法表里根本没有字母以外的运算符以外的东西能进求值。正确性上:交给 eval 就得接受 JS 自己的规则,而在 JS 里 ^ 是按位异或、1e400 会静默变成 Infinity、超 2^53 的整数直接丢低位;本页把优先级写成一张表,-3**2 = -9、2**3**2 = 512 这类结论由表说了算,也能被测试逐条钉住。可解释性上:解析产出的是 AST,所以能回写规范化表达式、能报「第几个字符处括号没闭合」,还能把每一步用到的数值轨道告诉你。

0.1+0.2 为什么不等于 0.3?sin(pi) 为什么不是 0?

因为 double 是二进制小数:0.1 存的是 0.1000000000000000055511151231257827021181583404541015625,两个近似数相加再圆整就得到 0.3000000000000000444…;同理 π 只能存成 3.1415926535897931…,它的「正弦」自然剩下 1.22e-16 的残差。这不是本页算错,也不是靠「看到很小的数就当 0」能修的——那样会把 1e-16 这个量级的真实信息抹掉。页面的选择是显示按 12 位有效数字圆整,同时把双精度的真实十进制展开原样贴出来,噪声可见但不碍事。要一位不差的整数结果就让表达式全程不带小数点与指数,它会走 BigInt 轨道。0.1+0.2 显示 0.3,同时给出 0.3000000000000000444089209850062616169452667236328125;sin(pi) 在弧度下不是 0 而是 1.2246467991473532e-16,因为 π 本身只能存成 3.141592653589793115997963468544185161590576171875;sin(30°) 显示 0.5,真实值是 0.499999999999999944488848768742172978818416595458984375。2**100 输出 1267650600228229401496703205376、2**200 输出完整 61 位,一位不错。

200+10% 到底该等于 220 还是 200.1?

本页只认一条规则:加减号右边的 p% 取的是「左边那个值的 p%」,所以 200+10% = 200+200×0.1 = 220,这是 Excel 和台式计算器几十年的口径;而 200×10% = 20、50% = 0.5、7%2 = 1(% 后面还接着数字时它是取模)。规则一旦触发,结果下方会专门打印这行换算式,所以不会让你猜是哪条路走通了;如果你想要的是「10% 这个数本身」,写成 200+(10/100) 或 200+0.1,结果就是 200.1。

%、// 与 mod/rem 这几种口径分别怎么取整?

`%` 后面不接「能开头的新因子」时它是百分比 postfix,接了就是二元取模。于是 50% = 0.5、200*10% = 20、7%2 = 1,而在加减语境里 p% 取的是「左边那个值的 p%」(Excel 与台式计算器的老口径),200+10% = 200+200×0.1 = 220、200-10% = 180;这条规则一触发,结果下方就会把这行算式贴出来,不让你猜是哪条路走通了。取整类运算分三个口径摆明差别:二元 % 与整除 // 按「符号跟被除数 / 向 −∞ 取整」处理((-7)%2 = -1、(-7)//2 = -4),函数 mod(a,b) 的余数符号跟除数(mod(-7,2) = 1,即 Python 的 %),rem(a,b) 与被除数同号,等于二元 %。

对应功能编号 #123无需安装,手机端同样可用按 Ctrl + K 换工具