“单位换算”看起来像把一个数字乘上系数:输入 10,输出 1000。这个模型对米和毫米有效,对平方米和平方毫米也大体有效,但一遇到摄氏度、硬盘容量、月份或年份,简单的“乘一个数”就会开始误导人。

本站的换算器不是通用量纲推理系统,而是一组按类别维护的基准单位与因子表。当前有 11 个换算页;本文只讨论其中四类最容易越过语义边界的实现:温度、面积、体积和时间,并补充数据存储页使用的十进制 / 二进制前缀。理解这些边界,比记住更多换算常数更重要。

先给结论:

  • 同一物理量、同一零点、不同刻度,通常是线性比例:y=kxy=kx
  • 温度的绝对读数带零点偏移,属于仿射变换:y=kx+by=kx+b;温差才可以只按比例换算。
  • 面积和体积不是“多了几个单位”,而是长度尺度分别经过二次方、三次方传播。
  • kBKiB 不是同一个单位的两种拼法;前者按 10001000 进位,后者按 10241024 进位。
  • “一个月”“一年”如果脱离日历或业务口径,就没有唯一的秒数。本站的月、季度、年是持续时间近似值,不是日期运算器。

1. 先判断换算属于哪一种关系

1.1 线性比例:零点必须相同

线性换算可以写成:

y=kxy = kx

这里的隐含前提是:两个单位都把同一个物理零点表示为 0,而且一个单位的增量始终是另一个单位增量的固定倍数。例如本站长度页把米作为基准,英寸使用精确的 0.02540.0254 米因子;面积页把平方米作为基准,平方英尺使用 0.092903040.09290304 平方米因子;体积页把升作为基准,立方米使用 10001000 升因子。

实现上,这类条目都遵循“先到基准,再从基准出去”的路径:

base = input × from.factor
output = base ÷ to.factor

它不是为每一对单位单独抄一个系数。这样做的好处是,单位数量增加时,关系仍然是 O(n)O(n) 条数据,并且任意一对转换都共享同一个基准值。上一篇单位换算的精度账已经实测了这套中心辐射式表:线性类别的往返误差最差只有 1 ulp;真正容易穿透显示层的,反而是抄错因子和不当的显示策略。

但“线性”不等于“结果永远精确”。例如 1/31/3 在二进制浮点数中仍然不能有限表示;线性只说明数学关系是比例,不会改变 number 的表示能力。浮点边界见为什么 0.1 + 0.2 不等于 0.3

1.2 仿射变换:绝对温度不能只乘系数

温度是最经典的反例。摄氏度与开尔文的关系是:

TK=T°C+273.15T_K = T_{°C} + 273.15

华氏度则是:

T°C=(T°F32)×59T_{°C} = (T_{°F} - 32) \times \frac{5}{9}

它们都有比例项,也都有偏移项,因此应写成:

y=kx+by = kx+b

如果错误地把摄氏度乘上 5/95/9 当成华氏度,0°C0\,°C 会变成 0°F0\,°F,但物理上 0°C=32°F0\,°C=32\,°F。错误不是末位舍入,而是把零点不同的两个温标当成了同一个线性空间。

本站温度页以开尔文为基准:摄氏度是 v + 273.15,华氏度是 ((v - 32) * 5) / 9 + 273.15,兰氏度是绝对温标,只按 5/95/9 与开尔文缩放,列氏度按 5/45/4 缩放后再加上摄氏零点。这里的“先到开尔文、再离开开尔文”不是排版习惯,而是把偏移集中在各自的闭包中,避免误用通用的线性 v * factor

更细的工程区分是:温度读数温差不是同一件事。20°C20\,°C 不是 20K20\,K,但温差 20°C20\,°C 与温差 20K20\,K 的增量相等;摄氏温差转华氏温差只乘 9/59/5,不能把绝对读数的 3232 也加到温差上。

BIPM 的《国际单位制 SI》明确区分开尔文的热力学温度与摄氏温度,并给出摄氏度与开尔文之间的零点关系。实现温度转换时,应先确认输入是“绝对温度”还是“温差”,再选择仿射模型或比例模型,而不是看到单位符号就套一个系数。BIPM SI Brochure(第 9 版,2019)

