'<' กับ '! =' เป็นเงื่อนไขในการวนรอบ 'สำหรับ'?


31

สมมติว่าคุณมีforลูปต่อไปนี้:

for (int i = 0; i < 10; ++i) {
    // ...
}

ซึ่งมันมักจะเขียนด้วย:

for (int i = 0; i != 10; ++i) {
    // ...
}

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

* แก้ตัวการใช้หมายเลขเวทย์มนตร์ แต่เป็นเพียงตัวอย่างเท่านั้น


18
ทางออกที่เหนือกว่าสำหรับทั้งสองวิธีนี้คือการใช้โอเปอเรเตอร์ลูกศร:int i = 10; while(i --> 0) { /* stuff */ }
corsiKa

@ glowcoder โอเปอเรเตอร์ลูกศรเป็นที่ชื่นชอบของฉัน
Carson Myers

3
@ glowcoder ดี แต่มันกลับมาจากด้านหลัง คุณอาจไม่ต้องการสิ่งนั้นเสมอไป

2
@ SuperElectric มันแยกวิเคราะห์เช่นwhile ((i--) > 0)
Kristopher Johnson

17
มีเรื่องราว (อาจไม่มีหลักฐาน) เกี่ยวกับอุบัติเหตุทางอุตสาหกรรมที่เกิดจากการทดสอบลูปสำหรับเซนเซอร์อินพุต! = MAX_TEMP น่าเสียดายที่วันหนึ่งเซ็นเซอร์มีค่าน้อยกว่า MAX_TEMP ถึงมากกว่า MAX_TEMP โดยไม่ผ่าน MAX_TEMP ทุกครั้ง กระบวนการทำให้ร้อนมากเกินไปโดยไม่ถูกตรวจจับและเกิดเพลิงไหม้ บางครั้งมีความแตกต่างระหว่าง! = และ <
Charles E. Grant

คำตอบ:


59

เหตุผลที่จะเลือกอย่างใดอย่างหนึ่งหรือมีที่อื่น ๆ เพราะความตั้งใจและเป็นผลจากการนี้มันจะเพิ่มความสามารถในการอ่าน

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

ความสามารถในการอ่าน: ผลลัพธ์ของการจดบันทึกสิ่งที่คุณหมายถึงคือการเข้าใจได้ง่ายขึ้น ตัวอย่างเช่นหากคุณใช้i != 10บางคนที่อ่านโค้ดอาจสงสัยว่าภายในลูปมีวิธีใดบ้างที่iอาจใหญ่กว่า 10 และลูปควรดำเนินต่อไป (btw: เป็นลักษณะที่ไม่ดีที่จะยุ่งกับตัววนซ้ำที่อื่นในหัว สถานะfor- แต่นั่นไม่ได้หมายความว่าคนไม่ได้ทำและเป็นผลให้ผู้ดูแลคาดหวัง)


3
ไม่ลูปไม่ควรรันตราบใดที่i“ เล็กกว่า 10” แต่ควรรันตราบเท่าที่ยังไม่ถึงขอบบน (ในกรณีนี้) เมื่อมีการใช้ซี ++ ช่วงเวลา / iterator ช่วงเหตุผลก็ไกลตรรกะมากขึ้นในการแสดงนี้ผ่านกว่า!= <
Konrad Rudolph

14
@ Konrad ฉันไม่เห็นด้วยกับเรื่องนี้เลย ประเด็นหลักคือไม่ต้องเป็นคนดื้อรั้น แต่ควรเลือกสิ่งก่อสร้างที่แสดงออกถึงเจตนาของเงื่อนไขได้ดีที่สุด ถ้าคุณเลือกที่จะวนซ้ำสิ่งที่เริ่มต้นที่ 0 และเลื่อนขึ้น<แสดงว่าได้อย่างแม่นยำ
Deckard

