การพิจารณาว่าตัวเลขเป็นผลคูณของสิบหรือภายในช่วงที่กำหนด


104

ฉันมีสองสามลูปที่ฉันต้องการในโปรแกรมของฉัน ฉันสามารถเขียนรหัสหลอกได้ แต่ฉันไม่แน่ใจว่าจะเขียนอย่างไรอย่างมีเหตุผล

ฉันต้องการ -

if (num is a multiple of 10) { do this }

if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90

เกมนี้มีไว้สำหรับเกมกระดานบันไดงูถ้ามันสมเหตุสมผลกว่าสำหรับคำถามของฉัน

ฉันคิดว่าคำสั่งifแรกฉันต้องใช้โมดูลัส จะif (num == 100%10)ถูกต้องหรือไม่?

อันที่สองฉันไม่รู้ ฉันเขียนออกมาได้เหมือนif (num > 10 && num is < 21 || etc.)แต่มันต้องมีอะไรที่ฉลาดกว่านั้น


16
โดยทั่วไปความยาวของรหัสที่ดีจะเป็นสัดส่วนกับความยาวของภาษาอังกฤษที่อธิบายถึงสิ่งที่มันทำ ดังนั้นเมื่อ "ข้อมูลจำเพาะ" ของคุณระบุว่า 11-20, 31-40, 51-60, 71-80, 91-100 คุณสามารถคาดหวังว่ารหัสของคุณจะกล่าวถึงตัวเลขเหล่านั้นด้วย หากตัวเลขเหล่านั้นมาจากที่ใดที่หนึ่งหรือสร้างขึ้นด้วยเหตุผลบางประการให้ดูว่าคุณสามารถเขียนรหัสเหตุผลแทนตัวเลขได้หรือไม่
luqui

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

2
@AmadeusDrZaius - ฉันทำแบบเดียวกันแทบไม่ได้ แต่สำหรับส่วนที่สำคัญด้านประสิทธิภาพเท่านั้น ห่วงที่แน่นที่สุดที่เรียกว่า 100 ล้านครั้งมีคุณสมบัติ - คำสั่ง if ในเกมงูและบันไดไม่มี จุดที่คุณลากเส้นระหว่างพวกเขาเป็นทางเลือกส่วนตัว
Floris

2
ฉันเกลียดที่จะพูดมัน แต่หลังจากทำงานขององค์กรมามากพอแล้วกับผู้เริ่มต้นเขียนโค้ดจริงฉันต้องแนะนำให้ใช้เดรัจฉานบังคับ เพราะงั้นคนใหม่จะเข้าใจและจะไม่ทำลายมัน เศร้า แต่จริง - ในบางกรณีมันฉลาดที่จะโง่
Richard Le Mesurier

22
นี่เป็นคำถามที่ดีและฉันไม่อยากเอาอะไรออกไปจากโปสเตอร์เลย แต่นี่ไม่สมควรได้รับคะแนนมากกว่า 500 คะแนน นี่คือวิธีที่เราจบลงด้วยเรื่องไร้สาระบางอย่างที่เราทำกับผู้คนที่มีคะแนนนับพันที่ดูเหมือนจะเป็นเจ้าหน้าที่ที่นี่ (อย่าลังเลที่จะย้ายความคิดเห็นนี้หากเป็นที่อื่น)
GaTechThomas

คำตอบ:


87

สำหรับหมายเลขแรกหากต้องการตรวจสอบว่าตัวเลขสามารถใช้ได้หลายครั้งหรือไม่:

if (num % 10 == 0) // It's divisible by 10

สำหรับอันที่สอง:

if(((num - 1) / 10) % 2 == 1 && num <= 100)

แต่ค่อนข้างหนาแน่นและคุณอาจจะดีกว่าเพียงแค่ระบุตัวเลือกอย่างชัดเจน


ตอนนี้คุณเข้าใจดีขึ้นแล้วว่าคุณกำลังทำอะไรอยู่ฉันจะเขียนเรื่องที่สองเป็น:

   int getRow(int num) {
      return (num - 1) / 10;
   }

   if (getRow(num) % 2 == 0) {
   }

