เป็นไปได้ไหมที่จะลดความซับซ้อน (x == 0 || x == 1) ลงในการดำเนินการเดียว?


106

ดังนั้นฉันจึงพยายามเขียนเลขที่nในลำดับฟีโบนักชีในฟังก์ชันที่กะทัดรัดที่สุด:

public uint fibn ( uint N ) 
{
   return (N == 0 || N == 1) ? 1 : fibn(N-1) + fibn(N-2);
}

แต่ฉันสงสัยว่าจะทำให้สิ่งนี้กะทัดรัดและมีประสิทธิภาพมากขึ้นได้หรือไม่โดยการเปลี่ยน

(N == 0 || N == 1)

เป็นการเปรียบเทียบเพียงครั้งเดียว มีการดำเนินการกะบิตแฟนซีที่สามารถทำได้หรือไม่?


111
ทำไม? อ่านได้เจตนาชัดเจนมากและไม่แพง เหตุใดจึงเปลี่ยนเป็นการจับคู่รูปแบบบิตที่ "ฉลาด" ซึ่งเข้าใจยากกว่าและไม่ระบุเจตนาอย่างชัดเจน
D Stanley

9
นี่ไม่ใช่ fibonaci จริงๆใช่มั้ย?
n8wrl

9
fibonaci เพิ่มสองค่าก่อนหน้านี้ คุณหมายถึงfibn(N-1) + fibn(N-2) แทนที่จะเป็นN * fibn(N-1)?
juharr

46
ฉันทุกคนสำหรับการโกนแบบนาโนวินาที แต่ถ้าคุณมีการเปรียบเทียบง่ายๆในวิธีการที่ใช้การเรียกซ้ำทำไมต้องใช้ความพยายามกับประสิทธิภาพของการเปรียบเทียบและปล่อยให้การเรียกซ้ำอยู่ที่นั่น?
Jon Hanna

25
คุณใช้วิธีวนซ้ำเพื่อคำนวณหมายเลข Fabonacci แล้วคุณต้องการปรับปรุงประสิทธิภาพหรือไม่? ทำไมไม่เปลี่ยนเป็นลูป หรือใช้ไฟเร็ว?
notbad

คำตอบ:


-9

อันนี้ก็ใช้ได้เช่นกัน

Math.Sqrt(N) == N 

รากที่สองของ 0 และ 1 จะส่งกลับ 0 และ 1 ตามลำดับ


20
Math.Sqrtเป็นฟังก์ชันทศนิยมที่ซับซ้อน มันทำงานช้าเมื่อเทียบกับทางเลือกจำนวนเต็มเท่านั้น !!
นายูกิ

1
สิ่งนี้ดูสะอาด แต่มีวิธีที่ดีกว่านี้หากคุณตรวจสอบคำตอบอื่น ๆ
Mafii

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

ใครในความคิดที่ถูกต้องของพวกเขาที่ทำเครื่องหมายนี้เป็นคำตอบ พูดไม่ออก
squashed.bugaboo

212

มีหลายวิธีในการทดสอบเลขคณิตของคุณโดยใช้เลขคณิตในระดับบิต การแสดงออกของคุณ:

  • x == 0 || x == 1

มีเหตุผลเทียบเท่ากับแต่ละสิ่งเหล่านี้:

  • (x & 1) == x
  • (x & ~1) == 0
  • (x | 1) == 1
  • (~x | 1) == (uint)-1
  • x >> 1 == 0

โบนัส:

  • x * x == x (การพิสูจน์ต้องใช้ความพยายามเล็กน้อย)

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

  • x == 0 || x == 1
  • x <= 1(เนื่องจากxเป็นจำนวนเต็มที่ไม่ได้ลงชื่อ)
  • x < 2(เนื่องจากxเป็นจำนวนเต็มที่ไม่ได้ลงชื่อ)

6
อย่าลืม(x & ~1) == 0
Lee Daniel Crocker

71
แต่อย่าเดิมพันว่าตัวใดตัวหนึ่ง "มีประสิทธิภาพมากกว่า" GCC จริงสร้างรหัสน้อยx == 0 || x == 1กว่าหรือ(x & ~1) == 0 (x | 1) == 1สำหรับครั้งแรกหนึ่งก็ฉลาดพอที่จะรับรู้ว่ามันเป็นเทียบเท่ากับและผลที่เรียบง่ายx <= 1 cmpl; setbeคนอื่น ๆ สับสนและสร้างรหัสที่แย่ลง
hobbs