6
@ Konrad คุณไม่มีจุด ตัวดำเนินการที่เพิ่มขึ้นในลูปนี้ทำให้เห็นได้ชัดว่าเงื่อนไขลูปเป็นขอบเขตบนไม่ใช่การเปรียบเทียบข้อมูลเฉพาะตัว หากคุณกำลังลดลงมันจะเป็นขอบเขตที่ต่ำกว่า หากคุณวนซ้ำคอลเลกชันที่ไม่ได้สั่งซื้อข้อมูลประจำตัวอาจเป็นเงื่อนไขที่เหมาะสม
Alex Feinman

3
@Alex การเพิ่มขึ้นไม่ใช่จุดของฉัน ช่วงเวลาไม่จำเป็นต้องมีคำสั่งซื้อ มันวนซ้ำไปเรื่อย… บางสิ่งจนกว่ามันจะถึงจุดจบ ตัวอย่างเช่นองค์ประกอบในชุดแฮช ใน C ++ สามารถทำได้โดยใช้ตัววนซ้ำและforวนซ้ำ ใช้<ที่นี่จะโง่ นอกจากนี้เด็คการ์ดดูเหมือนจะยอมรับว่า ฉันเห็นด้วยอย่างมากกับความคิดเห็นของเขาในการตอบสนองต่อฉัน
Konrad Rudolph

1
หมายเหตุถ้าคุณใช้บัฟเฟอร์โรตารีพร้อมตัวชี้การไล่ล่าคุณต้องใช้!=
SF

48

<รูปแบบโดยทั่วไปสามารถใช้งานได้แม้ว่าการเพิ่มขึ้นเกิดขึ้นไม่ว่าจะเป็น 1 ว่า

วิธีนี้ช่วยให้สามารถทำลูปได้โดยไม่ต้องคำนึงถึงว่าจะทำอย่างไร


6
นอกจากนี้ยังช่วยให้iสามารถปรับเปลี่ยนภายในวงได้อย่างปลอดภัยหากต้องการ
Matthew Scharley

1
หรือถ้า 'i' ถูกปรับเปลี่ยนโดยสิ้นเชิงอย่างไม่ปลอดภัย ... ทีมอื่นมีปัญหาเซิร์ฟเวอร์แปลก ๆ มันรายงานการใช้งาน CPU 100% และมันต้องมีปัญหากับเซิร์ฟเวอร์หรือระบบตรวจสอบใช่มั้ย ไม่ฉันพบสภาพลูปที่เขียนโดย 'โปรแกรมเมอร์อาวุโสผู้เชี่ยวชาญ' ซึ่งมีปัญหาเดียวกันกับที่เรากำลังพูดถึง
jqa

12
ยกเว้นว่าไม่สามารถใช้ C ++ สำหรับลูปได้ทั้งหมด<เช่นตัววนซ้ำในลำดับและดังนั้นจึง!=เป็นวิธีการทั่วไปในการวนซ้ำใน C ++
David Thornley

@SnOrfus: ฉันไม่ได้แยกวิเคราะห์ความคิดเห็นนั้น โดยทั่วไปคุณจะไม่ได้รับข้อยกเว้นสำหรับการเพิ่มตัววนซ้ำอย่างน่าเชื่อถือมากเกินไป (แม้ว่าจะมีสถานการณ์ที่เฉพาะเจาะจงมากขึ้นที่คุณจะทำ)
David Thornley

ดีฉันทำตาม<รูปแบบเพราะต้องกดแป้นพิมพ์หนึ่งแทนของทั้งสองที่มีรูปแบบและสี่ด้วย> !=มันเป็นเรื่องของประสิทธิภาพเหมือน OCD จริง ๆ
Spoike

21

ใน C ++ คำแนะนำโดยสก็อตไมเออร์ในการที่มีประสิทธิภาพมากกว่า C ++ (ข้อ 6) อยู่เสมอที่จะใช้สองถ้าคุณมีเหตุผลที่จะไม่เพราะมันหมายความว่าคุณมีไวยากรณ์เดียวกันสำหรับ iterator และจำนวนเต็มดัชนีเพื่อให้คุณสามารถสลับต่อเนื่องระหว่างintและ iterator ไม่มีการเปลี่ยนแปลงในไวยากรณ์ใด ๆ

ในภาษาอื่น ๆ มันใช้ไม่ได้ดังนั้นฉันคิดว่า<น่าจะดีกว่าเพราะประเด็นของThorbjørn Ravn Andersen