มันเป็นตรรกะเดียวกัน แต่การใช้ฟังก์ชันทำให้เราเข้าใจชัดเจนขึ้นว่ามันหมายถึงอะไร


79
if((num - 1) / 10) % 2 == 1 && num < 100)- ฉันจะร้องไห้ถ้าเห็นแบบนั้น
Daniel Kamil Kozar

32
@DanielKamilKozar เท่าที่ควร
Winston Ewert

2
@ user3419168 เพียงแค่ตัวมันเองทำให้คนสงสัยว่ามันหมายถึงอะไรในโลกนี้ ไม่ได้ให้คำแนะนำว่าในโลกนี้พยายามจะทำอะไร นั่นเป็นเหตุผลว่าทำไมในการแก้ไขฉันจึงแสดงเวอร์ชันที่แยกตรรกะออกเป็นฟังก์ชันซึ่งทำให้ชัดเจนขึ้นว่าการคำนวณกำลังทำอะไรอยู่
Winston Ewert

3
อาจเป็นการระมัดระวังที่จะยืนยันnum >= 11ว่าเป็น (1) ว่าขีด จำกัด ล่างถูกสั่งห้ามและ (2) %บนจำนวนลบจะส่งกลับจำนวนลบเช่นกัน (ต้องยอมรับว่าใช้& 1ที่นี่ "ปลอดภัยกว่า" แต่ก็ถือว่าได้ความรู้เพิ่มเติมด้วย)
usr2564301

2
+1 สำหรับการแก้ไขจะอธิบายถึงสาเหตุของรายการช่วงและนำเสนอในลักษณะที่อ่านได้ IMO ขั้นตอนหนึ่งคือgetRow(num) % 2 == 0การรวมฟังก์ชันไว้ด้วยเพื่อให้ชัดเจนว่าเจตนาคืออะไร bool inEvenRow(int num){ return getRow(num) % 2 ==0;}
Mr.Mindor

40

ถ้า (num คือผลคูณของ 10) {do this}

if (num % 10 == 0) {
  // Do something
}

ถ้า (ตัวเลขอยู่ภายใน 11-20, 31-40, 51-60, 71-80, 91-100) {do this}

เคล็ดลับที่นี่คือการมองหาความเหมือนกันระหว่างช่วงต่างๆ แน่นอนคุณสามารถใช้วิธี "brute force" ได้เสมอ:

if ((num > 10 && num <= 20) ||
    (num > 30 && num <= 40) ||
    (num > 50 && num <= 60) ||
    (num > 70 && num <= 80) ||
    (num > 90 && num <= 100)) {
  // Do something
}

แต่คุณอาจสังเกตเห็นว่าถ้าคุณลบ1จากnumคุณจะมีช่วง:

10-19, 30-39, 50-59, 70-79, 90-99

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

if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
  // Do something
}

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

ช่วยสมมติว่านักพัฒนาคนต่อไปที่ทำงานกับโค้ดนั้นมีอาวุธและรู้ว่าคุณอาศัยอยู่ที่ไหน :-)


7
ฉันยังคงใช้รหัสที่ชาญฉลาด แต่เปลี่ยนเป็นรหัสที่บำรุงรักษาได้โดยการแยกฟังก์ชัน มันจะอ่านได้พอ ๆ กันถ้าบิตสุดท้ายพูด&& isTensDigitOdd(num)บางทีอาจจะมีข้อคิดเห็นก่อนหน้าที่จะอธิบายว่ามันทำอะไร หากมีรูปแบบดังกล่าวความคิดเห็นที่อธิบายเหตุผลของรูปแบบนั้นจะให้ความกระจ่างสำหรับการบำรุงรักษา
chris

