แนะนำให้ดู Visual introduction to parabolas
พาราโบลาทุกอันมีรูปทรงเดียวกัน ต่างกันที่เราขยับ หมุน และซูมเข้าออกอย่างไร (เหมือนกับวงกลมทุกอันคล้ายกันหมด แค่ซูมเข้าออก) แนะนำให้ดู There is only One True Parabola
ปกติเราจะเขียนสมการพาราโบลาในรูป $y(x) = a x^2 + b x + c$ โดยที่ $a$ ไม่เป็น 0
ถ้าเราจะหาว่าพาราโบลาตัดแกน $x$ ที่ไหน เราก็ต้องหาค่า $x$ ที่ทำให้ $y(x) = 0$ ก็คือการแก้สมการ $a x^2 + b x + c = 0$ นั่นเอง
เราแก้สมการได้ด้วยวิธีที่เรียกว่า completing the square: คือจัดรูปให้เป็นกำลังสองของอะไรบางอย่างเท่ากับอะไรบางอย่างอีกก้อนหนึ่ง:
$a x^2 + b x + c = 0$
$ x^2 + \frac{b}{a} x + \frac{c}{a} = 0$
$ x^2 + 2 (\frac{b}{2 a}) x + \frac{c}{a} = 0$
$ x^2 + 2 (\frac{b}{2 a}) x + (\frac{b}{2 a})^2 -(\frac{b}{2 a})^2 + \frac{c}{a} = 0$
$ (x + (\frac{b}{2 a}))^2 -(\frac{b}{2 a})^2 + \frac{c}{a} = 0$
$ (x + (\frac{b}{2 a}))^2 = (\frac{b}{2 a})^2 - \frac{c}{a} $
$ (x + (\frac{b}{2 a}))^2 = \frac{b^2 - 4 a c}{4 a^2}$
$ x + (\frac{b}{2 a}) = \pm \sqrt{\frac{b^2 - 4 a c}{4 a^2}}$
$ x = -(\frac{b}{2 a}) \pm \sqrt{\frac{b^2 - 4 a c}{4 a^2}}$
$ x = \frac{-b \pm \sqrt{b^2 - 4 a c}}{2 a}$
ดังนั้น ค่า $ x = \frac{-b \pm \sqrt{b^2 - 4 a c}}{2 a}$ จะเป็นค่า $x$ ที่ทำให้พาราโบลา $a x^2 + b x + c$ ตัดแกน $x$
# เราสร้างฟังก์ชั่นเพื่อคำนวณตามความสัมพันธ์ข้างบน
import math
def zeroes_of_parabola(a,b,c):
"""หาค่า x ที่ทำให้ a x**2 + b x + c == 0
ค่า x ที่หาได้คือจุดที่พาราโบลาตัดแกน x
a ต้องไม่เป็น 0 """
if a == 0: # ถ้า a เป็น 0 จะไม่่คำนวณอะไรให้
return None
if b**2 - 4*a*c < 0: #ถ้าสิ่งที่อยู่ในสแควร์รูทเป็นลบก็จะไม่คำนวณอะไรให้
return None
if b**2 - 4*a*c == 0: #ถ้า b**2 เท่ากับ 4*a*c พอดีจะมีคำตอบเดียว
return [-b/(2*a)]
return [(-b + math.sqrt(b**2-4*a*c))/(2*a),\
(-b - math.sqrt(b**2-4*a*c))/(2*a)] #ไม่งั้นจะมีสองคำตอบ
# -x^2 + 4 = 0 มีคำตอบที่ x = ± 2
zeroes_of_parabola(-1,0,4)
[-2.0, 2.0]
# x^2 - 2x + 1 มีคำตอบที่ x = 1
zeroes_of_parabola(1,-2,1)
[1.0]
# x^2 - 2x + 4 ไม่มีคำตอบที่เป็นจำนวนจริงเพราะ b^2 - 4ac น้อยกว่า 0
zeroes_of_parabola(1,-2,4)
สมการของพาราโบลาที่มี $x$ ยกกำลังสูงสุดเท่ากับ $x^2$ เรียกว่าสมการควอดราติก (quadratic equation)
เรามีสูตร $ x = \frac{-b \pm \sqrt{b^2 - 4 a c}}{2 a}$ สำหรับแก้สมการควอดราติก $a x^2 + b x + c = 0$
ถ้าสมการมี $x^3$ เป็นกำลังสูงสุดเราเรียกว่าคิวบิก (cubic equation) ถ้ามี $x^4$ เป็นกำลังสูงสุดเราเรียกว่าควอติก (quartic equation) สมการกำลังห้าเรียกว่าควินติก (quintic equation)
เมื่อประมาณสี่ห้าร้อยปีมาแล้วนักคณิตศาสตร์พบสูตรแก้สมการคิวบิกและควอติก กล่าวคือมีคนค้นพบสูตรสำหรับแก้สมการ $a x^3 + b x^2 + c x + d = 0$ และ $a x^4 + b x^3 + c x^2 + d x + e = 0$ แม้ว่าสูตรจะยุ่งยากและยาวกว่าสูตรของควอดราติกมากก็ตาม เวลาผ่านไปอีกเกือบๆ 300 ปีก่อนที่จะมีคนค้นพบว่าสมการที่มีกำลังตั้งแต่ 5 ขึ้นไปจะไม่มีสูตรทั่วไปที่จะแก้สมการเหล่านั้น
สำหรับสมการที่ไม่มีสูตรสำหรับแก้ เราสามารถหาคำตอบโดยการประมาณได้หลายวิธี วิธีแรกที่จะใช้วันนี้เรียกว่าวิธีแบ่งครึ่งหาคำตอบ (bisection method) โดยเราจะอาศัยเทคนิควาดกราฟเพื่อดูก่อนว่าคำตอบของสมการ $f(x) = 0$ อยู่แถวๆไหน แล้วกำหนดช่วง $(xmin, xmax)$ ที่คำตอบเราอยู่แถวๆนั้นโดยระวังว่าเครื่องหมายของ $f(xmin)$ และ $f(xmax)$ ต้องตรงกันข้ามกัน คือถ้าฟังก์ชั่น $f$ มีการเปลี่ยนเครื่องหมายจากบวกไปลบหรือลบไปบวกในช่วง $(xmin, xmax)$ ก็แสดงว่าค่าฟังก์ชั่นต้องเป็น 0 ที่ไหนสักแห่งในช่วง $(xmin, xmax)$ นั้น จากนั้นเราก็จะแบ่งครึ่งช่วง $(xmin, xmax)$ เป็นสองช่วงเล็กๆ แล้วดูว่าฟังก์ชั่น $f$ เปลี่ยนเครื่องหมายในช่วงไหน ถ้าเปลี่ยนในช่วงไหนก็แสดงว่าคำตอบ $f(x) = 0$ อยู่ในช่วงนั้น เราสามารถแบ่งครึ่งช่วงอย่างนี้ไปเรื่อยๆให้ช่วงเล็กลงมากๆได้ พอช่วงมีขนาดเล็กพอเราก็บอกว่าคำตอบ $f(x) = 0$ อยู่ในช่วงเล็กๆนั้น อาจจะใช้ค่าตรงกลางช่วง (พอใช้ได้) หรือเทียบบัญญัติไตรยางค์ระหว่างค่าฟังก์ชั่นที่ขอบทั้งสองของช่วงก็ได้ (ได้คำตอบดีกว่า)
# ตัวอย่างฟังก์ชั่นกำลังห้าของเรา
def quintic(x):
return x**5 + x**4 - x**3 + 2*x**2 - 5*x + 6
กราฟฟังก์ชั่นกำลังห้าของเรา ($x^5+x^4-x^3+2x^2 - 5x + 6)$ จะเห็นได้ว่าค่าฟังก์ชั่นเป็นศูนย์ (ตัดแกน $x$) ในช่วง (-3, -2):
# ฟังก์ชั่น bisection method เวอร์ชั่นแรก
# พิมพ์ว่า xmin, xmax มีขนาดเท่าไร ผลคูณ f(xmin)*f(xmax) เป็นเท่าไร
# หยุดทำงานเมื่อขนาด xmin ห่างจาก xmax ไม่เกิน 0.0001
# bisection มีการเรียกตัวเองด้วย (recursion)
def bisection1(f, xmin, xmax):
"พยายามหาค่า x ที่ทำให้ f(x)==0, xmin และ xmax คือช่วงที่เราเดาว่าคำตอบอยู่ในนั้น"
if xmin > xmax: # จัดการให้ xmin น้อยกว่า xmax เสมอ
xmin, xmax = xmax, xmin
print(f"xmin, xmax = {xmin}, {xmax}\t f(xmin)*f(xmax) = {f(xmin)*f(xmax):.5f}")
if xmax-xmin < 0.0001:
print(f'Found a solution: {(xmax+xmin)/2}')
return( (xmin+xmax)/2 )
if f(xmin) == 0: #ถ้า xmin หรือ xmax ทำให้ค่าฟังก์ชั่นเป็นศูนย์ก็ตอบ xmin หรือ xmax เลย
return xmin
if f(xmax) == 0:
return xmax
if f(xmin)*f(xmax) > 0: #ถ้าฟังก์ชั่น f ไม่เปลี่ยนเครื่องหมายจากบวกไปลบหรือลบไปบวก
#ระหว่าง xmin และ xmax ก็ควรไปเดาใหม่ว่า xmin, xmax คืออะไร
print("Bad xmin, xmax")
return None
xmid = (xmin + xmax)/2 #หาจุดกลางระหว่าง xmin และ xmax
if f(xmin)*f(xmid) < 0: #ถ้าฟังก์ชั่นเปลี่ยนเครื่องหมายระหว่าง xmin กับจุดกลาง ก็ไปหาต่อในช่วงนี้
x = bisection1(f,xmin, xmid)
else: #ไม่งั้นก็หาต่อในช่วงจุดกลางถึง xmax
x = bisection1(f,xmid, xmax)
return x
# พยายามหาค่า x ที่ทำให้ฟังก์ชั่นข้างบนของเรามีค่าเท่ากับ 0 โดยเริ่มเดาว่า x อยู่ระหว่าง -3 และ -2
x = bisection1(quintic,-3,-2)
xmin, xmax = -3, -2 f(xmin)*f(xmax) = -1536.00000 xmin, xmax = -2.5, -2 f(xmin)*f(xmax) = -191.50000 xmin, xmax = -2.5, -2.25 f(xmin)*f(xmax) = -80.54361 xmin, xmax = -2.375, -2.25 f(xmin)*f(xmax) = -8.04282 xmin, xmax = -2.375, -2.3125 f(xmin)*f(xmax) = -3.69322 xmin, xmax = -2.375, -2.34375 f(xmin)*f(xmax) = -1.23367 xmin, xmax = -2.359375, -2.34375 f(xmin)*f(xmax) = -0.06170 xmin, xmax = -2.359375, -2.3515625 f(xmin)*f(xmax) = -0.02938 xmin, xmax = -2.359375, -2.35546875 f(xmin)*f(xmax) = -0.01299 xmin, xmax = -2.359375, -2.357421875 f(xmin)*f(xmax) = -0.00473 xmin, xmax = -2.359375, -2.3583984375 f(xmin)*f(xmax) = -0.00058 xmin, xmax = -2.35888671875, -2.3583984375 f(xmin)*f(xmax) = -0.00024 xmin, xmax = -2.358642578125, -2.3583984375 f(xmin)*f(xmax) = -0.00007 xmin, xmax = -2.358642578125, -2.3585205078125 f(xmin)*f(xmax) = -0.00001 xmin, xmax = -2.35858154296875, -2.3585205078125 f(xmin)*f(xmax) = -0.00000 Found a solution: -2.358551025390625
#ตรวจสอบว่าค่าที่หามาได้ทำให้ฟังก์ชั่นใกล้ๆศูนย์ไหม
print(f"x = {x:.3f}, f(x) = {quintic(x):.3f}")
x = -2.359, f(x) = -0.001
# เวอร์ชั่นที่ 2 กำหนดว่าจะหยุดหาเมื่อ xmin ห่างจาก xmax ไม่เกิน tolerance ที่เราตั้งค่าไว้
# ฟังก์ชั่นเรียกตัวเองด้วย (recursion)
def bisection2(f, xmin, xmax):
"พยายามหาค่า x ที่ทำให้ f(x)==0, xmin และ xmax คือช่วงที่เดาว่าคำตอบอยู่ในนั้น"
tolerance = 1e-6 #ตั้งค่่าไว้ว่าให้หยุดหาคำตอบเมื่อ 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
if xmax-xmin < tolerance:
return( (xmin+xmax)/2 )
if f(xmin) == 0: #ถ้า xmin หรือ xmax ทำให้ค่าฟังก์ชั่นเป็นศูนย์ก็ตอบ xmin หรือ xmax เลย
return xmin
if f(xmax) == 0:
return xmax
xmid = (xmin + xmax)/2 #หาจุดกลางระหว่าง xmin และ xmax
if f(xmin)*f(xmid) < 0: #ถ้าฟังก์ชั่นเปลี่ยนเครื่องหมายระหว่าง xmin กับจุดกลาง ก็ไปหาต่อในช่วงนี้
x = bisection2(f,xmin, xmid)
else: #ไม่งั้นก็หาต่อในช่วงจุดกลางถึง xmax
x = bisection2(f,xmid, xmax)
return x
x = bisection2(quintic,-3,-2)
print(f"Value at x = {x:.6f} is {quintic(x):.6f}")
Value at x = -2.358535 is 0.000007
# เวอร์ชั่น 3 ฟังก์ชั่นไม่เรียกตัวเองแล้ว (non-recursive)
# ยังพิมพ์ดูว่า xmin, xmax, f(xmin)*f(xmax) เป็นเท่าไร
# คำตอบที่ได้จะเป็นตรงกลางของ xmin และ xmax
def bisection3(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
return (xmin+xmax)/2 #คำตอบที่ได้จะเป็นตรงกลางของ xmin และ xmax ที่ห่างกันน้อยกว่า tolerance
x = bisection3(quintic,-3,-2)
print(f"Value at x = {x} is {quintic(x)}")
xmin, xmax = -3, -2 f(xmin)*f(xmax) = -1536.00000 xmin, xmax = -2.5, -2 f(xmin)*f(xmax) = -191.50000 xmin, xmax = -2.5, -2.25 f(xmin)*f(xmax) = -80.54361 xmin, xmax = -2.375, -2.25 f(xmin)*f(xmax) = -8.04282 xmin, xmax = -2.375, -2.3125 f(xmin)*f(xmax) = -3.69322 xmin, xmax = -2.375, -2.34375 f(xmin)*f(xmax) = -1.23367 xmin, xmax = -2.359375, -2.34375 f(xmin)*f(xmax) = -0.06170 xmin, xmax = -2.359375, -2.3515625 f(xmin)*f(xmax) = -0.02938 xmin, xmax = -2.359375, -2.35546875 f(xmin)*f(xmax) = -0.01299 xmin, xmax = -2.359375, -2.357421875 f(xmin)*f(xmax) = -0.00473 xmin, xmax = -2.359375, -2.3583984375 f(xmin)*f(xmax) = -0.00058 xmin, xmax = -2.35888671875, -2.3583984375 f(xmin)*f(xmax) = -0.00024 xmin, xmax = -2.358642578125, -2.3583984375 f(xmin)*f(xmax) = -0.00007 xmin, xmax = -2.358642578125, -2.3585205078125 f(xmin)*f(xmax) = -0.00001 xmin, xmax = -2.35858154296875, -2.3585205078125 f(xmin)*f(xmax) = -0.00000 xmin, xmax = -2.358551025390625, -2.3585205078125 f(xmin)*f(xmax) = -0.00000 xmin, xmax = -2.3585357666015625, -2.3585205078125 f(xmin)*f(xmax) = -0.00000 xmin, xmax = -2.3585357666015625, -2.3585281372070312 f(xmin)*f(xmax) = -0.00000 xmin, xmax = -2.3585357666015625, -2.358531951904297 f(xmin)*f(xmax) = -0.00000 xmin, xmax = -2.3585357666015625, -2.3585338592529297 f(xmin)*f(xmax) = -0.00000 Value at x = -2.3585352897644043 is 7.0031444749929506e-06
# เวอร์ชั่น 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
# ทดลองเดา xmin, xmax = -3, -2
x = bisection4(quintic,-3,-2)
print(f"Value at x = {x:.6f} is {quintic(x):.6f}")
Value at x = -2.358535 is 0.000000
# ทดลองเดา xmin, xmax = -3, 0
x = bisection4(quintic,-3,0)
print(f"Value at x = {x:.6f} is {quintic(x):.6f}")
Value at x = -2.358535 is 0.000000
ลองหาคำตอบ $x^2 - 4 = 0$ แถวๆระหว่าง 1.7 และ 2.2 (คำตอบที่ถูกคือ 2)
# ลองใช้วิธี bisection หาคำตอบของควอดราติก x**2 - 4 = 0 แถวๆ (1.7,2.2):
def quad(x):
return x**2 - 4
x = bisection4(quad, 1.7, 2.2)
print(f"Value at x = {x:.6f} is {quad(x):.6f}")
Value at x = 2.000000 is -0.000000
ลองหาคำตอบ $\frac{1}{1+x^2} - 1/2 = 0$ แถวๆระหว่าง 0.7 และ 1.2 (คำตอบที่ถูกต้องคือ x = 1)
# หาคำตอบ 1/(1+x**2) - 1/2 = 0 แถวๆระหว่าง 0.7 และ 1.2 (คำตอบที่ถูกต้องคือ x = 1)
def f1(x):
return 1/(1+x**2) - 1/2
x = bisection4(f1, 0.7, 1.2)
print(f"Value at x = {x:.6f} is {f1(x):.6f}")
Value at x = 1.000000 is -0.000000
ลองหาคำตอบ $cos(\frac{x}{2}) = 0$ แถวๆ 2.8 และ 3.2 (คำตอบที่ถูกต้องคือค่า $\pi$)
def f2(x):
return math.cos(x/2)
x = bisection4(f2, 2.8, 3.2)
print(f"Value at x = {x:.6f} is {f2(x):.6f}")
Value at x = 3.141593 is 0.000000