อีกวันหนึ่งที่ฉันพูดคุยเรื่องนี้กับผู้พัฒนารายอื่นและเขาบอกว่าเหตุผลที่ชอบ<มากกว่า!=ก็เพราะiอาจเพิ่มขึ้นมากกว่าหนึ่งครั้งโดยไม่ได้ตั้งใจและนั่นอาจทำให้สภาพการแบ่งไม่พบ นั่นคือ IMO เรื่องไร้สาระ


17
"load of nonsense" ... จนกว่าจะถึงวันที่คุณมี i ++ พิเศษในส่วนของ loop

2
+1 โดยเฉพาะอย่างยิ่งสำหรับ“ ภาระไร้สาระ” เพราะเป็น หากร่างกายวนเพิ่มขึ้นเคาน์เตอร์โดยไม่ได้ตั้งใจคุณมีปัญหาที่ใหญ่กว่า
Konrad Rudolph

12
@B Tyler เราเป็นมนุษย์เท่านั้นและมีข้อผิดพลาดที่ใหญ่กว่าเกิดขึ้นมาก่อน พิจารณาว่า<จะเป็นโปรแกรมป้องกันมากกว่า!=นั้น ...

2
@ Thorbjørn Ravn Andersen - ฉันไม่ได้บอกว่าฉันไม่เห็นด้วยกับคุณฉันทำ; <มีการป้องกันมากกว่าและเพื่อนร่วมงานของฉันเกลียดถ้าฉันเขียน!=ดังนั้นฉันไม่ อย่างไรก็ตามมีกรณีสำหรับ!=ใน C ++ และนั่นคือสิ่งที่ฉันได้นำเสนอ

9
สถานการณ์หนึ่งที่หนึ่งสามารถจบลงด้วยการเสริมพิเศษโดยบังเอิญi++คือเมื่อเปลี่ยนห่วงขณะที่เป็นห่วง ไม่แน่ใจว่าการวนซ้ำครึ่งหนึ่งนั้นดีกว่าลูป (ใกล้ -) ที่ไม่มีที่สิ้นสุด หลังอาจทำให้ข้อผิดพลาดชัดเจนขึ้น
ak2

12

การใช้ (i <10) ถือเป็นแนวทางปฏิบัติที่ปลอดภัยกว่า มันจับจำนวนสูงสุดของการเลิกคดีที่อาจเกิดขึ้น - ทุกสิ่งที่มากกว่าหรือเท่ากับ 10 เปรียบเทียบกับกรณีอื่น (i! = 10) มันจะจับได้เฉพาะกรณีการเลิกหนึ่งกรณี - เมื่อฉันคือ 10 เท่านั้น

ผลพลอยได้จากสิ่งนี้คือมันช่วยเพิ่มความสามารถในการอ่าน นอกจากนี้หากการเพิ่มขึ้นเป็นอย่างอื่น 1 มันสามารถช่วยลดโอกาสในการเกิดปัญหาได้ถ้าเราทำผิดพลาดเมื่อเขียนกรณีเลิก

พิจารณา:

1) for (i = 1; i < 14; i+=2)

2) for (i = 1; i != 14; i+=2)

แม้ว่าทั้งสองกรณีมีแนวโน้มที่จะมีข้อบกพร่อง / ไม่ถูกต้อง แต่กรณีที่สองมีแนวโน้มที่จะผิดพลาดมากขึ้นเนื่องจากจะไม่ออก กรณีแรกจะเลิกและมีโอกาสสูงกว่าที่จะออกจากจุดที่ถูกต้องแม้ว่า 14 อาจเป็นหมายเลขผิด (15 อาจจะดีกว่า)


กรณีแรกอาจถูกต้อง! หากคุณต้องการวนซ้ำจำนวนธรรมชาติน้อยกว่า 14 แสดงว่าไม่มีวิธีที่ดีกว่าในการแสดง - การคำนวณขอบเขตบน "เหมาะสม" (13) น่าจะเป็นเรื่องธรรมดา
maaartinus

9

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

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

