วิธีการแก้ปัญหาแบบฮิวริสติก "ลองใช้กรณีทดสอบ": อัลกอริทึมที่ปรากฏถูกต้อง แต่จริง ๆ แล้วไม่ถูกต้อง


105

ในการพยายามทดสอบว่าอัลกอริทึมสำหรับปัญหาบางอย่างถูกต้องหรือไม่จุดเริ่มต้นตามปกติคือลองใช้อัลกอริทึมด้วยมือในกรณีทดสอบง่ายๆ - ลองกับตัวอย่างกรณีปัญหารวมถึงกรณีมุมง่าย ๆ สองสามตัวอย่าง " นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยม: มันเป็นวิธีที่ดีในการกำจัดความพยายามที่ไม่ถูกต้องอย่างรวดเร็วของอัลกอริทึมและเพื่อทำความเข้าใจเกี่ยวกับสาเหตุที่อัลกอริทึมไม่ทำงาน

อย่างไรก็ตามเมื่อการเรียนรู้อัลกอริทึมนักเรียนบางคนถูกล่อลวงให้หยุดที่นั่น: หากอัลกอริทึมของพวกเขาทำงานอย่างถูกต้องกับตัวอย่างจำนวนหนึ่งรวมถึงกรณีมุมทั้งหมดที่พวกเขาสามารถคิดได้ลองพวกเขาสรุปว่าอัลกอริทึมต้องถูกต้อง มีนักเรียนคนหนึ่งที่ถามอยู่เสมอ: "ทำไมฉันต้องพิสูจน์อัลกอริทึมของฉันให้ถูกต้องถ้าฉันลองได้ในบางกรณีทดสอบ?"

ดังนั้นคุณจะหลอก "ฮิวริสติกแบบทดสอบกรณี" ได้อย่างไร ฉันกำลังมองหาตัวอย่างที่ดีเพื่อแสดงว่าฮิวริสติกนี้ไม่เพียงพอ กล่าวอีกนัยหนึ่งฉันกำลังมองหาหนึ่งหรือมากกว่าหนึ่งตัวอย่างของอัลกอริทึมที่เผินๆดูเหมือนว่ามันอาจจะถูกต้องและผลลัพธ์ที่ได้คำตอบที่ถูกต้องในอินพุตขนาดเล็กทั้งหมดที่ทุกคนมีแนวโน้มที่จะเกิดขึ้น ไม่ทำงาน อัลกอริทึมอาจทำงานได้อย่างถูกต้องกับอินพุตขนาดเล็กทั้งหมดและล้มเหลวสำหรับอินพุตขนาดใหญ่เท่านั้นหรือล้มเหลวเฉพาะสำหรับอินพุตที่มีรูปแบบที่ผิดปกติ

โดยเฉพาะฉันกำลังมองหา:

  1. อัลกอริทึม ข้อบกพร่องจะต้องอยู่ในระดับอัลกอริทึม ฉันไม่ได้กำลังมองหาข้อผิดพลาดในการใช้งาน (ตัวอย่างเช่นอย่างน้อยที่สุดตัวอย่างควรเป็นผู้ไม่เชื่อเรื่องภาษาและข้อบกพร่องควรเกี่ยวข้องกับความกังวลด้านอัลกอริทึมมากกว่าปัญหาด้านวิศวกรรมซอฟต์แวร์หรือปัญหาการใช้งาน)

  2. อัลกอริทึมที่บางคนอาจมีความน่าเชื่อถือ รหัสเทียมควรมีลักษณะที่ถูกต้องอย่างน้อยน่าจะเป็นไปได้ (เช่นรหัสที่ obfuscated หรือน่าสงสัยว่าไม่ได้เป็นตัวอย่างที่ดี) คะแนนโบนัสหากเป็นอัลกอริทึมที่นักเรียนบางคนคิดขึ้นมาเมื่อพยายามแก้ไขปัญหาการบ้านหรือการสอบ

  3. อัลกอริทึมที่จะผ่านกลยุทธ์การทดสอบด้วยตนเองอย่างสมเหตุสมผลด้วยความน่าจะเป็นสูง คนที่ลองใช้กรณีทดสอบเล็ก ๆ น้อย ๆ ด้วยมือไม่น่าจะค้นพบข้อบกพร่อง ตัวอย่างเช่น "จำลอง QuickCheck ด้วยมือในกรณีทดสอบขนาดเล็กโหล" ไม่น่าจะเปิดเผยว่าอัลกอริทึมไม่ถูกต้อง

  4. เป็นอัลกอริทึมที่กำหนดขึ้นโดยเฉพาะ ฉันเคยเห็นนักเรียนหลายคนคิดว่า "ลองใช้กรณีทดสอบด้วยมือ" เป็นวิธีที่สมเหตุสมผลในการตรวจสอบว่าอัลกอริธึมที่กำหนดขึ้นถูกต้องหรือไม่ แต่ฉันสงสัยว่านักเรียนส่วนใหญ่จะไม่คิดว่าการลองใช้กรณีทดสอบสองสามอันเป็นวิธีที่ดี อัลกอริทึม สำหรับอัลกอริธึมความน่าจะเป็นมักจะไม่มีวิธีที่จะบอกได้ว่าเอาต์พุตใด ๆ ที่ถูกต้องหรือไม่ และคุณไม่สามารถยกตัวอย่างได้มากพอที่จะทำการทดสอบทางสถิติที่มีประโยชน์กับการกระจายสัญญาณ ดังนั้นฉันอยากจะมุ่งเน้นไปที่อัลกอริธึมที่กำหนดขึ้นเนื่องจากพวกเขาเข้าใจหัวใจของความเข้าใจผิดของนักเรียนมากขึ้น

ฉันต้องการสอนความสำคัญของการพิสูจน์อัลกอริทึมของคุณให้ถูกต้องและฉันหวังว่าจะใช้ตัวอย่างสองสามอย่างเช่นนี้เพื่อช่วยกระตุ้นการพิสูจน์ความถูกต้อง ฉันต้องการตัวอย่างที่ค่อนข้างง่ายและเข้าถึงได้สำหรับนักศึกษาระดับปริญญาตรี ตัวอย่างที่ต้องใช้เครื่องจักรกลหนักหรือพื้นหลังทางคณิตศาสตร์ / อัลกอริธึมจำนวนมากมีประโยชน์น้อยกว่า นอกจากนี้ฉันไม่ต้องการอัลกอริทึมที่ "ผิดธรรมชาติ"; ในขณะที่มันอาจจะง่ายในการสร้างอัลกอริธึมประดิษฐ์แปลก ๆ เพื่อหลอกฮิวริสติกถ้ามันดูผิดธรรมชาติอย่างมากหรือมีแบ็คดอร์ที่เห็นได้ชัดที่สร้างขึ้นเพื่อหลอกฮิวริสติกนี้ ตัวอย่างที่ดีใด ๆ


2
ฉันรักคำถามของคุณมันเกี่ยวข้องกับคำถามที่น่าสนใจอย่างมากที่ฉันเห็นในวิชาคณิตศาสตร์ในวันอื่น ๆ ที่เกี่ยวข้องกับการพิสูจน์การอนุมานด้วยค่าคงที่ขนาดใหญ่ คุณสามารถค้นหาได้ที่นี่
ZeroUltimax

1
บางคนขุดขึ้นและผมพบว่าผู้ที่สองขั้นตอนวิธีการทางเรขาคณิต
ZeroUltimax

