วิธีที่มีประสิทธิภาพมากที่สุดในการใช้ฟังก์ชั่นพลังงานแบบอิงจำนวนเต็ม pow (int, int)


249

อะไรคือวิธีที่มีประสิทธิภาพที่สุดในการเพิ่มจำนวนเต็มเป็นกำลังของจำนวนเต็มอื่นใน C?

// 2^3
pow(2,3) == 8

// 5^5
pow(5,5) == 3125

3
เมื่อคุณพูดว่า "ประสิทธิภาพ" คุณต้องระบุประสิทธิภาพที่เกี่ยวข้องกับสิ่งที่ ความเร็ว? การใช้ความจำ? ขนาดรหัส? การบำรุงรักษา?
Andy Lester

C ไม่มีฟังก์ชัน pow () หรือไม่
jalf

16
ใช่ แต่ใช้งานได้กับการลอยหรือเป็นสองเท่าไม่ได้อยู่ใน ints
Nathan Fellman

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

pow()ไม่ใช่ฟังก์ชั่นที่ปลอดภัย
EsmaeelE

คำตอบ:


391

การยกกำลังด้วยการยกกำลังสอง

int ipow(int base, int exp)
{
    int result = 1;
    for (;;)
    {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        if (!exp)
            break;
        base *= base;
    }

    return result;
}

นี่เป็นวิธีมาตรฐานสำหรับการยกกำลังเลขชี้กำลังสำหรับจำนวนมากในการเข้ารหัสแบบอสมมาตร


38
คุณควรเพิ่มเช็คที่ "exp" ไม่ติดลบ ปัจจุบันฟังก์ชั่นนี้จะให้คำตอบที่ผิดหรือวนซ้ำตลอดไป (ขึ้นอยู่กับว่า >> = บน int ที่ลงนามแล้วไม่ทำให้เกิดช่องว่างภายในหรือการขยายสัญญาณ - คอมไพเลอร์ C ได้รับอนุญาตให้เลือกลักษณะการทำงานอย่างใดอย่างหนึ่ง)
user9876

23
ฉันเขียนเวอร์ชันที่เหมาะที่สุดของนี้ดาวน์โหลดได้อย่างอิสระที่นี่: gist.github.com/3551590 บนเครื่องของฉันเร็วขึ้นประมาณ 2.5 เท่า
orlp

10
@AkhilJain: มันดีมาก C; เพื่อทำให้ถูกต้องใน Java แทนที่while (exp)และif (exp & 1)ด้วยwhile (exp != 0)และif ((exp & 1) != 0)ตามลำดับ
Ilmari Karonen

3
ฟังก์ชั่นของคุณน่าจะมีunsigned expหรืออย่างอื่นจัดการเชิงลบexpอย่างถูกต้อง
Craig McQueen

5
@ZinanXing การคูณ n ครั้งจะทำให้เกิดการคูณมากขึ้นและช้าลง วิธีการนี้จะบันทึกการคูณด้วยการใช้ซ้ำอย่างมีประสิทธิภาพ ตัวอย่างเช่นการคำนวณ n ^ 8 วิธีnaïveของการn*n*n*n*n*n*n*nใช้ 7 การคูณ อัลกอริธึมนี้แทนที่จะคำนวณm=n*nจากo=m*mนั้นp=o*oโดยที่p= n ^ 8 ด้วยการคูณเพียงสามครั้ง ด้วยเลขชี้กำลังขนาดใหญ่ความแตกต่างของประสิทธิภาพจึงมีความสำคัญ
bames53

69

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

ตัวอย่างเช่นหากคุณต้องการคำนวณ x ^ 15 วิธีการยกกำลังด้วยการยกกำลังสองจะให้:

x^15 = (x^7)*(x^7)*x 
x^7 = (x^3)*(x^3)*x 
x^3 = x*x*x

นี่คือการคูณทั้งหมด 6 ครั้ง

มันจะเปิดออกนี้สามารถทำได้โดยใช้ "เพียงแค่" 5 คูณผ่านการยกกำลังนอกจากห่วงโซ่

n*n = n^2
n^2*n = n^3
n^3*n^3 = n^6
n^6*n^6 = n^12
n^12*n^3 = n^15

