使用方法
- 选分账口径:按人数均分适合聚餐 AA;按份额比例分摊适合按股份、按使用次数分账。两个单选按钮切换后,页面会显隐对应输入框。
- 在「总金额」填账单金额(默认 268.00,允许 0.01~1000000 元)。这个数只用来做一次乘法:
Math.round(268.00 × 100) = 26800分,之后全程整数运算。 - 均分模式下填「人数」(默认 7,整数 1~200)。份额模式下把权重填进多行框(默认 3 2 5 7 11,合计 28),按 Ctrl/Cmd + Enter 触发。
- 选「0.01 元尾差归属」:逐分派给前几位让每人只多 1 分,全部由最后一人承担把整笔尾差压给一个人。默认选前者。
- 点「计算分账」后,四张卡给出总额、人数、每人金额与尾差;下方名单逐行列出每人金额;1000.00 元的对照表可导出 CSV。
这个 AA分账计算器能解决什么问题
一是让「各付多少」当场就能收齐。聚餐 268 元 7 个人,最难的不是除法,而是除不尽之后那 0.04 元归谁。用计算器除一下得到 38.2857…,按四舍五入每个人都付 38.29 元,7 个人合计 268.03 元,比账单多 3 分——收钱的时候这 3 分就是一笔糊涂账。AA分账计算器的做法是先取 3828 分作基本份,再把剩下的 4 分一人一分地派给前 4 位,合计精确回到 26800 分。
二是按份额而不是按人头分账。合租时水费按人头、电费按度数、网费按月数摊,权重不一样。份额模式下 268 元按 3:2:5:7:11 分下去是 28.71 / 19.14 / 47.86 / 67.00 / 105.29 元,合计正好 268.00 元。
三是小费一并算清,不给商家留尾差。填 12% 小费后,小费是 round(26800 × 0.12) = 3216 分 = 32.16 元,总额变成 30016 分 = 300.16 元;这个数恰好被 7 整除,每人 42.88 元,一分不差。
本页的 AA分账计算器不做这些事:不按「谁点了菜」追溯个体消费,那需要点单明细;不算美元以外的外币汇率换算,那是汇率换算器;也不替你记账或收款。本页只解决一件事:把一个总额,无损地拆成若干份。
分账原理:整数分、最大余数法,以及 0.01 元为什么必须先剥离
第一步,把元换成分。页面读入的 268.00 先做 Math.round(268.00 × 100) 得到整数 26800,之后所有加减乘除都在整数域内完成,Math.floor 取整和 % 求余都不再有浮点误差。这一步不是洁癖:1.005 × 100 在 IEEE 754 双精度里实际是 100.49999999999999,Math.round 之后得到 100 而不是期望的 101,凭空少 1 分;1.015 × 100 同理少 1 分,0.145 × 100 得到 14.499999999999998、四舍五入成 14 分。三个数字都是现实里会输入的金额,元级小数在二进制里无法精确表示——换成分就绕开了这个坑。
第二步,按人数均分时用「商 + 余数」分解。公式是 base = floor(总额分 ÷ n)、rem = 总额分 − base × n,于是 rem 恒在 [0, n) 区间内。把这 rem 分一人一分派给前 rem 位,剩下的人各拿 base 分。26800 分分 7 人:base = floor(26800 ÷ 7) = 3828,rem = 26800 − 3828 × 7 = 4,所以 4 人拿 3829 分(38.29 元)、3 人拿 3828 分(38.28 元)。不变量是 任意两队相差 ≤ 1 分,且 Σ = 总额分 恒成立,两条都由构造保证,不需要事后校验。
第三步,按份额分摊时用最大余数法(Largest Remainder Method,也叫 Hare 配额法)。不能直接 Math.round(总额 × s_i ÷ Σs)——这个做法在多数情况下会让合计丢掉或超出几分。复算 268.00 元按 1:1:1 分:每人原始值 8933.3333 分,各自四舍五入得 8933 分,合计 26799 分,比总额少 1 分。最大余数法的做法是:先全部 floor 得 8933 × 3 = 26799 分,算出还差 1 分,再按小数部分从大到小排序把这一分补给小数最大的人。本页的三段式实现里,小数部分相同时按原始下标升序,保证结果可复现。268.00 元按 11:8:5 分是同样的故事:朴素四舍五入得 122.83 / 89.33 / 55.83,合计 267.99 元;最大余数法得 122.84 / 89.33 / 55.83,合计正好 268.00 元。
为什么尾差不能靠「最后一人承担」。它数学上也正确(base + rem 仍是整数分,合计不变),但 268.00 元分 7 人时最后一人要付 38.32 元、其他人 38.28 元,差距 4 分;人数更多时差距会线性放大——1000.00 元分 21 人时前 19 人各 47.61 元、2 人 47.62 元,改成最后一人承担就是 47.61 × 20 + 48.00,比基本份多 39 分。所以页面把它保留为一个选项(结算时确实常这么约定),但默认给「逐分派给前几位」。
小费为什么也走整数分。Math.round(26800 × 0.12) 得 3216 分,即 32.16 元;0.12 本身在二进制里是 0.12000000000000000266…,但只要乘的是整数分再取整,最终结果的误差被限制在 1 分以内且方向确定,不会像逐项浮点累加那样越滚越大。关键还有一点:先加小费再分摊,和餐费小费各自摊,是两种不同口径。前者把 300.16 元整除给 7 人,每人 42.88 元;后者餐费每人 38.28/38.29、小费每人 4.59/4.60,两处各留一处尾差。两者合计都是 300.16 元,但每人实际掏的钱不同,对账时必须先说清用哪种。页面默认走「先加小费再分摊」,因为它只产生一处尾差。
完整示例(数值仅作演示)
示例条件与页面默认值完全一致:总金额 268.00 元、人数 7 人、尾差逐分派给前几位、小费 0。逐项核对:
- 总额转分:
Math.round(268.00 × 100)= 26800 分; - 基本份:
floor(26800 ÷ 7)= 3828 分 = 38.28 元; - 尾差:
26800 − 3828 × 7= 4 分 = 0.04 元,相对总额 0.0149%; - 分配结果:38.29 / 38.29 / 38.29 / 38.29 / 38.28 / 38.28 / 38.28 元;
- 合计:4 × 3829 + 3 × 3828 = 15316 + 11484 = 26800 分 = 268.00 元,与总额逐位相同;
- 反面校验:如果每个人都按
(268/7).toFixed(2)取 38.29,7 × 38.29 = 268.03 元,凭空多出 3 分,这就是「先各自取整再相加」与「先分再取整」的差。
上面每个数字都能在下方「1000.00 元分给 1~24 人」对照表的第 7 行(7 人、余 5 分、5 人各多 0.01)互相印证结构,在「完整示例」的份额模式里也能用 3:2:5:7:11 复现同一套余数分配逻辑。示例数值不代表任何真实消费或报价。
输入范围与对照表
- 总金额:0.01~1000000 元,两位小数。它对应 1~100000000 分,上限之内所有中间量都是精确整数。低于 0.01 元或高于 1000000 元会被拒绝并指出是哪个字段超界。
- 人数:1~200 的整数。填 0、负数、小数或字母都会得到具体提示。200 人不是随便定的:它已经覆盖家庭聚餐、班级分组等绝大多数真实场景,再往上名单本身就难以核对。
- 份额:1~20 个,每个份额 0.01~1000000 之间的正数。允许用空格、逗号、顿号、分号或换行分隔。份额合计不要求等于任何特定值——页面按
Σs归一化,所以 3 2 5 7 11(合计 28)和 6 4 10 14 22(合计 56)会得到完全相同的分配结果。 - 小费比例:0~100%,可留 0 关闭。它只影响总额,不影响分摊算法。
换到别的总额时不要照抄上面那张表。1000.00 元分 3 人是 333.33 + 1 分,分 11 人是 90.90 + 10 分(10 个人各多 0.01),分 21 人是 47.61 + 19 分——尾差分的人多了,人均差距仍然只有 1 分,这正是商余分解优于「最后一人承担」的地方。
边界与精度说明
- 金额换算的三类掉精度实测。
1.005 × 100 = 100.49999999999999→ 100 分(少 1 分);1.015 × 100 = 101.49999999999999→ 101 分(少 1 分);0.145 × 100 = 14.499999999999998→ 14 分(少 1 分)。作为对照,1.045 × 100 = 104.5精确命中 105 分,8.675 × 100 = 867.5000000000001也能正确进位到 868 分。所以「转分会不会少钱」的答案取决于二进制尾数落在哪一侧——本页的做法是提前一次性取整,之后再无浮点参与,这才是它可控的原因。 - 整数分方案彻底避开浮点除法。对照
8.7 / 3 = 2.9:浮点除法结果toFixed(2)得 2.90,而 870 分 ÷ 3 = 290 分也是 2.90 元。本例两者一致,但换成100 / 3就分道扬镳——toFixed(2)得 33.33,×3 只有 99.99 元;整数分方案得 33.34 / 33.33 / 33.33,合计精确 100.00 元。 - 上限之内不存在大整数精度问题。本页最大中间量是 100000000 分(1000000.00 元),除以 200 人得 500000 分(5000.00 元)。JavaScript 的安全整数上限是 253 − 1 = 9007199254740991,本页面最大量与它相差约 9 万倍,一个分位都不会丢。
- 最小可分单位是 1 分。0.01 元分给 3 人时,基本份是 0 分、余数 1 分,结果是 0.01 / 0.00 / 0.00 元——有两个人分到 0 元。这是「最小货币单位不可再分」的必然结果,页面会照常显示而不是四舍五入成 0.01 / 0.01 / 0.01(那样会多出 2 分)。
- 上限定在 1000000 元不是因为算不动(100 万点数在整数域内毫无压力),而是因为超过这个量级的 AA 场景极少,而更大的金额通常涉及汇率、手续费或分账周期,规则完全不同。
- 显示与计算分离。界面固定显示两位小数,内部不做中途取整。所以「每人先四舍五入再相加」与「相加后再分」必然差几分——这是取整顺序造成的,不是算错,页面顶部会一直显示合计校验值供你核对。
常见问题
为什么不让每个人都付 38.29 元?
那样合计是 268.03 元,比账单多 3 分。根因是 268 ÷ 7 = 38.285714…,toFixed(2) 把所有人都推到更高的那一侧。正确做法是先取 38.28 作基本份,再把剩下的 4 分一人一分派给前 4 位,合计精确等于 268.00 元。
「最后一人承担尾差」什么时候才用?
只在结算约定明确要求时用,典型场景是「多出来的那几毛由发起人(AA 发起者)承担」。它的数学正确性有保证(base + rem 仍是整数分,合计不变),但代价是那一个人会比别人多付 rem 分:268 元分 7 人时多 4 分,1000 元分 21 人时多 19 分。人数越多,这个代价越明显。
按份额分摊时,为什么不用「乘完直接四舍五入」?
因为会丢分。复算 268 元按 1:1:1 分:每人 8933.3333 分,四舍五入全得 8933 分,合计 26799 分,比总额少 1 分。按 4:4:3 分则是 97.45 + 97.45 + 73.09 = 267.99 元,同样少 1 分。最大余数法先 floor 再把差额按小数部分排序补回去,才能保证合计等于总额。注意这不代表朴素四舍五入每次都错——3:2:5:7:11 那组两者恰好相同,这是巧合,不能作为依赖。
份额要不要加起来等于 100 或 1?
不需要。页面按份额合计 Σs 归一化后再分配,所以 3 2 5 7 11(合计 28)、6 4 10 14 22(合计 56)、0.3 0.2 0.5 0.7 1.1(合计 2.8)会得到同一组分摊结果。权重用整数比小数更不容易出错,页面因此只接受数字、不接受 30% 这种带百分号的写法。
小费是「先加再分」还是「餐费小费各自分」?
两种都对,但结果不同。268 元 + 12% 小费 = 300.16 元,先加再分时 300.16 ÷ 7 = 42.88 恰好整除,每人 42.88 元;各自分时餐费每人 38.28/38.29、小费每人 4.59/4.60,会出现两处尾差。合计都是 300.16 元,但每人掏的钱不一样。本页默认「先加再分」,因为它只产生一处尾差;若你要按小费单独立账,切换口径后分别填入即可。
转成分的时候会不会莫名其妙少一分钱?
会,而且这是真实存在的现象:1.005 × 100 = 100.49999999999999,Math.round 得 100 而不是 101;1.015 和 0.145 同样少 1 分。本页的做法是在读入时一次性取整,之后全程整数运算,不再有第二次转换,所以这个偏差不会在运算链上累积。它也解释了为什么本页显示的金额可能与「你在 Excel 里手算」差 1 分——Excel 内部同样是二进制浮点。
人数填 0 或小数会怎样?
会被拒绝并指出具体字段:「人数」必须是 1~200 的整数,当前是 0 或 3.5。填 3.5 的常见原因是把「3 个人分 5 份」理解成了人数加小数。金额留空则提示填一个 0.01~1000000 之间的数字。页面不会静默归零。
名单和金额会被上传吗?
不会。整条链路只有 Math.round、Math.floor、乘法和加减法,全部在当前页面执行,没有任何网络请求,也不写 Cookie 或 localStorage。你可以在开发者工具的 Network 面板里连点几次「计算分账」,面板始终是空的。