【JS】Pontaの実質還元率をJavaScriptで求める
こんにちは!今日はJavaScriptを用いたアルゴリズムについて身近なPontaを例に書きます。
Ponta
Pontaとはローソンで出すと100円で1ポイント貰えるあれです。 説明不要ですね。
代金からもらえるPontaを求める関数はこんな感じ。
const getPonta = price => (price / 100) | 0
console.log(getPonta(100)) // 1
console.log(getPonta(200)) // 2
|0は小数点以下切り捨てです。
ローソンで1億円買ったら
Pontaは還元率1%。1億買ったらPontaは1,000,000円貰えるのでしょうか。
試してみよう
console.log(getPonta(100000000)) // 1000000
貰えました。しかし…
Ponta端数問題
Pontaは端数切り捨てです。100円でも199円でも同じ。
console.log(getPonta(100)) // 1
console.log(getPonta(199)) // 1
つまり何が言いたいのか
Pontaを例にしましたが、準通貨の還元率は往々にして切り捨て方式だったりします。
クレジットカードで「還元率○○%!」ってあるやつは 実際もっと低かったりすることもある、ということです:(
クレジットカードを選ぶ時はその辺にも気をつけるといいですよ!!
Pontaの還元率を求める
え?終わりじゃないの?
もう言いたいことは終わりましたが、技術ブログなのでここからがおまけ本題です。
じゃあ実際にローソンで1億円分買って検証してみましょう。JavaScriptで。
前提条件
- ローソンで1億円分買う。
- 1億円に到達するまで買い続ける。
- Pontaは100円で1ポイント貯まるとする。
- 1回の買い物は0円(トイレ借りるだけ)〜1,000円(大人がコンビニで躊躇せずに使える)とする。
- 1億42円とか最後がオーバーするのはok。
やっていきましょう。
アルゴリズム
いくつかの関数を考えてみます。
さっき作ったgetPonta
const getPonta = price => (price / 100) | 0
次に0〜1,000をランダムで返す関数。
const getPayment = () => (Math.random() * 1000) | 0
配列の合計を求める関数。
const sum = payments => payments.reduce((total, payment) => total + payment)
1億円まで買い続ける関数shop at lawson。
延々と再帰を行い買い物を続け、毎回支払った金額の配列を [183, 744, 938…]みたいな感じで作ります。
const shopAtLawson = payments =>
sum(payments) >= 100000000
? payments
: shopAtLawson([...payments, getPayment()])
↑の支払った金額から合計Pontaを求める関数。
const sumTotalPontas = totalPayments =>
totalPayments.reduce((total, payment) => total + getPonta(payment), 0)
最後に、還元率を求める式。
const rate = (totalPoints / 1000000) * 100
これらの関数を用いて、答えを求めていきます。
答え(注: 糞重い)
注: 糞重い
const getPonta = price => (price / 100) | 0
const getPayment = () => (Math.random() * 1000) | 0
const sum = payments => payments.reduce((total, payment) => total + payment)
const shopAtLawson = payments =>
sum(payments) >= 100000000
? payments
: shopAtLawson([...payments, getPayment()])
const totalPayments = shopAtLawson([0])
const sumTotalPontas = totalPayments =>
totalPayments.reduce((total, payment) => total + getPonta(payment), 0)
const totalPoints = sumTotalPontas(totalPayments)
const rate = (totalPoints / 100000000) * 100
console.log(rate) // 0.9010
今回のケースでは還元率は1%ではなく0.9%に近似されました。
数学的な答え(多分)
実質還元率
= 還元率 -
(((端数の最小値 + 最大値) / 2 )
/ ((支払い額の最小値 + 最大値) / 2))
= 1 - (((0 + 100) / 2) / ((0 + 1000) / 2))
= 0.9
結論
- ポイントの切り捨てに注意しよう。特に少額の支払いをちょいちょいするやつ。
- 再帰関数は糞重い
今日はいい記事が書けた!ハッピー<3<3<3