3
Chris นั่นเป็นกลยุทธ์ที่ยอดเยี่ยมเมื่อ "ความฉลาด" มีข้อได้เปรียบที่ชัดเจน: รหัสที่สั้นกว่ามาก (ซึ่งหมายถึงโอกาสที่จะพิมพ์ผิดน้อยลงโดยเฉพาะอย่างยิ่งหากมีการเปลี่ยนแปลง) หรือมีการปรับปรุงประสิทธิภาพอย่างมาก มีการแลกเปลี่ยนระหว่างความกะทัดรัดความชัดเจนและประสิทธิภาพเกือบตลอดเวลาและการค้นหาการประนีประนอมที่ดีเป็นทักษะที่ดีในการพัฒนา (ดูstackoverflow.com/a/2151844/29157สำหรับ snicker)
Adam Liss

1
นี่เป็นแนวทางที่ดีกว่ามาก เข้าใจง่ายกว่า 'รหัสฉลาด' มากและความแตกต่างของประสิทธิภาพอาจเล็กน้อย
user1477388

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

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

30

หากคุณใช้ GCC หรือคอมไพเลอร์ใด ๆ ที่รองรับช่วงเคสคุณสามารถทำได้ แต่โค้ดของคุณจะไม่พกพาได้

switch(num)
{
case 11 ... 20:
case 31 ... 40:
case 51 ... 60:
case 71 ... 80:
case 91 ... 100:
    // Do something
    break;
default:
    // Do something else
    break;
}

1
คุณช่วยบอกฉันได้ไหมว่าทำไมโค้ดนี้ถึงไม่พกพา
M Sharath Hegde

8
@MSharathHegde เพราะต้องใช้ส่วนขยาย GCC ซึ่งไม่ใช่ส่วนหนึ่งของมาตรฐานและคอมไพเลอร์บางตัวไม่รองรับ
Bryan Chen

5
นี่เป็นคำตอบที่ถูกต้องเพราะมันชัดเจนทันทีว่าเจตนาคืออะไร คำตอบที่ 'ฉลาด' ทั้งหมดของโมดูโล่เป็นฝันร้ายในการบำรุงรักษาแม้จะมีความคิดเห็นก็ตาม
smirkingman

@smirkingman นั่นคือสิ่งที่ฉันพูดในความคิดเห็นของฉันต่อคำถามหลัก ต้องใช้ประสบการณ์ของผู้เขียนโค้ดใหม่ในงานขององค์กรเพื่อให้ตระหนักว่าวิธีที่ชัดเจนมักจะดีกว่าวิธีที่ชาญฉลาดของนินจา
Richard Le Mesurier

15

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

template<typename It, typename Elem>
bool in_any_interval(It first, It last, const Elem &val) {
    return std::any_of(first, last, [&val](const auto &p) {
        return p.first <= val && val <= p.second;
    });
}

เพื่อความง่ายฉันใช้แลมบ์ดาแบบหลายตัว (C ++ 14) แทนpairอาร์กิวเมนต์ที่ชัดเจน สิ่งนี้ควรยึดติดกับการใช้งาน<และ==เพื่อให้สอดคล้องกับอัลกอริทึมมาตรฐาน แต่จะทำงานเช่นนี้ตราบเท่าที่Elemได้<=กำหนดไว้ อย่างไรก็ตามสามารถใช้งานได้ดังนี้:

std::pair<int, int> intervals[]{
    {11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100}
};

const int num = 15;
std::cout << in_any_interval(std::begin(intervals), std::end(intervals), num);

มีตัวอย่างจริงเป็นที่นี่


โซลูชันที่เรียบร้อย ฉันอาจจะใช้อาร์เรย์เดียวเนื่องจากคุณสามารถจัดรูปแบบด้วยตัวเลข 2 ตัวต่อบรรทัดเพื่อแทนคู่
Kevin Lam

@ HunterGuy2 จุดที่ดีมาก ฉันกำลังจะเปลี่ยนมันให้ใช้งานเป็นคู่เพราะฉันคิด แต่เรื่อง zip iterators ด้วยเหตุผลบางประการ
chris