การwhileวนซ้ำใช้เพื่อดำเนินการต่อในขณะที่ตรงตามเงื่อนไขที่ระบุ หากคุณไม่ได้ประมวลผลตามลำดับคุณอาจต้องการwhileวนรอบแทน การโต้เถียงของ Guard มีความคล้ายคลึงกันที่นี่ แต่การตัดสินใจระหว่าง a whileและforloop ควรเป็นสิ่งที่มีสติมาก การwhileวนซ้ำนั้นไม่นิยมใน IMO ของแวดวง C ++

หากคุณกำลังประมวลผลคอลเลกชันของรายการ (การforใช้งานทั่วไป - ลูป) คุณควรใช้วิธีการเฉพาะเพิ่มเติม น่าเสียดายที่std::for_eachC ++ ค่อนข้างจะเจ็บปวดด้วยเหตุผลหลายประการ ในหลายกรณีการแยกลำตัวของforลูปในฟังก์ชั่นยืนฟรี (ในขณะที่ค่อนข้างเจ็บปวด) ส่งผลในการแก้ปัญหาที่สะอาดมากขึ้น เมื่อทำงานร่วมกับคอลเลกชัน, พิจารณาstd::for_each, หรือstd::transform std::accumulate การใช้อัลกอริธึมหลายอย่างกระชับและชัดเจนเมื่อแสดงในลักษณะนี้ ไม่ต้องพูดถึงว่าการแยกลำตัวของวงออกเป็นฟังก์ชัน / วิธีแยกต่างหากจะบังคับให้คุณจดจ่อกับอัลกอริทึมข้อกำหนดการป้อนข้อมูลและผลลัพธ์

หากคุณกำลังใช้ Java, Python, Ruby, หรือแม้กระทั่งC ++ 0xแล้วคุณควรจะใช้คอลเลกชันที่เหมาะสมforeachห่วง เนื่องจากคอมไพเลอร์ C ++ ใช้คุณสมบัตินี้จำนวนforลูปจะหายไปเช่นเดียวกับการสนทนาประเภทนี้


2
"อย่างไรก็ตามการใช้โอเปอเรเตอร์ที่ จำกัด น้อยกว่านั้นเป็นสำนวนการตั้งโปรแกรมการป้องกันที่พบบ่อยมาก ผลรวมนี้จะมากหรือน้อย
James P.

+1 สำหรับ discussin ความแตกต่างในความตั้งใจที่มีการเปรียบเทียบกับwhile, forและforeach(หรือ equivilant ภาษา)
เควิน Peno

พูดอย่างเคร่งครัดห่วงถูกนำมาใช้เพื่อดำเนินการต่อการประมวลผลจนกว่าเงื่อนไขที่เฉพาะเจาะจงจะไม่ได้พบกันwhile
Alnitak

@Alnitak - D'oh ... ฉันจะแก้ไขมัน :)
D.Shawley

ฉันสับสนโดยความหมายที่เป็นไปได้สองข้อของ "การ จำกัด น้อยลง": มันอาจอ้างถึงโอเปอเรเตอร์ที่ผ่อนปรนในค่าที่มันผ่าน ( <) หรือโอเปอเรเตอร์ที่ผ่อนปรนในค่าที่ล้มเหลว ( !=)
Mateen Ulhaq

4

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


2

เหตุผลหนึ่งที่ฉันชอบless thanมากกว่าnot equalsคือการทำหน้าที่เป็นยาม ในบางสถานการณ์ที่ จำกัด (การเขียนโปรแกรมไม่ดีหรือการฆ่าเชื้อ) not equalsสามารถข้ามได้ในขณะที่less thanยังคงมีผลอยู่

นี่คือตัวอย่างหนึ่งที่การขาดการตรวจสอบการฆ่าเชื้อทำให้เกิดผลลัพธ์แปลก ๆ : http://www.michaeleisen.org/blog/?p=358


0