13
x <= 1 หรือ x <2 นั้นง่ายกว่า
gnasher729

9
@Kevin True สำหรับ C ++ เนื่องจากมาตรฐานนั้นพยายามจริง ๆ ยากมากที่จะทำให้ไม่สามารถเขียนโค้ดที่สอดคล้องกันได้ โชคดีที่นี่เป็นคำถามเกี่ยวกับ C #;)
Voo

5
คอมไพเลอร์สมัยใหม่ส่วนใหญ่สามารถเพิ่มประสิทธิภาพการเปรียบเทียบเช่นนี้ได้แล้วแม้ว่าฉันจะไม่รู้ว่าคอมไพเลอร์ C # และ. NET JITter ฉลาดแค่ไหน ต้องใช้การเปรียบเทียบเพียงครั้งเดียวในรหัสจริง
phuclv

78

เนื่องจากอาร์กิวเมนต์เป็นuint( ไม่ได้ลงชื่อ ) คุณสามารถใส่

  return (N <= 1) ? 1 : N * fibn(N-1);

อ่านได้น้อยลง (IMHO) แต่ถ้าคุณนับอักขระแต่ละตัว ( Code Golfหรือเหมือนกัน)

  return N < 2 ? 1 : N * fibn(N-1);

แก้ไข : สำหรับคำถามที่คุณแก้ไข :

  return (N <= 1) ? 1 : fibn(N-1) + fibn(N-2);

หรือ

  return N < 2 ? 1 : fibn(N-1) + fibn(N-2);

12
ถ้าเป็น Code Golf ก็จะเป็นreturn N<2?1:f(N-1)+f(n-2)เช่นนั้น : P
Conor O'Brien

36

คุณสามารถตรวจสอบว่าบิตอื่น ๆ ทั้งหมดเป็น 0 ดังนี้:

return (N & ~1) == 0 ? 1 : N * fibn(N-1);

เพื่อความสมบูรณ์ขอบคุณMattทางออกที่ดียิ่งขึ้น:

return (N | 1) == 1 ? 1 : N * fibn(N-1);

==ในทั้งสองกรณีที่คุณต้องดูแลวงเล็บเพราะผู้ประกอบการระดับบิตมีความสำคัญต่ำกว่า


ฉันชอบมัน! ขอบคุณ.
user6048670

15
1 น้อยตัวอักษร:(N|1)==1
แมตต์

1
@atk 3 | 1 คือ 3 เพราะ b0011 | b0001 คือ b0011
René Vogt

3
@atk นี่เป็นบิตหรือไม่ใช่ตรรกะหรือ. ไม่มีการลัดวงจร
isaacg

2
@Hoten ที่ถูกต้อง แต่แมตต์กล่าวว่า 1 น้อยตัวอักษรไม่น้อยกว่า 1 การดำเนินงาน
Ivan Stoev

20

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

class Sequences
{
    // Store the complete list of values that will fit in a 32-bit unsigned integer without overflow.
    private static readonly uint[] FibonacciSequence = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
        233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418,
        317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169,
        63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073
    };

    public uint fibn(uint N)
    {
        return FibonacciSequence[N];
    }
}

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


14

วิธีทำด้วย bitshift

หากคุณต้องการใช้ bitshift และทำให้โค้ดค่อนข้างคลุมเครือ (แต่สั้น) คุณสามารถทำได้:

public uint fibn ( uint N ) {
   return N >> 1 != 0? fibn(N-1) + finb(N-2): 1;
}

สำหรับจำนวนเต็มที่ไม่ได้ลงชื่อNในภาษา c ให้N>>1ปิดบิตลำดับต่ำ ถ้าผลลัพธ์นั้นไม่ใช่ศูนย์แสดงว่า N มีค่ามากกว่า 1

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

วิธีที่เร็วกว่า

คำนวณหนึ่งรอบแทนที่จะสร้างต้นไม้ขนาด fibonaci (N) โดยปริยาย:

uint faster_fibn(uint N) { //requires N > 1 to work
  uint a = 1, b = 1, c = 1;
  while(--N != 0) {
    c = b + a;
    a = b;
    b = c;
  }
  return c;
}

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