2. 面积和体积:维度幂不是装饰性的上标

2.1 长度缩放会平方或立方传播

若长度单位满足:

1 in=0.0254 m1\ \mathrm{in}=0.0254\ \mathrm{m}

那么面积单位必须平方:

1 in2=(0.0254 m)2=0.00064516 m21\ \mathrm{in^2}=(0.0254\ \mathrm{m})^2=0.00064516\ \mathrm{m^2}

体积则必须立方:

1 in3=(0.0254 m)3=0.000016387064 m31\ \mathrm{in^3}=(0.0254\ \mathrm{m})^3=0.000016387064\ \mathrm{m^3}

所以把 in 的因子直接拿来换 in²,或者把英尺的因子直接拿来换 ft³,都会产生数量级错误。平方和立方不是字符串格式,而是物理量维度的一部分。

在代码层面,本站面积和体积页目前保存的是已经完成维度传播的直接因子:面积的 ft²0.09290304 平方米,体积的 ft³28.316846592 升;页面不会从长度页的 ft 条目运行一个通用的“求幂引擎”。这使页面数据直观,也意味着新增单位时必须把定义写在正确的维度表里,不能只复制一个看起来相近的长度条目。

2.2 面积单位还常常带领域语义

面积页同时覆盖平方米、公顷、市亩、顷、英亩、平方英尺、平方码和平方英里。它们的数学关系是线性的,但使用语境不同:公顷和平方千米适合土地尺度,平方英尺常见于建筑面积,市亩与顷则带有明确的中文传统土地计量语境。

例如本站将公顷定义为 10,000 m210{,}000\ \mathrm{m^2},市亩使用 2000/3 m22000/3\ \mathrm{m^2},顷使用 200000/3 m2200000/3\ \mathrm{m^2}。这里写分数比手抄一个有限位小数更能表达定义;但浏览器最终仍以双精度浮点数执行,页面输出还会经过显示格式化。因此“定义关系是精确的”与“每个十进制数字都能由 JavaScript number 逐位保存”是两个问题。

2.3 体积、容量和“同名单位”要留意体系

体积页的基准是升,包含毫升、立方厘米、升、立方米、美制液量单位、英制液量单位、石油桶以及立方英寸、立方英尺、立方码。1 mL = 1 cm³ 是公制体系内的定义关系;美制加仑和英制加仑则是两个不同的单位,本站分别使用 galuk_gal,不能因为中文都常译成“加仑”就合并。

同理,US cup、美制液量盎司与英制液量盎司并不是跨地区可互换的“杯”和“盎司”。换算器可以给出数值,但不能替用户决定食谱、法规标签或实验协议采用哪套定义。工程接口中最好把体系写进枚举名、字段名或单位符号,而不要把它隐藏在展示语言里。

权威单位资料也采用这种谨慎做法:NIST SP 811 将单位名称、符号和换算因子分开列出,避免把同名俗称当成同一单位。NIST SP 811《Guide for the Use of the International System of Units (SI)》

3. 数据单位:十进制前缀与二进制前缀是两套系统

3.1 kBKiB 的分歧来自进位基数

数据存储页明确并列两组单位:

类别 示例 定义 常见语境
十进制字节 KBMBGBTB 1 KB=1000 B1\ \mathrm{KB}=1000\ \mathrm{B},每级乘 10001000 硬盘、SSD、厂商容量
二进制字节 KiBMiBGiBTiB 1 KiB=1024 B1\ \mathrm{KiB}=1024\ \mathrm{B},每级乘 10241024 操作系统、内存、文件大小

因此:

1 GB=109 B1\ \mathrm{GB}=10^9\ \mathrm{B}

而:

1 GiB=230 B=1,073,741,824 B1\ \mathrm{GiB}=2^{30}\ \mathrm{B}=1{,}073{,}741{,}824\ \mathrm{B}

