博客

Boring Expenses 如何存储金额(以及为什么用整数)

  • 工程
  • iOS
  • Swift

有一种经典的丢掉一分钱的方式。问几乎任何一种编程语言 0.1 + 0.2 等于多少,它都会告诉你 0.30000000000000004。这不是语言的 bug——二进制浮点数本来就是这样工作的。它们无法精确表示大多数十进制小数,于是细小的误差就悄悄混了进来。算物理没问题,算钱可不行。

对一个理财 App 来说,“差不多”就是错误答案。所以 Boring Expenses 从不把金额存成小数。

用整数存储最小单位

处理钱的软件一直以来的做法,是用最小单位计算,并把它保存为整数。不存 $4.20,而是存 420——也就是分的数量。整数是精确的。整天加加减减、汇总求和,也不会积累任何舍入的尘埃。

Boring Expenses 更进一步,把金额存成非常精细的子单位(大致是“每一个单位一亿份”),这样既为各种货币和未来的需要留足了余地,又让一切保持为普通的 Int。与屏幕上显示的数字之间的转换只发生在最边缘——你输入金额的时候,以及我们把它格式化显示出来的时候。

// 仅为示意,并非实际代码:
let display = Decimal(amountInSubunits) / Decimal(subunitsPerUnit)
let text = display.formatted(.currency(code: userCurrency))

这对你意味着什么

这是一个小小的、不起眼的决定——正是我们喜欢的那种。你永远不会看到它,而这正是重点:数字就是对得上。