ไม่มีอัลกอริทึมที่มีประสิทธิภาพในการค้นหาลำดับการคูณที่เหมาะสมที่สุดนี้ จากWikipedia :

ปัญหาในการค้นหาสายโซ่การเติมที่สั้นที่สุดไม่สามารถแก้ไขได้ด้วยการเขียนโปรแกรมแบบไดนามิกเพราะมันไม่เป็นไปตามสมมติฐานของโครงสร้างพื้นฐานที่ดีที่สุด นั่นคือมันไม่เพียงพอที่จะย่อยสลายพลังงานไปสู่พลังที่เล็กลงซึ่งแต่ละอันนั้นคำนวณได้น้อยที่สุดเนื่องจากการเพิ่มเชนสำหรับพลังที่เล็กกว่าอาจเกี่ยวข้องกัน (เพื่อแบ่งปันการคำนวณ) ตัวอย่างเช่นในห่วงโซ่การเติมที่สั้นที่สุดสำหรับa¹⁵ข้างต้นโปรแกรมย่อยสำหรับa⁶จะต้องคำนวณเป็น (a³) ²เนื่องจากa³ถูกนำมาใช้อีกครั้ง )


4
@JeremySalwen: ตามคำตอบนี้การยกกำลังเลขฐานสองไม่ได้เป็นวิธีที่ดีที่สุดโดยทั่วไป ขณะนี้ไม่มีอัลกอริทึมที่มีประสิทธิภาพสำหรับการค้นหาลำดับขั้นต่ำของการคูณ
Eric Postpischil

2
@EricPostpischil ขึ้นอยู่กับใบสมัครของคุณ โดยปกติเราไม่ต้องการอัลกอริทึมทั่วไปในการทำงานกับตัวเลขทั้งหมด ดูศิลปะการเขียนโปรแกรมคอมพิวเตอร์ปีที่ 19 2: อัลกอริธึม Seminumerical
Pacerier

3
มีการอธิบายปัญหาที่แน่นอนนี้ได้ดีตั้งแต่คณิตศาสตร์ไปจนถึงการเขียนโปรแกรมทั่วไปโดย Alexander Stepanov และ Daniel Rose หนังสือเล่มนี้ควรอยู่บนชั้นวางของผู้ปฏิบัติงานซอฟต์แวร์ทุกคน IMHO
Toby Speight

2
ดูยังen.wikipedia.org/wiki/...
lhf

สิ่งนี้สามารถปรับให้เหมาะสมสำหรับจำนวนเต็มเพราะมีพลังน้อยกว่า 255 จำนวนเต็มที่จะไม่ทำให้เกิดการล้นสำหรับจำนวนเต็ม 32 บิต คุณสามารถแคชโครงสร้างการคูณที่ดีที่สุดสำหรับแต่ละ int ฉันคิดรหัส + ข้อมูลจะยังคงมีขนาดเล็กกว่าเพียงแค่แคชอำนาจทั้งหมด ...
ไซ Yoder

22

หากคุณต้องการยกกำลัง 2 ให้ได้ วิธีที่เร็วที่สุดในการทำเช่นนั้นคือการเปลี่ยนไปตามอำนาจ

2 ** 3 == 1 << 3 == 8
2 ** 30 == 1 << 30 == 1073741824 (A Gigabyte)

มีวิธีที่สวยงามในการทำเช่นนั้น 2 ** 0 == 1 หรือไม่
Rob Smallshire

16
2 ** 0 == 1 << 0 == 1
Jake

14

นี่คือวิธีการใน Java

private int ipow(int base, int exp)
{
    int result = 1;
    while (exp != 0)
    {
        if ((exp & 1) == 1)
            result *= base;
        exp >>= 1;
        base *= base;
    }

    return result;
}

ไม่ได้ผลสำหรับชาขนาดใหญ่เช่น pow (71045970,41535484)
Anushree Acharjee

16
@AnushreeAcharjee ไม่แน่นอน การคำนวณจำนวนนั้นจะต้องใช้เลขคณิตความแม่นยำโดยพลการ
David Etler

ใช้ BigInteger # modPow หรือ Biginteger # pow สำหรับตัวเลขขนาดใหญ่อัลกอริทึมที่เหมาะสมตามขนาดของข้อโต้แย้งมีการใช้งานแล้ว
Raman Yelianevich

