わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

ワンライナーでポイント制度の支払額計算

さて、ポイント制度で20%の還元を受けるのと、現金で15%引きとなるのでは、どちらがより得だろうか。
ポイント分の精算にはポイントがつかないというのが要点だ。別表に1万円の商品を3回購入したときの試算を示した。最初の購入で2000円分のポイント還元が受けられるため、「500円得した」と思うかもしれないが、3回購入時でも現金割引のほうが総計の支払額は900円少ない。ポイント還元のほうが支払額が少なくなるのは9回購入時以降となる。

http://zasshi.news.yahoo.co.jp/article?a=20100603-00000001-president-bus_all

面白い話ですね.「9回」は自明ではないので,ワンライナーで確かめてみました.なお,処理を簡単にするため,1円(1ポイント)未満は切り捨てではなく値として保持しています(ただし出力は整数にしています).
コマンド:

$ ruby -e 'a=10000;b=0.2;p=0;q=0;r=0;1.upto(10){|i| q=a-r;r=q*b;p+=q;puts "%2d: paid \\%d, %dpts, total \\%d (\\%d)"%[i,q,r,p,p/i]}'

出力:

 1: paid \10000, 2000pts, total \10000 (\10000)
 2: paid \8000, 1600pts, total \18000 (\9000)
 3: paid \8400, 1680pts, total \26400 (\8800)
 4: paid \8320, 1664pts, total \34720 (\8680)
 5: paid \8336, 1667pts, total \43056 (\8611)
 6: paid \8332, 1666pts, total \51388 (\8564)
 7: paid \8333, 1666pts, total \59722 (\8531)
 8: paid \8333, 1666pts, total \68055 (\8506)
 9: paid \8333, 1666pts, total \76388 (\8487)
10: paid \8333, 1666pts, total \84722 (\8472)

毎回の請求額は1万円で,ポイントがあればそれを使い,足りない分は現金で払います.各行の数値は順に,支払額,支払後のポイント,支払い総額,それまでの1回あたりの支払額です.
たしかに,ポイント還元のほうが支払額が少なくなるのは9回購入時以降です.
ポイントをためてから,どかんと使う場合は,どうでしょうか…これですね.

他のモデルを考える。6回1万円のものを買うとしよう。
・ポイントなら、5回1万円を払う。6回目はポイントで買う
・割引なら、6×8500円で5万1000払う。
こちらは、ポイントで 1000円お得になる。

http://d.hatena.ne.jp/yoisho63/20100603

ワンライナーを書き換えてみます.

$ ruby -e 'a=10000;b=0.2;p=0;q=0;r=0;1.upto(10){|i| if r>=a then q=0;r-=a else q=a;r+=a*b;p+=a end;puts "%2d: paid \\%d, %dpts, total \\%d (\\%d)"%[i,q,r,p,p/i]}'

出力は:

 1: paid \10000, 2000pts, total \10000 (\10000)
 2: paid \10000, 4000pts, total \20000 (\10000)
 3: paid \10000, 6000pts, total \30000 (\10000)
 4: paid \10000, 8000pts, total \40000 (\10000)
 5: paid \10000, 10000pts, total \50000 (\10000)
 6: paid \0, 0pts, total \50000 (\8333)
 7: paid \10000, 2000pts, total \60000 (\8571)
 8: paid \10000, 4000pts, total \70000 (\8750)
 9: paid \10000, 6000pts, total \80000 (\8888)
10: paid \10000, 8000pts, total \90000 (\9000)

お得感がよく分かりません.数を10回ではなく,もっと増やしましょう(非現実的ですが).あと,出力をほんの少し,見やすくします.

$ ruby -e 'a=10000;b=0.2;p=0;q=0;r=0;1.upto(99){|i| if r>=a then q=0;r-=a else q=a;r+=a*b;p+=a end;puts "%2d: paid \\%5d, %5dpts, total \\%d (\\%d)" % [i,q,r,p,p/i]}'

こうなります:

 1: paid \10000,  2000pts, total \10000 (\10000)
 2: paid \10000,  4000pts, total \20000 (\10000)
 3: paid \10000,  6000pts, total \30000 (\10000)
 4: paid \10000,  8000pts, total \40000 (\10000)
 5: paid \10000, 10000pts, total \50000 (\10000)
 6: paid \    0,     0pts, total \50000 (\8333)
 7: paid \10000,  2000pts, total \60000 (\8571)
 8: paid \10000,  4000pts, total \70000 (\8750)
 9: paid \10000,  6000pts, total \80000 (\8888)
10: paid \10000,  8000pts, total \90000 (\9000)
11: paid \10000, 10000pts, total \100000 (\9090)
12: paid \    0,     0pts, total \100000 (\8333)
13: paid \10000,  2000pts, total \110000 (\8461)
(略)
95: paid \10000, 10000pts, total \800000 (\8421)
96: paid \    0,     0pts, total \800000 (\8333)
97: paid \10000,  2000pts, total \810000 (\8350)
98: paid \10000,  4000pts, total \820000 (\8367)
99: paid \10000,  6000pts, total \830000 (\8383)

長期的には…1万円の請求が100回というのは非現実的なのには目をつぶるとして…20%ポイント還元の割引率が16.666…%に近づくのが確認できます.
1回あたりの支払額が8500円を超える(=15%現金割引のほうが得になる)最大は,47回だというのも,知ることができました.
どうでもいいかあ.入試には使えそうにないし,プログラミング課題としても面白みがないなあ.

nakag0711 割引率=還元率/(1+還元率)の公式に触れてない時点で問題外。再提出のこと。20%還元はこの式だと約17%割引相当なので、還元の方がトクなようだが……というのを前フリにしなければならない。 2010/06/03

http://b.hatena.ne.jp/nakag0711/20100603#bookmark-22028447

ふうん,公式になっているのですね.
(翌朝いくつか書き換えました.翌晩に,ワンライナーと出力を分離しました.)