前置:分工、比较优势与交换 · 市场价格与弹性
早餐价格上涨,卖方多收的钱是不是社会损失?政府每份征两元税,收到的税款是不是又要算一次损失?要回答,先把“某个人少了多少”与“交易双方合计少了多少”分开。
本篇沿同一个市场比较无税、征税与补贴。评价口径暂时是按货币计的买方估值减卖方机会成本,不含第三方影响、征管成本和不同收入者对一元钱的不同价值。这个口径能解释交易得失,但不是全部社会福利。
一笔交易的支付与剩余
买方最高愿付 12 元,卖方机会成本 4 元,成交价为 7。买方获得的净好处是 12−7=5,称消费者剩余;卖方是 7−4=3,称生产者剩余。合计为 8,恰好等于估值 12 减成本 4。
如果价格改为 8,买方剩余变 4,卖方变 4,总和仍为 8。价格改变把一元剩余从买方转给卖方,商品是否交易和真实资源成本没有变化,所以这笔转移本身不是交易总剩余的损失。
不要把卖方收入 7 当作生产者剩余 7,成本还未扣除;也不要把消费者剩余和完整营业收入相加后称作净收益。先给每笔钱找到另一方的对应项,才能避免重复计算。
谁成交,决定总收益能否实现
四位买方估值为 12、10、8、6,四位卖方成本为 2、4、6、8,每人最多交易一份。若按高估值买方与低成本卖方依次匹配,前三份的交易收益为 10、6、2,共 18;第四份估值 6 低于成本 8,强行成交会减少总剩余 2。
相同数量也可能有不同结果。如果把一份从估值 12 的买方交给估值 6 的买方,卖方成本不变,总剩余减少 6。因而“卖了三份”并不足以证明效率;我们还需要知道商品给谁、由谁提供。竞争模型中的有效匹配依赖明确条件,不能把任意排队或配给结果自动代入。
高支付意愿还受购买力影响。货币剩余最大不等于最贫困的人吃到了早餐;若评价目标包括基本保障,需要另外说明分配权重和规则。先把效率与分配分别描述,才能看清政策是在交换什么。
两元税怎样进入同一个价格系统
回到上一课的大市场:Qd=120−10Pb,Qs=20+10Ps。Pb 是买方实际支付,Ps 是卖方税后净收。无税时两者都为 5、数量为 70;每份征税 2 后,二者必须满足 Pb−Ps=2。
把 Pb=Ps+2 放进买卖数量相等的条件:120−10(Ps+2)=20+10Ps,得到卖方净收 4、买方支付 6、数量 60。税由卖家向政府上缴时,他表面收到 6 再交出 2;经济上仍只留下 4。
| 指标 | 无税 | 每份税 2 |
| 买方支付 Pb | 5 | 6 |
| 卖方净收 Ps | 5 | 4 |
| 成交量 Q | 70 | 60 |
| 政府税收 | 0 | 120 |
若法律改为由买家申报并交税,只要市场、执行和交易成本等其余条件不变,买方总支出与卖方净收仍由同一税楔决定。法定缴税者与最终承受价格变化的人不是同一概念。
把损失分成转移和消失的交易
先看仍成交的 60 份:买方每份多付 1,少了 60;卖方每份少留 1,也少了 60;两项恰好成为政府税收 120。计入政府后,这部分是主体间转移。
再看不再成交的第 61–70 份。无税时这些边际交易仍有正收益;税让买方价格上升、卖方净收下降,双方不再同时愿意交易。在本例的线性关系下,这 10 份原有的估值与成本差从 2 逐渐降到 0,平均为 1,总计失去 10。
也可以逐方核对:买方剩余减少 60×1+10×1/2=65,卖方剩余也减少 65;合计减少 130,其中 120 进入政府,剩余 10 没有人得到,称死重损失。它来自原本有益的交易消失,不是从税款里再扣一次 120。
正在呈现知识画面
改变条件,核对结果无税价格固定为 5、数量 70;需求与供给反应相同时,每件税 2 使买价为 6、卖价为 4、数量为 60。改变需求反应可比较税负。
{"id":"economics-08","title":"改变条件,核对结果","summary":"无税价格固定为 5、数量 70;需求与供给反应相同时,每件税 2 使买价为 6、卖价为 4、数量为 60。改变需求反应可比较税负。","height":750,"html":"<div class=\"controls\"><label for=\"response\"><span data-i18n=\"response\"></span><select id=\"response\"><option value=\"5\" data-i18n=\"low\"></option><option value=\"10\" selected data-i18n=\"equal\"></option><option value=\"20\" data-i18n=\"high\"></option></select></label><label for=\"tax\"><span data-i18n=\"tax\"></span><output id=\"out-tax\" for=\"tax\"></output><input id=\"tax\" type=\"range\" min=\"0\" max=\"4\" step=\"0.5\" value=\"2\"></label></div><button id=\"reset\" type=\"button\" data-i18n=\"reset\"></button><div id=\"graphic\"></div><div id=\"results\" class=\"results\" role=\"status\" aria-live=\"polite\" data-i18n-label=\"result\"></div><p class=\"scope\" data-i18n=\"scope\"></p>","css":"body{padding:20px}h2{font-size:19px;margin:0 0 14px}.controls{display:grid;gap:16px}label{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;font-size:15px}select,input{grid-column:1/-1;width:100%;min-width:0;font:inherit}select{padding:10px;background:var(--paper);color:var(--ink);border:1px solid var(--rule);border-radius:6px;white-space:normal}input{accent-color:var(--accent)}button{min-height:44px;margin:16px 0;font:inherit}.plot{display:block;width:100%;max-width:560px;height:auto;margin:auto}.plot text{fill:var(--ink);font-size:14px}.legend{display:flex;gap:12px;flex-wrap:wrap;margin:8px 0;font-size:14px}.legend i{display:inline-block;width:16px;height:3px;margin-right:5px;vertical-align:middle}.results{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:16px}.metric{border:1px solid var(--rule);padding:10px;border-radius:6px;min-width:0}.metric span{display:block;font-size:14px;min-height:3.5em;overflow-wrap:anywhere}.metric strong{font-size:22px;font-weight:600}.barrow{margin:14px 0;font-size:15px}.barlabel{display:flex;justify-content:space-between;gap:10px}.bar{height:16px;background:var(--surface);margin-top:5px}.bar i{display:block;height:100%;background:var(--accent)}.stack{display:flex;height:35px;margin:15px 0}.stack span{display:flex;align-items:center;justify-content:center;color:var(--paper);font-size:13px}.scope{font-size:14px;color:var(--muted);margin:14px 0 0;line-height:1.65}@media(max-width:380px){body{padding:14px 10px}.results{gap:6px}.metric{padding:8px}.metric strong{font-size:19px}}.accounts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.account{border:1px solid var(--rule);border-radius:8px;padding:12px;min-width:0}.account h3{font-size:16px;margin:0 0 12px}.account dl{margin:0}.account dt{font-size:13px;overflow-wrap:anywhere}.account dd{margin:2px 0 12px;font-variant-numeric:tabular-nums}.account .changed{font-weight:700;color:var(--accent)}.area-legend{font-size:14px;line-height:1.7}.area-legend span{display:block}.area-legend i{display:inline-block;width:12px;height:12px;margin-right:6px}@media(max-width:480px){.accounts{grid-template-columns:1fr}}","js":"const N=8,DEFAULTS={\"response\": 10, \"tax\": 2};\n/* Pure, deterministic teaching models. Values are synthetic, not estimates. */\nfunction economy(n,p){\n if(n===6){const q=p.remaining,P0=10,P1=12,Q0=100;return{metrics:{oldRevenue:P0*Q0,newRevenue:P1*q,retainedGain:(P1-P0)*q,lostRevenue:P0*(Q0-q),elasticity:Math.abs(((q-Q0)/((q+Q0)/2))/((P1-P0)/((P1+P0)/2)))},revenueAreas:{remaining:q,oldPrice:P0,newPrice:P1,oldQuantity:Q0}};}\n if(n===5){const shift=p.scenario===1?20:0,supply=p.scenario===2?-20:0,P=(100+shift-supply)/20,Q=20+supply+10*P;return{metrics:{price:P,quantity:Q},plot:{xmax:140,ymax:14,x:'quantity',y:'price',lines:[{key:'demand',points:[[0,(120+shift)/10],[120+shift,0]]},{key:'supply',points:[[Math.max(0,20+supply),0],[140,(120-supply)/10]]},{key:'base',points:[[0,5],[140,5]],dash:true}],dot:[Q,P]}};}\n if(n===8){const b=p.response,bs=10,t=p.tax,Pb=5+bs*t/(b+bs),Ps=5-b*t/(b+bs),Q=70-b*bs*t/(b+bs);return{metrics:{buyer:Pb,seller:Ps,quantity:Q,revenue:t*Q,loss:.5*t*(70-Q)},plot:{xmax:100,ymax:20,x:'quantity',y:'price',areas:[{key:'revenue',points:[[0,Ps],[Q,Ps],[Q,Pb],[0,Pb]]},{key:'loss',points:[[Q,Ps],[Q,Pb],[70,5]]}],lines:[{key:'demand',points:[[0,5+70/b],[Math.min(100,70+5*b),Math.max(0,5+(70-100)/b)]]},{key:'supply',points:[[20,0],[100,8]]},{key:'base',points:[[0,5],[100,5]],dash:true},{key:'wedge',points:[[Q,Ps],[Q,Pb]]}],dot:[Q,Pb]}};}\n if(n===18){let index=100+p.weight*p.rise/100;return{metrics:{index,inflation:index-100},bars:[{key:'base',v:100},{key:'new',v:index}],max:180};}\n if(n===19){let E=60,U=10,N=30;if(p.scenario===1){E+=5;U-=5;}if(p.scenario===2){U-=5;N+=5;}if(p.scenario===3){U+=5;N-=5;}return{metrics:{employment:E,unemployment:U,participation:100*(E+U)/100,urate:100*U/(E+U),erate:E},stack:[E,U,N],stackKeys:['employment','unemployment','outside']};}\n if(n===20){const step=p.scenario;let reserves=100,loan=0,deposit=80,equity=20,br=0,bd=0;if(step!==0){loan=60;deposit=140;}if(step===2){reserves-=60;deposit-=60;br=60;bd=60;}if(step===3){loan=40;deposit=120;}const vals={reserves,loan,deposit,equity,bankBreserves:br,bankBdeposits:bd,borrowerDeposit:step===2?0:loan,borrowerGoods:step===2?60:0,borrowerDebt:loan,merchantDeposit:bd,merchantGoods:step===2?0:60};const prev=step>1?economy(20,{scenario:1}).accounts:economy20initial();return{metrics:{reserves,loan,deposit,equity,bankBreserves:br,bankBdeposits:bd,assets:reserves+loan,liabilities:deposit+equity},accounts:vals,ledger:[['bankA',['reserves','loan','deposit','equity']],['bankB',['bankBreserves','bankBdeposits']],['borrower',['borrowerDeposit','borrowerGoods','borrowerDebt']],['merchant',['merchantDeposit','merchantGoods']]].map(([title,keys])=>({title,items:keys.map(key=>({key,value:vals[key],delta:vals[key]-prev[key]}))}))};}\n if(n===22){const c=p.consume,shock=p.shock,rounds=Array.from({length:8},(_,k)=>shock*c**k);return{metrics:{total:shock/(1-c),shown:rounds.reduce((a,b)=>a+b,0),multiplier:1/(1-c)},bars:rounds.map((v,k)=>({label:String(k+1),v})),max:100,rounds};}\n if(n===25){const e=p.rate;return{metrics:{importBill:10*e,exportBill:70/e,debtBill:100*e},bills:true};}\n if(n===26){const A=p.tech,s=p.save/100,d=.1,k=(s*A/d)**2,y=A*Math.sqrt(k),trajectory=[];let current=25;for(let t=0;t<=60;t++){const output=A*Math.sqrt(current),investment=s*output,depreciation=d*current;trajectory.push({t,k:current,y:output,consumption:(1-s)*output,investment,depreciation});current+=investment-depreciation;}return{metrics:{capital:k,output:y,consumption:(1-s)*y},trajectory,plot:{xmax:60,ymax:Math.max(10,...trajectory.map(a=>a.y))*1.1,x:'period',y:'perPersonFlow',lines:[{key:'baselineConsumption',points:[[0,7.5],[60,7.5]],dash:true},{key:'outputPath',points:trajectory.map(a=>[a.t,a.y])},{key:'consumptionPath',points:trajectory.map(a=>[a.t,a.consumption])}]}};}\n throw Error('Unknown lesson');\n}\nfunction economy20initial(){return{reserves:100,loan:0,deposit:80,equity:20,bankBreserves:0,bankBdeposits:0,borrowerDeposit:0,borrowerGoods:0,borrowerDebt:0,merchantDeposit:0,merchantGoods:60};}\nif(typeof module!=='undefined')module.exports={economy};\n\nfunction renderTeachingView(r,el){\n if(r.ledger){\n el.innerHTML='<div class=\"accounts\">'+r.ledger.map(a=>'<section class=\"account\"><h3>'+escape(viz.t(a.title))+'</h3><dl>'+a.items.map(v=>`<dt>${escape(viz.t(v.key))}</dt><dd class=\"${v.delta?'changed':''}\">${viz.number(v.value)} (${v.delta>0?'+':''}${viz.number(v.delta)})</dd>`).join('')+'</dl></section>').join('')+'</div><p class=\"scope\">'+escape(viz.t('delta'))+'</p>';\n $('#results').hidden=true;\n }\n if(r.revenueAreas){const a=r.revenueAreas,x=q=>45+q*2.65,y=p=>213-p*14,q=a.remaining;\n let s=`<svg class=\"plot\" viewBox=\"0 0 360 270\" role=\"img\" aria-label=\"${escape(viz.t('figure'))}\"><path d=\"M45 28V213H322\" fill=\"none\" stroke=\"var(--rule)\"/>`;\n const rect=(x0,x1,p0,p1,c)=>`<rect x=\"${x(x0)}\" y=\"${y(p1)}\" width=\"${(x1-x0)*2.65}\" height=\"${(p1-p0)*14}\" fill=\"${c}\" fill-opacity=\".48\" stroke=\"${c}\"/>`;\n s+=rect(0,q,0,10,'#5277ab')+rect(0,q,10,12,'#247756')+rect(q,100,0,10,'#b56838');\n for(const p of[0,10,12])s+=`<text x=\"37\" y=\"${y(p)+4}\" text-anchor=\"end\">${p}</text>`;\n for(const v of[0,50,100])s+=`<text x=\"${x(v)}\" y=\"235\" text-anchor=\"middle\">${v}</text>`;\n s+=`<text x=\"45\" y=\"20\">${escape(viz.t('price'))}</text><text x=\"310\" y=\"261\" text-anchor=\"end\">${escape(viz.t('quantity'))}</text></svg>`;\n el.innerHTML=s+'<div class=\"area-legend\">'+[['retainedBase','#5277ab'],['retainedGain','#247756'],['lostRevenue','#b56838']].map(([k,c])=>`<span><i style=\"background:${c}\"></i>${escape(viz.t(k))}</span>`).join('')+'</div>';\n }\n}\n\nconst $=s=>document.querySelector(s),col=['var(--accent)','var(--second)','#7581ae','#b36b47'];\nconst escape=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nfunction render(){\n let p={};for(const k of Object.keys(DEFAULTS)){p[k]=Number($('#'+k).value);let o=$('#out-'+k);if(o)o.textContent=viz.number(p[k]);}\n const r=economy(N,p);document.body.dataset.result=JSON.stringify(r.metrics);document.body.dataset.params=JSON.stringify(p);\n $('#results').innerHTML=Object.entries(r.metrics).map(([k,v])=>`<div class=\"metric\"><span>${escape(viz.t(k))}</span><strong data-metric=\"${k}\">${viz.number(v,2)}</strong></div>`).join('');\n const el=$('#graphic');el.replaceChildren();\n if(r.plot){const a=r.plot,x=q=>48+q/a.xmax*278,y=v=>205-v/a.ymax*164;\n let svg=`<svg class=\"plot\" viewBox=\"0 0 360 258\" role=\"img\" aria-label=\"${escape(viz.t('figure'))}\"><path d=\"M48 30V205H333\" fill=\"none\" stroke=\"var(--rule)\"/>`;\n for(const q of [0,a.xmax/2,a.xmax])svg+=`<text x=\"${x(q)}\" y=\"226\" text-anchor=\"middle\">${viz.number(q,1)}</text>`;\n for(const v of [0,a.ymax/2,a.ymax])svg+=`<text x=\"39\" y=\"${y(v)+4}\" text-anchor=\"end\">${viz.number(v,1)}</text>`;\n svg+=`<text x=\"48\" y=\"20\">${escape(viz.t(a.y))}</text><text x=\"326\" y=\"251\" text-anchor=\"end\">${escape(viz.t(a.x))}</text>`;\n (a.areas||[]).forEach((region,j)=>{svg+=`<polygon points=\"${region.points.map(([xx,yy])=>x(xx)+','+y(yy)).join(' ')}\" fill=\"${j===0?'#4c8c9d':'#bd7446'}\" fill-opacity=\".30\"/>`;});\n a.lines.forEach((l,j)=>{svg+=`<polyline fill=\"none\" stroke=\"${col[j]}\" stroke-width=\"${l.key==='wedge'?5:2.5}\" ${l.dash?'stroke-dasharray=\"5 4\"':''} points=\"${l.points.map(([xx,yy])=>x(xx)+','+y(yy)).join(' ')}\"/>`;});\n if(a.dot)svg+=`<circle cx=\"${x(a.dot[0])}\" cy=\"${y(a.dot[1])}\" r=\"5\" fill=\"var(--ink)\"/>`;\n el.innerHTML=svg+'</svg><div class=\"legend\">'+a.lines.map((l,j)=>`<span><i style=\"background:${col[j]}\"></i>${escape(viz.t(l.key))}</span>`).join('')+(a.areas||[]).map((a,j)=>`<span><i style=\"height:10px;background:${j===0?'#4c8c9d':'#bd7446'}\"></i>${escape(viz.t(a.key))}</span>`).join('')+'</div>';\n }else if(r.bars){el.innerHTML=r.bars.map(b=>`<div class=\"barrow\"><div class=\"barlabel\"><span>${escape(b.key?viz.t(b.key):viz.t('round')+' '+b.label)}</span><strong>${viz.number(b.v)}</strong></div><div class=\"bar\"><i style=\"width:${Math.abs(b.v)/Math.max(r.max,...r.bars.map(a=>Math.abs(a.v)))*100}%\"></i></div></div>`).join('')+(N===22?`<p class=\"scope\">${escape(viz.t('negative'))}</p>`:'');\n }else if(r.stack){el.innerHTML='<div class=\"stack\">'+r.stack.map((v,j)=>`<span style=\"width:${v}%;background:${col[j]}\">${v}</span>`).join('')+'</div><div class=\"legend\">'+r.stackKeys.map((k,j)=>`<span><i style=\"background:${col[j]}\"></i>${escape(viz.t(k))}</span>`).join('')+'</div>';}\nrenderTeachingView(r,el);\n}\nfor(const k of Object.keys(DEFAULTS))$('#'+k).addEventListener('input',render);\n$('#reset').addEventListener('click',()=>{for(const[k,v]of Object.entries(DEFAULTS))$('#'+k).value=v;render();});render();\n","audio":false,"strings":{"base":"基准","buyer":"买方支付 / 每件","demand":"需求","equal":"相同:10","figure":"当前参数下的模型图;准确值见下方结果。","high":"较强:20","loss":"死重损失","low":"较弱:5","price":"单位价格 P","quantity":"数量 Q","reset":"恢复基准","response":"需求数量反应系数","result":"计算结果","revenue":"税收收入","scope":"无税价格固定为 5、数量 70;需求与供给反应相同时,每件税 2 使买价为 6、卖价为 4、数量为 60。改变需求反应可比较税负。","seller":"卖方净收 / 每件","supply":"供给","tax":"每件税额","wedge":"税楔"}}
先保持双方反应相同,再改变需求反应系数。图中的买卖价格间距始终等于每份税,数量决定税收面积;沿着楔子找到不再成交的范围,并用下方精确值核对。图形延伸是简化关系,本篇只用相关数量区间的变化解释损失,不把局部直线外推当成真实早餐生产技术。
哪一方更难调整,哪一方往往承担更多
如果买方对价格反应较弱,涨价后退出不多;卖方更容易转去生产别的商品,就较难被迫长期接受大幅降价。税负更可能落到买方。
在交互中把需求反应系数从 10 改为 5,固定无税基准为 5、70,供给系数仍为 10。税为 2 时,买方价格约 6.33、卖方净收约 4.33,数量约 63.33。买方每份负担约 1.33,卖方约 0.67,两者合计仍为 2。需求反应系数改为 20 时,负担方向相反。
这是围绕同一基准比较相对反应,不能隔着不同坐标尺度说“哪条线更平就由谁承担”。实际税负还会随时间变化:短期店铺位置与设备固定,长期企业可以进入退出。估计具体税收政策需要当地市场与制度证据。
补贴为什么也需要完整账
若改为每份补贴 2,卖方净得比买方支付高 2,即 Ps=Pb+2。同一关系给出 Pb=4、Ps=6、Q=80;政府支出为 2×80=160。
买方因降价而增加的剩余为 70×1+10×1/2=75,卖方也增加 75,共 150;政府付出 160,净差为 −10。在这个没有外部性、原无税均衡有效的模型里,新增的 10 份交易中,边际资源成本超过买方估值,因此产生损失。
但这不推出“所有补贴都不好”。若消费有未计入的公共健康收益,或存在信息障碍,原先的私人成交量可能偏低;若政策目标是帮助特定家庭,分配收益也需要另行评估。先问原来漏了什么,再把它明确加入,而不是用一句“现实很复杂”跳过账表。
财政资金的来源也有代价。此处把一元政府支出按一元计,尚未纳入筹资、征管与其他公共项目的机会成本。对真实政策,应把这些成本与实际收益放在同一期间和单位下比较。
用新规则检查你的理解
政府向卖方收每份两元税,卖方说“税全部由我上缴,所以买家没有承担”。用本篇基准解释这句话遗漏了什么。
展开推理
无税买方付 5,有税付 6,买方已经通过更高价格承担每份 1;卖方从净收 5 到 4 承担另一份 1。谁把钱汇给税务部门是法定责任,谁的实际支付或净收入变化是经济归宿。比较还要用一致的无税对照,不能把税前标价、税后标价和卖方净收混作一个变量。
一个项目支付补贴 160,给买卖双方带来货币剩余 150;另有可核实的第三方收益 30。按同一货币评价口径、忽略其他成本,净收益是多少?能否据此说每个居民都受益?
展开推理
净收益为 150+30−160=20。不能说每人都受益:补贴由谁负担、买卖双方和第三方分别是谁,仍决定个人结果。若第三方收益只是未经检验的猜测,也不能把 30 当作已经兑现的收入。总量评价、分配评价与证据质量需要分别交代。
资料与延伸阅读
以下资料用于核对概念与统计口径;本文数字、算例和图形为原创教学设定。
CORE · Firms and Markets for Goods and Services · CORE · Public Policy for Fairness and Efficiency · OpenStax · Price Elasticity