一美元有 100 美分,这句话只在一部分世界里成立。
日元没有小数位,科威特第纳尔有千分单位,比特币有 1 亿聪。到了软件里,麻烦还要再加一层:不能放心用浮点数记账。1.03 - 0.42 可能变成 0.6100000000000001。在普通计算里这是小毛刺,在账本里就是事故的种子。
HandsOnMoney 作者最近做商品/货币支持时,翻出了 GnuCash 的一个老设计:它不把钱简单存成小数,也不只存最小单位整数,而是把金额和价格存成分数。
这听着像上世纪遗物。可它真正说明的是,金融软件最难的不是把钱存进去,而是别把未来堵死。
钱不是普通小数
多数记账系统会用一个朴素办法:把金额按最小单位存成整数。
5.23 美元,不存 5.23,存 523 美分。整数好算,也避开了浮点误差。对普通消费、工资、发票系统,这套办法够稳。
问题在前提:精度必须先定死。
| 对象 | 常见最小单位 | 对系统的要求 |
|---|---|---|
| 日元 | 1 日元 | 不能默认两位小数 |
| 科威特第纳尔 | 0.001 第纳尔 | 需要三位精度 |
| 比特币 | 1 聪,等于 0.00000001 BTC | 需要八位精度 |
| 早期美股报价 | 曾有 1/8 美元等分数报价 | 价格可能天然是分数 |
这就是 GnuCash 当年面对的世界。它不只处理美元账本,还要处理股票、基金、商品、不同货币和历史交易单位。
它诞生在 1990 年代末。美股全面十进制化还没完成。2001 年前后,美国主要交易所才完成十进制报价切换。更早的时候,1/8 美元、1/16 美元这类报价并不稀奇。
所以 GnuCash 用分数,不是工程师突然想炫技。它是在一个报价单位尚未完全统一的金融世界里,给数据库留活口。
受影响最直接的是两类人:做金融软件的数据建模者,以及要兼容 GnuCash 数据的记账工具开发者。前者要决定金额字段怎么存;后者要决定是完整继承分数模型,还是牺牲一部分兼容性换简单和速度。
GnuCash 的分数设计强在哪里
分数模型的优点,是它不急着替世界定规矩。
原文里最好的例子是比特币。假设 2011 年有人买了 1 BTC,当时账本只按“1 个比特币”记。后来大家更频繁按聪交易,GnuCash 可以把 BTC 的精度调整到 100,000,000。旧账还能算,新交易也能写成 3 / 100000000 BTC。
固定精度整数模型也能支持比特币,但它通常要求一开始就把精度想清楚。改精度不是不能做,而是会牵涉迁移、显示、报表、历史数据一致性。
HandsOnMoney 选择的是固定精度整数。每个账户绑定自己的商品精度。计算更简单,性能更好,代码也更干净。代价也说得清楚:不完全兼容 GnuCash,不能随时改变商品精度,也不支持某些非标准分数商品。
| 路线 | 适合什么 | 主要代价 |
|---|---|---|
| GnuCash 分数模型 | 历史报价、多资产、高精度资产、兼容旧账 | 计算复杂,性能更差,显示更难解释 |
| 固定精度整数模型 | 现代十进制市场、常规记账、轻量工具 | 精度调整困难,兼容性更弱 |
我不太买账的是那种简单嘲笑:老系统怎么还这么怪。
很多老系统确实怪。但怪不等于错。金融软件里,最怕的不是字段难看,而是历史账本被新规则打断。账本一旦要重算,技术问题马上会变成信任问题。
“天下熙熙,皆为利来。”金融系统麻烦,正因为人会不断发明新的资产、新的报价、新的交易单位。软件如果太早把世界钉死在两位小数上,后来只能补洞。
真正的账在性能和选型
分数模型不是免费午餐。
两个分数相加,要处理分母;结果要约分;排序、汇总、报表、导入导出都要多走一步。交易量一大,这些复杂度就会变成性能账。对现代主流十进制市场来说,很多时候是在为少数边界场景支付日常成本。
这也是今天选型最该看的变量:你的系统到底要兼容多少历史和异常资产。
如果只是个人记账、普通企业收支、主流币种和标准小数商品,固定精度整数通常更划算。开发者会少写一堆转换逻辑,用户也更少遇到奇怪显示。
如果目标是兼容 GnuCash、处理长期历史账本、覆盖股票和商品,再加上加密资产这类高精度对象,分数模型仍然有价值。它贵,但贵在有理由。
这里可以拿铁路轨距做个不完全类比。很多标准不是从最优解开始,而是从旧交易习惯、现实约束和迁移成本里长出来。历史不会直接设计今天的系统,但会把尺寸留在接口里。
GnuCash 也是这个味道。早年的分数报价环境,不是今天所有金融软件都必须继承的规则;但它提醒开发者,数据模型一旦进入账本,就很难轻松换掉。
接下来最该观察的,不是 GnuCash 分数模型会不会被证明“更先进”。这个问题太粗。
更现实的观察点有两个:HandsOnMoney 的固定精度模型在导入 GnuCash 数据时,会在哪些资产和历史交易上遇到边界;以及大交易量场景下,分数模型的性能成本是否还值得用户承担。
这件事最后落回一个很硬的判断:金融软件别迷信优雅模型,也别迷信简单模型。你要先知道自己的账本服务谁。
普通用户要的是少出错、能看懂、跑得快。金融软件开发者要的是迁移时不炸、历史账能平、边界资产有交代。两边都想要,就得付更多工程成本。
模型可以很漂亮,账本不能装腔。钱最后要算平。
