เมื่อเราเอาเงินไปลงทุนที่อัตราตอบแทนทบต้น $r$ เปอร์เซ็นต์ต่อปี “กฎของ 72” บอกว่าจะใช้เวลา $\frac{72}{r}$ ปีที่จะทำให้เงินงอกเงยเป็นสองเท่า เช่นถ้าผลตอบแทนเท่ากับ 3% ต่อปีจะใช้เวลา $\frac{72}{3} = 24$ ปี ถ้าผลตอบแทนเท่ากับ 8% ต่อปีจะใช้เวลา$\frac{72}{8} = 9$ ปี
(กฎนี้ไม่ใช่กฎที่ไอน์สไตน์คิดนะครับ น่าจะมีมาก่อนไอน์สไตน์หลายร้อยปีแล้ว แต่ไอน์สไตน์เคยพูดเรื่องดอกเบี้ยทบต้นไว้ว่า “Compound interest is the eighth wonder of the world. He who understands it earns it … he who doesn’t … pays it.” เลยมีคนเข้าใจผิดว่าไอน์สไตน์เป็นคนคิด)
กฎนี้เป็นการประมาณเท่านั้น แต่ประมาณได้ใกล้เคียงกับความเป็นจริงมากเมื่อผลตอบแทนไม่สูงเกินไป (เช่นต่ำกว่า 30% ต่อปีลงมา) บางครั้งเราจะใช้เลข 70 แทน 72 ก็ได้ ขึ้นอยู่กับว่าหาร 70 หรือ 72 ง่ายกว่า
สำหรับเด็กๆที่รู้จัก logarithm เราสามารถคำนวณเวลาที่ทำให้เงินงอกเป็นสองเท่าได้เป๊ะๆเท่ากับ $\frac{log(2)}{log(1+\frac{r}{100})}$
ถ้าเด็กรู้จัก logarithm และ calculus มีคำอธิบายอ่านได้ที่ กฎของ "70" (หรือ "72") ครับ เป็นผลลัพธ์จากการกระจาย Taylor's series ของ $\frac{log(2)}{log(1+\frac{r}{100})}$
แต่ถ้าไม่รู้จักคณิตศาสตร์เหล่านั้น เราสามารถใช้วิธี bisection ที่เราเคยใช้ในอดีตมาคำนวณเวลาที่ทำให้เงินเพิ่มเป็นสองเท่าก็ได้
ก่อนอื่นทดลองเปรียบเทียบเวลาที่เงินกลายเป็นสองเท่าที่คำนวณจากสูตร $\frac{log(2)}{log(1+\frac{r}{100})}$ กับเวลาที่คำนวณจากกฎของ 72 และ 70 ดู จะพบว่าถ้าผลตอบแทนน้อยกว่า 30% ลงมา คำตอบประมาณจากกฎของ 72 และ 70 จะผิดเพี้ยนน้อย:
from math import log #ใช้ฟังก์ชั่น math.log ในการคำนวณ logarithm
print("%\tคำตอบ\tกฎ 72\tกฎ 70")
for r in (1, 2, 5, 8, 10, 15, 20, 25, 30, 50, 100):
ans = log(2)/(log(1+r/100)) # คำตอบเป๊ะๆ
ans_72 = 72/r # คำตอบประมาณจาก 72/r
ans_70 = 70/r # คำตอบประมาณจาก 70/r
print(f"{r}\t{ans:.1f}\t{ans_72:.1f}\t{ans_70:.1f}") #ใช้ f-string แสดงทศนิยม 1 ตำแหน่ง
% คำตอบ กฎ 72 กฎ 70 1 69.7 72.0 70.0 2 35.0 36.0 35.0 5 14.2 14.4 14.0 8 9.0 9.0 8.8 10 7.3 7.2 7.0 15 5.0 4.8 4.7 20 3.8 3.6 3.5 25 3.1 2.9 2.8 30 2.6 2.4 2.3 50 1.7 1.4 1.4 100 1.0 0.7 0.7
สมมุติว่าเราไม่รู้จัก logarithm และ calculus เราจะใช้วิธี bisection มาหาคำตอบว่าใช้เวลากี่ปีเงินถึงจะเพิ่มเป็นสองเท่าได้ ก่อนอื่นเราเอาฟังก์ชั่น bisection4 มาจากการเรียนในอดีตที่ วิทย์ม.ต้น: เขียนโปรแกรมไพธอนหาว่าพาราโบลาตัดแกน x ที่ไหน, วิธีหาคำตอบโดย Bisection Method
# bisection เวอร์ชั่น 4 ฟังก์ชั่นไม่เรียกตัวเองแล้ว (non-recursive)
# ไม่พิมพ์ดูว่า xmin, xmax, f(xmin)*f(xmax) เป็นเท่าไรแล้ว
# คำตอบที่ได้จะเทียบบัญญัติไตรยางค์ระหว่างจุด (xmin, f(xmin)) และ จุด (xmax, f(xmax))
# ซื่งน่าจะได้คำตอบที่ใกล้ความจริงมากกว่าแบบตอบตรงกลางระหว่าง xmin และ xmax
def bisection4(f,xmin, xmax):
"พยายามหาค่า x ที่ทำให้ f(x)==0, xmin และ xmax คือช่วงที่เดาว่าคำตอบอยู่ในนั้น"
tolerance = 1e-6 #ตั้งค่า tolerance ไว้ให้หยุดทำงาน
#จะหยุดทำงานเมื่อ xmin ห่างจาก xmax น้อยกว่า tolerance
if xmin > xmax: # จัดการให้ xmin น้อยกว่า xmax เสมอ
xmin, xmax = xmax, xmin
if f(xmin)*f(xmax) > 0:
print("Bad xmin, xmax") #ถ้าฟังก์ชั่น f ไม่เปลี่ยนเครื่องหมายจากบวกไปลบหรือลบไปบวก
#ระหว่าง xmin และ xmax ก็ควรไปเดาใหม่ว่า xmin, xmax คืออะไร
return None
while xmax-xmin > tolerance: # ทำตรงนี้วนๆไปตราบใดท่ี xmin และ xmax ยังห่างกันกว่า tolerance
#print(f"xmin, xmax = {xmin}, {xmax}\t f(xmin)*f(xmax) = {f(xmin)*f(xmax):.5f}")
if f(xmin) == 0:
return xmin
if f(xmax) == 0:
return xmax
xmid = (xmin + xmax)/2 #หาจุดกลางระหว่าง xmin และ xmax
if f(xmin)*f(xmid) < 0: #ถ้าฟังก์ชั่นเปลี่ยนเครื่องหมายระหว่าง xmin กับจุดกลาง ก็ไปหาต่อในช่วงนี้
xmin, xmax = xmin, xmid
else: #ไม่งั้นก็หาต่อในช่วงจุดกลางถึง xmax
xmin, xmax = xmid, xmax
slope = (f(xmax)-f(xmin))/(xmax-xmin)
x = xmin + (0-f(xmin))/slope # คำตอบที่ได้จะเทียบบัญญัติไตรยางค์ระหว่างจุด (xmin, f(xmin)) และ จุด (xmax, f(xmax))
return x
#เราสามารถตั้งชื่อฟังก์ชั่น bisection4 ใหม่ให้เป็นชื่อที่ง่ายขึ้นก็ได้ดังนี้
solve = bisection4
# ทดลองหาเวลาที่ทำให้การลงทุนทบต้นที่ผลตอบแทน 10% ต่อปีเติบโตเป็นสองเท่าด้วยวิธี bisection
# กำหนดฟังก์ชั่นที่รับตัวแปร y คิดเป็นปีเข้าไป
# แล้วจะให้ค่าเท่ากับ 0 เมื่อ (1+10/100) ** y เท่ากับ 2
def f10(y):
return (1+10/100)**y - 2
ymin = 0 #เดาว่าคำตอบอยู่ระหว่าง 0-10 ปี
ymax = 10
#แก้สมการด้วย bisection (ซึ่งเราตั้งชื่อใหม่ว่า solve แล้วจากข้างบน)
ans_bisect = solve(f10, ymin, ymax)
#คำตอบเป๊ะจากสูตร log(2)/log(1+10/100)
ans = log(2)/log(1+10/100)
#เปรียบเทียบกัน
print(f"คำตอบจาก bisection:\t{ans_bisect}")
print(f"คำตอบจากสูตร log():\t{ans}")
คำตอบจาก bisection: 7.272540897341712 คำตอบจากสูตร log(): 7.272540897341713
ลองเปรียบเทียบคำตอบจากกฎ 72, 70, และคำตอบที่หาจากวิธี bisection ดู
จะพบว่าถ้าเรารู้จักใช้ bisection เราก็สามารถหาคำตอบได้ถูกต้องเหมือนๆสูตรจาก log
print("%\tคำตอบ\tกฎ 72\tกฎ 70\tbisect")
for r in (1, 2, 5, 8, 10, 15, 20, 25, 30, 50, 100):
ans = log(2)/(log(1+r/100)) # คำตอบเป๊ะๆ
ans_72 = 72/r # คำตอบประมาณจาก 72/r
ans_70 = 70/r # คำตอบประมาณจาก 70/r
def f(y): # ฟังก์ชั่นนี้รับตัวแปร y เป็นปีเข้าไป
return (1+r/100)**y - 2 # จะให้ค่าเป็น 0 เมื่อทบต้น y ปีแล้วเงินเพิ่มเป็น 2 เท่า
ans_bisect = solve(f,0,100) # คำตอบจากวิธี bisection
print(f"{r}\t{ans:.1f}\t{ans_72:.1f}\t{ans_70:.1f}\t{ans_bisect:.1f}") #ใช้ f-string แสดงทศนิยม 1 ตำแหน่ง
% คำตอบ กฎ 72 กฎ 70 bisect 1 69.7 72.0 70.0 69.7 2 35.0 36.0 35.0 35.0 5 14.2 14.4 14.0 14.2 8 9.0 9.0 8.8 9.0 10 7.3 7.2 7.0 7.3 15 5.0 4.8 4.7 5.0 20 3.8 3.6 3.5 3.8 25 3.1 2.9 2.8 3.1 30 2.6 2.4 2.3 2.6 50 1.7 1.4 1.4 1.7 100 1.0 0.7 0.7 1.0
สมมุติว่าเราต้องการทราบว่าเราต้องออมเงินปีละเท่าไรเป็นเวลา 40 ปี ด้วยผลตอบแทนทบต้นปีละ 8% ถึงจะมีเงินเมื่อสิ้นปีที่ 40 เท่ากับ 40,000,000 บาท ถ้าเราไม่รู้สูตรอะไรเลยเราก็สามารถใช้ bisection หาคำตอบให้ได้เหมือนกัน
ก่อนอื่นเราเอาฟังก์ชั่นคำนวณเงินอนาคตจาก วิทย์ม.ต้น: การเติบโตของเงินออมเป็นประจำ, หัดใช้ MU-EDITOR มาใช้เพื่อความสะดวกก่อน:
def future_value(present_value, interest, periods):
"""คำนวณมูลค่าเงินในอนาคต (future value)
ถ้าเรารู้ค่าเงินปัจจุบัน (present value),
อัตราผลตอบแทนต่อปีหรือต่อเดือน (interest),
และจำนวนปีหรือเดือน (periods) ที่ออมเงินไว้ให้งอกเงย
"""
return present_value * (1+interest) ** periods
def total_future_value(deposit, interest, n_periods):
"""คำนวณค่าเงินในอนาคตทั้งหมด ถ้าออมเงินเท่าๆกันทุกปี = deposit
ด้วยผลตอบแทนต่อปี = interest (เช่น 5% = 0.05)
เป็นจำนวนปีทั้งหมด = n_periods
"""
sum = 0.0
for i in range(1,n_periods+1):
sum = sum + future_value(deposit, interest, i)
return sum
แล้วเราก็ทำการคำนวณคำตอบแบบนี้ก็ได้:
# สร้างฟังก์ชั่นที่รับตัวแปร deposit (คือเงินฝากต่อปี เป็นตัวแปรที่เราต้องการหาคำตอบ)
# ฟังก์ชั่นนี้ให้ค่าเท่ากับ 0 ถ้าเงินฝากปีละ deposit
# ด้วยผลตอบแทนทบต้น 8% ต่อปีเป็นเวลา 40ปี แล้วมีเงินทั้งหมด 40 ล้าน
def fd(deposit):
return total_future_value(deposit, 0.08, 40) - 40_000_000
# แก้ด้วยวิธี bisection เดาว่าคำตอบอยู่ระหว่าง 100,000-1,000,000
ans = solve(fd, 100_000, 1_000_000)
print(f"ต้องออมเงินปีละ {ans:.0f} บาท ที่ผลตอบแทนทบต้น 8% เป็นเวลา 40 ปีถึงจะมีเงิน 40 ล้านบาท")
ต้องออมเงินปีละ 142969 บาท ที่ผลตอบแทนทบต้น 8% เป็นเวลา 40 ปีถึงจะมีเงิน 40 ล้านบาท
สมมุติว่าเราต้องการออมเงินทุกปีเป็นเวลา 20 ปี ปีละ 100,000 บาท แล้วเราต้องการให้เงินตอนจบเป็น 10 ล้านบาท เราต้องหาผลตอบแทนทบต้นปีละกี่เปอร์เซ็นต์ เราก็สามารถคำนวณดังนี้ได้:
# สร้างฟังก์ชั่นที่รับตัวแปร r (อัตราผลตอบแทนต่อปี เป็นตัวแปรที่เราต้องการหาคำตอบ)
# ฟังก์ชั่นนี้จะให้ค่าเท่ากับ 0 ถ้าฝากปีละ 100,000 บาท
# ทบต้นที่อัตราผลตอบแทน r ต่อปีเป็นเวลา 20 ปี แล้วมีเงินทั้งหมด 10 ล้าน
def fr(r):
return total_future_value(100_000, r, 20) - 10_000_000
# แก้ด้วยวิธี bisection เดาว่าผลตอบแทนอยู่ระหว่าง 0% และ 20%
ans = solve(fr,0,0.2)
print(f"ต้องหาผลตอบแทนทบต้น {ans*100:.1f}% ต่อปี ฝากปีละ 100,000 เป็นเวลา 20 ปี ถึงจะมีเงิน 10 ล้านบาท")
ต้องหาผลตอบแทนทบต้น 13.7% ต่อปี ฝากปีละ 100,000 เป็นเวลา 20 ปี ถึงจะมีเงิน 10 ล้านบาท