@ZeroUltimax คุณพูดถูกจุด pt กลางของ 3 แต้มที่ไม่ใช้สีไม่ได้รับประกันว่าอยู่ภายใน วิธีการรักษาอย่างรวดเร็วคือการได้รับ pt บนเส้นแบ่งระหว่างซ้ายสุดและขวาสุด มีปัญหาอื่นอีกไหม?
InformedA

หลักฐานของคำถามนี้ดูเหมือนจะแปลกสำหรับฉันที่ฉันมีปัญหาในการรับหัวของฉัน แต่ฉันคิดว่ามันลงมาเป็นกระบวนการสำหรับการออกแบบอัลกอริทึมตามที่อธิบายไว้เป็นพื้นฐานเสีย แม้แต่นักเรียนที่ไม่ 'หยุด' ก็ถึงวาระแล้ว 1> เขียนอัลกอริธึม 2> คิดถึง / เรียกใช้กรณีทดสอบ 3a> หยุดหรือ 3b> พิสูจน์ถูกต้อง ขั้นตอนแรกสวยมากได้รับการระบุการเรียนการป้อนข้อมูลสำหรับโดเมนปัญหา เคสมุมและอัลกอริทึมนั้นเกิดขึ้นจากสิ่งเหล่านั้น (ต่อ)
Mr.Mindor

1
คุณแยกข้อผิดพลาดในการใช้งานอย่างเป็นทางการจากอัลกอริธึมที่มีข้อบกพร่องอย่างไร ฉันสนใจคำถามของคุณ แต่ในเวลาเดียวกันฉันรู้สึกกังวลกับความจริงที่ว่าสถานการณ์ที่คุณอธิบายดูเหมือนจะเป็นกฎมากกว่าข้อยกเว้น หลายคนทำการทดสอบสิ่งที่พวกเขาใช้ แต่พวกเขามักจะยังมีข้อบกพร่อง ตัวอย่างที่สองของคำตอบที่ถูกโหวตมากที่สุดคือข้อผิดพลาดที่แม่นยำ
babou

คำตอบ:


70

ข้อผิดพลาดทั่วไปที่ฉันคิดคือการใช้อัลกอริทึมโลภซึ่งไม่ได้เป็นแนวทางที่ถูกต้องเสมอไป แต่อาจใช้ได้ในกรณีทดสอบส่วนใหญ่

ตัวอย่าง:เหรียญ ได้แก่และตัวเลข , แสดงเป็นผลรวมของ : s ด้วยเหรียญน้อยที่สุด n n d id1,,dknndi

วิธีการที่ไร้เดียงสาคือการใช้เหรียญที่ใหญ่ที่สุดเท่าที่จะเป็นไปได้ก่อน

ยกตัวอย่างเช่นเหรียญมีมูลค่า ,และ จะให้คำตอบที่ถูกต้องด้วยโลภสำหรับตัวเลขทั้งหมดระหว่างและ ยกเว้นหมายเลข 55 1 1 14 10 = 6 + 1 + 1 + 1 + 1 = 5 + 565111410=6+1+1+1+1=5+5


10
นี่เป็นตัวอย่างที่ดีโดยเฉพาะอย่างยิ่งว่านักเรียนผิดพลาดเป็นประจำ คุณไม่เพียงต้องเลือกชุดเหรียญเฉพาะ แต่ยังต้องมีค่าเฉพาะเพื่อดูอัลกอริทึมที่ล้มเหลว
กราฟิลส์

2
นอกจากนี้ให้ฉันบอกว่านักเรียนมักจะมีข้อพิสูจน์ที่ผิดในตัวอย่างนี้ (มีข้อโต้แย้งที่ไร้เดียงสาที่ล้มเหลวในการตรวจสอบอย่างใกล้ชิด) ดังนั้นมากกว่าหนึ่งบทเรียนสามารถเรียนรู้ได้ที่นี่
กราฟิลส์

2
ระบบเหรียญบริติชแบบเก่า (ก่อนปี ค.ศ. 1971) เป็นตัวอย่างที่แท้จริงของเรื่องนี้ อัลกอริทึมโลภสำหรับการนับสี่ชิลลิงจะใช้ครึ่งมงกุฎ (2½ชิลลิง) เหรียญหนึ่งชิลลิงหนึ่งและเพนนีหกเพนนี (½ชิลลิง) แต่ทางออกที่ดีที่สุดนั้นใช้สอง florins (2 ชิลลิงแต่ละอัน)
Mark Dominus

1
แท้จริงแล้วในหลายกรณีอัลกอริทึมโลภดูสมเหตุสมผล แต่ไม่ได้ผล - ตัวอย่างอื่นคือการจับคู่สองฝ่ายสูงสุด ในอีกทางหนึ่งก็มีตัวอย่างที่ดูเหมือนว่าอัลกอริทึมโลภไม่ควรทำงาน แต่จะทำเช่นนั้น: ต้นไม้ขยายสูงสุด
jkff

62

ฉันจำตัวอย่างจากอาร์ Backhouseได้ทันที(นี่อาจเป็นหนึ่งในหนังสือของเขา) เห็นได้ชัดว่าเขาได้รับมอบหมายการเขียนโปรแกรมที่นักเรียนต้องเขียนโปรแกรมปาสคาลเพื่อทดสอบความเท่าเทียมกันของสองสาย หนึ่งในโปรแกรมที่เปิดโดยนักเรียนมีดังต่อไปนี้:

issame := (string1.length = string2.length);

if issame then
  for i := 1 to string1.length do
    issame := string1.char[i] = string2.char[i];

write(issame);

ตอนนี้เราสามารถทดสอบโปรแกรมด้วยอินพุตต่อไปนี้:

"มหาวิทยาลัย" "มหาวิทยาลัย" จริง ตกลง

"หลักสูตร" "หลักสูตร" จริง; ตกลง

"" "" จริง ตกลง

"มหาวิทยาลัย" "หลักสูตร" เท็จ; ตกลง

"บรรยาย" "หลักสูตร" เท็จ; ตกลง

"ความแม่นยำ" "ความแม่นยำ" เท็จ, ตกลง

ทั้งหมดนี้ดูมีแนวโน้มมาก: โปรแกรมอาจใช้งานได้จริง แต่การทดสอบอย่างระมัดระวังยิ่งขึ้นด้วยการพูดว่า "บริสุทธิ์" และ "จริง" เผยให้เห็นผลลัพธ์ที่ผิดพลาด อันที่จริงแล้วโปรแกรมบอกว่า "จริง" ถ้าสตริงมีความยาวเท่ากันและมีอักขระตัวสุดท้ายเหมือนกัน!

อย่างไรก็ตามการทดสอบนั้นค่อนข้างละเอียด: เรามีสตริงที่มีความยาวต่างกันสตริงที่มีความยาวเท่ากัน แต่เนื้อหาที่แตกต่างกันและแม้แต่สตริงที่เท่ากัน นอกจากนี้นักเรียนยังได้ทดสอบและดำเนินการทุกสาขา คุณไม่สามารถโต้แย้งการทดสอบที่นี่ได้โดยไม่สนใจเลยเนื่องจากโปรแกรมนั้นง่ายมากมันอาจจะยากที่จะหาแรงจูงใจและพลังงานในการทดสอบอย่างละเอียดเพียงพอ