1
ไม่เพียง แต่หลีกเลี่ยงต้นไม้ที่กำลังเติบโตแบบเอ็กซ์โพเนนเชียล แต่คุณยังหลีกเลี่ยงการแตกกิ่งก้านสาขาที่อาจเกิดขึ้นของตัวดำเนินการที่เกี่ยวข้องซึ่งอาจอุดตันท่อซีพียูที่ทันสมัย
mathreadler

2
รหัส 'วิธีที่เร็วกว่า' ของคุณจะไม่ทำงานใน C # เนื่องจากuintไม่สามารถส่งโดยปริยายได้boolและคำถามจะถูกแท็กโดยเฉพาะเป็น C #
Pharap

1
@pharap แล้วทำ--N != 0แทน. ประเด็นก็คือสิ่งที่ O (n) เป็นที่ต้องการของ O (fibn (n))
Matthew Gunn

1
เพื่อขยายจุดของ @ MatthewGunn O (fib (n)) คือ O (phi ^ n) (ดูที่มานี้stackoverflow.com/a/360773/2788187 )
Connor Clark

@ RenéVogtฉันไม่ใช่นักพัฒนา ac # ส่วนใหญ่ฉันพยายามแสดงความคิดเห็นเกี่ยวกับอัลกอริทึม O (fibn (N)) ที่ไร้สาระโดยสิ้นเชิง ตอนนี้คอมไพล์ไหม (ฉันเพิ่ม! = 0 เนื่องจาก c # ไม่ถือว่าผลลัพธ์ที่ไม่ใช่ศูนย์เป็นจริง) มันใช้งานได้ (และทำงาน) ตรง c ถ้าคุณแทนที่ uint ด้วยสิ่งที่เป็นมาตรฐานเช่น uint64_t
Matthew Gunn

10

เมื่อคุณใช้ uint ซึ่งไม่สามารถติดลบได้คุณสามารถตรวจสอบได้ว่า n < 2

แก้ไข

หรือสำหรับกรณีฟังก์ชันพิเศษนั้นคุณสามารถเขียนได้ดังนี้:

public uint fibn(uint N)
    return (N == 0) ? 1 : N * fibn(N-1);
}

ซึ่งจะนำไปสู่ผลลัพธ์เดียวกันแน่นอนโดยมีค่าใช้จ่ายของขั้นตอนการเรียกซ้ำเพิ่มเติม


4
@CatthalMF: แต่ผลลัพธ์ก็เหมือนกันเพราะ1 * fibn(0) = 1 * 1 = 1
derpirscher

3
ฟังก์ชันของคุณคำนวณแฟกทอเรียลไม่ใช่ฟีโบนักชีใช่หรือไม่
Barmar

2
@Barmar ใช่นั่นคือแฟกทอเรียลเพราะนั่นคือคำถามเดิม
derpirscher

3
อาจจะดีที่สุดที่จะไม่เรียกตอนfibnนั้น
pie3636

1
@ pie3636 ฉันเรียกมันว่า fibn เพราะนั่นเป็นวิธีที่เรียกในคำถามเดิมและฉันไม่ได้อัปเดตคำตอบในภายหลัง
derpirscher

6

เพียงตรวจสอบเพื่อดูว่าNเป็น <= 1 หรือไม่เนื่องจากคุณทราบว่า N ไม่ได้ลงนามมีเพียง 2 เงื่อนไขN <= 1ที่ส่งผลให้TRUE: 0 และ 1

public uint fibn ( uint N ) 
{
   return (N <= 1) ? 1 : fibn(N-1) + finb(N-2);
}

แม้ว่าจะมีการลงนามหรือไม่ได้ลงนาม? อัลกอริทึมสร้างการเรียกซ้ำแบบไม่มีที่สิ้นสุดด้วยอินพุตเชิงลบดังนั้นจึงไม่มีอันตรายใด ๆ ในการปฏิบัติต่อพวกมันเทียบเท่ากับ 0 หรือ 1
Barmar

@Barmar แน่ใจว่ามันสำคัญโดยเฉพาะอย่างยิ่งในกรณีเฉพาะนี้ OP ถามว่าเขาสามารถทำให้ง่ายขึ้นได้(N == 0 || N == 1)หรือไม่ คุณจะรู้ว่ามันจะไม่น้อยกว่า 0 (เพราะมันจะถูกเซ็นชื่อ!) และค่าสูงสุดคือ 1 N <= 1ทำให้มันง่ายขึ้น ฉันเดาว่าไม่รับประกันประเภทที่ไม่ได้ลงชื่อ แต่ฉันควรจะจัดการที่อื่น
เจมส์

