piapia123
zh

数学表达式求值

网络

所有处理都在浏览器本地完成,数据不上传服务器

输入
把文件拖到这里可直接载入
输出

一行一个表达式,逐行给出结果。支持 `+ - * / %` 与 `^`(幂)、括号与一元正负,常量 `pi` 与 `e`,以及 `sqrt` `abs` `round` `floor` `ceil` `exp` `log` `log2` `log10` `min` `max` `pow`。 ⚠️ 这个工具不用 `eval`,这不是洁癖。用 `eval` 实现的话,输入框里的东西会在当前页面的环境里执行:`fetch("/x")`、`location="https://…"` 都会被老老实实跑掉,而这个页面上还有别的数据。常见的补救是「用正则过滤,只允许数字和运算符」,但那类正则是出了名的漏。所以这里自己写解析器(调度场算法转后缀式再求值),除了列出的那些字符,别的一律不认。 两处容易踩的地方说在前面:`^` 是幂不是按位异或(要按位运算请用「位运算」那个工具),而且它右结合 —— `2^3^2` 是 `512` 不是 `64`;三角函数的输入与输出跟着角度单位一起换,只改一半的话 `sin(asin(0.5))` 就不等于 0.5。

功能

  • 四则运算、取余、幂与括号,一元正负(`-3`、`2 * -3`、`2^-1` 都认)
  • ⚠️ `^` 是幂且右结合:`2^3^2` = 512;按位异或请看「位运算」工具
  • 常量 `pi` 与 `e`;函数 sqrt / abs / round / floor / ceil / exp / log / log2 / log10 / min / max / pow
  • 三角函数可切弧度制与角度制,输入输出一起换(`sin(30)` 在角度制下是 0.5)
  • 可以定义变量:变量栏写 `a=3`,表达式里就能用 a;后面的定义能看到前面定义过的
  • 可指定保留小数位,完整精度另给一行说明
  • 一行一个表达式,一次算一整列
  • ⚠️ 自己写解析器求值,不使用 eval;函数名与常量之外的名字一律拒绝
  • 全部在浏览器本地完成,表达式不外传

使用方法

  1. 一行一个表达式粘进来
  2. 需要角度制就切「角度单位」;要复用中间结果就在变量栏定义
  3. 要四舍五入就填小数位,原始精度会另附一行
  4. 结果逐行可复制,也可以整块复制

常见问题

为什么说不用 eval 是个特点?
因为用 eval 实现这个工具太容易了,而它会把输入框里的内容当成当前页面的代码执行。`fetch("/x")` 会发出请求、`location="https://…"` 会跳转、`constructor.constructor("…")()` 能绕开大多数黑名单。更麻烦的是常见的缓解办法(正则只允许数字和运算符)本身就不严密,而失败方式是静默的。所以这里把解析、优先级、求值全部自己写了一遍,代价是没有办法支持任意函数,收益是输入里除了数字、运算符、括号和列出的函数名之外,什么都不可能被执行。
`2^-1` 能算吗?负号在幂的右边。
能。一元负号是优先级最高的运算符,所以 `2^-1` 被理解成 `2^(-1)`,结果是 0.5。有些实现把负号处理成「乘 -1」,那种做法在 `2^-1` 这种位置上会直接崩掉,所以这里用的是独立的一元运算符。
变量怎么用?
变量栏一行定义一个,形如 `a=3`;等号右边可以是表达式(`b=a*3`),而且后面的定义能用前面定义过的 —— 上一行写完 `a=2`,下一行就能写 `b=a*3`。表达式里引用变量名不区分大小写,但常量优先:定义了 `pi=3` 也不会遮住真正的 π。
为什么 `1/0` 不给我一个 Infinity?
因为在这个场景里 Infinity 基本总是「算错了」的信号,而不是想要的结果 —— 除以零、对负数开平方、给 log 喂 0 或负数都会得到它,而这三种情况的原因完全不同。直接甩一个 Infinity 出来,用户得自己猜是哪儿写错了。所以这里把这三种统一报成「结果是无穷或未定义」,并列出常见的三种成因。

相关工具