อีกตัวอย่างที่น่ารักคือการค้นหาแบบไบนารี่ ใน TAOCP, Knuth กล่าวว่า "แม้ว่าแนวคิดพื้นฐานของการค้นหาแบบไบนารี่จะค่อนข้างตรงไปตรงมา แต่รายละเอียดอาจยุ่งยากอย่างน่าประหลาด" เห็นได้ชัดว่าข้อผิดพลาดในการใช้งานการค้นหาแบบไบนารีของ Java ก็ไม่มีใครสังเกตเห็นมานานกว่าทศวรรษ มันเป็นข้อผิดพลาดล้นจำนวนเต็มและประจักษ์เท่านั้นด้วยการป้อนข้อมูลที่มีขนาดใหญ่พอ รายละเอียดยุ่งยากของการใช้งานค้นหา binary ยังถูกปกคลุมไปด้วยเบนท์ลีย์ในหนังสือเล่มไข่มุกเขียนโปรแกรม

บรรทัดล่าง: มันอาจเป็นเรื่องยากอย่างน่าประหลาดใจที่จะแน่ใจว่าอัลกอริธึมการค้นหาแบบไบนารี่นั้นถูกต้องเพียงแค่ทำการทดสอบ


9
แน่นอนข้อบกพร่องค่อนข้างชัดเจนจากแหล่งที่มา (ถ้าคุณเคยเขียนสิ่งที่คล้ายกันมาก่อน)
ราฟาเอล

3
แม้ว่าจะมีการแก้ไขข้อบกพร่องง่ายๆในโปรแกรมตัวอย่าง แต่สตริงก็มีปัญหาที่น่าสนใจอยู่บ้าง! การกลับตัวสตริงเป็นคลาสสิก - วิธี "พื้นฐาน" ของการทำมันคือเพียงแค่ย้อนกลับไบต์ จากนั้นการเข้ารหัสจะเข้าสู่การเล่น จากนั้นตัวแทน (ปกติสองครั้ง) แน่นอนว่าปัญหาคือไม่มีวิธีง่ายๆในการพิสูจน์วิธีการของคุณอย่างถูกต้อง
Ordous

6
บางทีฉันอาจตีความคำถามผิดไปหมด แต่ดูเหมือนว่านี่จะเป็นข้อบกพร่องในการนำไปใช้แทนที่จะเป็นข้อบกพร่องในอัลกอริธึมเอง
Mr.Mindor

8
@ Mr.Mindor: คุณจะบอกได้อย่างไรว่าโปรแกรมเมอร์ได้เขียนอัลกอริธึมที่ถูกต้องแล้วนำไปใช้อย่างไม่ถูกต้องหรือเขียนขั้นตอนวิธีที่ไม่ถูกต้องแล้วนำไปใช้อย่างซื่อสัตย์ (ฉันลังเลที่จะพูดว่า "ถูกต้อง"!)
Steve Jessop

1
@ กระต่ายนั่นเป็นที่ถกเถียงกัน สิ่งที่ชัดเจนสำหรับคุณอาจไม่ชัดเจนสำหรับนักเรียนชั้นปีที่หนึ่ง
Juho

30

ตัวอย่างที่ดีที่สุดที่ฉันเคยเจอคือการทดสอบเบื้องต้น:

อินพุต: จำนวนธรรมชาติ p, p! = 2
เอาท์พุท: เป็น pa นายกหรือไม่?
อัลกอริทึม: คำนวณ 2 ** (p-1) mod p ถ้า result = 1 ดังนั้น p คือไพร์มอย่างอื่น p ไม่ใช่

วิธีนี้ใช้ได้กับ (เกือบ) ทุกหมายเลขยกเว้นตัวอย่างตัวนับจำนวนน้อยมากและอีกอันหนึ่งต้องการเครื่องเพื่อค้นหาตัวอย่างตัวอย่างในช่วงเวลาที่เป็นจริง ตัวอย่างตัวอย่างแรกคือ 341 และความหนาแน่นของตัวอย่างจริงลดลงเมื่อเพิ่มค่า p แม้ว่าจะเป็นลอการิทึม

แทนที่จะใช้ 2 เป็นพื้นฐานของกำลังคนอาจปรับปรุงอัลกอริทึมโดยใช้เพิ่มเติมเพิ่ม primes ขนาดเล็กเป็นพื้นฐานในกรณีที่นายกคนก่อนกลับมา 1 และยังคงมีตัวอย่างกับโครงการนี้คือหมายเลขคาร์ไมเคิล ค่อนข้างหายาก แต่


การทดสอบแบบดั้งเดิมของแฟร์มาต์เป็นการทดสอบความน่าจะเป็นดังนั้นโพสต์เงื่อนไขของคุณไม่ถูกต้อง
Femaref

5
ofc เป็นการทดสอบความน่าจะเป็น แต่คำตอบแสดงให้เห็นอย่างชัดเจน (โดยทั่วไป) วิธีที่อัลกอริธึมความน่าจะเป็นที่เข้าใจผิดสำหรับคนที่แน่นอนสามารถเป็นแหล่งที่มาของข้อผิดพลาด ข้อมูลเพิ่มเติมเกี่ยวกับหมายเลข Carmichael
vzn

2
นี่เป็นตัวอย่างที่ดีที่มีข้อ จำกัด : สำหรับการใช้งานจริงของการทดสอบแบบดั้งเดิมที่ฉันคุ้นเคยคือการสร้างคีย์เข้ารหัสแบบไม่สมมาตรเราใช้อัลกอริธึมที่น่าจะเป็น! ตัวเลขมีขนาดใหญ่เกินไปสำหรับการทดสอบที่แน่นอน (หากไม่เป็นเช่นนั้นพวกเขาจะไม่เหมาะสำหรับการเข้ารหัสลับเพราะกุญแจสามารถพบได้โดยกำลังดุร้ายในเวลาจริง)
Gilles

1
ข้อ จำกัด ที่คุณอ้างถึงนั้นใช้งานได้จริงไม่ใช่เชิงทฤษฎีและการทดสอบที่สำคัญในระบบ crypto เช่นRSAอาจมีความล้มเหลวที่หายาก / ไม่น่าจะเป็นไปได้สูงสำหรับเหตุผลเหล่านี้อย่างแท้จริงอีกครั้งเน้นความสำคัญของตัวอย่าง เช่นในทางปฏิบัติบางครั้งข้อ จำกัด นี้ได้รับการยอมรับว่าหลีกเลี่ยงไม่ได้ มีอัลกอริธึม P เวลาสำหรับการทดสอบแบบดั้งเดิมเช่นAKSแต่ใช้เวลานานเกินไปสำหรับตัวเลขที่ "เล็กกว่า" ที่ใช้ในทางปฏิบัติ
vzn

หากคุณทดสอบไม่เพียง แต่มี 2 p แต่มี p สำหรับค่าสุ่ม 50 ค่าที่แตกต่างกัน 2 ≤ a <p คนส่วนใหญ่จะรู้ว่ามันน่าจะเป็น แต่มีความล้มเหลวดังนั้นจึงไม่น่าเป็นไปได้ที่จะเกิดความผิดปกติในคอมพิวเตอร์ของคุณ คำตอบที่ผิด ด้วย 2 p, 3 p, 5 p และ 7 p ความล้มเหลวหายากมากแล้ว
gnasher729

21

นี่คืออันที่ฉันขว้างโดย google reps ในการประชุมที่ฉันไป มันถูกเข้ารหัสใน C แต่มันทำงานในภาษาอื่น ๆ ที่ใช้การอ้างอิง ขออภัยที่ต้องใช้รหัสใน [cs.se] แต่เป็นเพียงสิ่งเดียวที่จะอธิบายได้

swap(int& X, int& Y){
    X := X ^ Y
    Y := X ^ Y
    X := X ^ Y
}