ประเด็นของฉันคือถ้ามันถูกประกาศint Nและคุณยังคงสภาพเดิมมันจะกลับคืนมาอย่างไม่มีที่สิ้นสุดเมื่อ N เป็นลบตามสภาพเดิมของเขา เนื่องจากเป็นพฤติกรรมที่ไม่ได้กำหนดเราจึงไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้ ดังนั้นเราจึงสามารถสรุปได้ว่า N ไม่เป็นลบไม่ว่าจะมีการประกาศอย่างไรก็ตาม
Barmar

หรือเราสามารถทำอะไรก็ได้ที่เราต้องการด้วยปัจจัยการผลิตเชิงลบรวมทั้งถือว่าเป็นกรณีฐานของการเรียกซ้ำ
Barmar

@Barmar ค่อนข้างแน่ใจว่า uint จะถูกแปลงเป็นไม่ได้ลงนามเสมอหากคุณพยายามตั้งค่าเป็นลบ
james

6

ข้อจำกัดความรับผิดชอบ: ฉันไม่รู้ C # และไม่ได้ทดสอบรหัสนี้:

แต่ฉันสงสัยว่าฉันสามารถทำให้สิ่งนี้กะทัดรัดและมีประสิทธิภาพมากขึ้นได้หรือไม่โดยการเปลี่ยน [... ] เป็นการเปรียบเทียบเพียงครั้งเดียว ...

ไม่จำเป็นต้องมีการขยับบิตหรือสิ่งนี้ใช้การเปรียบเทียบเพียงครั้งเดียวและมันควรจะมีประสิทธิภาพมากกว่านี้(O (n) เทียบกับ O (2 ^ n) ฉันคิดว่า?) เนื้อความของฟังก์ชั่นมีขนาดกะทัดรัดมากขึ้นแม้ว่าจะใช้เวลานานขึ้นเล็กน้อยด้วยการประกาศ

(ในการลบค่าใช้จ่ายออกจากการเรียกซ้ำมีเวอร์ชันซ้ำเช่นเดียวกับในคำตอบของ Mathew Gunn )

public uint fibn ( uint N, uint B=1, uint A=0 ) 
{
    return N == 0 ? A : fibn( N--, A+B, B );
}

                     fibn( 5 ) =
                     fibn( 5,   1,   0 ) =
return 5  == 0 ? 0 : fibn( 5--, 0+1, 1 ) =
                     fibn( 4,   1,   1 ) =
return 4  == 0 ? 1 : fibn( 4--, 1+1, 1 ) =
                     fibn( 3,   2,   1 ) =
return 3  == 0 ? 1 : fibn( 3--, 1+2, 2 ) =
                     fibn( 2,   3,   2 ) =
return 2  == 0 ? 2 : fibn( 2--, 2+3, 3 ) =
                     fibn( 1,   5,   3 ) =
return 1  == 0 ? 3 : fibn( 1--, 3+5, 5 ) =
                     fibn( 0,   8,   5 ) =
return 0  == 0 ? 5 : fibn( 0--, 5+8, 8 ) =
                 5
fibn(5)=5

PS: นี่เป็นรูปแบบการทำงานทั่วไปสำหรับการวนซ้ำด้วยตัวสะสม หากคุณแทนที่N--ด้วยN-1คุณได้อย่างมีประสิทธิภาพโดยไม่ใช้การกลายพันธุ์ซึ่งทำให้สามารถใช้งานได้ในแนวทางการทำงานที่แท้จริง


4

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

public uint fibn(uint N) 
{
    switch(N)
    {
        case  0: return 1;

        case  1: return 1;

        default: return fibn(N-1) + fibn(N-2);
    }
}

นิยามทางคณิตศาสตร์ของ Fibonacci number ในทำนองเดียวกัน ..

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

ดำเนินการต่อไปเพื่อบังคับให้สวิตช์เคสสร้างตารางการค้นหา