从 Windows 操作系统的角度来看(以二进制 10241024 为基准):1 GB1\ \mathrm{GB} 在系统中仅被识别为 10003102430.9313226 GiB\frac{1000^3}{1024^3} \approx \mathbf{0.9313226}\ \mathrm{GiB}(折损约 6.87%6.87\%;若反过来以十进制为分母看 1 GiB1\ \mathrm{GiB}1 GB1\ \mathrm{GB} 多出多少则是约 7.37%7.37\%)。 随着量级由 GB 递进到 TB,四次方级联使这种折减进一步加深:10004102440.9094947 TiB\frac{1000^4}{1024^4} \approx \mathbf{0.9094947}\ \mathrm{TiB},这就是为什么厂商标称的 1 TB 硬盘插在 Windows 里显示为约 931.32 GiB(缩水了整整 9.05%9.05\%)。这并不是厂商少给了容量,而是十进制与二进制的计数基准不同。

IEC 80000-13 使用 Ki, Mi, Gi, Ti 等二进制前缀来表示 10241024 的幂,并把它们与 SI 的 k, M, G, T 十进制前缀区分开。IEC 80000-13: Information technology — Quantities and units — Part 13: Information science and technology

本站数据页也按这个原则命名:KBEB1000n1000^nKiBEiB1024n1024^n。这里不会把所有带有“千、兆、吉、太”字样的本地化名称强行改成同一个中文词;页面的单位短符号保留 KB / KiB 差异,避免用户只看汉字而漏掉关键的 i

3.2 bit、byte 和带宽的时间口径

数据页还包含 bit 与 byte。1 B = 8 b,但网络带宽通常以 Mb/sGb/s 表示,下载工具和文件大小却常以 MBMiB 表示。比较两者时,除了 bit/byte 的 8 倍,还要确认十进制还是二进制,以及带宽中的“每秒”是否已经包含协议开销。

换算器只负责数值单位的转换:例如 100 Mb12.5 MB 的比值来自 8 bit/byte 和十进制前缀。它不会估计 Wi-Fi、TCP、TLS、磁盘或运营商线路的有效吞吐量,也不会把一个“标称速率”变成实际下载时间。实际吞吐是性能测量问题,不是单位表可以推出来的常数。

4. 时间单位:月和年必须先问“哪个上下文”

4.1 秒、分、小时、天是持续时间关系

时间页从皮秒、纳秒、微秒、毫秒、秒一直列到分、小时、天、周和旬。对于这些固定持续时间,关系可以安全地写成比例:

  • 1 min=60 s1\ \mathrm{min}=60\ \mathrm{s}
  • 1 h=3600 s1\ \mathrm{h}=3600\ \mathrm{s}
  • 1 d=86400 s1\ \mathrm{d}=86400\ \mathrm{s}
  • 1 wk=7 d1\ \mathrm{wk}=7\ \mathrm{d}
  • 本站的旬是 10 d10\ \mathrm{d}

“天”在这里是 24 小时的持续时间,不是某个时区日历上从午夜到午夜的日期跨度。遇到夏令时的本地日期,两个午夜之间可能不是 24 个实际小时;这已经超出一个固定比例换算器的职责。

4.2 本站的月、季度、年是近似持续时间

时间页当前明确写出:

  • month (mo, 30.44d):平均月约 30.44 天;
  • quarter:3 个月约 91.31 天;
  • year (yr, 365d):平年 365 天;
  • leap year (366d):闰年 366 天;
  • century:按 100 年的长期口径保存。

这些条目服务于持续时间的数量级比较,例如把平均月数换算成秒,或把平年天数换算成秒。它们表示“从 2026-01-31 加一个月一定得到多少秒”,也不判断某个具体年份是否闰年,更不会处理公历、时区、夏令时或闰秒。

这也是本文最需要强调的“不承诺”:本站时间换算器没有日历月换算。一个日历月可能是 28、29、30 或 31 天;“一年”可以指平年、闰年、回归年、儒略年或金融产品合同年。若业务要求日期加减,应使用带时区和日历规则的日期时间库,并明确“月末溢出”“时区”和“夏令时”的策略;不能把换算器的 mo 因子伪装成日历算法。