อัลกอริทึมนี้จะทำงานสำหรับค่าใด ๆ ที่กำหนดให้กับ x และ y แม้ว่าพวกเขาจะมีค่าเดียวกัน มันจะไม่ทำงาน แต่ถ้ามันถูกเรียกว่า swap (x, x) ในสถานการณ์นั้น x สิ้นสุดเป็น 0 ทีนี้สิ่งนี้อาจไม่เป็นที่พอใจคุณเนื่องจากคุณสามารถพิสูจน์การดำเนินการนี้ว่าถูกต้องทางคณิตศาสตร์ แต่ก็ยังลืมเกี่ยวกับกรณีขอบนี้


1
เคล็ดลับที่ใช้ในการประกวด C ทุจริตในการผลิตการดำเนินงาน RC4 ข้อบกพร่อง การอ่านบทความนั้นอีกครั้งฉันเพิ่งสังเกตเห็นว่าแฮ็คนี้อาจถูกส่งโดย @DW
CodesInChaos

7
ข้อบกพร่องนี้เป็นสิ่งที่ลึกซึ้งอย่างแท้จริง แต่ข้อบกพร่องนั้นเป็นภาษาเฉพาะดังนั้นจึงไม่ใช่ข้อบกพร่องในอัลกอริทึม มันเป็นข้อบกพร่องในการใช้งาน หนึ่งอาจเกิดขึ้นกับตัวอย่างอื่น ๆ ของความแปลกประหลาดทางภาษาที่ทำให้ง่ายต่อการปกปิดข้อบกพร่องเล็กน้อย แต่นั่นไม่ใช่สิ่งที่ฉันกำลังมองหา (ฉันกำลังมองหาบางสิ่งบางอย่างในระดับของอัลกอริทึมนามธรรม) ไม่ว่าในกรณีใดข้อบกพร่องนี้ไม่ได้เป็นการสาธิตคุณค่าของการพิสูจน์ที่สมบูรณ์แบบ นอกจากว่าคุณกำลังคิดเรื่องนามแฝงอยู่คุณอาจมองข้ามปัญหาเดียวกันเมื่อคุณเขียน "หลักฐาน" ของความถูกต้อง
DW

นั่นเป็นสาเหตุที่ฉันประหลาดใจที่คะแนนสูงมาก
ZeroUltimax

2
@DW นั่นเป็นเรื่องของการที่คุณกำหนดอัลกอริธึมในแบบใดถ้าคุณลงไปถึงระดับที่การอ้างอิงหน่วยความจำมีความชัดเจน ข้อบกพร่องนั้นไม่ได้มีเฉพาะในภาษา แต่จะปรากฏขึ้นในภาษาใดก็ตามที่รองรับการแชร์การอ้างอิงหน่วยความจำ
Gilles

16

มีทั้งชั้นของขั้นตอนวิธีการที่ยากที่โดยเนื้อแท้ในการทดสอบคือสุ่มหลอกกำเนิดจำนวน คุณไม่สามารถทดสอบเอาต์พุตเดี่ยว แต่ต้องตรวจสอบเอาต์พุต (หลายชุด) ด้วยวิธีทางสถิติ ขึ้นอยู่กับว่าคุณทดสอบอะไรและอย่างไรคุณอาจพลาดคุณลักษณะที่ไม่ใช่แบบสุ่ม

กรณีหนึ่งที่มีชื่อเสียงสิ่งที่ผิดพลาดไปอย่างน่ากลัวคือRandu มันผ่านการตรวจสอบที่มีอยู่ในเวลา - ซึ่งล้มเหลวในการพิจารณาพฤติกรรมของสิ่งอันดับของผลลัพธ์ที่ตามมา triples แสดงโครงสร้างจำนวนมากแล้ว:

โดยพื้นฐานแล้วการทดสอบไม่ครอบคลุมทุกกรณีการใช้งาน: ในขณะที่การใช้ RANDU แบบมิติเดียว (อาจเป็นส่วนใหญ่) ก็ดี แต่ก็ไม่สนับสนุนให้ใช้เพื่อทดสอบตัวอย่างจุดสามมิติ (ด้วยวิธีนี้)

การสุ่มตัวอย่างแบบหลอกเทียมที่เหมาะสมเป็นธุรกิจที่ยุ่งยาก โชคดีที่มีห้องทดสอบที่ทรงพลังอยู่หลายวันเช่นdieharderที่เชี่ยวชาญในการขว้างสถิติทั้งหมดที่เรารู้จักที่เครื่องกำเนิดไฟฟ้าที่เสนอ มันเพียงพอหรือไม่

เพื่อความเป็นธรรมฉันไม่ทราบว่าคุณสามารถพิสูจน์ได้สำหรับ PRNG อย่างไร


2
ตัวอย่างที่ดีอย่างไรก็ตามโดยทั่วไปแล้วไม่มีวิธีพิสูจน์ว่า PRNG ไม่มีข้อบกพร่องมีเพียงลำดับชั้นที่ไม่มีที่สิ้นสุดของการทดสอบที่อ่อนแอ อันที่จริงการพิสูจน์อย่างใดอย่างหนึ่งคือ "สุ่ม" ในความหมายที่เข้มงวดใด ๆ ที่คาดเดาไม่ได้ (havent เห็นว่าพิสูจน์แล้ว)
vzn

1
เป็นความคิดที่ดีสำหรับบางสิ่งที่ยากต่อการทดสอบ แต่ RNG ก็ยากที่จะพิสูจน์ PRNG ไม่ได้มีแนวโน้มที่จะบั๊กในการใช้งานมากเท่าที่ระบุไว้ไม่ดี การทดสอบเช่นมิจฉาทิฐินั้นดีสำหรับการใช้งานบางอย่าง แต่สำหรับการเข้ารหัสลับคุณสามารถผ่านมิจฉาทิฐิและยังคงถูกหัวเราะออกจากห้อง ไม่มี CSPRNG ที่“ พิสูจน์แล้วว่าปลอดภัย” สิ่งที่ดีที่สุดที่คุณสามารถหวังได้คือการพิสูจน์ว่าหาก CSPRNG ของคุณแตกหักดังนั้น AES ก็คือ
Gilles

@Gilles ฉันไม่ได้พยายามที่จะเข้าสู่ crypto เพียงการสุ่มทางสถิติ (ฉันคิดว่าทั้งสองมีความต้องการมุมฉากมาก) ฉันควรอธิบายให้ชัดเจนในคำตอบหรือไม่?
ราฟาเอล

1
การเข้ารหัสแบบสุ่มหมายถึงการสุ่มทางสถิติ ทั้งสองมีนิยามทางคณิตศาสตร์อย่างเป็นทางการแม้ว่าเท่าที่ฉันรู้นอกเหนือจากอุดมคติ (และขัดแย้งกับแนวคิดของ PRNG ดำเนินการบนเครื่องทัวริงกำหนดขึ้น) แนวคิดของการสุ่มข้อมูลตามทฤษฎี การสุ่มทางสถิติมีคำจำกัดความที่เป็นทางการเกินกว่า "จะต้องเป็นอิสระจากการแจกแจงที่เราจะทดสอบกับ" หรือไม่?
Gilles

1
@ vzn: ความหมายของการเรียงลำดับตัวเลขแบบสุ่มสามารถกำหนดได้หลายวิธี แต่สิ่งที่ง่ายคือ "ความซับซ้อนขนาดใหญ่ของ Komolgorov" ในกรณีดังกล่าวมันเป็นเรื่องง่ายที่จะแสดงให้เห็นว่าการพิจารณาแบบสุ่มนั้นไม่สามารถตัดสินใจได้
ดี้

9

สูงสุด 2 มิติในท้องถิ่น