นี่คือเหตุผลหนึ่งที่คุณอาจชอบใช้มากกว่า< !=หากคุณกำลังใช้ภาษาที่มีการกำหนดขอบเขตตัวแปรทั่วโลกเป็นสิ่งที่เกิดขึ้นถ้าปรับเปลี่ยนรหัสอื่น ๆi? หากคุณกำลังใช้งาน<มากกว่า!=สิ่งที่แย่ที่สุดที่เกิดขึ้นคือการทำซ้ำเสร็จเร็วกว่า: อาจเพิ่มรหัสอื่น ๆiโดยบังเอิญและคุณข้ามการทำซ้ำสองสามครั้งใน for for loop แต่จะเกิดอะไรขึ้นถ้าคุณวนลูป 0 ถึง 10 และลูปถึง 9 และการเพิ่มจำนวนเธรดที่เขียนไม่ดีiด้วยเหตุผลแปลก ๆ จากนั้นการวนซ้ำของคุณจะเสร็จสิ้นการวนซ้ำและการเพิ่มขึ้นiเพื่อให้ค่าอยู่ในขณะนี้ 11 เนื่องจากการวนซ้ำได้ข้ามเงื่อนไขการออก ( iไม่เท่ากับ 10) มันจะวนซ้ำไม่สิ้นสุด

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


3
แน่นอนว่านี่เป็นข้อโต้แย้งที่สมบูรณ์แบบสำหรับแต่ละลูปและรูปแบบการเขียนโปรแกรมที่ใช้งานได้มากกว่าโดยทั่วไป แต่ทำไมคุณถึงอยากทำเช่นนั้นเมื่อตัวแปรที่ผันแปรได้นั้นสนุกกว่านี้มาก!
Tom Morris

3
ฉันไม่คิดว่าเป็นเหตุผลที่ดีชะมัด ในแบบที่คุณมีข้อผิดพลาดที่ต้องพบและแก้ไข แต่วนรอบไม่สิ้นสุดมีแนวโน้มที่จะทำให้บั๊กค่อนข้างชัดเจน
ak2

0

ในโลกที่ฝังตัวโดยเฉพาะอย่างยิ่งในสภาพแวดล้อมที่มีเสียงดังคุณไม่สามารถวางใจได้ว่า RAM จะต้องทำงานตามที่ควรจะเป็น ในเงื่อนไข (สำหรับในขณะที่ถ้า) ที่คุณเปรียบเทียบโดยใช้ '==' หรือ '! =' คุณมักจะเสี่ยงต่อการที่ตัวแปรของคุณข้ามค่าที่สำคัญที่ยุติลูป - สิ่งนี้อาจมีผลกระทบร้ายแรง - Mars Lander ผลกระทบระดับ การใช้ '<' หรือ '>' ในเงื่อนไขจะช่วยเพิ่มระดับความปลอดภัยในการจับ 'unknowns unknown'

ในตัวอย่างดั้งเดิมหากiถูกอธิบายอย่างไม่ถูกต้องกับค่าที่มากกว่า 10 การเปรียบเทียบ '<' จะจับข้อผิดพลาดทันทีและออกจากลูป แต่ '! =' จะนับต่อไปเรื่อยiๆจนกว่าจะผ่านรอบ 0 และย้อนหลัง ถึง 10


2
มีรูปแบบอื่นที่เกี่ยวข้องกับรหัสเช่นfor (i=4; i<length; i++) csum+=dat[i];ที่ซึ่งแพ็กเก็ตที่ถูกกฎหมายจะมีlengthอย่างน้อยสี่รายการ แต่หนึ่งอาจได้รับแพ็คเก็ตที่เสียหาย หากประเภทแพ็คเก็ตที่แตกต่างกันมีข้อกำหนดความยาวแตกต่างกันเราอาจต้องการตรวจสอบความยาวซึ่งเป็นส่วนหนึ่งของการประมวลผลที่แตกต่างกันสำหรับประเภทแพ็คเก็ตแต่ละประเภท แต่ตรวจสอบความถูกต้องของเช็คซัมเป็นส่วนหนึ่ง หากได้รับแพ็คเก็ตที่มีความยาวต่ำกว่าจะไม่สำคัญว่าการคำนวณการตรวจสอบจะรายงานว่า "ดี" หรือ "ไม่ดี" แต่ไม่ควรผิดพลาด
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.