ถ้าเรามีเวลาออมเงิน 20, 30, 40 ปี
ก่อนอื่นเราเอาฟังก์ชั่น solve/bisection4, future_value, total_future_value ที่เคยกำหนดไว้ในอดีตมาใช้สำหรับปัญหาเหล่านี้:
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
solve = bisection4
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
# ข้อ 1
# ถ้าผลตอบแทน = 0.08 (8%) ต่อปี และเราออมปีละ 100,000 บาท เราจะมีเงินตอนท้ายเท่าไร
# สังเกต :,.0f ใน f-string (, แปลว่าใช้คอมม่ากั้นตัวเลขทุกสามหลัก และ .0 แปลว่าไม่แสดงทศนิยม)
print(f"20 years: {total_future_value(100_000, 0.08, 20):,.0f} บาท")
print(f"30 years: {total_future_value(100_000, 0.08, 30):,.0f} บาท")
print(f"40 years: {total_future_value(100_000, 0.08, 40):,.0f} บาท")
20 years: 4,942,292 บาท 30 years: 12,234,587 บาท 40 years: 27,978,104 บาท
# เราอาจจะให้คอมพิวเตอร์ทำงานซ้ำๆให้เราแทนที่เราจะทำเองด้วยมือ:
for y in (20,30,40):
print(f"{y} years: {total_future_value(100_000, 0.08, y):,.0f} บาท")
20 years: 4,942,292 บาท 30 years: 12,234,587 บาท 40 years: 27,978,104 บาท
# ข้อ 2
# ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000 เราต้องหาผลตอบแทนเท่าไร
# สำหรับ 20 ปี เรากำหนดฟังก์ชั่น fr20 ที่จะรับตัวแปรอัตราผลตอบแทน r
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 20 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr20, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr20(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.23 หรือ 23%
def fr20(r):
return 40_000_000 - total_future_value(120000, r, 20)
solve(fr20, 0, 0.5)
0.23063254839934963
# ข้อ 2
# สำหรับ 30 ปี เรากำหนดฟังก์ชั่น fr30 ที่จะรับตัวแปรอัตราผลตอบแทน r
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 30 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr30, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr30(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.13 หรือ 13%
def fr30(r):
return 40_000_000 - total_future_value(120000, r, 30)
solve(fr30, 0, 0.5)
0.1302971150054346
# ข้อ 2
# สำหรับ 40 ปี เรากำหนดฟังก์ชั่น fr40 ที่จะรับตัวแปรอัตราผลตอบแทน r
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 40 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr40, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr40(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.086 หรือ 8.6%
def fr40(r):
return 40_000_000 - total_future_value(120000, r, 40)
solve(fr40, 0, 0.5)
0.08639077047155595
# เราอาจจะสั่งให้คอมพิวเตอร์ทำงานซ้ำๆแทนเราได้:
print("ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000")
for y in (20, 30, 40):
def find_r(r):
return 40_000_000 - total_future_value(120_000, r, y)
r = solve(find_r,0, 0.5)
print(f"สำหรับ {y} ปี เราต้องการอัตราผลตอบแทนต่อปี = {r}\
หรือประมาณ {100*r:.1f}%")
ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000 สำหรับ 20 ปี เราต้องการอัตราผลตอบแทนต่อปี = 0.23063254839934963 หรือประมาณ 23.1% สำหรับ 30 ปี เราต้องการอัตราผลตอบแทนต่อปี = 0.1302971150054346 หรือประมาณ 13.0% สำหรับ 40 ปี เราต้องการอัตราผลตอบแทนต่อปี = 0.08639077047155595 หรือประมาณ 8.6%
# ข้อ 3
# ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10% เราต้องออมเงินปีละเท่าไร
# สำหรับ 20 ปี รากำหนดฟังก์ชั่น fd20 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 20 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd20,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd20(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 634,895 บาท
def fd20(deposit):
return 40_000_000 - total_future_value(deposit, 0.1, 20)
solve(fd20,10_000, 1_000_000)
634895.4462743916
# ข้อ 3
# สำหรับ 30 ปี รากำหนดฟังก์ชั่น fd30 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 30 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd30,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd30(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 221,064 บาท
def fd30(deposit):
return 40_000_000 - total_future_value(deposit, 0.1, 30)
solve(fd30,10_000, 1_000_000)
221063.57282305096
# ข้อ 3
# สำหรับ 40 ปี รากำหนดฟังก์ชั่น fd40 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 40 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd40,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd40(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 82,161 บาท
def fd40(deposit):
return 40_000_000 - total_future_value(deposit, 0.1, 40)
solve(fd40,10_000, 1_000_000)
82160.52415889046
# เราอาจจะสั่งให้คอมพิวเตอร์ทำงานซ้ำๆแทนเราได้:
print("ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10%")
for y in (20,30,40):
def find_deposit(deposit):
return 40_000_000 - total_future_value(deposit, 0.1, y)
d = solve(find_deposit, 10_000, 1_000_000)
print(f"ถ้าออม {y} ปี ต้องออมปีละ {d:,.0f} บาท")
ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10% ถ้าออม 20 ปี ต้องออมปีละ 634,895 บาท ถ้าออม 30 ปี ต้องออมปีละ 221,064 บาท ถ้าออม 40 ปี ต้องออมปีละ 82,161 บาท
อ่านเรื่องนี้ที่ Comprehending Python’s Comprehensions หรือดูที่ส่วน "การสร้างลิสต์จาก for" ที่หน้านี้
ลองใช้ list comprehension ดูเช่น
# ลิสต์ 0 ถึง 9
[k for k in range(0,10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# ค่ายกกำลังสองของเลขตั้งแต่ 0 ถึง 10
[k**2 for k in range(0,11)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# คู่ลำดับ (x, x**2) สำหรับ x ตั้งแต่ 0 ถึง 10
[(x, x**2) for x in range(0,11)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49), (8, 64), (9, 81), (10, 100)]
# ค่ายกกำลังสองของเลขตั้งแต่ 0 ถึง 10 แต่เลือกเฉพาะที่ยกกำลังสองแล้วหาร 3 ลงตัว
[k**2 for k in range(0,11) if k**2 % 3 == 0]
[0, 9, 36, 81]
# คู่ลำดับ (k, k**2) ของเลข k ตั้งแต่ 0 ถึง 10 แต่เลือกเฉพาะที่ยกกำลังสองแล้วหาร 3 ลงตัว
[(k,k**2) for k in range(0,11) if k**2 % 3 == 0]
[(0, 0), (3, 9), (6, 36), (9, 81)]
# for ได้หลายครั้ง
[(i,j,k) for i in (0,1) for j in (0,1) for k in (0,1)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
# โยนเหรียญหัวก้อย (H, T) สามครั้งจะออกได้แบบไหนบ้าง
[(i, j, k) for i in ("H","T") for j in ("H","T") for k in ("H","T")]
[('H', 'H', 'H'), ('H', 'H', 'T'), ('H', 'T', 'H'), ('H', 'T', 'T'), ('T', 'H', 'H'), ('T', 'H', 'T'), ('T', 'T', 'H'), ('T', 'T', 'T')]
# สร้างลิสต์ของเลขทศนิยม
[0.5*(k-5) for k in range(0,11)]
[-2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
# สร้างลิสต์ของเลขทศนิยม ไม่ให้มี 0 อยู่ในลิสต์
[0.5*k-0.25 for k in range(-5,7)]
[-2.75, -2.25, -1.75, -1.25, -0.75, -0.25, 0.25, 0.75, 1.25, 1.75, 2.25, 2.75]
# สร้างลิสต์ของเลขทศนิยม
[0.5*k for k in range(-5,6)]
[-2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
ให้พิมพ์ตามตัวอย่างใน Pyplot Tutorial แต่ให้ใส่ %matplotlib inline ไว้ใน Jupyter Notebook ด้วยเพื่อแสดงกราฟต่างๆใน notebook
%matplotlib inline
import matplotlib.pyplot as plt
# ข้อมูลที่เราจะวาดจะอยู่ในลิสต์สองอันที่ป้อนเข้าไปใน plt.plot(...)
# ลิสต์แรกคือแกนนอน ลิสต์ที่สองคือแกนตั้ง
plt.plot([1,2,3,4], [1, 8, 27, 64])
plt.ylabel('x^3')
plt.xlabel('x')
plt.show()
#เราสามารถใช้รูปแบบของ LaTeX เพื่อแสดงผลที่แกนให้ดูสวยงาม
#เนื่องจากคำสั่ง LaTeX จะมี \ เยอะ ไพธอนจะตีความ \ ว่าตามด้วยอะไรเป็นตัวอักษรต่างๆ
#เช่น \n จะถูกตีความว่าเป็นบรรทัดใหม่ (newline)
#ถ้าจะบอกให้ไพธอนอย่าพึ่งตีความอะไรให้ใช้ raw string ที่หน้าตาแบบ r"..."
#อ่านเรื่อง raw string ได้ที่ https://knowledge.kitchen/Raw_strings_in_Python
plt.plot([1,2,3,4],[1,4,9,16])
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.show()
# เพิ่มจำนวนจุดให้กราฟดูสวยขึ้น
plt.plot([0, 0.5, 1, 1.5,2, 2.5,3,3.5,4],[0, 0.25, 1, 2.25, 4, 6.25, 9, 12.25, 16])
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.show()
# ใช้ list comprehension สร้างข้อมูลสำหรับ x และ y
x = [0.1*k for k in range(0, 41)]
y = [k**2 for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
# ถ้าความสัมพันธ์ของ y และ x ดูยุ่งยาก ให้กำหนดฟังก์ชั่นมาช่วย
x = [0.1*k for k in range(-100,100)]
def f(x):
return x**3 - 2*x**2 + 10*x +5
y = [f(k) for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=x^3- 2 x^2 + 10x + 5$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
# ซูมเข้าไปดูแถวๆ x = -2 ถึง 2
# เห็นว่ากราฟตัดแกน x ระหว่าง x = -1 และ 0
x = [0.1*k for k in range(-20,20)]
def f(x):
return x**3 -2*x**2 + 10*x +5
y = [f(k) for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=x^3-2 x^2 + 10x + 5$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
# ใช้ solve หาคำตอบว่าตัดแกน x ที่ไหน
# เดาว่า x อยู่ระหว่าง -1 และ 0
# ได้คำตอบประมาณ -0.45
solve(f,-1,0)
-0.4503122847689626
# ลองวาดกราฟ y(x) = 1/x
# ถ้า x เป็น 0 จะเกิดการหารด้วย 0 ขึ้น
x = [0.01*k for k in range(-200,200)]
def f(x):
return 1/x
y = [f(k) for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=\frac{1}{x}$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-30-bb01fceb637d> in <module> 5 def f(x): 6 return 1/x ----> 7 y = [f(k) for k in x] 8 9 plt.plot(x, y) <ipython-input-30-bb01fceb637d> in <listcomp>(.0) 5 def f(x): 6 return 1/x ----> 7 y = [f(k) for k in x] 8 9 plt.plot(x, y) <ipython-input-30-bb01fceb637d> in f(x) 4 x = [0.01*k for k in range(-200,200)] 5 def f(x): ----> 6 return 1/x 7 y = [f(k) for k in x] 8 ZeroDivisionError: float division by zero
# ลองวาดกราฟ y(x) = 1/x
# ถ้า x เป็น 0 จะเกิดการหารด้วย 0 ขึ้น
# แก้ไขโดยสร้างลิสต์ x ที่ไม่มี 0 อยู่ในนั้น
# บรรทัด x = [0.01*k + 0.005 for k in range(-200,200)]
# เทียบกับ x = [0.01*k for k in range(-200,200)] ในตัวอย่างข้างบน
x = [0.01*k + 0.005 for k in range(-200,200)]
def f(x):
return 1/x
y = [f(k) for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=\frac{1}{x}$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()