นี่ไม่ใช่คำถาม Java!
Cacahuete Frito

7
int pow( int base, int exponent)

{   // Does not work for negative exponents. (But that would be leaving the range of int) 
    if (exponent == 0) return 1;  // base case;
    int temp = pow(base, exponent/2);
    if (exponent % 2 == 0)
        return temp * temp; 
    else
        return (base * temp * temp);
}

ไม่ใช่การลงคะแนนของฉัน แต่pow(1, -1)ไม่ปล่อยให้ช่วงของ int แม้จะมีเลขชี้กำลังเป็นลบ pow(-1, -1)ตอนนี้ที่หนึ่งในการทำงานโดยการเกิดอุบัติเหตุเช่นเดียวกับ
MSalters

เลขชี้กำลังเป็นลบเพียงอย่างเดียวที่อาจไม่ทำให้คุณออกจากช่วงของ int คือ -1 และใช้งานได้ถ้าฐานคือ 1 หรือ -1 ดังนั้นจึงมีเพียงสองคู่ (ฐาน, exp) กับ exp <0 ที่จะไม่นำไปสู่พลังที่ไม่ใช่จำนวนเต็ม แม้ว่าฉันจะเป็นนักแต่งภาพและฉันชอบ
วอนตัม

6

หากคุณต้องการรับค่าจำนวนเต็มสำหรับ 2 ยกกำลังของบางสิ่งจะดีกว่าเสมอที่จะใช้ตัวเลือก shift:

pow(2,5) สามารถถูกแทนที่ด้วย 1<<5

นี้มีประสิทธิภาพมากขึ้น


6

power()ฟังก์ชั่นเพื่อใช้งานกับจำนวนเต็มเท่านั้น

int power(int base, unsigned int exp){

    if (exp == 0)
        return 1;
    int temp = power(base, exp/2);
    if (exp%2 == 0)
        return temp*temp;
    else
        return base*temp*temp;

}

ความซับซ้อน = O (บันทึก (exp))

power()ฟังก์ชั่นการทำงานสำหรับประสบการณ์เชิงลบและฐานลอย

float power(float base, int exp) {

    if( exp == 0)
       return 1;
    float temp = power(base, exp/2);       
    if (exp%2 == 0)
        return temp*temp;
    else {
        if(exp > 0)
            return base*temp*temp;
        else
            return (temp*temp)/base; //negative exponent computation 
    }

} 

ความซับซ้อน = O (บันทึก (exp))


สิ่งนี้แตกต่างจากคำตอบของAbhijit Gaikwadและchuxอย่างไร โปรดโต้แย้งการใช้งานfloatในบล็อกโค้ดที่สองที่นำเสนอ (ลองพิจารณาว่าpower(2.0, -3)จะคำนวณอย่างไร)
เทา

@greybeard ฉันได้พูดถึงความคิดเห็น อาจเป็นได้ว่าสามารถแก้ไขแบบสอบถามของคุณ
roottraveller

1
GNU Scientific Library มีฟังก์ชั่นที่สองของคุณอยู่แล้ว: gnu.org/software/gsl/manual/html_node/Small-integer-powers.html
Cacahuete Frito

@rootraveller คุณช่วยอธิบายnegative exp and float baseวิธีแก้ปัญหาได้มั้ย ทำไมเราใช้ temp แยก exp ด้วย 2 และตรวจสอบ exp (แม้กระทั่ง / คี่) ขอบคุณ!
เลฟ

6

กรณีพิเศษอย่างยิ่งคือเมื่อคุณต้องการบอกว่า 2 ^ (- x ถึง y) โดยที่ x แน่นอนว่าเป็นลบและ y ใหญ่เกินกว่าที่จะเปลี่ยนเป็น int ได้ คุณยังสามารถทำ 2 ^ x ในเวลาคงที่โดยการขันสกรูด้วยทุ่น

struct IeeeFloat
{

    unsigned int base : 23;
    unsigned int exponent : 8;
    unsigned int signBit : 1;
};


union IeeeFloatUnion
{
    IeeeFloat brokenOut;
    float f;
};

inline float twoToThe(char exponent)
{
    // notice how the range checking is already done on the exponent var 
    static IeeeFloatUnion u;
    u.f = 2.0;
    // Change the exponent part of the float
    u.brokenOut.exponent += (exponent - 1);
    return (u.f);
}

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