public uint fibn(uint N) 
{
    switch(N)
    {
        case  0: return 1;
        case  1: return 1;
        case  2: return 2;
        case  3: return 3;
        case  4: return 5;
        case  5: return 8;
        case  6: return 13;
        case  7: return 21;
        case  8: return 34;
        case  9: return 55;
        case 10: return 89;
        case 11: return 144;
        case 12: return 233;
        case 13: return 377;
        case 14: return 610;
        case 15: return 987;
        case 16: return 1597;
        case 17: return 2584;
        case 18: return 4181;
        case 19: return 6765;
        case 20: return 10946;
        case 21: return 17711;
        case 22: return 28657;
        case 23: return 46368;
        case 24: return 75025;
        case 25: return 121393;
        case 26: return 196418;
        case 27: return 317811;
        case 28: return 514229;
        case 29: return 832040;
        case 30: return 1346269;
        case 31: return 2178309;
        case 32: return 3524578;
        case 33: return 5702887;
        case 34: return 9227465;
        case 35: return 14930352;
        case 36: return 24157817;
        case 37: return 39088169;
        case 38: return 63245986;
        case 39: return 102334155;
        case 40: return 165580141;
        case 41: return 267914296;
        case 42: return 433494437;
        case 43: return 701408733;
        case 44: return 1134903170;
        case 45: return 1836311903;
        case 46: return 2971215073;

        default: return fibn(N-1) + fibn(N-2);
    }
}

1
ข้อดีของโซลูชันของคุณคือคำนวณเมื่อจำเป็นเท่านั้น ดีที่สุดคือตารางการค้นหา โบนัสทางเลือก: f (n-1) = someCalcOf (f (n-2)) ดังนั้นจึงไม่จำเป็นต้องรีรันใหม่ทั้งหมด
Karsten

@Karsten ฉันได้เพิ่มค่าเพียงพอสำหรับสวิตช์เพื่อสร้างตารางการค้นหาสำหรับมัน ฉันไม่แน่ใจว่าโบนัสทางเลือกทำงานอย่างไร
Khaled.K

1
สิ่งนี้ตอบคำถามได้อย่างไร?
Clark Kent

@SaviourSelf มันลงมาในตารางการค้นหาและมีแง่มุมที่อธิบายไว้ในคำตอบ stackoverflow.com/a/395965/2128327
Khaled.K

ทำไมคุณถึงใช้ a switchเมื่อคุณมีคำตอบมากมาย?
นายูกิ


1

คำตอบของ Dmitry นั้นดีที่สุด แต่ถ้าเป็นประเภทผลตอบแทน Int32 และคุณมีจำนวนเต็มชุดใหญ่กว่าให้เลือกคุณสามารถทำได้

return new List<int>() { -1, 0, 1, 2 }.Contains(N) ? 1 : N * fibn(N-1);

2
ที่สั้นกว่าเดิมอย่างไร?
MCMastery

2
@MCMastery มันไม่ได้สั้นลง ดังที่ฉันได้กล่าวไปแล้วจะดีกว่าหากประเภทการส่งคืนเดิมเป็น int32 และเขากำลังเลือกจากชุดตัวเลขที่ถูกต้องจำนวนมาก Insead ที่ต้องเขียน (N == -1 || N == 0 || N == 1 || N == 2)
CathalMF

1
เหตุผลของ OP ดูเหมือนจะเกี่ยวข้องกับการเพิ่มประสิทธิภาพ นี่เป็นความคิดที่ไม่ดีด้วยเหตุผลหลายประการ: 1) การสร้างอินสแตนซ์อ็อบเจ็กต์ใหม่ภายในการเรียกซ้ำแต่ละครั้งเป็นความคิดที่แย่มาก 2) List.Containsคือ O (n), 3) เพียงแค่ทำการเปรียบเทียบสองรายการแทน ( N > -3 && N < 3) จะทำให้โค้ดสั้นลงและอ่านง่ายขึ้น
Groo

@Groo และถ้าค่าเป็น -10, -2, 5, 7, 13
CathalMF

ไม่ใช่สิ่งที่ OP ถาม แต่อย่างไรก็ตามคุณยังคง 1) ไม่ต้องการสร้างอินสแตนซ์ใหม่ในการโทรแต่ละครั้ง 2) ควรใช้แฮช (เดี่ยว) แทนดีกว่า 3) สำหรับปัญหาเฉพาะคุณยังสามารถปรับฟังก์ชันแฮชให้เหมาะสมได้ บริสุทธิ์หรือแม้กระทั่งใช้การดำเนินการที่มีการจัดเรียงอย่างชาญฉลาดเหมือนที่แนะนำในคำตอบอื่น ๆ
Groo