แนวทางที่ดีจริงๆ! รักเลย!
higuaro

5

คนแรกเป็นเรื่องง่าย คุณต้องใช้ตัวดำเนินการโมดูโลกับค่า num ของคุณ:

if ( ( num % 10 ) == 0)

เนื่องจาก C ++ กำลังประเมินทุกจำนวนที่ไม่เป็น 0 ตามความเป็นจริงคุณจึงสามารถเขียน:

if ( ! ( num % 10 ) )  // Does not have a residue when divided by 10

สำหรับข้อที่สองฉันคิดว่าสิ่งนี้เข้าใจได้ง่ายกว่า:

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

หากต้องการรับสิ่งเหล่านี้ให้ใช้ num-1 หรือ num + 19 ที่ดีกว่าเพื่อหลีกเลี่ยงการจัดการกับจำนวนลบ

if ( ( ( num + 19 ) % 20 ) > 9 )

นี่คือสมมติว่ารูปแบบนั้นซ้ำไปเรื่อย ๆ ดังนั้นสำหรับ 111-120 มันจะใช้อีกครั้งและอื่น ๆ มิฉะนั้นคุณจะต้อง จำกัด ตัวเลขไว้ที่ 100:

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )

5

ด้วยความคิดเห็นที่ดีสองสามข้อในโค้ดทำให้สามารถเขียนได้ค่อนข้างกระชับและอ่านง่าย

// Check if it's a multiple of 10
if (num % 10 == 0) { ... }

// Check for whether tens digit is zero or even (1-10, 21-30, ...)
if ((num / 10) % 2 == 0) { ... }
else { ... }

2
ความคิดเห็นแรกไม่จำเป็น โปรแกรมเมอร์คนnum % 10 == 0ไหนที่มีประสบการณ์น้อยจะรู้ว่ามันเหมือนกับnumผลคูณของ 10
จัสติน

7
ใช่ แต่ผู้เริ่มต้นอ่านไซต์นี้ด้วย ปกติฉันจะไม่ใช้ความคิดเห็นนั้นในรหัสของตัวเอง แต่จะทำให้คำตอบชัดเจนขึ้นสำหรับผู้เริ่มต้นที่จะได้รับประโยชน์จากคำถามเริ่มต้นนี้
La-comadreja

2
โปรดอย่าทำเช่นนี้ มันช่วยลดความสามารถในการอ่านได้จริงโดยการทำให้ผู้อ่านช้าลงและบังคับให้พวกเขาอ่านทุกอย่างสองครั้ง โปรแกรมเมอร์คนใดที่ไม่เข้าใจว่าif (num % 10 == 0)หมายความเช่นเดียวกับที่// Check if it's a multiple of 10ไม่ควรดูแลรหัสของคุณ นี่คือรูปแบบการต่อต้านที่รู้จักกันดี
Dawood ibn Kareem

1
@DavidWallace ดูความคิดเห็นด้านบน เราไม่สามารถรับประกันได้ว่าผู้อ่านโพสต์นี้จะรู้จักรูปแบบการต่อต้านนี้
La-comadreja

1
ไม่ฉันหมายความว่าการแสดงความคิดเห็นแต่ละบรรทัดเพื่อบอกว่ามันเป็นการต่อต้านรูปแบบ ฉันไม่ได้หมายความว่าการใช้%เป็นการต่อต้านรูปแบบ เห็นได้ชัดว่ามันไม่ใช่ จริงๆแล้วสมมติว่าผู้อ่านหลาย ๆ คนในโพสต์นี้จะเป็นผู้เริ่มต้นการสอนพวกเขาในรูปแบบการเขียนความคิดเห็นนี้จะส่งผลเสียต่อพัฒนาการของพวกเขาในฐานะโปรแกรมเมอร์
Dawood ibn Kareem

4

โดยพื้นฐานแล้วคุณอธิบายคำตอบด้วยตัวคุณเอง แต่นี่คือรหัสในกรณีนี้