n×nA

(i,j)A[i,j]

A[i,j+1],A[i,j1],A[i1,j],A[i+1,j]A

0134323125014013

จากนั้นแต่ละเซลล์ที่เป็นตัวหนาจะมีค่าสูงสุดในท้องถิ่น อาเรย์ที่ไม่ว่างจะมีค่าสูงสุดในท้องถิ่นอย่างน้อยหนึ่งค่า

O(n2)

AXXA(i,j)X(i,j)(i,j)

AXAX(i,j)A

AA

(i,j)AA(i,j)

n2×n2A(i,j)

T(n)n×nT(n)=T(n/2)+O(n)T(n)=O(n)

ดังนั้นเราได้พิสูจน์ทฤษฎีบทต่อไปนี้:

O(n)n×n

หรือว่าพวกเรา


T(n)=O(nlogn)T(n)=T(n/2)+O(n)

2
นี่เป็นตัวอย่างที่สวยงาม ! ฉันรักมัน. ขอขอบคุณ. (ในที่สุดฉันก็ค้นพบข้อบกพร่องในอัลกอริทึมนี้จากการประทับเวลาคุณสามารถลดขอบเขตระยะเวลาที่ฉันใช้ฉันอายเกินไปที่จะเปิดเผยเวลาจริง :-)
DW

1
O(n)

8

นี่เป็นตัวอย่างเบื้องต้นเพราะเป็นเรื่องธรรมดา

(1) อันดับแรกใน SymPy ฉบับที่ 1789 มีการทดสอบที่ไม่ถูกต้องวางอยู่บนเว็บไซต์ที่รู้จักกันดีซึ่งไม่ได้ล้มเหลวจนกระทั่งหลังจาก 10 ^ 14 ในขณะที่การแก้ไขถูกต้องมันเป็นเพียงการปะแก้หลุมมากกว่าคิดใหม่ปัญหา

(2) Primality ใน Perl 6 Perl6 ได้เพิ่ม is-prime ซึ่งใช้จำนวนการทดสอบ MR ที่มีฐานคงที่ มีตัวอย่างที่รู้จักกันดี แต่มีขนาดค่อนข้างใหญ่เนื่องจากจำนวนการทดสอบเริ่มต้นมีขนาดใหญ่มาก (โดยทั่วไปซ่อนปัญหาจริงโดยการลดประสิทธิภาพ) สิ่งนี้จะได้รับการแก้ไขในไม่ช้า

(3) ชนพื้นเมืองในฟลิ้นท์ n_isprime () คืนค่า true สำหรับคอมโพสิตเนื่องจากได้รับการแก้ไขแล้ว โดยทั่วไปปัญหาเดียวกันกับ SymPy การใช้ฐานข้อมูล Feitsma / Galway ของ pseudoprimes SPRP-2 ถึง 2 ^ 64 เราสามารถทดสอบสิ่งเหล่านี้ได้

(4) คณิตศาสตร์ของ Perl :: Primality เสีย is_aks_prime ลำดับนี้ดูเหมือนจะคล้ายกับการใช้งาน AKS มากมาย - รหัสจำนวนมากที่ทำงานโดยไม่ตั้งใจ (เช่นหลงทางในขั้นตอนที่ 1 และจบลงด้วยการทำสิ่งทั้งหมดโดยการแบ่งการทดลอง) หรือไม่ทำงานสำหรับตัวอย่างขนาดใหญ่ น่าเสียดายที่ AKS ช้ามากจนยากที่จะทดสอบ

(5) Pari pre-2.2 is_prime คณิตศาสตร์ :: ตั๋ว มันใช้ฐานสุ่ม 10 ฐานสำหรับการทดสอบ MR (ด้วยเมล็ดพืชคงที่เมื่อเริ่มต้นแทนที่จะเป็นเมล็ดตายตัวของ GMP ทุกครั้งที่เรียก) มันจะบอกคุณว่า 9 เป็นเรื่องสำคัญเกี่ยวกับ 1 จากการโทร 1M ทุกครั้ง หากคุณเลือกหมายเลขที่ถูกต้องคุณสามารถทำให้มันล้มเหลวบ่อยครั้ง แต่ตัวเลขนั้นกลายเป็นตัวแยกคำดังนั้นมันจึงไม่ปรากฏขึ้นมากนักในทางปฏิบัติ พวกเขาได้เปลี่ยนอัลกอริทึมและ API

นี่ไม่ผิดแต่เป็นคลาสสิกของการทดสอบความน่าจะเป็น: คุณบอกว่ามีกี่รอบที่ mpz_probab_prime_p ถ้าเราให้ 5 รอบมันดูเหมือนว่าจะทำงานได้ดี - ตัวเลขต้องผ่านการทดสอบเบส -210 แฟร์มาต์และจากนั้นเลือกเบสมิลเลอร์ราบิน 5 การทดสอบพื้นฐานที่เลือกไว้ล่วงหน้า คุณจะไม่พบตัวอย่างตัวอย่างจนกว่าจะถึง 3892757297131 (ด้วย GMP 5.0.1 หรือ 6.0.0a) ดังนั้นคุณต้องทำการทดสอบมากมายเพื่อค้นหา แต่มีตัวอย่างนับพันภายใต้ 2 ^ 64 ดังนั้นคุณจึงเพิ่มจำนวน ไกลแค่ไหน? มีปฏิปักษ์ไหม คำตอบที่ถูกต้องสำคัญแค่ไหน? คุณสับสนฐานสุ่มกับฐานคงที่หรือไม่? คุณรู้ขนาดของอินพุตที่คุณจะได้รับหรือไม่?

1016

การทดสอบเหล่านี้ค่อนข้างยาก กลยุทธ์ของฉันรวมถึงการทดสอบหน่วยที่เห็นได้ชัดรวมถึงกรณีขอบและตัวอย่างของความล้มเหลวที่เห็นก่อนหน้าหรือในแพ็คเกจอื่น ๆ ทดสอบกับฐานข้อมูลที่เป็นไปได้ (เช่นถ้าคุณทำการทดสอบ MR-base-2 ครั้งเดียว ภารกิจในการทดสอบ 2 ^ 64 ตัวเลขไปยังการทดสอบประมาณ 32 ล้านหมายเลข) และสุดท้ายการทดสอบแบบสุ่มจำนวนมากโดยใช้แพคเกจอื่นเป็นมาตรฐาน จุดสุดท้ายใช้งานได้กับฟังก์ชั่นอย่าง primality ที่มีอินพุตค่อนข้างง่ายและเอาต์พุตที่รู้จัก แต่มีงานบางอย่างที่ค่อนข้างเช่นนี้ ฉันใช้สิ่งนี้เพื่อค้นหาข้อบกพร่องทั้งในรหัสการพัฒนาของตัวเองและปัญหาที่เกิดขึ้นเป็นครั้งคราวในแพ็คเกจเปรียบเทียบ แต่เมื่อกำหนดพื้นที่อินพุตไม่สิ้นสุดเราไม่สามารถทดสอบทุกสิ่งได้

