โพสต์นี้จะใช้ตัวเลข Fibonacciเป็นเครื่องมือในการที่จะสร้างขึ้นเพื่ออธิบายประโยชน์ของเครื่องกำเนิดไฟฟ้าหลาม
โพสต์นี้จะมีทั้งรหัส C ++ และ Python
หมายเลข Fibonacci ถูกกำหนดเป็นลำดับ: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ....
หรือโดยทั่วไป:
F0 = 0
F1 = 1
Fn = Fn-1 + Fn-2
สิ่งนี้สามารถถ่ายโอนไปยังฟังก์ชัน C ++ ได้อย่างง่ายดายมาก:
size_t Fib(size_t n)
{
//Fib(0) = 0
if(n == 0)
return 0;
//Fib(1) = 1
if(n == 1)
return 1;
//Fib(N) = Fib(N-2) + Fib(N-1)
return Fib(n-2) + Fib(n-1);
}
แต่ถ้าคุณต้องการพิมพ์ตัวเลข Fibonacci ทั้งหกตัวแรกคุณจะต้องคำนวณค่าจำนวนมากด้วยฟังก์ชั่นด้านบน
ตัวอย่างเช่นFib(3) = Fib(2) + Fib(1)
แต่ยังคำนวณFib(2)
Fib(1)
มูลค่าที่คุณต้องการคำนวณยิ่งสูงเท่าไรคุณก็ยิ่งแย่ลงเท่านั้น
ดังนั้นหนึ่งอาจถูกล่อลวงให้เขียนใหม่ข้างต้นโดยการติดตามของรัฐmain
มา
// Not supported for the first two elements of Fib
size_t GetNextFib(size_t &pp, size_t &p)
{
int result = pp + p;
pp = p;
p = result;
return result;
}
int main(int argc, char *argv[])
{
size_t pp = 0;
size_t p = 1;
std::cout << "0 " << "1 ";
for(size_t i = 0; i <= 4; ++i)
{
size_t fibI = GetNextFib(pp, p);
std::cout << fibI << " ";
}
return 0;
}
main
แต่นี้เป็นที่น่าเกลียดมากและมันมีความซับซ้อนตรรกะของเราใน มันจะเป็นการดีกว่าถ้าคุณไม่ต้องกังวลกับสถานะในการmain
ทำงานของเรา
เราสามารถคืนvector
ค่าa ของและใช้iterator
เพื่อย้ำมากกว่าชุดของค่านั้น แต่ต้องใช้หน่วยความจำจำนวนมากทั้งหมดในครั้งเดียวสำหรับค่าตอบแทนจำนวนมาก
กลับไปที่แนวทางเดิมของเราจะเกิดอะไรขึ้นถ้าเราต้องการทำอย่างอื่นนอกเหนือจากการพิมพ์ตัวเลข? เราต้องคัดลอกและวางบล็อคทั้งหมดของรหัสmain
และเปลี่ยนข้อความสั่งผลลัพธ์เป็นสิ่งอื่นที่เราต้องการจะทำ และถ้าคุณคัดลอกและวางรหัสคุณควรจะถูกยิง คุณไม่ต้องการถูกยิงใช่ไหม
เพื่อแก้ปัญหาเหล่านี้และเพื่อหลีกเลี่ยงการถูกยิงเราอาจเขียนบล็อครหัสนี้อีกครั้งโดยใช้ฟังก์ชั่นการโทรกลับ ทุกครั้งที่พบหมายเลข Fibonacci ใหม่เราจะเรียกฟังก์ชันการเรียกกลับ
void GetFibNumbers(size_t max, void(*FoundNewFibCallback)(size_t))
{
if(max-- == 0) return;
FoundNewFibCallback(0);
if(max-- == 0) return;
FoundNewFibCallback(1);
size_t pp = 0;
size_t p = 1;
for(;;)
{
if(max-- == 0) return;
int result = pp + p;
pp = p;
p = result;
FoundNewFibCallback(result);
}
}
void foundNewFib(size_t fibI)
{
std::cout << fibI << " ";
}
int main(int argc, char *argv[])
{
GetFibNumbers(6, foundNewFib);
return 0;
}
นี่คือการปรับปรุงที่ชัดเจนตรรกะของคุณmain
ไม่ยุ่งเหยิงและคุณสามารถทำทุกอย่างที่คุณต้องการด้วยหมายเลขฟีโบนักชีเพียงกำหนดหมายเลขโทรกลับใหม่
แต่นี่ยังไม่สมบูรณ์แบบ ถ้าคุณต้องการได้รับหมายเลข Fibonacci สองหมายเลขแรกเท่านั้นจากนั้นทำบางสิ่งบางอย่างจากนั้นรับจำนวนมากขึ้นจากนั้นทำอย่างอื่น
เราสามารถดำเนินต่อไปเหมือนที่เคยเป็นมาและเราสามารถเริ่มเพิ่มสถานะอีกครั้งmain
เพื่อให้ GetFibNumbers เริ่มต้นจากจุดที่กำหนดเอง แต่มันจะขยายโค้ดของเราออกไปและมันก็ดูใหญ่เกินไปสำหรับงานง่าย ๆ เช่นการพิมพ์หมายเลขฟีโบนักชี
เราสามารถใช้รูปแบบผู้ผลิตและผู้บริโภคผ่านกระทู้สองสามข้อ แต่นี่ทำให้รหัสซับซ้อนยิ่งขึ้น
เรามาพูดถึงเครื่องกำเนิดไฟฟ้ากันดีกว่า
Python มีคุณสมบัติภาษาที่ดีมากที่แก้ปัญหาเช่นนี้เรียกว่าเครื่องกำเนิดไฟฟ้า
เครื่องกำเนิดช่วยให้คุณสามารถใช้งานฟังก์ชั่นหยุดที่จุดใดก็ได้แล้วดำเนินการต่อในจุดที่คุณค้างไว้ ทุกครั้งที่ส่งคืนค่า
พิจารณารหัสต่อไปนี้ที่ใช้ตัวสร้าง:
def fib():
pp, p = 0, 1
while 1:
yield pp
pp, p = p, pp+p
g = fib()
for i in range(6):
g.next()
ซึ่งให้ผลลัพธ์กับเรา:
0 1 1 2 3 5
yield
คำสั่งใช้ร่วมกับเครื่องกำเนิดไฟฟ้าหลาม มันช่วยประหยัดสถานะของฟังก์ชั่นและส่งกลับค่า Yeilded ในครั้งถัดไปที่คุณเรียกใช้ฟังก์ชันถัดไป () บนตัวสร้าง
นี่คือสะอาดกว่าโค้ดฟังก์ชันการเรียกกลับ เรามีโค้ดที่สะอาดกว่าโค้ดที่เล็กกว่าและไม่ต้องพูดถึงโค้ดที่ใช้งานได้มากกว่า (Python อนุญาตให้มีจำนวนเต็มขนาดใหญ่โดยพลการ)
แหล่ง
send
ข้อมูลไปยังเครื่องกำเนิด เมื่อคุณทำเช่นนั้นคุณจะมี 'coroutine' มันง่ายมากที่จะใช้รูปแบบเช่นผู้บริโภค / ผู้ผลิตที่กล่าวถึงกับ coroutines เพราะพวกเขาไม่จำเป็นต้องใช้Lock
และดังนั้นจึงไม่สามารถหยุดชะงักได้ เป็นการยากที่จะอธิบาย coroutines โดยไม่ต้องทุบตีหัวข้อดังนั้นฉันจะบอกว่า coroutines เป็นทางเลือกที่สวยงามมากในการทำเกลียว