if((x % 10) == 0) {
  // Do this
}
if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) {
  // Do this
}

2
แก้ไขx < 41 x > 50และใส่วงเล็บ
101010

1
ในทางเทคนิคแล้ว @ 40two operator&&มีลำดับความสำคัญสูงกว่าoperator||ดังนั้นจึงใช้ได้ แต่ฉันค่อนข้างมั่นใจว่า GCC เตือนเกี่ยวกับเรื่องนี้อยู่แล้ว
chris

18
พิจารณาเป็นตัวแทนของความไม่สมดุลกัน10 < x < 21เป็นมากกว่า10 < x && x < 21 x > 10 && x < 21การอ่านอสมการจะง่ายกว่าเมื่อมันอยู่ในลำดับเดียวกับที่คุณเขียนในทางคณิตศาสตร์
Eric Lippert

5
รหัสนี้ค่อนข้างอ่านไม่ได้และพูดถึงตรรกะที่แท้จริงเพียงเล็กน้อย ฉันไม่ชอบคำตอบนี้
Dariusz

3
ฉันลงคะแนนนี้เพราะคุณตอบว่า OP ทำอะไร
Bruno Ferreira

3

คุณอาจคิดมากเกินไป

if (x % 10)
{
   .. code for 1..9 ..
} else
{
   .. code for 0, 10, 20 etc.
}

บรรทัดแรกif (x % 10)ทำงานเพราะ (ก) ค่าที่มีหลาย 10 คำนวณเป็น '0', หมายเลขอื่น ๆ ส่งผลให้ remainer ของพวกเขา (ข) ค่าเป็น 0 ในifถือว่าเป็นfalseค่าอื่น ๆ trueคือ

แก้ไข:

หากต้องการสลับไปมาในวัยยี่สิบให้ใช้เคล็ดลับเดียวกัน คราวนี้หมายเลขสำคัญคือ10:

if (((x-1)/10) & 1)
{
  .. code for 10, 30, ..
} else
{
   .. code for 20, 40, etc.
}

x/10ส่งกลับตัวเลขใด ๆ จาก 0 ถึง 9 เป็น010 ถึง 19 เป็น1และอื่น ๆ การทดสอบคู่หรือคี่ - the & 1- บอกคุณว่ามันเป็นคู่หรือคี่ เนื่องจากจริงๆแล้วช่วงของคุณคือ "11 ถึง 20" ให้ลบ 1 ก่อนทดสอบ


1

ข้ออ้างสำหรับการอ่าน

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

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

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

#include <stdio.h>

enum {NO, YES, WINNER};
enum {OUT_OF_RANGE=-1, ODD, EVEN};

int notInRange(int square) {
  return(square < 1 || square > 100)?YES:NO;
}

int isEndOfRow(int square) {
  if (notInRange(square)) return OUT_OF_RANGE;
  if (square == 100) return WINNER; // I am making this up...
  return (square % 10 == 0)? YES:NO;
}

int rowType(unsigned int square) {
  // return 1 if square is in odd row (going to the right)
  // and 0 if square is in even row (going to the left)
  if (notInRange(square)) return OUT_OF_RANGE; // trap this error
  int rowNum = (square - 1) / 10;
  return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc.
                                       // and 1 (EVEN) for 11-20, 31-40, ...
}

int main(void) {
  int a = 12;
  int rt;
  rt = rowType(a); // this replaces your obscure if statement

  // and here is how you handle the possible return values:
  switch(rt) {
  case ODD:
    printf("It is an odd row\n");
    break;
  case EVEN:
    printf("It is an even row\n");
    break;
  case OUT_OF_RANGE:
    printf("It is out of range\n");
    break;
  default:
    printf("Unexpected return value from rowType!\n");
  }

  if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n");
  if(isEndOfRow(100)==WINNER) printf("We have a winner!\n");
}

3
มันไม่พยายามที่จะผลักดันมันมากเกินไปด้วยYESและNO?
rmobis