สำหรับการพิสูจน์ความถูกต้องนี่เป็นอีกตัวอย่างหนึ่งของชนพื้นเมือง วิธีการ BLS75 และ ECPP มีแนวคิดของการรับรองแบบดั้งเดิม โดยทั่วไปหลังจากที่พวกเขาปั่นทำการค้นหาเพื่อค้นหาค่าที่ใช้ได้กับบทพิสูจน์พวกเขาสามารถส่งออกได้ในรูปแบบที่รู้จัก หนึ่งสามารถเขียนตัวตรวจสอบหรือให้คนอื่นเขียนได้ สิ่งเหล่านี้ทำงานได้เร็วมากเมื่อเทียบกับการสร้างและตอนนี้ (1) โค้ดทั้งสองชิ้นนั้นไม่ถูกต้อง (เพราะเหตุใดคุณจึงต้องการโปรแกรมเมอร์คนอื่นสำหรับ verifier) ​​หรือ (2) คณิตศาสตร์ที่อยู่เบื้องหลังแนวคิดการพิสูจน์นั้นผิด # 2 เป็นไปได้เสมอ แต่โดยทั่วไปแล้วสิ่งเหล่านี้ได้รับการตีพิมพ์และตรวจสอบโดยคนหลายคน (และในบางกรณีนั้นง่ายสำหรับคุณที่จะเดินผ่านตัวคุณเอง)

ในการเปรียบเทียบวิธีต่างๆเช่น AKS, APR-CL, แผนกการทดลองหรือการทดสอบ Rabin แบบกำหนดค่าได้ทั้งหมดไม่สร้างผลลัพธ์ใด ๆ นอกจาก "นายก" หรือ "คอมโพสิต" ในกรณีหลังเราอาจมีปัจจัยที่สามารถตรวจสอบได้ แต่ในกรณีก่อนหน้านี้เราไม่มีอะไรเหลือนอกจากเอาท์พุทหนึ่งบิตนี้ โปรแกรมทำงานถูกต้องหรือไม่? dunno

มันเป็นสิ่งสำคัญที่จะทดสอบซอฟต์แวร์มากกว่าตัวอย่างของเล่นเพียงไม่กี่ตัวอย่างและยังต้องผ่านตัวอย่างบางส่วนในแต่ละขั้นตอนของอัลกอริทึมและพูดว่า "ให้ข้อมูลนี้มันสมเหตุสมผลไหมที่ฉันมาอยู่ที่นี่กับสถานะนี้"


1
ดูเหมือนว่าข้อผิดพลาดในการใช้งาน (1) ข้อผิดพลาด (อัลกอริธึมพื้นฐานถูกต้อง แต่ไม่ได้นำไปใช้อย่างถูกต้อง) ซึ่งน่าสนใจ แต่ไม่ใช่ประเด็นของคำถามนี้หรือ (2) ตัวเลือกโดยเจตนา ทำงานได้อย่างรวดเร็วและส่วนใหญ่ แต่อาจล้มเหลวด้วยความน่าจะเป็นที่น้อยมาก (สำหรับรหัสที่ทดสอบกับฐานสุ่มหนึ่งฐานหรือฐานคงที่ / สุ่มสองสามอันฉันหวังว่าใครก็ตามที่เลือกที่จะรู้ว่าพวกเขากำลังทำการแลกเปลี่ยนประสิทธิภาพ)
DW

คุณอยู่ในจุดแรก - อัลกอริทึมที่ถูกต้อง + ข้อผิดพลาดไม่ได้เป็นจุดแม้ว่าการอภิปรายและตัวอย่างอื่น ๆ กำลัง conflating พวกเขาเช่นกัน เขตข้อมูลนั้นเต็มไปด้วยการคาดคะเนที่ทำงานกับจำนวนน้อย แต่ไม่ถูกต้อง สำหรับจุด (2) ที่เป็นจริงสำหรับบางคน แต่ตัวอย่างของฉัน # 1 และ # 3 ไม่ใช่กรณีนี้ - เชื่อว่าอัลกอริทึมถูกต้อง (ฐาน 5 เหล่านี้ให้ผลลัพธ์ที่พิสูจน์แล้วสำหรับตัวเลขที่ต่ำกว่า 10 ^ 16) หลังจากนั้น ค้นพบว่ามันไม่ได้
DanaJ

นี่ไม่ใช่ปัญหาพื้นฐานของการทดสอบหลอกเทียมหรือไม่?
asmeurer

asmeurer ใช่ใน # 2 ของฉันและการอภิปรายในภายหลังของพวกเขา แต่ # 1 และ # 3 เป็นทั้งสองกรณีของการใช้ Miller-Rabin กับฐานที่รู้จักกันเพื่อให้ผลลัพธ์ที่ถูกต้องกำหนดไว้ต่ำกว่าเกณฑ์ ดังนั้นในกรณีนี้ "อัลกอริทึม" (การใช้คำอย่างหลวม ๆ เพื่อให้ตรงกับ OP) ไม่ถูกต้อง # 4 ไม่ใช่การทดสอบที่น่าจะเป็นไปได้ แต่ DW ชี้ให้เห็นว่าอัลกอริทึมทำงานได้ดีมันเป็นเพียงการติดตั้งที่ยาก ฉันรวมไว้เพราะมันนำไปสู่สถานการณ์ที่คล้ายกัน: จำเป็นต้องมีการทดสอบและไกลแค่ไหนที่คุณจะไปไกลกว่าตัวอย่างง่ายๆก่อนที่คุณจะพูดว่ามันทำงานอย่างไร
DanaJ

โพสต์ของคุณบางส่วนดูเหมือนจะพอดีกับคำถามในขณะที่บางโพสต์ไม่ได้ (ความคิดเห็นของ cf @ DW) โปรดลบตัวอย่าง (และเนื้อหาอื่น ๆ ) ที่ไม่ตอบคำถาม
ราฟาเอล

7

Fisher-Yates-Knuth ขั้นตอนวิธีการสับเป็น (ปฏิบัติ) ตัวอย่างและหนึ่งในซึ่งหนึ่งในนักเขียนของเว็บไซต์นี้มีความเห็นเกี่ยวกับ

อัลกอริทึมสร้างการเปลี่ยนลำดับแบบสุ่มของอาร์เรย์ที่กำหนดดังนี้:

 // To shuffle an array a of n elements (indices 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]

ij0ji

อัลกอริทึม "ไร้เดียงสา" อาจเป็น:

 // To shuffle an array a of n elements (indices 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ n-1
       exchange a[j] and a[i]

องค์ประกอบที่จะสลับถูกเลือกจากองค์ประกอบทั้งหมดที่มีอยู่ อย่างไรก็ตามเรื่องนี้ทำให้เกิดการสุ่มตัวอย่างลำเอียงของพีชคณิต (บางคนเป็นตัวแทน - ฯลฯ )

จริงหนึ่งสามารถมาขึ้นกับสับ Fisher-Yates-knuth ใช้ง่าย (หรือไร้เดียงสา) การวิเคราะห์การนับ

nn!=n×n1×n2..nn1

ปัญหาหลักในการตรวจสอบว่าอัลกอริธึมการสับเปลี่ยนนั้นถูกต้องหรือไม่ ( ลำเอียงหรือไม่ ) นั้นเป็นเพราะสถิติทำให้ต้องมีตัวอย่างจำนวนมาก บทความ codinghorrorฉันเชื่อมโยงดังกล่าวข้างต้นอธิบายว่าที่ (และกับการทดสอบจริง)


1
ดูที่นี่สำหรับตัวอย่างการพิสูจน์ความถูกต้องสำหรับอัลกอริทึมแบบสุ่ม
ราฟาเอล

5

