“单位换算”看起来像把一个数字乘上系数:输入 10,输出 1000。这个模型对米和毫米有效,对平方米和平方毫米也大体有效,但一遇到摄氏度、硬盘容量、月份或年份,简单的“乘一个数”就会开始误导人。
本站的换算器不是通用量纲推理系统,而是一组按类别维护的基准单位与因子表。当前有 11 个换算页;本文只讨论其中四类最容易越过语义边界的实现:温度、面积、体积和时间,并补充数据存储页使用的十进制 / 二进制前缀。理解这些边界,比记住更多换算常数更重要。
先给结论:
- 同一物理量、同一零点、不同刻度,通常是线性比例:。
- 温度的绝对读数带零点偏移,属于仿射变换:;温差才可以只按比例换算。
- 面积和体积不是“多了几个单位”,而是长度尺度分别经过二次方、三次方传播。
kB与KiB不是同一个单位的两种拼法;前者按 进位,后者按 进位。- “一个月”“一年”如果脱离日历或业务口径,就没有唯一的秒数。本站的月、季度、年是持续时间近似值,不是日期运算器。
1. 先判断换算属于哪一种关系
1.1 线性比例:零点必须相同
线性换算可以写成:
这里的隐含前提是:两个单位都把同一个物理零点表示为 0,而且一个单位的增量始终是另一个单位增量的固定倍数。例如本站长度页把米作为基准,英寸使用精确的 米因子;面积页把平方米作为基准,平方英尺使用 平方米因子;体积页把升作为基准,立方米使用 升因子。
实现上,这类条目都遵循“先到基准,再从基准出去”的路径:
base = input × from.factor
output = base ÷ to.factor
它不是为每一对单位单独抄一个系数。这样做的好处是,单位数量增加时,关系仍然是 条数据,并且任意一对转换都共享同一个基准值。上一篇单位换算的精度账已经实测了这套中心辐射式表:线性类别的往返误差最差只有 1 ulp;真正容易穿透显示层的,反而是抄错因子和不当的显示策略。
但“线性”不等于“结果永远精确”。例如 在二进制浮点数中仍然不能有限表示;线性只说明数学关系是比例,不会改变 number 的表示能力。浮点边界见为什么 0.1 + 0.2 不等于 0.3。
1.2 仿射变换:绝对温度不能只乘系数
温度是最经典的反例。摄氏度与开尔文的关系是:
华氏度则是:
它们都有比例项,也都有偏移项,因此应写成:
如果错误地把摄氏度乘上 当成华氏度, 会变成 ,但物理上 。错误不是末位舍入,而是把零点不同的两个温标当成了同一个线性空间。
本站温度页以开尔文为基准:摄氏度是 v + 273.15,华氏度是 ((v - 32) * 5) / 9 + 273.15,兰氏度是绝对温标,只按 与开尔文缩放,列氏度按 缩放后再加上摄氏零点。这里的“先到开尔文、再离开开尔文”不是排版习惯,而是把偏移集中在各自的闭包中,避免误用通用的线性 v * factor。
更细的工程区分是:温度读数与温差不是同一件事。 不是 ,但温差 与温差 的增量相等;摄氏温差转华氏温差只乘 ,不能把绝对读数的 也加到温差上。
BIPM 的《国际单位制 SI》明确区分开尔文的热力学温度与摄氏温度,并给出摄氏度与开尔文之间的零点关系。实现温度转换时,应先确认输入是“绝对温度”还是“温差”,再选择仿射模型或比例模型,而不是看到单位符号就套一个系数。BIPM SI Brochure(第 9 版,2019)
2. 面积和体积:维度幂不是装饰性的上标
2.1 长度缩放会平方或立方传播
若长度单位满足:
那么面积单位必须平方:
体积则必须立方:
所以把 in 的因子直接拿来换 in²,或者把英尺的因子直接拿来换 ft³,都会产生数量级错误。平方和立方不是字符串格式,而是物理量维度的一部分。
在代码层面,本站面积和体积页目前保存的是已经完成维度传播的直接因子:面积的 ft² 是 0.09290304 平方米,体积的 ft³ 是 28.316846592 升;页面不会从长度页的 ft 条目运行一个通用的“求幂引擎”。这使页面数据直观,也意味着新增单位时必须把定义写在正确的维度表里,不能只复制一个看起来相近的长度条目。
2.2 面积单位还常常带领域语义
面积页同时覆盖平方米、公顷、市亩、顷、英亩、平方英尺、平方码和平方英里。它们的数学关系是线性的,但使用语境不同:公顷和平方千米适合土地尺度,平方英尺常见于建筑面积,市亩与顷则带有明确的中文传统土地计量语境。
例如本站将公顷定义为 ,市亩使用 ,顷使用 。这里写分数比手抄一个有限位小数更能表达定义;但浏览器最终仍以双精度浮点数执行,页面输出还会经过显示格式化。因此“定义关系是精确的”与“每个十进制数字都能由 JavaScript number 逐位保存”是两个问题。
2.3 体积、容量和“同名单位”要留意体系
体积页的基准是升,包含毫升、立方厘米、升、立方米、美制液量单位、英制液量单位、石油桶以及立方英寸、立方英尺、立方码。1 mL = 1 cm³ 是公制体系内的定义关系;美制加仑和英制加仑则是两个不同的单位,本站分别使用 gal 与 uk_gal,不能因为中文都常译成“加仑”就合并。
同理,US cup、美制液量盎司与英制液量盎司并不是跨地区可互换的“杯”和“盎司”。换算器可以给出数值,但不能替用户决定食谱、法规标签或实验协议采用哪套定义。工程接口中最好把体系写进枚举名、字段名或单位符号,而不要把它隐藏在展示语言里。
权威单位资料也采用这种谨慎做法:NIST SP 811 将单位名称、符号和换算因子分开列出,避免把同名俗称当成同一单位。NIST SP 811《Guide for the Use of the International System of Units (SI)》
3. 数据单位:十进制前缀与二进制前缀是两套系统
3.1 kB 与 KiB 的分歧来自进位基数
数据存储页明确并列两组单位:
| 类别 | 示例 | 定义 | 常见语境 |
|---|---|---|---|
| 十进制字节 | KB、MB、GB、TB |
,每级乘 | 硬盘、SSD、厂商容量 |
| 二进制字节 | KiB、MiB、GiB、TiB |
,每级乘 | 操作系统、内存、文件大小 |
因此:
而:
从 Windows 操作系统的角度来看(以二进制 为基准): 在系统中仅被识别为 (折损约 ;若反过来以十进制为分母看 比 多出多少则是约 )。
随着量级由 GB 递进到 TB,四次方级联使这种折减进一步加深:,这就是为什么厂商标称的 1 TB 硬盘插在 Windows 里显示为约 931.32 GiB(缩水了整整 )。这并不是厂商少给了容量,而是十进制与二进制的计数基准不同。
IEC 80000-13 使用 Ki, Mi, Gi, Ti 等二进制前缀来表示 的幂,并把它们与 SI 的 k, M, G, T 十进制前缀区分开。IEC 80000-13: Information technology — Quantities and units — Part 13: Information science and technology
本站数据页也按这个原则命名:KB 到 EB 是 ,KiB 到 EiB 是 。这里不会把所有带有“千、兆、吉、太”字样的本地化名称强行改成同一个中文词;页面的单位短符号保留 KB / KiB 差异,避免用户只看汉字而漏掉关键的 i。
3.2 bit、byte 和带宽的时间口径
数据页还包含 bit 与 byte。1 B = 8 b,但网络带宽通常以 Mb/s、Gb/s 表示,下载工具和文件大小却常以 MB、MiB 表示。比较两者时,除了 bit/byte 的 8 倍,还要确认十进制还是二进制,以及带宽中的“每秒”是否已经包含协议开销。
换算器只负责数值单位的转换:例如 100 Mb 与 12.5 MB 的比值来自 8 bit/byte 和十进制前缀。它不会估计 Wi-Fi、TCP、TLS、磁盘或运营商线路的有效吞吐量,也不会把一个“标称速率”变成实际下载时间。实际吞吐是性能测量问题,不是单位表可以推出来的常数。
4. 时间单位:月和年必须先问“哪个上下文”
4.1 秒、分、小时、天是持续时间关系
时间页从皮秒、纳秒、微秒、毫秒、秒一直列到分、小时、天、周和旬。对于这些固定持续时间,关系可以安全地写成比例:
- ;
- ;
- ;
- ;
- 本站的旬是 。
“天”在这里是 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 对秒的定义和时间频率测量有严格的物理语境;而应用中的日、月、年还要叠加日历与民用时间规则。因此工程接口应把 duration 与 calendar date 分成不同类型,而不是让一个 number 字段同时承担两者。NIST Time and Frequency
5. 显示、舍入与“看起来精确”
换算分成两层:内部数值和用户看到的字符串。两层的目标不同,不能用显示位数倒推内部精度。
本站换算器沿用计算器引擎的 formatNumber:有限数通常保留 12 位有效数字;绝对值达到 或小于 时采用科学计数法;安全整数优先完整输出,NaN 显示为 undefined,无穷大显示为 ∞ 或 -∞。这套策略有三个工程动机:
- 有效数字比固定小数位更适合跨尺度单位。
toFixed(6)会让纳米级结果变成0.000000,也会给大型整数补上没有意义的零; - 过滤二进制浮点噪声。
0.1 + 0.2内部可能是0.30000000000000004,显示到 12 位有效数字会回到用户需要的0.3; - 保住可精确表示的大整数。
1 TiB = 1099511627776 B是安全整数时应完整显示,而不是过早压成短科学计数法;超过 后,JavaScriptnumber本身就不能保证每一位整数精确,科学计数法反而更诚实。
“显示为 25.4”不等于内部数学值只有三位有效数字;“显示为 1.152922e+18”也不意味着程序知道这个数量的每一个字节。显示层是在可读性、浮点噪声和可见精度之间取舍。前端业务如果需要金额分、计量检定或可审计的十进制结果,应在数据模型层使用整数、定点数或十进制高精度类型,不能只把 toPrecision() 换成更多位。
舍入还必须在正确的阶段发生。换算链中应保留内部结果到最后,再对最终输出舍入;若先把中间的平方米截成两位小数再换成亩,误差会被带入后续结果。对账、计费和计量报告则应把舍入模式、保留位数、单位和原始输入一起记录,避免“页面上看起来一样”掩盖了业务规则不同。
6. 一张实现边界清单
面对一个新单位,先回答以下问题,再决定能不能把它加入线性因子表:
| 问题 | 若答案为“是” | 若答案为“否” |
|---|---|---|
| 零点是否相同? | 可以考虑 | 需要仿射模型或独立规则,温度是典型例子 |
| 量纲是否相同? | 可以在同一类别内换算 | 不能把长度因子直接用于面积或体积 |
| 前缀的进位基数是否相同? | 可按同一套前缀换算 | 区分 kB/KiB、MB/MiB |
| 数值是否代表固定持续时间? | 秒、小时、固定天数可按比例 | 月、年要注明平均、平年、闰年或日历语义 |
| 定义是否精确且可追溯? | 用定义、分数或可复算表达式记录 | 标签注明工况或近似值,不能伪装成精确定义 |
| 结果是否能被当前数值类型完整表示? | 可在显示层保留完整整数 | 使用高精度类型或明确误差与舍入策略 |
这张表也说明了本站工具的边界:温度、面积、体积和时间页可以帮助用户做同类单位的数值换算,但不会自动推断物理量、日历或业务语义。它们的正确性首先来自单位定义,其次来自基准表的一致性,最后才是浮点运算和显示格式。
7. 换算器不是语义推断器
一个可靠的单位转换接口,不是把单位名称和一串小数塞进下拉框,而是让每个数字都回答三个问题:它的物理量是什么,它的零点与维度是什么,它的定义和上下文是什么。
线性比例适合米、升、秒等固定关系;仿射模型保护温度零点;面积和体积把长度因子提升到正确的维度;IEC 二进制前缀避免把 GiB 当成 GB;月年条目则必须诚实地标成平均或平年口径。在展示端,显示层只负责把可用的数值变成人能读的字符串,不能替代精确数据模型。
如果需求是“把 3.5 英尺换成米”,工具可以直接给答案;如果需求是“把合同期限 3 个月换成秒”“把 1 TB 换成操作系统可用空间”或“把 20 °C 的温差换成华氏度”,真正缺的不是一个更大的换算表,而是对上下文的明确说明。