@Raphael_ - มันอาจจะเป็น: ฉันแค่แสดง "ตัวอย่าง" หลายคนใช้จริง / เท็จอย่างเห็นได้ชัด แต่ฉันไม่เคยจำได้ (เพราะภาษาที่แตกต่างใช้การประชุมที่แตกต่างกัน): คือเป็นTRUE, Trueหรือtrue? และถ้ามีไฟล์ส่วนหัวอะไรบ้างที่ฉันต้องรวมไว้ใน C ธรรมดา? ก็เลยรีดของตัวเอง สงสัยว่านั่นคือสิ่งที่ได้รับการโหวตลดลง ...
Floris

1

สำหรับคนแรก:

if (x % 10 == 0)

จะนำไปใช้กับ:

10, 20, 30, .. 100 .. 1000 ...

สำหรับอันที่สอง:

if (((x-1) / 10) % 2 == 1)

จะสมัครสำหรับ:

11-20, 31-40, 51-60, ..

โดยพื้นฐานแล้วเราต้องทำก่อนx-1เพื่อรับ:

10-19, 30-39, 50-59, ..

จากนั้นเราหารด้วย10เพื่อให้ได้:

1, 3, 5, ..

เราจึงตรวจสอบว่าผลลัพธ์นี้เป็นเลขคี่หรือไม่


1

คุณสามารถลองทำสิ่งต่อไปนี้:

// Multiple of 10
if ((num % 10) == 0)
{
   // Do something
}
else if (((num / 10) % 2) != 0)
{
    // 11-20, 31-40, 51-60, 71-80, 91-100
}
 else
{
    // Other case
}

ในคำถาม OP การตรวจสอบผลคูณของ 10 ไม่เกี่ยวข้องกับการตรวจสอบช่วงและในการตรวจสอบช่วง 20 จะต้องอยู่ในช่วง 11 เดียวกันโดยมีรหัสของคุณ ((20/10)% 2) -> ( 2% 2) -> 0
Serpiton

0

ฉันรู้ว่าคำถามนี้มีคำตอบมากมาย แต่ฉันก็จะทิ้งฉันไว้ที่นี่อยู่ดี ...

นำมาจากCode Completeของ Steve McConnell ฉบับที่ 2: "Stair-Step Access Tables:

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

ใส่คำอธิบายภาพที่นี่

รูปที่ 18-5 แนวทางแบบขั้นบันไดแบ่งประเภทของแต่ละรายการโดยกำหนดระดับที่จะชน "บันได" "ขั้นตอน" จะกำหนดหมวดหมู่

ตัวอย่างเช่นหากคุณกำลังเขียนโปรแกรมตัดเกรดช่วงรายการ“ B” อาจอยู่ระหว่าง 75 เปอร์เซ็นต์ถึง 90 เปอร์เซ็นต์ นี่คือเกรดต่างๆที่คุณอาจต้องตั้งโปรแกรมสักวันหนึ่ง:

ใส่คำอธิบายภาพที่นี่

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

ใส่คำอธิบายภาพที่นี่

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

Code Complete , 2nd Edition, หน้าที่ 426 - 428 (บทที่ 18)


ทำไมคุณถึงคิดว่าเป็นคำถามที่ผิด? เพียงเพราะฉันไม่ได้ให้ตัวอย่างเคส OP ไม่ได้หมายความว่าฉันตอบคำถามผิด ...
lauCosma

0

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

มันสามารถช่วยในการทำให้โปรแกรมของคุณมีความยืดหยุ่นมากขึ้นในกรณีที่คุณตัดสินใจในภายหลังว่าคุณต้องการเกมเวอร์ชันสำหรับเด็กวัยเตาะแตะบนกระดาน 6 x 6 หรือเวอร์ชันขั้นสูง (ที่คุณสามารถเล่นได้ตลอดทั้งคืน) บนกระดาน 40 x 50 .

ดังนั้นฉันจะเขียนโค้ดดังนี้:

// What is the size of the game board?
#define ROWS            10
#define COLUMNS         10