NIST 对秒的定义和时间频率测量有严格的物理语境;而应用中的日、月、年还要叠加日历与民用时间规则。因此工程接口应把 durationcalendar date 分成不同类型,而不是让一个 number 字段同时承担两者。NIST Time and Frequency

5. 显示、舍入与“看起来精确”

换算分成两层:内部数值和用户看到的字符串。两层的目标不同,不能用显示位数倒推内部精度。

本站换算器沿用计算器引擎的 formatNumber:有限数通常保留 12 位有效数字;绝对值达到 101210^{12} 或小于 10910^{-9} 时采用科学计数法;安全整数优先完整输出,NaN 显示为 undefined,无穷大显示为 -∞。这套策略有三个工程动机:

  1. 有效数字比固定小数位更适合跨尺度单位。 toFixed(6) 会让纳米级结果变成 0.000000,也会给大型整数补上没有意义的零;
  2. 过滤二进制浮点噪声。 0.1 + 0.2 内部可能是 0.30000000000000004,显示到 12 位有效数字会回到用户需要的 0.3
  3. 保住可精确表示的大整数。 1 TiB = 1099511627776 B 是安全整数时应完整显示,而不是过早压成短科学计数法;超过 25312^{53}-1 后,JavaScript number 本身就不能保证每一位整数精确,科学计数法反而更诚实。

“显示为 25.4”不等于内部数学值只有三位有效数字;“显示为 1.152922e+18”也不意味着程序知道这个数量的每一个字节。显示层是在可读性、浮点噪声和可见精度之间取舍。前端业务如果需要金额分、计量检定或可审计的十进制结果,应在数据模型层使用整数、定点数或十进制高精度类型,不能只把 toPrecision() 换成更多位。

舍入还必须在正确的阶段发生。换算链中应保留内部结果到最后,再对最终输出舍入;若先把中间的平方米截成两位小数再换成亩,误差会被带入后续结果。对账、计费和计量报告则应把舍入模式、保留位数、单位和原始输入一起记录,避免“页面上看起来一样”掩盖了业务规则不同。

6. 一张实现边界清单

面对一个新单位,先回答以下问题,再决定能不能把它加入线性因子表:

问题 若答案为“是” 若答案为“否”
零点是否相同? 可以考虑 y=kxy=kx 需要仿射模型或独立规则,温度是典型例子
量纲是否相同? 可以在同一类别内换算 不能把长度因子直接用于面积或体积
前缀的进位基数是否相同? 可按同一套前缀换算 区分 kB/KiBMB/MiB
数值是否代表固定持续时间? 秒、小时、固定天数可按比例 月、年要注明平均、平年、闰年或日历语义
定义是否精确且可追溯? 用定义、分数或可复算表达式记录 标签注明工况或近似值,不能伪装成精确定义
结果是否能被当前数值类型完整表示? 可在显示层保留完整整数 使用高精度类型或明确误差与舍入策略

这张表也说明了本站工具的边界:温度、面积、体积和时间页可以帮助用户做同类单位的数值换算,但不会自动推断物理量、日历或业务语义。它们的正确性首先来自单位定义,其次来自基准表的一致性,最后才是浮点运算和显示格式。

7. 换算器不是语义推断器

一个可靠的单位转换接口,不是把单位名称和一串小数塞进下拉框,而是让每个数字都回答三个问题:它的物理量是什么,它的零点与维度是什么,它的定义和上下文是什么。

线性比例适合米、升、秒等固定关系;仿射模型保护温度零点;面积和体积把长度因子提升到正确的维度;IEC 二进制前缀避免把 GiB 当成 GB;月年条目则必须诚实地标成平均或平年口径。在展示端,显示层只负责把可用的数值变成人能读的字符串,不能替代精确数据模型。

如果需求是“把 3.5 英尺换成米”,工具可以直接给答案;如果需求是“把合同期限 3 个月换成秒”“把 1 TB 换成操作系统可用空间”或“把 20 °C 的温差换成华氏度”,真正缺的不是一个更大的换算表,而是对上下文的明确说明。