Wednesday 12 July 2017

Perl เคลื่อนไหว เฉลี่ย ตัวอย่างเช่น


บทนี้จะแนะนำแนวคิดเกี่ยวกับโมดูล Perl โมดูลและชั้นเรียน นอกจากนี้ยังแสดงวิธีการสร้างโมดูลตัวอย่างบางส่วนด้วย โมดูล Perl คือชุดของรหัส Perl ที่ทำหน้าที่เหมือนไลบรารีการเรียกฟังก์ชัน โมดูลคำใน Perl มีความหมายเหมือนกันกับชุดคำ แพคเกจเป็นคุณลักษณะของ Perl 4 ในขณะที่โมดูลเป็นที่แพร่หลายใน Perl 5. คุณสามารถเก็บรหัส Perl ที่นำมาใช้ซ้ำได้ทั้งหมดของคุณเฉพาะชุดงานในโมดูล Perl ดังนั้นฟังก์ชันทั้งหมดที่เกี่ยวข้องกับงานหนึ่งประเภทมีอยู่ในไฟล์เดียว ง่ายต่อการสร้างแอพพลิเคชันในบล็อกแบบแยกส่วนเหล่านี้ ดังนั้นโมดูลคำใช้เวลามากกว่าแพคเกจ นี่เป็นบทนำสู่โมดูลอย่างรวดเร็ว บางหัวข้อในส่วนนี้จะครอบคลุมรายละเอียดตลอดช่วงที่เหลือของหนังสือ อ่านย่อหน้าต่อไปนี้อย่างละเอียดเพื่อให้ได้ภาพรวมของสิ่งที่อยู่ข้างหน้าขณะที่คุณเขียนและใช้โมดูลของคุณเอง สิ่งที่ทำให้เกิดความสับสนคือโมดูลคำและแพคเกจใช้สลับกันได้ในเอกสาร Perl ทั้งหมดและทั้งสองคำนี้หมายถึงสิ่งเดียวกัน ดังนั้นเมื่ออ่านเอกสาร Perl เพียงแค่คิดว่า quotpackagequot เมื่อคุณเห็น quotmodulequot และในทางกลับกัน ดังนั้นสิ่งที่เป็นหลักฐานสำหรับการใช้โมดูลดีโมดูลจะมีแพคเกจ (ให้อภัย pun) ตัวแปรสัญลักษณ์และรายการข้อมูลเชื่อมต่อกัน ตัวอย่างเช่นการใช้ตัวแปรส่วนกลางที่มีชื่อทั่วไปเช่น k j. หรือฉันในโปรแกรมโดยทั่วไปไม่ใช่ความคิดที่ดี นอกจากนี้ตัวนับวงรอบ i. ควรได้รับอนุญาตให้ทำงานได้อย่างอิสระในสองส่วนที่แตกต่างกันของรหัส ประกาศว่า i เป็นตัวแปรส่วนกลางและเพิ่มจากภายในรูทีนย่อยจะสร้างปัญหาที่ไม่สามารถจัดการได้ด้วยรหัสแอ็พพลิเคชันของคุณเนื่องจากอาจมีการเรียกใช้รูทีนจากภายในลูปที่ใช้ตัวแปรที่เรียกว่า i การใช้โมดูลใน Perl ช่วยให้ตัวแปรที่มีชื่อเดียวกันถูกสร้างขึ้นในตำแหน่งที่ต่างกันและแตกต่างกันในโปรแกรมเดียวกัน สัญลักษณ์ที่กำหนดไว้สำหรับตัวแปรของคุณจะถูกเก็บไว้ในอาร์เรย์แบบเชื่อมโยงเรียกว่าตารางสัญลักษณ์ ตารางสัญลักษณ์เหล่านี้ไม่ซ้ำกันสำหรับแพ็คเกจ ดังนั้นตัวแปรที่มีชื่อเดียวกันในชุดที่แตกต่างกันสองชุดอาจมีค่าที่ต่างกัน แต่ละโมดูลมีตารางสัญลักษณ์ของสัญลักษณ์ทั้งหมดที่ประกาศภายใน ตารางสัญลักษณ์โดยทั่วไปแยกชื่อตรงกันในโมดูลหนึ่งจากอีก ตารางสัญลักษณ์กำหนดเนมสเปซ นั่นคือช่องว่างสำหรับชื่อตัวแปรอิสระที่มีอยู่ดังนั้นการใช้โมดูลแต่ละอันมีตารางสัญลักษณ์ของตัวเองจึงป้องกันตัวแปรที่ประกาศในส่วนหนึ่งจากการเขียนทับค่าตัวแปรอื่นที่มีชื่อเดียวกันประกาศไว้ที่อื่นในบรรทัดเดียวกัน โครงการ แท้ที่จริงแล้วตัวแปรทั้งหมดใน Perl จะอยู่ในแพ็คเกจ ตัวแปรในโปรแกรม Perl อยู่ในแพคเกจหลัก แพคเกจอื่น ๆ ทั้งหมดภายในโปรแกรม Perl จะซ้อนกันอยู่ภายในแพคเกจหลักนี้หรืออยู่ในระดับเดียวกัน มีตัวแปรระดับโลกอย่างแท้จริงเช่นอาร์เรย์ SIG ตัวจัดการสัญญาณ ที่มีให้กับโมดูลอื่น ๆ ทั้งหมดในโปรแกรมประยุกต์และไม่สามารถแยกผ่าน namespaces เฉพาะตัวระบุตัวแปรเหล่านี้ที่ขึ้นต้นด้วยตัวอักษรหรือขีดล่างจะถูกเก็บไว้ในตารางสัญลักษณ์ของโมดูล สัญลักษณ์อื่น ๆ ทั้งหมดเช่นชื่อ STDIN STDOUT STDERR ARGV ARGOUT ENV Inc และ SIG ถูกบังคับให้อยู่ในแพคเกจหลัก การสลับระหว่างแพ็กเกจจะส่งผลต่อเฉพาะเทมเพลตเท่านั้น ทั้งหมดที่คุณกำลังทำเมื่อคุณใช้แพคเกจหนึ่งชุดหรืออีกเครื่องหนึ่งคือการประกาศว่าตารางสัญลักษณ์ใดที่จะใช้เป็นตารางสัญลักษณ์เริ่มต้นสำหรับการค้นหาชื่อตัวแปร เฉพาะตัวแปรแบบไดนามิกเท่านั้นที่ได้รับผลกระทบจากการใช้ตารางสัญลักษณ์ ตัวแปรที่ประกาศโดยใช้คำหลักของฉันจะได้รับการแก้ไขด้วยการบล็อกโค้ดที่เกิดขึ้นและไม่ได้ถูกอ้างถึงผ่านตารางสัญลักษณ์ ในความเป็นจริงขอบเขตของการประกาศแพคเกจจะยังคงใช้งานได้ภายในบล็อครหัสที่ประกาศไว้เท่านั้นดังนั้นหากคุณเปลี่ยนตารางสัญลักษณ์โดยใช้แพคเกจภายในโปรแกรมย่อยระบบจะเรียกคืนตารางสัญลักษณ์เดิมเมื่อเรียกใช้งาน เมื่อผลตอบแทนของโปรโตคอล การเปลี่ยนตารางสัญลักษณ์มีผลต่อการค้นหาเริ่มต้นของชื่อตัวแปรไดนามิกเท่านั้น คุณยังคงสามารถดูตัวแปร, ไฟล์จัดการและอื่น ๆ ในแพคเกจเฉพาะได้โดยการระบุชื่อแพคเกจไว้ล่วงหน้า ไปยังชื่อตัวแปร คุณเห็นสิ่งที่บริบทของแพ็กเกจคือเมื่อใช้การอ้างอิงในบทที่ 3 บริบทของแพ็กเกจแสดงถึงการใช้ตารางสัญลักษณ์โดยล่าม Perl เพื่อแก้ชื่อตัวแปรในโปรแกรม เมื่อเปลี่ยนตารางสัญลักษณ์คุณจะเปลี่ยนบริบทของแพคเกจ โมดูลสามารถซ้อนกันภายในโมดูลอื่น ๆ ได้ โมดูลที่ซ้อนกันสามารถใช้ตัวแปรและฟังก์ชันของโมดูลที่ซ้อนกันภายใน สำหรับโมดูลที่ซ้อนกันคุณจะต้องใช้ moduleName nestedModuleName และอื่น ๆ การใช้ทวิภาคคู่ (::) เป็นความหมายเหมือนกันกับการใช้คำพูดกลับ () อย่างไรก็ตามในลำไส้ใหญ่คู่เป็นที่ต้องการในอนาคตของการกำหนดตัวแปรภายในโมดูล การอธิบายที่อยู่อย่างชัดเจนของตัวแปรโมดูลจะกระทำโดยการอ้างอิงที่สมบูรณ์ ตัวอย่างเช่นสมมติว่าคุณมีโมดูลการลงทุน ซึ่งเป็นแพคเกจเริ่มต้นในการใช้งานและคุณต้องการระบุโมดูลอื่นพันธะ ซึ่งอยู่ภายในโมดูลการลงทุน ในกรณีนี้คุณไม่สามารถใช้ Bond :: ได้ คุณจะต้องใช้ Investment :: Bond :: เพื่อระบุตัวแปรและฟังก์ชันภายในโมดูล Bond การใช้พันธบัตร :: จะบ่งบอกถึงการใช้พันธบัตรแพคเกจที่ซ้อนกันภายในโมดูลหลักและไม่อยู่ในโมดูลการลงทุน ตารางสัญลักษณ์สำหรับโมดูลจะถูกจัดเก็บไว้ในอาร์เรย์แบบรวมของชื่อโมดูลที่ต่อท้ายด้วยเครื่องหมายจุดสองจุด ตารางสัญลักษณสําหรับโมดูลที่เรียกวา Bond จะเรียกวา bond bond :: ชื่อของตารางสัญลักษณ์สำหรับโมดูลหลักคือ :: และสามารถย่อให้สั้นลงได้ :: ในทำนองเดียวกันแพ็กเกจที่ซ้อนกันทั้งหมดจะมีสัญลักษณ์อยู่ในอาร์เรย์แบบคั่นด้วยเครื่องหมายทวิภาคคู่ที่แยกแต่ละระดับการซ้อนกัน ตัวอย่างเช่นในโมดูลตราสารหนี้ที่ซ้อนกันภายในโมดูลการลงทุนอาร์เรย์แบบผสมสำหรับสัญลักษณ์ในโมดูลพันธบัตรจะมีชื่อว่า Investment :: Bond :: Typeglob เป็นประเภทสากลสำหรับชื่อสัญลักษณ์ คุณสามารถดำเนินการ aliasing โดยการกำหนดให้ typeglob รายการอย่างน้อยหนึ่งรายการในอาร์เรย์ที่เชื่อมโยงกันสำหรับสัญลักษณ์จะถูกใช้เมื่อมีการมอบหมายงานผ่าน typeglob ค่าที่แท้จริงในแต่ละรายการของอาร์เรย์ที่เชื่อมโยงกันคือสิ่งที่คุณอ้างถึงเมื่อคุณใช้สัญกรณ์ variableName ดังนั้นจึงมีสองวิธีในการอ้างถึงชื่อตัวแปรในแพ็กเกจ: การลงทุน :: เงินการลงทุน :: ตั๋วเงินในวิธีแรกคุณอ้างถึงตัวแปรผ่านการอ้างอิง typeglob การใช้ตารางสัญลักษณ์การลงทุน :: เป็นนัยที่นี่และ Perl จะเพิ่มประสิทธิภาพการค้นหาสำหรับเงินสัญลักษณ์และค่า นี่คือวิธีการที่ง่ายและรวดเร็วในการระบุสัญลักษณ์ วิธีที่สองใช้การค้นหาค่าของตัวแปรที่ระบุโดยเงินและตั๋วเงินในอาร์เรย์ที่ใช้สำหรับสัญลักษณ์การลงทุน :: อย่างชัดเจน การค้นหานี้จะทำแบบไดนามิกและจะไม่ได้รับการปรับให้เหมาะกับ Perl ดังนั้นการค้นหาจะถูกบังคับให้ตรวจสอบอาร์เรย์ที่เชื่อมโยงทุกครั้งที่ดำเนินการคำสั่ง ดังนั้นวิธีที่สองไม่ได้มีประสิทธิภาพและควรใช้เฉพาะสำหรับการสาธิตวิธีใช้ตารางสัญลักษณ์ภายในเท่านั้น อีกตัวอย่างหนึ่งในคำสั่งนี้ kamran husain ทำให้ตัวแปร subroutines และไฟล์ที่จัดการโดยชื่อสัญลักษณ์ kamran จะถูกส่งผ่านสัญลักษณ์ husain นั่นคือรายการสัญลักษณ์ทั้งหมดในตารางสัญลักษณ์ปัจจุบันที่มีคีย์ kamran ตอนนี้จะมีการอ้างอิงถึงสัญลักษณ์เหล่านั้นที่สำคัญโดย husain เพื่อป้องกันไม่ให้งานดังกล่าวเป็นแบบส่วนกลางคุณสามารถใช้การอ้างอิงที่ชัดเจนได้ ตัวอย่างเช่นข้อความต่อไปนี้จะแจ้งให้คุณทราบถึงเนื้อหาของ husain ผ่านตัวแปร kamran kamran husain อย่างไรก็ตามอาร์เรย์ใด ๆ เช่น kamran และ husain จะไม่เหมือนกัน เฉพาะสิ่งที่อ้างอิงที่ระบุไว้อย่างชัดเจนจะมีการเปลี่ยนแปลง สรุปเมื่อคุณกำหนด typeglob หนึ่งให้อีกหนึ่งรายการคุณจะมีผลต่อรายการทั้งหมดในตารางสัญลักษณ์โดยไม่คำนึงถึงประเภทของตัวแปรที่ถูกอ้างถึง เมื่อคุณกำหนดข้อมูลอ้างอิงจากตัวแปรประเภทหนึ่งไปยังอีกเครื่องหนึ่งคุณจะส่งผลต่อรายการหนึ่งรายการเท่านั้นในตารางสัญลักษณ์ ไฟล์โมดูล Perl มีรูปแบบดังนี้: PackageName Package ใส่รหัสโมดูล 1 ชื่อไฟล์ต้องเรียกว่า ModuleName. pm ชื่อของโมดูลต้องสิ้นสุดลงในสตริง. pm โดยการประชุม คำสั่งแพคเกจคือบรรทัดแรกของไฟล์ บรรทัดสุดท้ายของไฟล์ต้องมีบรรทัดที่มีคำสั่ง 1 ซึ่งส่งผลต่อค่าที่แท้จริงของโปรแกรมประยุกต์โดยใช้โมดูล ไม่ใช้คำสั่ง 1 จะทำให้โมดูลไม่สามารถโหลดได้อย่างถูกต้อง คำสั่ง package บอกให้ล่าม Perl เริ่มต้นด้วยโดเมน namespace ใหม่ โดยทั่วไปตัวแปรทั้งหมดของคุณในสคริปต์ Perl อยู่ในแพคเกจที่เรียกว่า main ทุกตัวแปรในชุดหลักสามารถเรียกได้ว่า mainvariable Heres ไวยากรณ์สำหรับการอ้างอิงเช่น: packageNamevariableName ใบเสนอราคาเดียว () เป็นตรงกันกับตัวดำเนินการสองลำไส้ใหญ่ (::) ฉันครอบคลุมการใช้งานของโอเปอเรเตอร์ :: ในบทถัดไป ในขณะนี้คุณต้องจำไว้ว่าสองงบต่อไปนี้จะเทียบเท่า packageNamevariableName packageName:: variableName ไวยากรณ์สองสายเป็นมาตรฐานในโลก Perl ดังนั้นเพื่อรักษาความสามารถในการอ่านได้ผมจึงใช้ไวยากรณ์แบบ double-colon ในส่วนที่เหลือของหนังสือเล่มนี้เว้นแต่จำเป็นอย่างยิ่งที่จะต้องมีข้อยกเว้นในการพิสูจน์จุด ใช้ค่าเริ่มต้นของตัวแปรชื่อ defers กับแพคเกจปัจจุบันที่ใช้งานอยู่ในขณะที่คอมไพล์ ดังนั้นหากคุณอยู่ในแพคเกจ Finance. pm และระบุตัวแปร pv ตัวแปรมีค่าเท่ากับ Finance :: pv การใช้โมดูล Perl: ใช้ vs. require คุณมีโมดูล Perl ในโปรแกรมของคุณโดยใช้คำสั่ง use หรือ require นี่คือวิธีการใช้คำสั่งต่อไปนี้: ใช้ ModuleName ต้องการ ModuleName โปรดทราบว่านามสกุล. pm ไม่ใช้ในโค้ดที่แสดงข้างต้น นอกจากนี้โปรดทราบว่าคำสั่งไม่ได้ช่วยให้ไฟล์รวมอยู่ในโปรแกรมได้มากกว่าหนึ่งครั้ง ต้องมีการส่งคืนค่าของ true (1) เป็นคำสั่งสุดท้ายเพื่อให้ Perl ทราบว่าจำเป็นต้องใช้ d หรือใช้โมดูล d ที่โหลดได้อย่างถูกต้องและทำให้ Perl interpreter ไม่สนใจโหลดซ้ำ โดยทั่วไปดีกว่าที่จะใช้คำสั่ง Module ใช้กว่าต้องการคำสั่งโมดูลในโปรแกรม Perl จะยังคงเข้ากันได้กับรุ่นอนาคตของ Perl สำหรับโมดูลคุณอาจต้องการพิจารณาที่จะใช้คำสั่ง require ต่อไป นี่คือเหตุผล: คำสั่ง use ใช้งานน้อยกว่าคำสั่ง require ในการเปลี่ยนแปลง namespace ของโมดูลที่มีโมดูลอื่น คุณต้องการให้มีการอัปเดต namespace เพิ่มขึ้นในโปรแกรม อย่างไรก็ตามเมื่อเขียนโค้ดสำหรับโมดูลคุณอาจไม่ต้องการให้เน็ทเวิร์คได้รับการเปลี่ยนแปลงเว้นแต่มีความจำเป็นอย่างชัดเจน ในกรณีนี้คุณจะใช้คำสั่ง require คำสั่ง require ต้องมีพา ธ ชื่อเต็มของไฟล์ในอาร์เรย์ Inc เพื่อให้ฟังก์ชันและตัวแปรในไฟล์โมดูลอยู่ในตำแหน่งที่รู้จักในช่วงเวลาดำเนินการ ดังนั้นฟังก์ชันที่นำเข้าจากโมดูลจะถูกนำเข้าผ่านการอ้างอิงโมดูลที่ชัดเจนในขณะทำงานด้วยคำสั่ง require คำสั่ง use ใช้คำสั่ง require เนื่องจากมีการปรับปรุงอาร์เรย์ Inc ด้วย pathnames เต็มของโมดูลที่โหลด รหัสสำหรับฟังก์ชันการใช้งานยังไปขั้นตอนต่อไปและเรียกใช้ฟังก์ชันการนำเข้าในโมดูลที่กำลังใช้ d เพื่อโหลดรายการฟังก์ชันที่ส่งออกอย่างชัดเจนในเวลารวบรวมข้อมูลซึ่งช่วยประหยัดเวลาที่ต้องใช้สำหรับความละเอียดที่ชัดเจนของชื่อฟังก์ชันระหว่างการดำเนินการ โดยทั่วไปคำสั่งใช้เทียบเท่ากับต้อง ModuleName นำเข้า ModuleName รายการของฟังก์ชันที่นำเข้าการใช้คำสั่ง use จะเปลี่ยน namespace ของโปรแกรมเนื่องจากชื่อฟังก์ชันที่นำเข้าถูกแทรกลงในตารางสัญลักษณ์ คำสั่ง require ไม่สามารถเปลี่ยน namespace ของโปรแกรมได้ ดังนั้นคำสั่งต่อไปนี้ใช้ ModuleName () จะเทียบเท่ากับคำสั่งนี้: ต้อง ModuleName Functions ถูกนำเข้าจากโมดูลผ่านทางสายไปยังฟังก์ชันที่เรียกว่า import คุณสามารถเขียนฟังก์ชันการนำเข้าของคุณเองในโมดูลหรือคุณสามารถใช้โมดูล Exporter และใช้ฟังก์ชันการนำเข้า ในเกือบทุกกรณีคุณจะใช้โมดูล Exporter เพื่อจัดเตรียมฟังก์ชันนำเข้าแทนการปรับโฉมล้อใหม่ (คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้ในส่วนถัดไป) หากคุณตัดสินใจที่จะไม่ใช้โมดูล Exporter คุณจะต้องเขียนฟังก์ชันการนำเข้าของคุณเองในแต่ละโมดูลที่คุณเขียน มันง่ายมากที่จะเพียงแค่ใช้โมดูล Exporter และปล่อยให้ Perl ทำงานให้กับคุณ โมดูล Sample. pm ตัวอย่างวิธีที่ดีที่สุดเพื่อแสดงความหมายของวิธีการใช้โมดูลใน Perl คือการเขียนโมดูลที่เรียบง่ายและแสดงวิธีการใช้งาน ลองใช้ตัวอย่างของฉลามเงินกู้ท้องถิ่น Rudious Maximus ผู้ที่เบื่อเพียงแค่พิมพ์ quotrequest เดียวกันสำหรับการชำระเงินตัวอักษร เป็นแฟนตัวยงของคอมพิวเตอร์และ Perl Rudious ใช้วิธีการเขียนโปรแกรมขี้เกียจและเขียนโมดูล Perl เพื่อช่วยให้เขาสร้างบันทึกช่วยจำและตัวอักษรของเขา ขณะนี้แทนที่จะพิมพ์ลงในฟิลด์ในไฟล์เทมเพลตบันทึกสิ่งที่เขาต้องทำคือพิมพ์ข้อความสองสามบรรทัดเพื่อสร้างโน้ตที่น่ากลัวและน่ากลัวของเขา รายการ 4.1 แสดงให้เห็นว่าเขาต้องพิมพ์อะไร รายชื่อ 4.1 การใช้โมดูล Letter 1 usrbinperl - w 2 3 จดบรรทัดด้านล่างเพื่อรวมไฟล์ปัจจุบันใน Inc. 4 push (Inc, pwd) 5 6 ใช้ Letter 7 8 Letter :: To (quotMr. การพนัน Manquot, quotThe เงินสำหรับ Lucky Dog, Race 2quot) 9 Letter :: ClaimMoneyNice () 10 Letter :: ThankDem () 11 Letter :: Finish () ใช้ Letter letter เพื่อบังคับให้ล่าม Perl ใส่รหัสสำหรับโมดูลในโปรแกรมแอ็พพลิเคชัน โมดูลควรอยู่ในไดเร็กทอรี usrlibperl5 หรือคุณสามารถวางไว้ในไดเร็กทอรีใดก็ได้ที่อยู่ในอาร์เรย์ Inc อาร์เรย์ Inc คือรายการไดเร็กทอรีที่ล่าม Perl จะค้นหาเมื่อพยายามโหลดโค้ดสำหรับโมดูลที่มีชื่อ บรรทัดที่แสดงความคิดเห็น (หมายเลข 4) จะแสดงวิธีเพิ่มไดเรกทอรีการทำงานปัจจุบันเพื่อรวมเส้นทาง สี่บรรทัดถัดไปในไฟล์สร้างเรื่องของตัวอักษร Heres ผลลัพธ์จากการใช้โมดูลจดหมาย: ถึง: นาย Gambling Man Fm: Rudious Maximus, เงินกู้ Shark Dt: พ. 7 กุมภาพันธ์ 10:35:51 CST 1996 Re: เงินสำหรับ Lucky Dog, Race 2 มันได้มาถึงความสนใจของฉัน บัญชีของคุณหมดไป คุณจะจ่ายเงินให้เราเร็ว ๆ นี้หรือคุณต้องการให้ฉันมา ovah ขอบคุณสำหรับการสนับสนุนของคุณ ไฟล์โมดูลจดหมายปรากฏในรายการ 4.2 ชื่อของแพคเกจถูกประกาศในบรรทัดแรก เนื่องจากฟังก์ชันโมดูลนี้จะถูกส่งออกฉันจะใช้โมดูล Exporter ดังนั้นการใช้คำสั่ง Exporter จึงจำเป็นต้องสืบทอดการทำงานจากโมดูล Exporter ขั้นตอนอื่นที่จำเป็นต้องใช้ก็คือใส่คำว่า Exported ในอาร์เรย์ ISA เพื่อให้สามารถค้นหา Exported. pm ได้ อาร์เรย์ ISA เป็นอาร์เรย์พิเศษภายในแต่ละแพ็คเกจ แต่ละรายการในอาร์เรย์จะแสดงตำแหน่งที่อื่นเพื่อค้นหาเมธอดถ้าไม่สามารถพบได้ในแพคเกจปัจจุบัน ลำดับที่แพคเกจอยู่ในอาร์เรย์ ISA คือลำดับที่ Perl ค้นหาสัญลักษณ์ที่ยังไม่ได้แก้ไข คลาสที่ระบุไว้ในอาร์เรย์ ISA เรียกว่าคลาสพื้นฐานของคลาสนั้น Perl จะแคชวิธีการที่ขาดหายไปที่พบในคลาสพื้นฐานสำหรับการอ้างอิงในอนาคต การปรับเปลี่ยนอาร์เรย์ ISA จะล้างแคชและทำให้ Perl ค้นหาวิธีการทั้งหมดอีกครั้ง ตอนนี้ให้ดูที่โค้ดสำหรับ Letter. pm ในรายการ 4.2 รายชื่อ 4.2 โมดูล Letter. pm 1 ชุดจดหมาย 2 3 ต้องการผู้ส่งออก 4 ISA (ผู้ส่งออก) 5 6 หัว 1 ชื่อ 7 8 ตัวอักษร - โมดูลตัวอย่างเพื่อสร้างหัวกระดาษจดหมายสำหรับคุณ 9 10 head1 บทสรุป 11 12 การใช้จดหมาย 13 14 จดหมาย :: วันที่ () 15 จดหมาย :: ถึง (ชื่อ , company, address) 16 17 ข้อใดข้อหนึ่งดังต่อไปนี้: 18 Letter :: ClaimMoneyNice () 19 Letter :: ClaimMoney () 20 Letter :: ThreatBreakLeg () 21 22 Letter :: ThankDem () 23 Letter :: Finish () 24 25 head1 DESCRIPTION 26 27 โมดูลนี้เป็นตัวอย่างสั้น ๆ ในการสร้างจดหมายสำหรับ 28 ฉลากยืมเพื่อนบ้านที่เป็นมิตร 29 30 รหัสเริ่มต้นหลังจากคำสั่ง quotcutquot 31 ตัด 32 33 ส่งออก qw (วันที่ 34 ถึง 35 เรียกร้องเงินมัดจำ 36 เรียกเก็บเงินมัดจำ 37 วันขอบคุณพระเจ้า 38 เสร็จสิ้น) 39 40 41 พิมพ์วันที่ปัจจุบัน 42 43 ตัวอักษรย่อย :: วันที่ 44 วันที่ลงวันที่ 45 พิมพ์วันนี้เป็นวันที่ 46 47 48 ย่อย Letter :: ถึง 49 local (name) shift 50 local (subject) shift 51 print quotn ถึง: namequot 52 print quotn Fm: Rudious Maximus, เงินกู้ Sharkquot 53 พิมพ์คำคม Dt: quot, วันที่ 54 พิมพ์เลขที่เรื่อง subjectquot 55 print quotnnquot 56 พิมพ์ quotnnquot 57 58 ตัวอักษร :: ClaimMoney () 59 print quotn คุณเป็นหนี้ฉัน ขอให้คุณส่ง Bruno ไปที่ใบเสนอราคาฉบับที่ 61 เพื่อเก็บรวบรวม หรือคุณจะจ่ายเงินเพิ่ม 62 63 64 ตัวอักษรย่อย :: ClaimMoneyNice () 65 print quotn เป็นที่มาของความสนใจของฉันว่าบัญชีของคุณมีจำนวนมากเกินกว่าที่กำหนดไว้ในใบเสร็จ 66 print quotn คุณจะจ่ายเงินให้เราเร็ว ๆ นี้ .. ใช่ พิมพ์ quotn หรือคุณต้องการให้ฉันมา ovahquot 69 70 71 sub ตัวอักษร :: ThreatBreakLeg () 72 print quotn apparently ตัวอักษรเช่นนี้ dont helpquot 73 พิมพ์ quotn ฉันจะต้องทำตัวอย่างของ youquot 74 print quotn n พบคุณในโรงพยาบาล , palquot 75 76 77 ตัวอักษรย่อย :: ThankDem () 78 พิมพ์ขอบคุณสำหรับการสนับสนุนของคุณ 79 80 81 ตัวอักษรย่อย :: Finish () 82 printf quotnnnn ขอแสดงความนับถือ 83 printf quotent Rudious n quot 84 85 86 1 บรรทัดที่มีเครื่องหมายเท่ากับ สำหรับเอกสาร คุณต้องเอกสารแต่ละโมดูลสำหรับการอ้างอิงของคุณเองโมดูล Perl ไม่จำเป็นต้องได้รับการจัดทำเป็นเอกสาร แต่ควรเขียนไม่กี่บรรทัดเกี่ยวกับโค้ดของคุณ ไม่กี่ปีต่อจากนี้คุณอาจลืมสิ่งที่เป็นโมดูล เอกสารที่ดีเป็นสิ่งจำเป็นเสมอถ้าคุณต้องการจดจำสิ่งที่คุณทำในอดีตที่ผ่านมาฉันครอบคลุมรูปแบบเอกสารที่ใช้สำหรับ Perl ในบทที่ 8 การจัดทำเอกสาร Perl Scripts. quot สำหรับโมดูลตัวอย่างนี้คำสั่ง head1 จะเริ่มต้นการจัดทำเอกสาร ทุกอย่างที่เกี่ยวข้องกับคำสั่งตัดจะถูกละเลยโดย Perl interpreter ถัดไปโมดูลจะแสดงรายการฟังก์ชันทั้งหมดที่เอ็กซ์พอร์ตส่งออกโดยโมดูลนี้ อาร์เรย์การส่งออกกำหนดชื่อฟังก์ชันทั้งหมดที่สามารถเรียกใช้โดยโค้ดภายนอก ถ้าคุณไม่ได้ระบุฟังก์ชันในอาร์เรย์การส่งออกนี้จะไม่สามารถมองเห็นได้จากโมดูลโค้ดภายนอก หลังจากอาร์เรย์การส่งออกเป็นเนื้อหาของโค้ดหนึ่ง subroutine ในแต่ละครั้ง หลังจากกำหนด subroutines ทั้งหมดคำสั่งสุดท้าย 1 จะสิ้นสุดไฟล์โมดูล 1 ต้องเป็นบรรทัดปฏิบัติการล่าสุดในไฟล์ ให้ดูที่ฟังก์ชันบางอย่างที่กำหนดไว้ในโมดูลนี้ ฟังก์ชันแรกที่ดูคือฟังก์ชัน Date แบบง่ายบรรทัด 43 ถึง 46 ซึ่งจะพิมพ์วันที่และเวลาของ UNIX ปัจจุบัน ไม่มีพารามิเตอร์สำหรับฟังก์ชันนี้และจะไม่ส่งกลับสิ่งที่มีความหมายสำหรับผู้โทร หมายเหตุการใช้งานของฉันก่อนวันที่ตัวแปรในบรรทัดที่ 44 คำหลักของฉันถูกใช้เพื่อ จำกัด ขอบเขตของตัวแปรให้อยู่ภายในวงเล็บปีกกา Date functions รหัสระหว่างวงเล็บปีกกาจะเรียกว่าเป็นบล็อก ตัวแปรที่ประกาศภายในบล็อกมีขอบเขต จำกัด ภายในวงเล็บปีกกา ใน 49 และ 50 ชื่อตัวแปรท้องถิ่นและหัวเรื่องสามารถมองเห็นได้กับทุกฟังก์ชัน นอกจากนี้คุณยังสามารถประกาศตัวแปรด้วยตัวคัดกรองท้องถิ่น การใช้โลคัลช่วยให้ตัวแปรสามารถอยู่ในขอบเขตสำหรับบล็อคปัจจุบันรวมถึงบล็อคอื่นของโค้ดที่เรียกจากภายในบล็อกนี้ ดังนั้นท้องถิ่น x ประกาศภายในหนึ่งบล็อกจะปรากฏแก่บล็อกที่ตามมาทั้งหมดที่เรียกจากภายในบล็อกนี้และสามารถอ้างอิงได้ ในตัวอย่างโค้ดต่อไปนี้สามารถเรียกใช้ตัวแปรชื่อฟังก์ชันชื่อ ToTitled ได้ แต่ไม่ใช่ข้อมูลใน iphone 1 sub letter :: ToTitled 2 local (name) shift 3 เปลี่ยนโทรศัพท์ของฉันโค้ดตัวอย่างสำหรับ Letter. pm แสดงวิธีการแยกพารามิเตอร์ครั้งละหนึ่งตัว กระบวนการย่อย To () ใช้เวลาสองพารามิเตอร์เพื่อตั้งค่าส่วนหัวสำหรับบันทึกช่วยจำ การใช้ฟังก์ชันภายในโมดูลไม่แตกต่างจากการใช้และการกำหนดโมดูล Perl ภายในไฟล์โค้ดเดียวกัน พารามิเตอร์จะถูกส่งโดยอ้างอิงเว้นแต่ระบุไว้เป็นอย่างอื่น อาร์เรย์หลายชุดที่ผ่านเข้าสู่ subroutine หากไม่ได้รับการระบุโดยใช้เครื่องหมายแบ็กสแลชจะถูกแบ่งส่วน อาร์เรย์อินพุตในฟังก์ชันอยู่เสมออาร์เรย์ของค่าเกลา การส่งผ่านค่าโดยการอ้างอิงเป็นวิธีที่ต้องการใน Perl เพื่อส่งผ่านข้อมูลจำนวนมากไปยัง subroutine (ดูบทที่ 3. quotReferences. quot) โมดูลตัวอย่างอื่น: การเงินโมดูลการเงินที่แสดงในรายการ 4.3 ใช้เพื่อคำนวณค่าเงินกู้ยืมแบบง่ายๆ การใช้โมดูลการเงินเป็นเรื่องง่าย ฟังก์ชั่นทั้งหมดจะถูกเขียนด้วยพารามิเตอร์เดียวกันดังแสดงในสูตรสำหรับฟังก์ชั่น ให้ดูว่าสามารถคำนวณมูลค่าในอนาคตของการลงทุนได้อย่างไร ตัวอย่างเช่นหากคุณลงทุนเงินจำนวนหนึ่ง pv ในพันธบัตรที่มีอัตราร้อยละคงที่ r. ใช้ในช่วงเวลาที่รู้จักกันสำหรับ n ช่วงเวลาค่าของพันธบัตรในขณะที่หมดอายุในกรณีนี้คุณจะใช้สูตรต่อไปนี้: fv pv (1r) n ฟังก์ชันเพื่อให้ได้ค่าในอนาคตถูกประกาศว่าเป็น FutureValue . ดูรายการ 4.3 เพื่อดูวิธีการใช้งาน รายการ 4.3 การใช้โมดูลการเงิน 1 usrbinperl - w 2 3 push (Inc, pwd) 4 ใช้การเงิน 5 6 เงินกู้ 5000.00 7 apr 3.5 เมษายน 8 ปี 10 ปี 9 10 ------------------------------------------------ ---------------- 11 คำนวณมูลค่า ณ สิ้นเงินกู้ถ้าดอกเบี้ย 12 ถูกนำมาใช้ทุกปี 13 -------------------------------------------------- --------------- 14 ปีปวช. 15 fv1 การเงิน :: FutureValue (loan, apr, time) 16 print quotn ถ้ามีการคิดดอกเบี้ย ณ สิ้นงวด yearquot 17 print quotn ค่าในอนาคตสำหรับ a เงินกู้ของ เงินกู้ quotnquot 18 print quot at APR of quot, apr. quot สำหรับ quot, time, quot yearsquot 19 printf คือ 8.2f nquot fv1 20 21 ----------------------------------------------- ----------------- 22 คำนวณมูลค่า ณ สิ้นเงินกู้ถ้ามีการใช้ดอกเบี้ย 23 ทุกเดือน 24 -------------------------------------------------- --------------- อัตรา 25 วันที่ 12 เมษายนเมษายน 26 ปี 12 เดือน 27 fv2 การเงิน :: FutureValue (เงินกู้, อัตรา, เวลา) 28 29 print quotn ถ้าดอกเบี้ยถูกนำไปใช้เมื่อสิ้นสุด ในแต่ละเดือน quotot 30 print quotn ในอนาคตมูลค่าของเงินกู้ของ เงินกู้ quotnquot 31 print quot at a APR of quot, พ. ศ. quot สำหรับ quot, time, quotquest quotot 32 printf คือ 8.2f nquot fv2 33 34 printf quotn ความแตกต่างของค่าคือ 8.2fquot, fv2 - fv1 35 printf quotn ด้วยเหตุนี้การใช้ดอกเบี้ยในช่วงเวลาที่สั้นลงจึงจะได้รับเงินจาก interest. nquot ต่อไปนี้เป็นตัวอย่างข้อมูลอินพุตและเอาต์พุตของ Listing 4.3 testme หากมีการคิดดอกเบี้ย ณ สิ้นปีมูลค่าปัจจุบันของเงินกู้ 5000 ที่เมษายนเท่ากับ 3.5 เป็นเวลา 10 ปีคือ 7052.99 ถ้ามีการคิดดอกเบี้ย ณ สิ้นเดือนแต่ละเดือนค่าในอนาคตสำหรับเงินกู้ 5000 ที่เมษายนเท่ากับ 3.5 สำหรับ 120 เดือนเป็น 7091.72 ความแตกต่างในมูลค่าคือ 38.73 ดังนั้นโดยการใช้ดอกเบี้ยในช่วงเวลาที่สั้นกว่าที่เรากำลังได้รับเงินมากขึ้นในความสนใจ การเปิดเผยในเอาท์พุทเป็นผลมาจากการเปรียบเทียบค่าระหว่าง fv1 และ fv2 ค่า fv1 คำนวณโดยการคำนวณดอกเบี้ยทุกๆปีตลอดอายุของพันธบัตร fv2 คือมูลค่าถ้าดอกเบี้ยถูกนำมาใช้ทุกเดือนในอัตราดอกเบี้ยรายเดือนที่เท่ากัน แพคเกจ Finance. pm แสดงในรายการ 4.4 ในระยะเริ่มแรก รายชื่อ 4.4. แพคเกจ Finance. pm 1 แพคเกจการเงิน 2 3 ต้องการผู้ส่งออก 4 ISA (ผู้ส่งออก) 5 6 หัว 1 Finance. pm 7 8 เครื่องคิดเลขการเงิน - การคำนวณทางการเงินทำได้ง่ายด้วย Perl 9 10 หัว 2 11 ใช้การเงิน 12 13 pv 10000.0 14 15 อัตรา 12.5 12 เมษายนต่อเดือน 16 17 เวลา 360 เดือนสำหรับเงินกู้เพื่อเป็นผู้ใหญ่ 18 19 fv FutureValue () 20 21 fv 22 23 ตัด 24 25 การส่งออก qw (FutureValue, 26 PresentValue, 27 FVofAnnuity, 28 AnnuityOfFV, 29 getLastAverage, 30 getMovingAverage, 31 SetInterest) 32 33 34 Globals ถ้ามี 35 36 37 local defaultInterest 5.0 38 39 sub Finance :: SetInterest () 40 อัตราดอกเบี้ยของฉัน () 41 default อัตราดอกเบี้ยสูงสุด 42 printf default default อัตราดอกเบี้ย 43 44 45 -------------- -------------------------------------------------- ---- 46 หมายเหตุ: 47 1. อัตราดอกเบี้ย r มีคาเทากับ 0-100 48 2. เงื่อนไขที่ระบุในข้อตกลงคืออัตราที่ใช้ดอกเบี้ย 49 50 51 ------------------------------------------------ -------------------- 52 53 ---------------------------- ---------------------------------------- 54 มูลค่าปัจจุบันของเงินลงทุน 55 fv - มูลค่าในอนาคต 56 r - อัตราต่องวด 57 n - จำนวนงวด 58 ---------------------------------- ---------------------------------- 59 การเงินย่อย :: FutureValue () 60 (pv, r, n ) 61 fv pv ของฉัน ((1 (r100)) n) 62 return fv 63 64 65 ------------------------------ -------------------------------------- 66 มูลค่าปัจจุบันของการลงทุนให้ 67 fv - อนาคต มูลค่า 68 r - อัตราต่องวด 69 n - จำนวนงวด 70 ------------------------------------ -------------------------------- 71 การเงินย่อย :: PresentValue () 72 my pv 73 my (fv, r, n) 74 pv fv ((1 (r100)) n) 75 return pv 76 77 78 79 ----------------------------- --------------------------------------- 80 รับค่าในอนาคตของเงินรายปีที่ได้รับ 81 mp - การชำระเงินรายปี 82 r - อัตราต่องวด 83 n - จำนวน o ช่วง f 84 ----------------------------------------------- ----------------------------- 85 86 fV 88 myReR 89 my (mp, r, n) 90 91 aR (1 r) n 92 fv mp ((1R - 1) r) 93 กลับมา fv 94 95 96 ---------------------------------- ----------------------------------- 97 รับเงินรายปีจากข้อมูลต่อไปนี้ 98 r - อัตราต่อ ระยะเวลา 99 n - จำนวนงวด 100 fv - มูลค่าในอนาคต 101 ------------------------------------- ------------------------------- 102 103 AnnuityOfFV ย่อย () 104 my mp mp - ชำระเงินรายเดือนของเงินรายปี 105 my aR 106 (fv, r, n) 107 108 1R (1R) n 109 mp fv (r (หนึ่งR - 1)) 110 กลับไปที่ 111 112 113 ----------------- -------------------------------------------------- - 114 รับค่าเฉลี่ยของค่า quotnquot ล่าสุดในอาร์เรย์ 115 -------------------------------------------------- ------------------- 116 จำนวนครั้งสุดท้ายขององค์ประกอบจากอาร์เรย์ในค่า 117 จำนวนรวมขององค์ประกอบในค่าอยู่ในจำนวน 118 119 sub getLastAverage () 120 (นับจำนวนค่า) 121 my i 122 123 a a 0 124 return 0 if (count 0) 125 for (i 0 ilt count i) 126 a ค่า - i - 1 127 128 กลับนับ 129 130 131 --- -------------------------------------------------- --------------- 132 รับค่าเฉลี่ยเคลื่อนที่ของค่า 133 -------------------------------------------------- ------------------- 134 ขนาดหน้าต่างเป็นพารามิเตอร์ตัวแรกจำนวนรายการในอาร์เรย์ที่ผ่านการผ่าน 135 เป็นอันดับถัดไป (ซึ่งสามารถคำนวณได้ง่ายภายในฟังก์ชัน 136 โดยใช้ฟังก์ชัน scalar () แต่โปรแกรมย่อยที่แสดงไว้ที่นี่ 137 ยังใช้เพื่อแสดงวิธีส่งผ่านพอยน์เตอร์) การอ้างอิงไปยังอาร์เรย์ 138 ของค่าจะถูกส่งต่อไปตามด้วย การอ้างอิงไปยังสถานที่ 139 ค่าที่ส่งกลับจะถูกเก็บไว้ 140 141 146 146 146 144 144 144 144 0 0 145 0 0 0 0 147 147 0 0 (นับ 0) 148 กลับ -1 ถ้า (นับจำนวน gt) 149 คืน - 2 ถ้า (นับ lt 2) 150 151 movingAve0 0 152 movingAvenumber - 1 0 153 สำหรับ (i0 iltcounti) 154 v ค่า 155 จาก 156 movingAvei 0 157 158 สำหรับ (icount iltnumberi) 159 ค่าใน 160 ค่า 161 v ค่า - นับ - 1 162 a - v count 163 movingAvei a 164 165 return 0 166 167 168 1 ดูการประกาศฟังก์ชัน FutureValue ด้วย () สัญญาณสามดอลล่าร์แสดงว่ามีการส่งผ่านตัวเลข 3 หมายเลขไปยังฟังก์ชัน ขอบเขตพิเศษนี้มีไว้สำหรับการตรวจสอบชนิดของพารามิเตอร์ที่ส่งผ่านเข้าสู่ฟังก์ชัน หากคุณต้องการส่งสตริงแทนตัวเลขเข้าไปในฟังก์ชันคุณจะได้รับข้อความที่คล้ายกับข้อความนี้มากเกินไป: มีการโต้เถียงมากเกินไปสำหรับ Finance :: FutureValue at. f4.pl line 15 ใกล้ quottime) quot การดำเนินการ. f4.pl ยกเลิกเนื่องจากมีข้อผิดพลาดในการคอมไพล์ การใช้ต้นแบบเมื่อกำหนดฟังก์ชันจะช่วยป้องกันไม่ให้คุณส่งค่าอื่นนอกเหนือจากที่ฟังก์ชันคาดไว้ ใช้หรือส่งผ่านอาร์เรย์ของค่า ถ้าคุณกำลังส่งผ่านโดยการอ้างอิงให้ใช้หรือเพื่อแสดงการอ้างอิงแบบสเกลาร์ไปยังอาร์เรย์หรือแฮชตามลำดับ ถ้าคุณไม่ใช้เครื่องหมายทับขวาพิมพ์อื่น ๆ ทั้งหมดในต้นแบบรายการอาร์กิวเมนต์จะถูกละเว้น disqualifiers ประเภทอื่น ๆ ได้แก่ เครื่องหมายสำหรับการอ้างอิงถึงฟังก์ชันเครื่องหมายดอกจันสำหรับประเภทใด ๆ และเครื่องหมายอัฒภาคเพื่อระบุว่าพารามิเตอร์อื่น ๆ ทั้งหมดเป็นตัวเลือก ตอนนี้ให้ดูที่การประกาศฟังก์ชัน lastMovingAverage ซึ่งระบุสองจำนวนเต็มในด้านหน้าและตามด้วยอาร์เรย์ วิธีอาร์กิวเมนต์ที่ใช้ในฟังก์ชันคือการกำหนดค่าให้กับทั้งสองสเกลารนับและจำนวน ขณะที่ทุกสิ่งทุกอย่างถูกส่งไปยังอาร์เรย์ ดูฟังก์ชัน getMovingAverage () เพื่อดูว่าอาร์เรย์ทั้งสองได้รับการส่งผ่านเพื่อให้ได้ค่าเฉลี่ยเคลื่อนที่ในรายการค่าใด วิธีการเรียกใช้ฟังก์ชัน getMovingAverage แสดงอยู่ในรายการ 4.5 รายการ 4.5. ใช้ฟังก์ชันเฉลี่ยเคลื่อนที่ 1 usrbinperl - w 2 3 push (Inc, pwd) 4 ใช้ Finance 5 6 ค่า (12,22,23,24,21,23,24,23,23,21,29,27,26,28) 7 mv ( 0) ขนาด 8 ตัวอักษร (ค่า) 9 print quotn ค่าที่จะใช้งานกับ nquot 10 print quot จำนวนของค่าที่ต้องการ size nquot 11 12 ------------------------ ---------------------------------------- 13 คำนวณค่าเฉลี่ยของฟังก์ชันข้างต้น 14 - -------------------------------------------------- ------------- 15 ave การเงิน :: getLastAverage (5, size, values) 16 printnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ) 19 print quotn ค่าเฉลี่ยเคลื่อนที่ 5 วันหน้าต่าง n nquot ผลลัพธ์จากรายการ 4.5: ค่าที่จะใช้งานกับจำนวนค่า 14 เฉลี่ย 5 วันที่ผ่านมา 26.2 ฟังก์ชัน getMovingAverage () ใช้เวลาสองสเกลาราแล้วสองการอ้างอิงไปยังอาร์เรย์เป็นสเกลาร์ ภายในฟังก์ชันทั้งสองสเกลารไปยังอาร์เรย์จะถูกตั้งค่าไว้สำหรับใช้เป็นอาร์เรย์ตัวเลข ชุดค่าที่ส่งคืนถูกแทรกลงในพื้นที่ที่ส่งผ่านไปเป็นข้อมูลอ้างอิงที่สอง หากพารามิเตอร์อินพุตไม่ได้ระบุไว้สำหรับแต่ละอาร์เรย์ที่อ้างอิงอาร์เรย์การย้ายอาร์เรย์ moveAve จะว่างเปล่าและอาจทำให้เกิดข้อผิดพลาดขณะรันไทม์ กล่าวได้ว่าการประกาศต่อไปนี้ไม่ถูกต้อง: sub getMovingAve () ข้อความที่เกิดขึ้นจากข้อความผิดพลาดจากต้นแบบฟังก์ชันที่ไม่ถูกต้องมีดังนี้: การใช้ค่าที่ไม่ได้เริ่มต้นที่บรรทัด Finance. pm 128 การใช้ค่าที่ไม่ได้เป็นอิสระที่บรรทัด Finance. pm 128. การใช้ค่าที่ยังไม่ได้เริ่มต้นที่บรรทัด Finance. pm บรรทัดที่ 128 การใช้ค่าที่ไม่ได้เริ่มต้นที่บรรทัด Finance. pm บรรทัดที่ 128 การใช้ค่าที่ไม่ได้เป็นอิสระที่บรรทัด Finance. pm บรรทัดที่ 128 การใช้ค่าที่ไม่ได้เป็นอิสระที่บรรทัด Finance. pm 133 การใช้ค่าที่ไม่ได้ริเริ่ม ที่ Finance. pm บรรทัด 135 การใช้ค่าที่ไม่ได้ตั้งใจที่ Finance. pm บรรทัดที่ 133 การใช้ค่าที่ไม่ได้เริ่มต้นที่บรรทัด Finance. pm 135 การใช้ค่าที่ไม่ได้ตั้งใจที่บรรทัด Finance. pm 133 การใช้ค่าที่ไม่ได้ตั้งใจที่ Finance. pm บรรทัดที่ 135 การใช้ค่าที่ไม่ได้เริ่มต้นที่บรรทัด Finance. pm 133 การใช้ค่าที่ไม่ได้เริ่มต้นที่ Finance. pm บรรทัด 135 การใช้ค่าที่ไม่ได้เป็นอิสระที่ Finance. pm บรรทัด 133 การใช้ค่าที่ไม่ได้เริ่มต้นที่ Finance. pm บรรทัด 135 การใช้ค่าที่ไม่ได้เริ่มที่ Finance. pm line 133. Use of uninitialized valu e at Finance. pm line 135. Use of uninitialized value at Finance. pm line 133. Use of uninitialized value at Finance. pm line 135. Use of uninitialized value at Finance. pm line 133. Use of uninitialized value at Finance. pm line 135. Use of uninitialized value at Finance. pm line 133. Use of uninitialized value at Finance. pm line 135. Average of last 5 days 26.2 Moving Average with 5 days window This is obviously not the correct output. Therefore, its critical that you pass by reference when sending more than one array. Global variables for use within the package can also be declared. Look at the following segment of code from the Finance. pm module to see what the default value of the Interest variable would be if nothing was specified in the input. (The current module requires the interest to be passed in, but you can change this.) Heres a little snippet of code that can be added to the end of the program shown in Listing 4.5 to add the ability to set interest rates. 20 local defaultInterest 5.0 21 sub Finance::SetInterest() 22 my rate shift() 23 rate -1 if (rate lt 0) 24 defaultInterest rate 25 printf quotn defaultInterest ratequot 26 The local variable defaultInterest is declared in line 20. The subroutine SetInterest to modify the rate is declared in lines 21 through 26. The rate variable uses the values passed into the subroutine and simply assigns a positive value for it. You can always add more error checking if necessary. To access the defaultInterest variables value, you could define either a subroutine that returns the value or refer to the value directly with a call to the following in your application program: Finance::defaultInterest The variable holding the return value from the module function is declared as my variable . The scope of this variable is within the curly braces of the function only. When the called subroutine returns, the reference to my variable is returned. If the calling program uses this returned reference somewhere, the link counter on the variable is not zero therefore, the storage area containing the returned values is not freed to the memory pool. Thus, the function that declares my pv and then later returns the value of pv returns a reference to the value stored at that location. If the calling routine performs a call like this one: Finance::FVofAnnuity(monthly, rate, time) there is no variable specified here into which Perl stores the returned reference therefore, any returned value (or a list of values) is destroyed. Instead, the call with the returned value assigned to a local variable, such as this one: fv Finance::FVofAnnuity(monthly, rate, time) maintains the variable with the value. Consider the example shown in Listing 4.6, which manipulates values returned by functions. Listing 4.6. Sample usage of the my function. 1 usrbinperl - w 2 3 push(Inc, pwd) 4 use Finance 5 6 monthly 400 7 rate 0.2 i. e. 6 APR 8 time 36 in months 9 10 print quotn ------------------------------------------------quot 11 fv Finance::FVofAnnuity(monthly, rate, time) 12 printf quotn For a monthly 8.2f at a rate of 6.2f for d periodsquot, 13 monthly, rate, time 14 printf quotn you get a future value of 8.2f quot, fv 15 16 fv 1.1 allow 10 gain in the house value. 17 18 mo Finance::AnnuityOfFV(fv, rate, time) 19 20 printf quotn To get 10 percent more at the end, i. e. 8.2fquot, fv 21 printf quotn you need a monthly payment value of 8.2fquot, mo, fv 22 23 print quotn ------------------------------------------------ nquot Here is sample input and output for this function: testme ------------------------------------------------ For a monthly 400.00 at a rate of 0.20 for 36 periods you get a future value of 1415603.75 To get 10 percent more at the end, i. e. 1557164.12 you need a monthly payment value of 440.00 ------------------------------------------------ Modules implement classes in a Perl program that uses the object-oriented features of Perl. Included in object-oriented features is the concept of inheritance . (Youll learn more on the object-oriented features of Perl in Chapter 5. quotObject-Oriented Programming in Perl. quot) Inheritance means the process with which a module inherits the functions from its base classes. A module that is nested within another module inherits its parent modules functions. So inheritance in Perl is accomplished with the :: construct. Heres the basic syntax: SuperClass::NextSubClass. ThisClass. The file for these is stored in. SuperClassNextSubClass133 . Each double colon indicates a lower-level directory in which to look for the module. Each module, in turn, declares itself as a package with statements like the following: package SuperClass::NextSubClass package SuperClass::NextSubClass::EvenLower For example, say that you really want to create a Money class with two subclasses, Stocks and Finance . Heres how to structure the hierarchy, assuming you are in the usrlibperl5 directory: Create a Money directory under the usrlibperl5 directory. Copy the existing Finance. pm file into the Money subdirectory. Create the new Stocks. pm file in the Money subdirectory. Edit the Finance. pm file to use the line package Money::Finance instead of package Finance . Edit scripts to use Money::Finance as the subroutine prefix instead of Finance:: . Create a Money. pm file in the usrlibperl5 directory. The Perl script that gets the moving average for a series of numbers is presented in Listing 4.7. Listing 4.7. Using inheriting modules. 1 usrbinperl - w 2 aa pwd 3 aa . quotMoneyquot 4 push(Inc, aa) 5 use Money::Finance 6 values ( 12,22,23,24,21,23,24,23,23,21,29,27,26,28 ) 7 mv (0) 8 size scalar(values) 9 print quotn Values to work with nquot 10 print quot Number of values size nquot 11 ---------------------------------------------------------------- 12 Calculate the average of the above function 13 ---------------------------------------------------------------- 14 ave Money::Finance::getLastAverage(5,size, values) 15 print quotn Average of last 5 days ave nquot 16 Money::Finance::getMovingAve(5,size, values, mv) 17 foreach i (values) 18 print quotn Moving with 5 days window mvi nquot 19 20 print quotn Moving Average with 5 days window n nquot Lines 2 through 4 add the path to the Money subdirectory. The use statement in line 5 now addresses the Finance. pm file in the. Money subdirectory. The calls to the functions within Finance. pm are now called with the prefix Money::Finance:: instead of Finance:: . Therefore, a new subdirectory is shown via the :: symbol when Perl is searching for modules to load. The Money. pm file is not required. Even so, you should create a template for future use. Actually, the file would be required to put any special requirements for initialization that the entire hierarchy of modules uses. The code for initialization is placed in the BEGIN() function. The sample Money. pm file is shown in Listing 4.8. Listing 4.8. The superclass module for Finance. pm . 1 package Money 2 require Exporter 3 4 BEGIN 5 printf quotn Hello Zipping into existence for younquot 6 7 1 To see the line of output from the printf statement in line 5, you have to insert the following commands at the beginning of your Perl script: use Money use Money::Finance To use the functions in the Stocks. pm module, you use this line: use Money::Stocks The Stocks. pm file appears in the Money subdirectory and is defined in the same format as the Finance. pm file, with the exceptions that use Stocks is used instead of use Finance and the set of functions to export is different. A number of modules are included in the Perl distribution. Check the usrlibperl5lib directory for a complete listing after you install Perl. There are two kinds of modules you should know about and look for in your Perl 5 release, Pragmatic and Standard modules. Pragmatic modules, which are also like pragmas in C compiler directives, tend to affect the compilation of your program. They are similar in operation to the preprocessor elements of a C program. Pragmas are locally scoped so that they can be turned off with the no command. Thus, the command no POSIX turns off the POSIX features in the script. These features can be turned back on with the use statement. Standard modules bundled with the Perl package include several functioning packages of code for you to use. Refer to appendix B, quotPerl Module Archives, quot for a complete list of these standard modules. To find out all the. pm modules installed on your system, issue the following command. (If you get an error, add the usrlibperl5 directory to your path.) find usrlibperl5 - name perl quot. pmquot - print Extension modules are written in C (or a mixture of Perl and C) and are dynamically loaded into Perl if and when you need them. These types of modules for dynamic loading require support in the kernel. Solaris lets you use these modules. For a Linux machine, check the installation pages on how to upgrade to the ELF format binaries for your Linux kernel. The term CPAN (Comprehensive Perl Archive Network) refers to all the hosts containing copies of sets of data, documents, and Perl modules on the Net. To find out about the CPAN site nearest you, search on the keyword CPAN in search engines such as Yahoo. AltaVista, or Magellan. A good place to start is the metronet site . This chapter introduced you to Perl 5 modules and described what they have to offer. A more comprehensive list is found on the Internet via the addresses shown in the Web sites metronet and perl . A Perl package is a set of Perl code that looks like a library file. A Perl module is a package that is defined in a library file of the same name. A module is designed to be reusable. You can do some type checking with Perl function prototypes to see whether parameters are being passed correctly. A module has to export its functions with the EXPORT array and therefore requires the Exporter module. Modules are searched for in the directories listed in the Inc array. Obviously, there is a lot more to writing modules for Perl than what is shown in this chapter. The simple examples in this chapter show you how to get started with Perl modules. In the rest of the book I cover the modules and their features, so hang in there. I cover Perl objects, classes, and related concepts in Chapter 5.With weight vector I mean the vector with weights that you have to multiply the observations in the window that slides over your data with so if you add those products together it returns the value of the EMA on the right side of the window. For a linear weighted moving average the formula for finding the weight vector is: (1:n)sum(1:n) (in R code). This series of length n adds up to 1. For n10 it will be 0.01818182 0.03636364 0.05454545 0.07272727 0.09090909 0.10909091 0.12727273 0.14545455 0.16363636 0.18181818 the numbers 1 to 10 55, with 55 the sum of the numbers 1 to 10. How do you calculate the weight vector for an exponential moving average (EMA) of length n if n is the length of the window, then alphalt-2(n1) and ilt-1:n so EmaWeightVectorlt-((alpha(1-alpha)(1-i))) Is this correct Even though the EMA is not really confined to a window with a start and an end, shouldnt the weights add up to 1 just like with the LWMA Thanks Jason, any pointers of how to approximate the EMA filter to any desired precision by approximating it with a long-enough FIR filter There39s a perl script on en. wikipedia. orgwikihellip that made the image of the EMA weight vector, but I don39t understand it: if they set the number of weights to 15 why are there 20 red bars instead of 15 ndash MisterH Dec 19 12 at 22:40Moving Average I have hundreds of th ousands of data points stored in data and need to do 100 data point moving average. Can anybody share the logic I know I have to do pop or shift but just cant figure out how to do the moving average. thanks in advance RE: Moving Average KevinADC (TechnicalUser) 18 Sep 08 16:28 I think you are going to need to explain what you are trying to do in detail. Or maybe some knows what 100 data point moving average means. Sample in and sample out data will be helpful. RE: Moving Average rharsh (TechnicalUser) 18 Sep 08 16:31 There are a few different ways to define a moving average. Not in terms of perl (since thats your question) what algorithm would you use to calculate the moving average For example, a simple moving average for 100 data points would be something like: SMA (p p-1 . p-99) 100 Is that what youre looking for RE: Moving Average PinkeyNBrain (ISIT--Management) 18 Sep 08 17:02 This looks a little academic, so just in case Ill explain versus writing code here: - Loop over your data pushing the data points into an array - Track a runningtotal of the values along the way - If size of array lt 99, goto start - calc amp print average - shift array and subtract that amount from your runningtotal - end of loop Red Flag Submitted Thank you for helping keep Tek-Tips Forums free from inappropriate posts. The Tek-Tips staff will check this out and take appropriate action. Reply To This Thread Posting in the Tek-Tips forums is a member-only feature. Click Here to join Tek-Tips and talk with other membersThe belief that a change will be easy to do correctly makes it less likely that the change will be done correctly. An XP programmer writes a unit test to clarify his intentions before he makes a change. We call this test-driven design (TDD) or test-first programming . because an API39s design and implementation are guided by its test cases. The programmer writes the test the way he wants the API to work, and he implements the API to fulfill the expectations set out by the test. Test-driven design helps us invent testable and usable interfaces. In many ways, testability and usability are one in the same. If you can39t write a test for an API, it39ll probably be difficult to use, and vice-versa. Test-driven design gives feedback on usability before time is wasted on the implementation of an awkward API. As a bonus, the test documents how the API works, by example. All of the above are good things, and few would argue with them. One obvious concern is that test-driven design might slow down development. It does take time to write tests, but by writing the tests first, you gain insight into the implementation, which speeds development. Debugging the implementation is faster, too, thanks to immediate and reproducible feedback that only an automated test can provide. Perhaps the greatest time savings from unit testing comes a few months or years after you write the test, when you need to extend the API. The unit test not only provides you with reliable documentation for how the API works, but it also validates the assumptions that went into the design of the API. You can be fairly sure a change didn39t break anything if the change passes all the unit tests written before it. Changes that fiddle with fundamental API assumptions cause the costliest defects to debug. A comprehensive unit test suite is probably the most effective defense against such unwanted changes. This chapter introduces test-driven design through the implementation of an exponential moving average (EMA), a simple but useful mathematical function. This chapter also explains how to use the CPAN modules Test::More and Test::Exception . Unit Tests A unit test validates the programmer39s view of the application. This is quite different from an acceptance test, which is written from the customer39s perspective and tests end-user functionality, usually through the same interface that an ordinary user uses. In constrast, a unit test exercises an API, formally known as a unit. Usually, we test an entire Perl package with a single unit test. Perl has a strong tradition of unit testing, and virtually every CPAN module comes with one or more unit tests. There are also many test frameworks available from CPAN. This and subsequent chapters use Test::More . a popular and well documented test module.2 I also use Test::Exception to test deviance cases that result in calls to die .3 Test First, By Intention Test-driven design takes unit testing to the extreme. Before you write the code, you write a unit test. For example, here39s the first test case for the EMA (exponential moving average) module: This is the minimal Test::More test. You tell Test::More how many tests to expect, and you import the module with useok as the first test case. The BEGIN ensures the module39s prototypes and functions are available during compilation of the rest of the unit test. The next step is to run this test to make sure that it fails: At this stage, you might be thinking, Duh Of course, it fails. Test-driven design does involve lots of duhs in the beginning. The baby steps are important, because they help to put you in the mindset of writing a small test followed by just enough code to satisfy the test. If you have maintenance programming experience, you may already be familiar with this procedure. Maintenance programmers know they need a test to be sure that their change fixes what they think is broken. They write the test and run it before fixing anything to make sure they understand a failure and that their fix works. Test-driven design takes this practice to the extreme by clarifying your understanding of all changes before you make them. Now that we have clarified the need for a module called EMA (duh), we implement it: And, duh, the test passes: Yeeha Time to celebrate with a double cappuccino so we don39t fall asleep. That39s all there is to the test-driven design loop: write a test, see it fail, satisfy the test, and watch it pass. For brevity, the rest of the examples leave out the test execution steps and the concomitant duhs and yeehas. However, it39s important to remember to include these simple steps when test-first programming. If you don39t remember, your programming partner probably will.4 Exponential Moving Average Our hypothetical customer for this example would like to maintain a running average of closing stock prices for her website. An EMA is commonly used for this purpose, because it is an efficient way to compute a running average. You can see why if you look at the basic computation for an EMA: today39s price x weight yesterday39s average x (1 - weight) This algorithm produces a weighted average that favors recent history. The effect of a price on the average decays exponentially over time. It39s a simple function that only needs to maintain two values: yesterday39s average and the weight. Most other types of moving averages, require more data storage and more complex computations. The weight, commonly called alpha . is computed in terms of uniform time periods (days, in this example): 2 (number of days 1) For efficiency, alpha is usually computed once, and stored along with the current value of the average. I chose to use an object to hold these data and a single method to compute the average. Test Things That Might Break Since the first cut design calls for a stateful object, we need to instantiate it to use it. The next case tests object creation: I sometimes forget to return the instance ( self ) so the test calls ok to check that new returns some non-zero value. This case tests what I think might break. An alternative, more extensive test is: This case checks that new returns a blessed reference of class EMA . To me, this test is unnecessarily complex. If new returns something, it39s probably an instance. It39s reasonable to rely on the simpler case on that basis alone. Additionally, there will be other test cases that will use the instance, and those tests will fail if new doesn39t return an instance of class EMA . This point is subtle but important, because the size of a unit test suite matters. The larger and slower the suite, the less useful it will be. A slow unit test suite means programmers will hesitate before running all the tests, and there will be more checkins which break unit andor acceptance tests. Remember, programmers are lazy and impatient, and they don39t like being held back by their programming environment. When you test only what might break, your unit test suite will remain a lightweight and effective development tool. Please note that if you and your partner are new to test-driven design, it39s probably better to err on the side of caution and to test too much. With experience, you39ll learn which tests are redundant and which are especially helpful. There are no magic formulas here. Testing is an art that takes time to master. Satisfy The Test, Don39t Trick It Returning to our example, the implementation of new that satisfies this case is: This is the minimal code which satisfies the above test. length doesn39t need to be stored, and we don39t need to compute alpha. We39ll get to them when we need to. But wait, you say, wouldn39t the following code satisfy the test, too Yes, you can trick any test. However, it39s nice to treat programmers like grown-ups (even though we don39t always act that way). No one is going to watch over your shoulder to make sure you aren39t cheating your own test. The first implementation of new is the right amount of code, and the test is sufficient to help guide that implementation. The design calls for an object to hold state, and an object creation is what needed to be coded. Test Base Cases First What we39ve tested thus far are the base cases . that is, tests that validate the basic assumptions of the API. When we test basic assumptions first, we work our way towards the full complexity of the complete implementation, and it also makes the test more readable. Test-first design works best when the implementation grows along with the test cases. There are two base cases for the compute function. The first base case is that the initial value of the average is just the number itself. There39s also the case of inputting a value equal to the average, which should leave the average unchanged. These cases are coded as follows: The is function from Test::More lets us compare scalar values. Note the change to the instantiation test case that allows us to use the instance ( ema ) for subsequent cases. Reusing results of previous tests shortens the test, and makes it easier to understand. The implementation that satisfies these cases is: The initialization of alpha was added to new . because compute needs the value. new initializes the state of the object, and compute implements the EMA algorithm. self-gt is initially undef so that case can be detected. Even though the implementation looks finished, we aren39t done testing. The above code might be defective. Both compute test cases use the same value, and the test would pass even if, for example, self-gt and value were accidentally switched. We also need to test that the average changes when given different values. The test as it stands is too static, and it doesn39t serve as a good example of how an EMA works. Choose Self-Evident Data In a test-driven environment, programmers use the tests to learn how the API works. You may hear that XPers don39t like documentation. That39s not quite true. What we prefer is self-validating documentation in the form of tests. We take care to write tests that are readable and demonstrate how to use the API. One way to create readable tests is to pick good test data. However, we have a little bootstrapping problem: To pick good test data, we need valid values from the results of an EMA computation, but we need an EMA implementation to give us those values. One solution is to calculate the EMA values by hand. Or, we could use another EMA implementation to come up with the values. While either of these choices would work, a programmer reading the test cases would have to trust them or to recompute them to verify they are correct. Not to mention that we39d have to get the precision exactly right for our target platform. Use The Algorithm, Luke A better alternative is to work backwards through the algorithm to figure out some self-evident test data.5 To accomplish this, we treat the EMA algorithm as two equations by fixing some values. Our goal is to have integer values for the results so we avoid floating point precision issues. In addition, integer values make it easier for the programmer to follow what is going on. When we look at the equations, we see alpha is the most constrained value: today39s average today39s price x alpha yesterday39s average x (1 - alpha) alpha 2 (length 1) Therefore it makes sense to try and figure out a value of alpha that can produce integer results given integer prices. Starting with length 1, the values of alpha decrease as follows: 1, 23, 12, 25, 13, 27, and 14. The values 1, 12, and 25 are good candidates, because they can be represented exactly in binary floating point. 1 is a degenerate case, the average of a single value is always itself. 12 is not ideal, because alpha and 1 - alpha are identical, which creates a symmetry in the first equation: today39s average today39s price x 0.5 yesterday39s average x 0.5 We want asymmetric weights so that defects, such as swapping today39s price and yesterday39s average, will be detected. A length of 4 yields an alpha of 25 (0.4), and makes the equation asymmetric: today39s average today39s price x 0.4 yesterday39s average x 0.6 With alpha fixed at 0.4, we can pick prices that make today39s average an integer. Specifically, multiples of 5 work nicely. I like prices to go up, so I chose 10 for today39s price and 5 for yesterday39s average. (the initial price). This makes today39s average equal to 7, and our test becomes: Again, I revised the base cases to keep the test short. Any value in the base cases will work so we might as well save testing time through reuse. Our test and implementation are essentially complete. All paths through the code are tested, and EMA could be used in production if it is used properly. That is, EMA is complete if all we care about is conformant behavior. The implementation currently ignores what happens when new is given an invalid value for length . Although EMA is a small part of the application, it can have a great impact on quality. For example, if new is passed a length of -1, Perl throws a divide-by-zero exception when alpha is computed. For other invalid values for length . such as -2, new silently accepts the errant value, and compute faithfully produces non-sensical values (negative averages for positive prices). We can39t simply ignore these cases. We need to make a decision about what to do when length is invalid. One approach would be to assume garbage-in garbage-out. If a caller supplies -2 for length . it39s the caller39s problem. Yet this isn39t what Perl39s divide function does, and it isn39t what happens, say, when you try to de-reference a scalar which is not a reference. The Perl interpreter calls die . and I39ve already mentioned in the Coding Style chapter that I prefer failing fast rather than waiting until the program can do some real damage. In our example, the customer39s web site would display an invalid moving average, and one her customers might make an incorrect investment decision based on this information. That would be bad. It is better for the web site to return a server error page than to display misleading and incorrect information. Nobody likes program crashes or server errors. Yet calling die is an efficient way to communicate semantic limits (couplings) within the application. The UI programmer, in our example, may not know that an EMA39s length must be a positive integer. He39ll find out when the application dies. He can then change the design of his code and the EMA class to make this limit visible to the end user. Fail fast is an important feedback mechanism. If we encounter an unexpected die . it tells us the application design needs to be improved. Deviance Testing In order to test for an API that fails fast, we need to be able to catch calls to die and then call ok to validate the call did indeed end in an exception. The function diesok in the module Test::Exception does this for us. Since this is our last group of test cases in this chapter, here39s the entire unit test with the changeds for the new deviance cases highlighted: There are now 9 cases in the unit test. The first deviance case validates that length can39t be negative. We already know -1 will die with a divide-by-zero exception so -2 is a better choice. The zero case checks the boundary condition. The first valid length is 1. Lengths must be integers, and 2.5 or any other floating point number is not allowed. length has no explicit upper limit. Perl automatically converts integers to floating point numbers if they are too large. The test already checks that floating point numbers are not allowed so no explicit upper limit check is required. The implementation that satisfies this test follows: The only change is the addition of a call to die with an unless clause. This simple fail fast clause doesn39t complicate the code or slow down the API, and yet it prevents subtle errors by converting an assumption into an assertion. Only Test The New API One of the most difficult parts of testing is to know when to stop. Once you have been test-infected, you may want to keep on adding cases to be sure that the API is perfect. For example, a interesting test case would be to pass a NaN (Not a Number) to compute . but that39s not a test of EMA . The floating point implementation of Perl behaves in a particular way with respect to NaNs6. and Bivio::Math::EMA will conform to that behavior. Testing that NaNs are handled properly is a job for the Perl interpreter39s test suite. Every API relies on a tremendous amount of existing code. There isn39t enough time to test all the existing APIs and your new API as well. Just as an API should separate concerns so must a test. When testing a new API, your concern should be that API and no others. Solid Foundation In XP, we do the simplest thing that could possibly work so we can deliver business value as quickly as possible. Even as we write the test and implementation, we39re sure the code will change. When we encounter a new customer requirement, we refactor the code, if need be, to facilitate the additional function. This iterative process is called continuous design . which is the subject of the next chapter. It39s like renovating your house whenever your needs change. 7 A system or house needs a solid foundation in order to support continuous renovation. Unit tests are the foundation of an XP project. When designing continuously, we make sure the house doesn39t fall down by running unit tests to validate all the assumptions about an implementation. We also grow the foundation before adding new functions. Our test suite gives us the confidence to embrace change. Quality Software Management: Vol. 1 Systems Thinking . Gerald Weinberg, Dorset House, 1991, p. 236. Part of the Test-Simple distribution, available at search. cpan. orgsearchqueryTest-Simple I used version 0.47 for this book. Just a friendly reminder to program in pairs, especially when trying something new. Thanks to Ion Yadigaroglu for teaching me this technique. In some implementations, use of NaNs will cause a run-time error. In others, they will cause all subsequent results to be a NaN. Don39t let the thought of continuous house renovation scare you off. Programmers are much quieter and less messy than construction workers.

No comments:

Post a Comment