นอกจากนี้ยังมีความเป็นไปได้ที่การเรียนรู้เพิ่มเติมเกี่ยวกับIEEE ลอยกรณีพิเศษอื่น ๆ ของการยกกำลังอาจนำเสนอตัวเอง


วิธีการแก้ปัญหาที่ดี แต่ unsigend?
paxdiablo

IEEE float เป็นฐาน x 2 ^ exp การเปลี่ยนค่าเลขชี้กำลังจะไม่นำไปสู่สิ่งอื่นนอกจากการคูณด้วยกำลังสองและโอกาสสูงมันจะทำให้การลอยตัวผิดปกติ ... ทางออกของคุณผิด IMHO
Drealmer

คุณเป็นคนที่ถูกต้องทั้งหมดฉัน misremembered ว่าวิธีการแก้ปัญหาของฉันถูกเขียนเดิมโอ้นานมาแล้วสำหรับพลังของ 2 อย่างชัดเจน ฉันเขียนคำตอบของฉันใหม่เพื่อแก้ปัญหากรณีพิเศษ
Doug T.

ประการแรกรหัสเสียตามที่ยกมาและต้องมีการแก้ไขเพื่อให้ได้รวบรวม ประการที่สองโค้ดเสียใน core2d โดยใช้ gcc เห็นการถ่ายโอนข้อมูลนี้ บางทีฉันทำอะไรผิด แต่ผมไม่คิดว่าการทำงานนี้จะตั้งแต่ตัวแทน IEEE ลอยเป็นฐาน 10
FreeSpace

3
ฐาน 10? เอ่อไม่เป็นฐาน 2 ถ้าคุณหมายถึง 10 ในไบนารี :)
Drealmer

4

เช่นเดียวกับการติดตามความคิดเห็นเกี่ยวกับประสิทธิภาพของการยกกำลังด้วยการยกกำลังสอง

ข้อดีของวิธีการนี้คือมันทำงานในเวลาเข้าสู่ระบบ (n) ตัวอย่างเช่นหากคุณกำลังคำนวณบางสิ่งที่ยิ่งใหญ่เช่น x ^ 1048575 (2 ^ 20 - 1) คุณต้องผ่านลูป 20 ครั้งไม่ใช่ 1 ล้าน + โดยใช้วิธีไร้เดียงสา

นอกจากนี้ในแง่ของความซับซ้อนของรหัสมันง่ายกว่าการพยายามหาลำดับการคูณที่เหมาะสมที่สุดซึ่งเป็นคำแนะนำของ la Pramod

แก้ไข:

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


2

ไปงานเลี้ยงสาย:

ด้านล่างเป็นวิธีแก้ปัญหาที่y < 0ดีที่สุดเท่าที่จะทำได้

  1. มันใช้ผลของintmax_tช่วงสูงสุด intmax_tมีการให้คำตอบที่ไม่เหมาะสมในการไม่เป็น
  2. powjii(0, 0) --> 1ซึ่งเป็นผลลัพธ์ทั่วไปสำหรับกรณีนี้
  3. pow(0,negative)ผลลัพธ์อื่นที่ไม่ได้กำหนดจะส่งคืน INTMAX_MAX

    intmax_t powjii(int x, int y) {
      if (y < 0) {
        switch (x) {
          case 0:
            return INTMAX_MAX;
          case 1:
            return 1;
          case -1:
            return y % 2 ? -1 : 1;
        }
        return 0;
      }
      intmax_t z = 1;
      intmax_t base = x;
      for (;;) {
        if (y % 2) {
          z *= base;
        }
        y /= 2;
        if (y == 0) {
          break; 
        }
        base *= base;
      }
      return z;
    }

รหัสนี้ใช้วนรอบถาวรfor(;;)เพื่อหลีกเลี่ยงการbase *= baseพบบ่อยสุดท้ายในโซลูชันวนลูปอื่น ๆ การคูณนั่นคือ 1) ไม่จำเป็นและ 2) อาจint*intล้นซึ่งเป็น UB


powjii(INT_MAX, 63)ทำให้เกิด UB base *= baseใน พิจารณาการตรวจสอบว่าคุณสามารถคูณหรือย้ายไปที่ไม่ได้ลงชื่อและปล่อยให้มันพันรอบ
Cacahuete Frito

ไม่มีเหตุผลที่จะต้องexpลงนาม มันซับซ้อนรหัสเนื่องจากสถานการณ์คี่ที่(-1) ** (-N)ถูกต้องและabs(base) > 1จะเป็น0ค่าลบของexpดังนั้นจึงเป็นการดีกว่าที่จะมีการลงนามและบันทึกรหัสนั้น
Cacahuete Frito

1
@CacahueteFrito ทรูที่yลงนามไม่จำเป็นจริงๆและนำภาวะแทรกซ้อนที่คุณแสดงความคิดเห็นบนยังคำขอ OP pow(int, int)เป็นที่เฉพาะเจาะจง ดังนั้นความคิดเห็นที่ดีเหล่านั้นเป็นของคำถามของ OP เนื่องจาก OP ไม่ได้ระบุว่าจะทำอย่างไรกับโอเวอร์โฟลว์คำตอบที่ผิดที่กำหนดไว้อย่างดีนั้นจะดีกว่า UB เพียงเล็กน้อยเท่านั้น ด้วยวิธีที่มีประสิทธิภาพมากที่สุดฉันสงสัยว่า OP ให้ความสำคัญกับเรื่องของ
chux - Reinstate Monica

1

วิธีแก้ปัญหาทั่วไปที่มากขึ้นเมื่อพิจารณาถึงเลขชี้กำลังเป็นลบ

private static int pow(int base, int exponent) {

    int result = 1;
    if (exponent == 0)
        return result; // base case;

    if (exponent < 0)
        return 1 / pow(base, -exponent);
    int temp = pow(base, exponent / 2);
    if (exponent % 2 == 0)
        return temp * temp;
    else
        return (base * temp * temp);
}

1
การหารจำนวนเต็มส่งผลให้เป็นจำนวนเต็มดังนั้นเลขชี้กำลังลบของคุณอาจมีประสิทธิภาพมากขึ้นเนื่องจากมันจะคืนค่าเป็น 0, 1 หรือ -1 เท่านั้น ...
jswolf19

pow(i, INT_MIN)อาจเป็นวงไม่สิ้นสุด
chux - Reinstate Monica

1
@chux: มันสามารถจัดรูปแบบฮาร์ดดิสก์ของคุณ: ล้นจำนวนเต็มเป็น UB
MSalters

@MSalters pow(i, INT_MIN)ไม่ใช่จำนวนเต็มล้น การกำหนดผลลัพธ์tempนั้นอาจล้นอย่างแน่นอนอาจทำให้หมดเวลาแต่ฉันจะตัดสินด้วยค่าสุ่มที่ดูเหมือนว่า :-)
chux - Reinstate Monica

0

อีกหนึ่งการใช้งาน (ใน Java) อาจไม่ใช่โซลูชันที่มีประสิทธิภาพสูงสุด แต่จำนวนการทำซ้ำ # นั้นเหมือนกับโซลูชันเอ็กซ์โปแนนเชียล

public static long pow(long base, long exp){        
    if(exp ==0){
        return 1;
    }
    if(exp ==1){
        return base;
    }

    if(exp % 2 == 0){
        long half = pow(base, exp/2);
        return half * half;
    }else{
        long half = pow(base, (exp -1)/2);
        return base * half * half;
    }       
}

ไม่ใช่คำถามเกี่ยวกับ Java!
Cacahuete Frito

0

ฉันใช้แบบเรียกซ้ำถ้าประสบการณ์ยังเท่ากับ 5 ^ 10 = 25 ^ 5

int pow(float base,float exp){
   if (exp==0)return 1;
   else if(exp>0&&exp%2==0){
      return pow(base*base,exp/2);
   }else if (exp>0&&exp%2!=0){
      return base*pow(base,exp-1);
   }
}

0

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

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

#include <stdint.h>

#define SQRT_INT64_MAX (INT64_C(0xB504F333))

int64_t alx_pow_s64 (int64_t base, uint8_t exp)
{
    int_fast64_t    base_;
    int_fast64_t    result;

    base_   = base;

    if (base_ == 1)
        return  1;
    if (!exp)
        return  1;
    if (!base_)
        return  0;

    result  = 1;
    if (exp & 1)
        result *= base_;
    exp >>= 1;
    while (exp) {
        if (base_ > SQRT_INT64_MAX)
            return  0;
        base_ *= base_;
        if (exp & 1)
            result *= base_;
        exp >>= 1;
    }

    return  result;
}

ข้อควรพิจารณาสำหรับฟังก์ชั่นนี้:

(1 ** N) == 1
(N ** 0) == 1
(0 ** 0) == 1
(0 ** N) == 0

หากมีการล้นหรือการพันทับเกิดขึ้น return 0;

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


0

ฉันใช้อัลกอริทึมที่จดจำพลังการคำนวณทั้งหมดแล้วใช้เมื่อจำเป็น ตัวอย่างเช่น x ^ 13 เท่ากับ (x ^ 2) ^ 2 ^ 2 * x ^ 2 ^ 2 * x โดยที่ x ^ 2 ^ 2 นำมาจากตารางแทนที่จะคำนวณอีกครั้ง นี่คือการใช้งานพื้นฐานของคำตอบ @Pramod (แต่ใน C #) จำนวนการคูณที่ต้องการคือ Ceil (บันทึก n)

public static int Power(int base, int exp)
{
    int tab[] = new int[exp + 1];
    tab[0] = 1;
    tab[1] = base;
    return Power(base, exp, tab);
}

public static int Power(int base, int exp, int tab[])
    {
         if(exp == 0) return 1;
         if(exp == 1) return base;
         int i = 1;
         while(i < exp/2)
         {  
            if(tab[2 * i] <= 0)
                tab[2 * i] = tab[i] * tab[i];
            i = i << 1;
          }
    if(exp <=  i)
        return tab[i];
     else return tab[i] * Power(base, exp - i, tab);
}

public? ฟังก์ชั่น 2 ชื่อเดียวกัน นี่คือคำถาม C
Cacahuete Frito

-1

เคสของฉันแตกต่างกันเล็กน้อยฉันพยายามสร้างหน้ากากจากอำนาจ แต่ฉันคิดว่าฉันจะแบ่งปันวิธีแก้ปัญหาที่พบ

เห็นได้ชัดว่ามันใช้งานได้เฉพาะกับพลังของ 2

Mask1 = 1 << (Exponent - 1);
Mask2 = Mask1 - 1;
return Mask1 + Mask2;

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

นั่นสำหรับ 1 << 64 หรือเปล่า นั่นคือล้น จำนวนเต็มที่ใหญ่ที่สุดอยู่ด้านล่าง: (1 << 64) - 1
Michaël Roy

1 << 64 == 0 นั่นคือเหตุผล บางทีการเป็นตัวแทนของคุณอาจดีที่สุดสำหรับแอปของคุณ ฉันชอบสิ่งที่สามารถใส่ในแมโครโดยไม่มีตัวแปรพิเศษเช่น #define MASK(e) (((e) >= 64) ? -1 :( (1 << (e)) - 1))นั้นสามารถคำนวณได้ในเวลารวบรวม
Michaël Roy

ใช่ฉันรู้ว่าการล้นคืออะไร เพียงเพราะฉันไม่ได้ใช้คำนั้นไม่ใช่คำเชิญที่ไม่จำเป็น อย่างที่ฉันบอกไปมันใช้งานได้สำหรับฉันและใช้ความพยายามเล็กน้อยในการค้นหา มันง่ายมาก
MarcusJ

ฉันขอโทษถ้าฉันทำให้คุณขุ่นเคือง ฉันไม่ได้ตั้งใจอย่างแท้จริง
Michaël Roy

-1

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

#include <iostream>

template<unsigned long N>
unsigned long inline exp_unroll(unsigned base) {
    return base * exp_unroll<N-1>(base);
}

เรายุติการสอบถามซ้ำโดยใช้ความเชี่ยวชาญเทมเพลต:

template<>
unsigned long inline exp_unroll<1>(unsigned base) {
    return base;
}

เลขชี้กำลังจำเป็นต้องรู้ ณ รันไทม์

int main(int argc, char * argv[]) {
    std::cout << argv[1] <<"**5= " << exp_unroll<5>(atoi(argv[1])) << ;std::endl;
}

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