同一句「按档算」有两种理解:全额跳档和分段累进。 多卖 1 元,跳档算法多给 300.08 元,累进只多 0.08 元。 200 个档位合计,两种算法差 657000 元。
上一节把循环讲完,这一节用循环算一张真实的奖金表。这是本书第一个「算错了会被人找上门」的实例。
一、两种理解,差一台电脑
规则写的是:1 万以内 5%,1 到 5 万 8%,5 到 10 万 12%,超 10 万 15%。这句话有歧义。 - 全额跳档:整笔业绩按它所在的档位算。8 万就全部按 12% 算。 - 分段累进:每一段只用自己那一档的税率。8 万=1 万按 5%、4 万按 8%、3 万按 12%,加起来。 Demo 把两种都实现了一遍,同一个 8 万:跳档给 9600,累进给 7300,差 2300 元。 这不是算术问题,是口径问题。口径没定,代码写得再对也是错的。
二、断崖:多卖一块钱多拿三百
跳档算法在档口会断崖。 Demo 算得很清楚:业绩从 10000 涨到 10001,提成从 500 跳到 800——多卖 1 块钱, 提成多 300.08 元。 累进算法同一位置只多 0.08 元,是一条连续的线。 断崖带来什么后果?业绩卡在 9900 的人会想办法凑到 10100;卡在 49900 的会想办法凑到 50100。 规则本身在激励凑单。 累进算法没有这个问题,因为每多一块钱都只多那 1 块钱对应的比例。 这也是为什么正规的个税、阶梯电价都用累进。
三、把两百个档位合计一遍
Demo 从 1000 到 200000 每隔 1000 取一个点,一共 200 个,两种算法都算一遍。 结果:跳档合计 2810850 元,累进合计 2153850 元,公司多付 657000 元。 65 万这个数字,比任何一句「差得不多」都有说服力。谈规则的时候,拿这张表出去,比讲道理管用。 注意这里的 200 个点是我为了演示取的等间隔值,不是真实业务分布。 真实数据要先拉出业绩分布,再按分布算——等间隔取样会高估高业绩档的权重。
四、写这类代码的固定套路
看一眼 Demo 的分段累进实现,结构是固定的:
1. 把档位写成一个列表:(段宽, 税率)。
2. 从左到右遍历,每段取 min(剩余, 段宽)。
3. 减掉用掉的额度,用完就 break。
最后一个档位宽度写一个极大值(比如 1e18),表示「剩下的全归这档」。这样不用特判,循环自己会收敛。
这个套路能直接套到阶梯电价、个税、物流阶梯运费、云服务阶梯计价——凡是「分段累进」的规则,
代码长得一模一样。
五、动手 Demo:算业绩提成,两种算法差出一台电脑
把两种口径各写成一个函数,对 9 个业绩点逐一算出两边的提成和差额; 再算档口处「多卖 1 元」的提成增量; 最后从 1000 到 200000 每 1000 取一个点,合计 200 个档位,比较两种算法的总额。
def step_full(x): # 全额跳档
if x <= 10000: return x * 0.05
if x <= 50000: return x * 0.08
if x <= 100000: return x * 0.12
return x * 0.15
def step_part(x): # 分段累进
bands = ((10000, 0.05), (40000, 0.08),
(50000, 0.12), (1e18, 0.15))
left, tot = x, 0.0
for width, rate in bands:
take = min(left, width)
tot += take * rate
left -= take
if left <= 0:
break
return tot
实跑输出:
--------------------------------------------------------------------
实例 1:算业绩提成,两种算法差出一台电脑
--------------------------------------------------------------------
规则 1 万以内 5%,1~5 万 8%,5~10 万 12%,超 10 万 15%
业绩 全额跳档 分段累进 差额
----------------------------------
8000 400 400 0
10000 500 500 0
10001 800 500 300
30000 2400 2100 300
50000 4000 3700 300
50001 6000 3700 2300
80000 9600 7300 2300
100000 12000 9700 2300
200000 30000 24700 5300
多卖 1 元,跳档算法多给 300.08 元
多卖 1 元,累进算法多给 0.08 元
跳档算法在档口会「断崖」:多卖 1 块钱,提成多 300 块。
累进算法永远是连续的一条线。做奖金表必须先问清是哪一种,
同一句「按档算」,两种理解在 5 万这一档差 300 元。
200 个档位合计(跳档) 2810850 元
200 个档位合计(累进) 2153850 元
公司多付 657000 元
九行对照表里,差额全是 0、300、2300、5300 这几个数——每一档刚跳过去时差额最小,越往上差得越多。
注意到 10000 和 10001 两行:跳档从 500 直接到 800,累进从 500 到 500。这就是断崖的现场。
「多卖 1 元」那两行:跳档多 300.08 元,累进多 0.08 元。
300 倍差距,全在一个 if 的边界上。
5 万这一档两种理解差 300 元——注意这里跳档是 4000、累进是 3700。
同一句「按 8% 算」,落地成代码能差这么多。
200 个档位合计 2810850 对 2153850,差 657000 元。这个数就是口径没对齐的代价。
30 秒实验
- 把档位改成「3 万以内 5%、3 到 8 万 10%、超 8 万 15%」,两种算法重算一遍。
- 算一下:业绩 50000 和 50001,跳档算法的提成差多少?
- 想一想:为什么阶梯电价、个税都用累进而不用跳档?
常见误区
- 「按档算就是乘以那档的比例」——那只是一种理解,还有累进。
- 「差一点点不用管」——200 个档位差 65 万。
- 「取等间隔样本就够了」——真实业绩分布不是均匀的,会算偏。
自测三问(点开对答案)
1. 全额跳档和分段累进的区别是什么? —— 跳档整笔按所在档的比例算;累进每段只按自己那档的比例算。 2. 为什么跳档算法会产生「凑单」激励? —— 档口处多卖 1 元,提成会跳好几百,跨过去就赚。 3. 分段累进的代码为什么最后一档写极大宽度? —— 表示剩下的全归这档,不用特判,循环自然收敛。奖金算完,下一个实例练排序——三种手写法和内置的差距会很明显。
- ☐ (本节完,下一节 3.3.2 实例2:使用Python由小到大排列数字)