// The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS)
// (top-left if ROWS is even, or top-right if ROWS is odd)
#define firstSquare     1
#define lastSquare      (ROWS * COLUMNS)
// We haven't started until we roll the die and move onto the first square,
// so there is an imaginary 'square zero'
#define notStarted(num) (num == 0)
// and we only win when we land exactly on the last square
#define finished(num)   (num == lastSquare)
#define overShot(num)   (num > lastSquare)

// We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS
// (apologies to C fanatics who believe the world should be zero-based, which would
//  have simplified these expressions)
#define getRow(num)   (((num - 1) / COLUMNS) + 1)
#define getCol(num)   (((num - 1) % COLUMNS) + 1)

// What direction are we moving in?
// On rows 1, 3, 5, etc. we go from left to right
#define isLeftToRightRow(num)    ((getRow(num) % 2) == 1)
// On rows 2, 4, 6, etc. we go from right to left
#define isRightToLeftRow(num)    ((getRow(num) % 2) == 0)

// Are we on the last square in the row?
#define isLastInRow(num)    (getCol(num) == COLUMNS)

// And finally we can get onto the code

if (notStarted(mySquare))
{
  // Some code for when we haven't got our piece on the board yet
}
else
{
  if (isLastInRow(mySquare))
  {
    // Some code for when we're on the last square in a row
  }


  if (isRightToLeftRow(mySquare))
  {
    // Some code for when we're travelling from right to left
  }
  else
  {
    // Some code for when we're travelling from left to right
  }
}

ใช่มันเป็นรายละเอียด แต่มันทำให้ชัดเจนว่าเกิดอะไรขึ้นบนกระดานเกม

หากฉันกำลังพัฒนาเกมนี้เพื่อแสดงบนโทรศัพท์หรือแท็บเล็ตฉันจะสร้างตัวแปร ROWS และ COLUMNS แทนค่าคงที่ดังนั้นจึงสามารถตั้งค่าแบบไดนามิก (เมื่อเริ่มเกม) เพื่อให้ตรงกับขนาดหน้าจอและการวางแนว

ฉันยังอนุญาตให้เปลี่ยนการวางแนวหน้าจอได้ตลอดเวลาในช่วงกลางเกมสิ่งที่คุณต้องทำคือเปลี่ยนค่าของ ROWS และ COLUMNS ในขณะที่ปล่อยทุกสิ่งทุกอย่างไว้ (หมายเลขสี่เหลี่ยมปัจจุบันที่ผู้เล่นแต่ละคนเปิดอยู่และ เริ่มต้น / สิ้นสุดกำลังสองของงูและบันไดทั้งหมด) ไม่เปลี่ยนแปลง จากนั้นคุณจะต้องวาดกระดานอย่างสวยงามและเขียนโค้ดสำหรับภาพเคลื่อนไหวของคุณ (ฉันคิดว่านั่นคือจุดประสงค์ของifข้อความของคุณ) ...


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

2
คุณควรใช้ฟังก์ชันอินไลน์แทน#define
Bryan Chen

เป็นแนวทางปฏิบัติที่ดีเมื่อคุณใช้#defineคำสั่งที่เหมือนฟังก์ชันโดยใส่วงเล็บรอบอาร์กิวเมนต์ซึ่งจะปรากฏในส่วนขยาย ดังนั้น#define finished(num) (num == lastSquare)คุณควรเขียน#define finished(num) ((num) == lastSquare)แทน เหตุผลก็คือหากคุณใช้คำสั่งดังกล่าวกับนิพจน์ที่มีตัวดำเนินการที่มีลำดับความสำคัญต่ำพอคุณจะไม่ได้รับคำตอบที่คุณคาดหวัง ในกรณีนี้หากคุณไม่ใช้วงเล็บเสริมให้finished(a & b)ขยายออกไป(a & b == lastSquare)ซึ่งแทบจะไม่ใช่สิ่งที่คุณต้องการ
Dawood ibn Kareem
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.