ตัวอย่างที่ดีที่สุด (อ่าน: สิ่งที่ฉันเจ็บปวดที่สุด) ที่ฉันเคยเห็นเกี่ยวกับการคาดคะเนโคลลาตซ์. ฉันอยู่ในการแข่งขันเขียนโปรแกรม (โดยมีรางวัล 500 ดอลล่าร์ในบรรทัดแรก) ซึ่งปัญหาอย่างหนึ่งคือการหาจำนวนขั้นต่ำของขั้นตอนที่ต้องใช้เพื่อให้ตัวเลขสองตัวถึงจำนวนเดียวกัน การแก้ปัญหาของหลักสูตรคือการสลับแต่ละขั้นตอนจนกว่าพวกเขาทั้งสองจะเข้าถึงสิ่งที่เคยเห็นมาก่อน เราได้รับช่วงของตัวเลข (ฉันคิดว่ามันอยู่ระหว่าง 1 ถึง 1000000) และบอกว่าการคาดคะเนโคลลาตซ์ได้รับการยืนยันถึง 2 ^ 64 ดังนั้นตัวเลขทั้งหมดที่เราได้รับจะมาบรรจบกันที่ 1 ในที่สุดฉันใช้ 32 บิต จำนวนเต็มที่ต้องทำตามขั้นตอนด้วย ปรากฎว่ามีหนึ่งหมายเลขชัดเจนระหว่าง 1 และ 1000000 (170,000 บางสิ่ง) ที่จะทำให้จำนวนเต็ม 32 บิตเพื่อล้นในเวลาที่กำหนด อันที่จริงตัวเลขเหล่านี้เป็นเสียงร้องที่หายากมาก 2 ^ 31 เราทดสอบระบบของเราสำหรับตัวเลขจำนวนมากที่มากกว่า 1000000 เพื่อ "มั่นใจ" ว่าการล้นไม่เกิดขึ้น ปรากฎว่ามีจำนวนน้อยกว่าที่เราไม่ได้ทดสอบทำให้เกิดการล้น เพราะฉันใช้ "int" แทน "long" ฉันได้รับรางวัลเพียง $ 300 แทนที่จะเป็น $ 500


5

เป้ 0/1ปัญหาเป็นสิ่งหนึ่งที่เกือบทุกนักเรียนคิดว่าแก้ปัญหาได้โดยธึม ที่เกิดขึ้นบ่อยครั้งมากขึ้นถ้าคุณก่อนหน้านี้แสดงให้เห็นการแก้ปัญหาโลภบางรุ่นที่เป็นปัญหาของเป้ที่โลภงานอัลกอริทึม

สำหรับปัญหาเหล่านั้นในชั้นเรียนฉันควรแสดงข้อพิสูจน์สำหรับเป้ 0/1 ( การเขียนโปรแกรมแบบไดนามิก ) เพื่อลบข้อสงสัยใด ๆ และสำหรับรุ่นปัญหาโลภด้วย จริงๆแล้วหลักฐานทั้งสองอย่างนั้นไม่สำคัญและนักเรียนอาจพบว่าพวกเขามีประโยชน์มาก นอกจากนี้ยังมีการแสดงความคิดเห็นเกี่ยวกับเรื่องนี้ในCLRS 3ed , บทที่ 16, หน้า 425-427

ปัญหา: ขโมยปล้นร้านค้าและสามารถบรรทุกน้ำหนัก W สูงสุดไว้ในกระเป๋าเป้สะพายหลังได้ มี n รายการและรายการที่มีน้ำหนัก wi และมีมูลค่า vi ดอลลาร์ สิ่งของที่โจรควรใช้ เพื่อเพิ่มผลประโยชน์ของเขา ?

ปัญหาเป้ 0/1 : การตั้งค่าเหมือนกัน แต่ไอเท็มอาจไม่แตกเป็นชิ้นเล็กดังนั้นโจรอาจตัดสินใจเลือกที่จะเอาไอเทมหรือปล่อยทิ้งไว้ (เลือกไบนารี) แต่อาจไม่ได้เศษเสี้ยวของไอเทม .

และคุณสามารถหาแนวคิดหรืออัลกอริทึมจากนักเรียนที่ทำตามแนวคิดเดียวกันกับปัญหารุ่นโลภนั่นคือ:

  • ใช้ความจุทั้งหมดของกระเป๋าแล้วใส่วัตถุที่มีค่ามากที่สุดเท่าที่จะเป็นไปได้และวนวิธีนี้จนกว่าคุณจะไม่สามารถใส่วัตถุเพิ่มเติมได้เนื่องจากถุงเต็มหรือไม่มีสิ่งของที่มีน้ำหนักน้อยกว่าสำหรับใส่ในกระเป๋า
  • วิธีคิดที่ผิดวิธีอื่น ๆ คือนำสิ่งของที่มีน้ำหนักเบาและใส่ของเหล่านี้ไว้สูงที่สุดถึงราคาต่ำสุด
  • ...

มีประโยชน์สำหรับคุณไหม? ที่จริงแล้วเรารู้ว่าปัญหาเหรียญเป็นรุ่นที่มีปัญหาเครื่องหลัง แต่มีตัวอย่างเพิ่มเติมในป่าของปัญหาเป้โดยตัวอย่างสิ่งที่เกี่ยวกับเป้ 2D (ที่เป็นประโยชน์จริงเมื่อคุณต้องการตัดไม้สำหรับทำเฟอร์นิเจอร์ผมเห็นในท้องถิ่นจากเมืองของฉัน) มันเป็นเรื่องธรรมดาคิดว่า โลภทำงานที่นี่เช่นกัน แต่ไม่ใช่


โลภถูกครอบคลุมไปแล้วในคำตอบที่ยอมรับแต่ปัญหาเครื่องหลังโดยเฉพาะอย่างยิ่งเหมาะที่จะตั้งกับดักบางอย่าง
ราฟาเอล

3

ข้อผิดพลาดทั่วไปคือการใช้อัลกอริทึมการสับผิด ดูการอภิปรายเกี่ยวกับวิกิพีเดีย

n!nn(n1)n


1
มันเป็นข้อผิดพลาดที่ดี แต่ไม่ใช่ตัวอย่างที่ดีในการหลอกกรณีทดสอบฮิวริสติกเนื่องจากการทดสอบไม่ได้นำไปใช้กับอัลกอริทึมแบบสับได้ (เป็นการสุ่มดังนั้นคุณจะทดสอบได้อย่างไรมันจะมีผลอย่างไรกับกรณีทดสอบ คุณจะตรวจจับสิ่งนั้นได้อย่างไรจากการดูผลลัพธ์?)
DW

คุณทดสอบสถิติอย่างแน่นอน ความสม่ำเสมอของการสุ่มอยู่ไกลจาก "อะไรก็ตามที่สามารถเกิดขึ้นได้ในผลลัพธ์" คุณจะไม่ต้องสงสัยถ้าโปรแกรมที่กล่าวว่าเลียนแบบลูกเต๋าให้จำนวน 100 3 ต่อเนื่องกันหรือไม่?
ต่อ Alexandersson

อีกครั้งฉันกำลังพูดถึงนักเรียน heuristic ของ "ลองกรณีทดสอบด้วยมือ" ฉันเคยเห็นนักเรียนหลายคนคิดว่านี่เป็นวิธีที่สมเหตุสมผลในการตรวจสอบว่าอัลกอริทึมที่กำหนดขึ้นถูกต้องหรือไม่ แต่ฉันคิดว่าพวกเขาจะไม่คิดว่ามันเป็นวิธีที่ดีในการทดสอบว่าอัลกอริทึมแบบสับได้ถูกต้องหรือไม่ ไม่มีวิธีที่จะบอกได้ว่าผลลัพธ์ที่ถูกต้องใด ๆ ไม่ว่าในกรณีใดคุณไม่สามารถยกตัวอย่างด้วยมือได้อย่างเพียงพอที่จะทำการทดสอบทางสถิติที่มีประโยชน์) ดังนั้นฉันไม่คิดว่าอัลกอริธึมการสับจะช่วยแก้ไขความเข้าใจผิดทั่วไปได้มากนัก
DW

