数值的整数次方次
题目

常规思路:
先对指数取绝对值累乘计算幂,然后若指数为负则取倒数。
同时考虑了指数为 0 和底数为 0 这些特殊边界条件,确保程序不异常中断。
double Power(double base, int exponent) {//处理指数为0的情况if (exponent == 0) {//0的0次方return 1.0;}//计算质数的绝对值平方double absExponent = exponent > 0 ? exponent : -exponent;double result = 1.0;for (int i = 0; i < absExponent; i++) {result *= base;}//再计算指数为负数的情况(取倒数)if (exponent < 0) {//如果底数为0且指数为负,结果无意义,这里简单返回0,(实际场景需根据需求处理)if (fabs(base) < 1e-9) {return 0.0;}return 1.0 / result;}return result;
}int main() {// 测试用例cout << "2的3次方:" << Power(2, 3) << endl;cout << "2的-3次方:" << Power(2, -3) << endl;cout << "0的5次方:" << Power(0, 5) << endl;cout << "5的0次方:" << Power(5, 0) << endl;return 0;
}
优化:快速幂计算
//计算指数的绝对值平方int absExponent = exponent > 0 ? exponent : -exponent;double result = 1.0;//快速幂计算double current = base;//当前累乘的底数(如a^1,a^2,a^4...)while (absExponent > 0) {if (absExponent % 2 == 1) {//若当前二进制位为1,则乘如乘法result *= current;}current *= current;absExponent /= 2;}
原代码在指数为整数且绝对值不大的场景下是正确的,能处理正指数、负指数、0 指数等情况。 但对于大指数(如 (10^9)),效率较低,建议改用快速幂算法优化。 对 “底数为 0 且指数为负” 的无意义情况,代码返回 0.0 是简化处理,实际可根据需求返回 NaN(更符合数学逻辑)。
优化:递归版快速幂

思路:
通过递归将 “计算 a^n 的问题分解为 “计算 a^{n/2} 后自乘(或自乘后再乘 a)” 的子问题,直到递归到边界条件。
#include <cmath> // 需包含cmath以使用fabs
double PowerWithUnsignedExponent(double base, long long unsignedExponent) {//出口if (unsignedExponent == 0) {return 1.0;//任何数的0次方为1}if (unsignedExponent == 1) {return base;//任何数的1次方为自身}double result = PowerWithUnsignedExponent(base, unsignedExponent >> 1);//等价于除以2result *= result;//平方得到base^(unsignedExponent/2*2)//若指数为奇数,需额外乘一次base(因为unsignedExpoent/2会额外截断小数部分)if (unsignedExponent & 1) {result *= base;}return result;
}//主函数:处理正负指数和特殊情况
double QuickPoweRecursive(double base, int exponent) {//处理指数为0的情况if (fabs(base) < 1e-9 && exponent<0) {return 0.0;//实际场景可返回NAN;}//转换指数为非负的long long 类型(避免int最小值取绝对值溢出)long long unsignedExpoent = exponent;if (exponent < 0) {unsignedExpoent = -unsignedExpoent;}//调用递归函数计算正指数幂double result = PowerWithUnsignedExponent(base, unsignedExpoent);//处理负指数(取倒数)if (exponent < 0) {result = 1.0 / result;}return result;1、递归边界条件:
if (exponent == 0) return 1;:任何数的 0 次方为 1(递归终止条件)。
if (exponent == 1) return base;:任何数的 1 次方为其本身(递归终止条件)2、 PowerWithUnsignedExponent中:
当指数 unsignedExponent 为奇数时,需要额外乘以一次 base。这是因为递归分解时,“整数除法” 会截断小数部分,导致幂次计算 “少了一次 base 的乘法”,必须通过这一步补全。
fabs
1、判断浮点数是否为0:if(fabs(base) < 1e-9)
fabs 是 C/C++ 标准库 <cmath> 中的函数,用于计算浮点数的绝对值(f 表示 float/double 类型,对应的整数绝对值函数是 abs)。
1e-9 是科学计数法,表示 10^{-9}(即 0.000000001),是一个极小的阈值。
语句含义:判断 base 的绝对值是否小于 10^{-9},用于安全地判断浮点数是否为 0。
2、为什么不直接用 base == 0.0?
==>
因为浮点数在内存中是近似存储的(例如 0.1 无法被二进制精确表示),直接用 == 比较可能因为精度误差导致逻辑错误。用 “绝对值小于极小阈值” 的方式,可以避免这种精度陷阱,更鲁棒地判断一个浮点数是否 “本质上是 0”。
总结:
1、除了我们知道的a^b,double a,intb>0的计算 还要讨论exponent<0(取倒数) 0^0无意义 o^-1无意义 的问题;
2、虽然说我们解决的是数值的整数次方次,exponent用int表示,但因为代码会有使用到-exponent,为了处理边界,我们得用long long absExponent=exponent>0?exponent:-exponent. 即用long long来存储。
3、除了常规的做法,我们使用了快速幂进行优化(迭代版和递归版)
递归版快速幂虽然代码简洁,但当指数非常大时(例如 \(10^{18}\)),递归深度会达到 log2(10^18),在大多数情况下不会溢出,但如果是极端场景(比如嵌入式设备的小栈空间),可能需要考虑迭代版或调整栈大小。
4、学到了fabs(),用于对浮点数(float/double)取绝对值,浮点数判断是否为0使用近似的方式, if(fabs(base)<1e9)
在判断浮点数是否为 0 时,
1e-9是一个常用阈值,但实际工程中可能需要根据场景调整。例如,在高精度计算中,可能需要更小的阈值(如 \(1e-15\));在低精度场景中,\(1e-6\) 也可能足够。
5、我们使用下面方式来代替计算更高效。 右移代替/2,即用exponent>>=exponent来代替exponent=exponent/2; &1来代替是否为奇数,即用absExponent&1来代替absExponent%2==1