0

ลำดับฟีโบนักชีคือชุดของตัวเลขที่พบตัวเลขโดยการบวกตัวเลขสองตัวไว้ข้างหน้า จุดเริ่มต้นมีสองประเภท: ( 0,1 , 1,2, .. ) และ ( 1,1 , 2,3)

-----------------------------------------
Position(N)| Value type 1 | Value type 2
-----------------------------------------  
1          |  0           |   1
2          |  1           |   1
3          |  1           |   2
4          |  2           |   3
5          |  3           |   5
6          |  5           |   8
7          |  8           |   13
-----------------------------------------

ตำแหน่งNในกรณีนี้เริ่มจาก1ไม่ใช่0-basedดัชนีอาร์เรย์

การใช้คุณลักษณะ C # 6 Expression-bodyและข้อเสนอแนะของ Dmitry เกี่ยวกับตัวดำเนินการ ternaryเราสามารถเขียนฟังก์ชันหนึ่งบรรทัดพร้อมการคำนวณที่ถูกต้องสำหรับประเภท 1:

public uint fibn(uint N) => N<3? N-1: fibn(N-1)+fibn(N-2);

และสำหรับประเภท 2:

public uint fibn(uint N) => N<3? 1: fibn(N-1)+fibn(N-2);

-2

ไปงานปาร์ตี้ช้าไปหน่อย แต่คุณก็ทำได้เช่นกัน (x==!!x)

!!xแปลงค่าเป็น1ถ้าไม่ใช่0และปล่อย0ให้เป็นค่านั้น
ฉันใช้สิ่งนี้ในการทำให้สับสน C มาก

หมายเหตุ: นี่คือ C ไม่แน่ใจว่าใช้งานได้ใน C # หรือไม่


4
ไม่แน่ใจว่าเหตุใดจึงมีการโหวตเพิ่มขึ้น แม้จะลองทำแบบคร่าวๆตามที่uint n = 1; if (n == !!n) { }ให้Operator '!' cannot be applied to operand of type 'uint'ไว้!nใน C # เพียงเพราะบางอย่างทำงานใน C ไม่ได้หมายความว่ามันทำงานใน C #; แม้#include <stdio.h>จะไม่ทำงานใน C # เนื่องจาก C # ไม่มีคำสั่ง "รวม" ตัวประมวลผลล่วงหน้า ภาษามีความแตกต่างกันมากกว่าภาษา C และ C ++
CVn

2
โอ้. ตกลง. ฉันขอโทษ :(
คืนหนึ่งปกติ

@OneNormalNight (x == !! x) วิธีนี้จะได้ผล พิจารณาข้อมูลของฉันคือ 5 (5 == !! 5) จะให้ผลลัพธ์เป็นจริง
VINOTH ENERGETIC

1
@VinothKumar !! 5 ประเมินเป็น 1 (5 == !! 5) ประเมิน (5 == 1) ซึ่งประเมินเป็นเท็จ
คืนหนึ่ง

@OneNormalNight ใช่ฉันเข้าใจแล้ว ! (5) ให้ 1 อีกครั้งใช้มันให้ 0. ไม่ใช่ 1
VINOTH ENERGETIC

-3

ดังนั้นฉันจึงสร้างListจำนวนเต็มพิเศษเหล่านี้และตรวจสอบว่าNเกี่ยวข้องกับมันหรือไม่

static List<uint> ints = new List<uint> { 0, 1 };

public uint fibn(uint N) 
{
   return ints.Contains(N) ? 1 : fibn(N-1) + fibn(N-2);
}

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

static class ObjectHelper
{
    public static bool PertainsTo<T>(this T obj, IEnumerable<T> enumerable)
    {
        return (enumerable is List<T> ? (List<T>) enumerable : enumerable.ToList()).Contains(obj);
    }
}

ใช้มัน:

N.PertainsTo(ints)

นี่อาจไม่ใช่วิธีที่เร็วที่สุด แต่สำหรับฉันแล้วดูเหมือนว่าจะเป็นรูปแบบที่ดีกว่า

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