1
@PerAlexandersson: แม้ว่าคุณจะสร้างเพียงสับเปลี่ยนเพียงครั้งเดียวมันไม่สามารถสุ่มโดยใช้ MT กับ n> 2080 ตอนนี้ค่าเบี่ยงเบนจากที่คาดไว้จะน้อยมากดังนั้นคุณอาจไม่สนใจ ... แต่สิ่งนี้ถึงแม้ว่า คุณสร้างน้อยกว่าระยะเวลา (ตามที่ผู้ให้คะแนนชี้ไว้ด้านบน)
ชาร์ลส์

2
คำตอบนี้ดูเหมือนจะล้าสมัยไปแล้วจากคำตอบที่ละเอียดอ่อนกว่าของ Nikos M. ?
ราฟาเอล

2

Pythons PEP450ที่นำเสนอฟังก์ชันสถิติในไลบรารีมาตรฐานอาจเป็นที่สนใจ ในฐานะที่เป็นส่วนหนึ่งของเหตุผลในการมีฟังก์ชั่นที่คำนวณความแปรปรวนในห้องสมุดมาตรฐานของไพ ธ อนผู้เขียน Steven D'Aprano เขียน:

def variance(data):
        # Use the Computational Formula for Variance.
        n = len(data)
        ss = sum(x**2 for x in data) - (sum(data)**2)/n
        return ss/(n-1)

ด้านบนดูเหมือนจะถูกต้องกับการทดสอบแบบไม่เป็นทางการ:

>>> data = [1, 2, 4, 5, 8]
>>> variance(data)
  7.5

แต่การเพิ่มค่าคงที่ทุกจุดข้อมูลไม่ควรเปลี่ยนค่าความแปรปรวน:

>>> data = [x+1e12 for x in data]
>>> variance(data)
  0.0

และความแปรปรวนไม่ควรเป็นค่าลบ:

>>> variance(data*100)
  -1239429440.1282566

ปัญหาเกี่ยวกับตัวเลขและความแม่นยำในการสูญหาย หากคุณต้องการความแม่นยำสูงสุดคุณจะต้องสั่งการปฏิบัติการของคุณด้วยวิธีใดวิธีหนึ่ง การนำไปใช้ที่ไร้เดียงสานำไปสู่ผลลัพธ์ที่ไม่ถูกต้องเนื่องจากการไม่แม่นยำมีขนาดใหญ่เกินไป นั่นเป็นปัญหาอย่างหนึ่งที่ฉันเรียนเกี่ยวกับตัวเลขที่มหาวิทยาลัย


1
n1

2
@ ราฟาเอล: แม้ว่าจะยุติธรรม แต่อัลกอริทึมที่เลือกนั้นเป็นที่รู้จักกันดีว่าเป็นตัวเลือกที่ไม่ดีสำหรับข้อมูลเลขทศนิยม

2
มันไม่เพียงเกี่ยวกับการใช้งานการดำเนินการเกี่ยวกับตัวเลขและความแม่นยำของการสูญเสีย หากคุณต้องการความแม่นยำสูงสุดคุณจะต้องสั่งการปฏิบัติการของคุณด้วยวิธีใดวิธีหนึ่ง นั่นเป็นปัญหาอย่างหนึ่งที่ฉันเรียนเกี่ยวกับตัวเลขที่มหาวิทยาลัย
Christian

นอกจากความเห็นที่ถูกต้องของราฟาเอลแล้วการขาดตัวอย่างนี้คือฉันไม่คิดว่าการพิสูจน์ความถูกต้องจะช่วยหลีกเลี่ยงข้อบกพร่องนี้ได้ หากคุณไม่ทราบเกี่ยวกับรายละเอียดปลีกย่อยของเลขทศนิยมคุณอาจคิดว่าคุณได้พิสูจน์แล้วว่าถูกต้อง (โดยพิสูจน์ว่าสูตรนั้นถูกต้อง) ดังนั้นจึงไม่ใช่ตัวอย่างที่ดีในการสอนนักเรียนว่าเหตุใดการพิสูจน์อัลกอริทึมให้ถูกต้องจึงเป็นสิ่งสำคัญ หากนักเรียนเห็นตัวอย่างนี้ความสงสัยของฉันคือพวกเขาจะวาดบทเรียนแทน "การคำนวณคะแนนแบบลอยตัว / ตัวเลขเป็นเรื่องยุ่งยาก"
DW

1

แม้ว่านี่จะไม่ใช่สิ่งที่คุณต้องการ แต่ก็เป็นเรื่องง่ายที่จะเข้าใจและทดสอบกรณีเล็ก ๆ โดยที่ไม่ต้องคิดอะไรเลยจะนำไปสู่อัลกอริทึมที่ไม่ถูกต้อง

nn2+n+410<dd divides n2+n+41d<n2+n+41

โซลูชันที่เสนอ :

int f(int n) {
   return 1;
}

n=0,1,2,,39n=40

"ลองบางกรณีเล็ก ๆ และสรุปอัลกอริธึมจากผลลัพธ์" เข้าหาพืชผลบ่อยขึ้น (แม้ว่าจะไม่มากเท่าที่นี่) ในการแข่งขันการเขียนโปรแกรมซึ่งความกดดันจะเกิดขึ้นกับอัลกอริทึมที่ (a) รวดเร็วในการนำไปใช้ ) มีเวลาทำงานที่รวดเร็ว


5
ผมไม่คิดว่านี่เป็นตัวอย่างที่ดีมากเพราะไม่กี่คนที่จะพยายามที่จะหาตัวหารของพหุนามโดยกลับ 1
ไบรอัน S

1
nn3n

สิ่งนี้อาจมีความเกี่ยวข้องในแง่ที่ว่าการคืนค่าคงที่สำหรับตัวหาร (หรือการคำนวณอื่น) อาจเป็นผลมาจากวิธีการอัลกอริทึมที่ผิดไปสู่ปัญหา (ตัวอย่างเช่นปัญหาทางสถิติหรือไม่จัดการขอบกรณีของอัลกอริธึม) อย่างไรก็ตามคำตอบนั้นจำเป็นต้องมีการปรับคำตอบ
Nikos M.

@NikosM หึ ฉันรู้สึกว่าฉันกำลังจะตายม้าที่นี่ แต่ย่อหน้าที่สองของคำถามบอกว่า "หากอัลกอริทึมของพวกเขาทำงานอย่างถูกต้องกับตัวอย่างจำนวนหนึ่งรวมถึงกรณีมุมทั้งหมดที่พวกเขาสามารถคิดได้ลองพวกเขาจึงสรุปว่า ถูกต้องมีนักเรียนเสมอที่ถามว่า: "ทำไมฉันต้องพิสูจน์อัลกอริทึมของฉันให้ถูกต้องถ้าฉันสามารถลองในกรณีทดสอบสองสามกรณี" ในกรณีนี้สำหรับค่า 40 ค่าแรก (มากกว่านักเรียนคือ น่าจะลอง) คืน 1 ถูกต้องดูเหมือนว่าฉันจะเป็นสิ่งที่ OP กำลังมองหา
Rick Decker

ตกลงใช่ แต่นี่เป็นประโยคที่ไม่สำคัญ (อาจเป็นเรื่องปกติ) แต่ไม่ใช่ในจิตวิญญาณของคำถาม ยังคงต้องมีการใช้ถ้อยคำใหม่
Nikos M.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.