“กฎของ 72”

เมื่อเราเอาเงินไปลงทุนที่อัตราตอบแทนทบต้น $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 จะผิดเพี้ยนน้อย:

In [1]:
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

In [2]:
# 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
In [3]:
#เราสามารถตั้งชื่อฟังก์ชั่น bisection4 ใหม่ให้เป็นชื่อที่ง่ายขึ้นก็ได้ดังนี้
solve = bisection4
In [4]:
# ทดลองหาเวลาที่ทำให้การลงทุนทบต้นที่ผลตอบแทน 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

In [5]:
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

ตัวอย่างการประยุกต์หาคำตอบด้วย bisection เพิ่มเติม

สมมุติว่าเราต้องการทราบว่าเราต้องออมเงินปีละเท่าไรเป็นเวลา 40 ปี ด้วยผลตอบแทนทบต้นปีละ 8% ถึงจะมีเงินเมื่อสิ้นปีที่ 40 เท่ากับ 40,000,000 บาท ถ้าเราไม่รู้สูตรอะไรเลยเราก็สามารถใช้ bisection หาคำตอบให้ได้เหมือนกัน

ก่อนอื่นเราเอาฟังก์ชั่นคำนวณเงินอนาคตจาก วิทย์ม.ต้น: การเติบโตของเงินออมเป็นประจำ, หัดใช้ MU-EDITOR มาใช้เพื่อความสะดวกก่อน:

In [6]:
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

แล้วเราก็ทำการคำนวณคำตอบแบบนี้ก็ได้:

In [7]:
# สร้างฟังก์ชั่นที่รับตัวแปร 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 ล้านบาท เราต้องหาผลตอบแทนทบต้นปีละกี่เปอร์เซ็นต์ เราก็สามารถคำนวณดังนี้ได้:

In [8]:
# สร้างฟังก์ชั่นที่รับตัวแปร 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 ล้านบาท
In [ ]:
 
In [ ]:
 
In [ ]: