นอกเหนือจากคำตอบของอีเลียสซึ่งเป็นสาเหตุของพฤติกรรมที่ไม่ได้กำหนดเมื่อใช้กับจำนวนเต็มที่ลงนามและค่าที่ไม่ถูกต้องสำหรับอินพุตที่สูงเมื่อนำไปใช้กับจำนวนเต็มที่ไม่ได้ลงนาม
นี่คือเวอร์ชันการแก้ไขการยกกำลังโดย 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
- หรือประเภทสูงสุด - เป็นจัตุรัสที่สมบูรณ์แบบคุณสามารถมีชีวิตอยู่ กับที่