linux C下利用递归函数求x的n次方

本文介绍如何使用递归方法计算幂函数s=pow(x,n),通过对比非递归与递归实现方式,展示正确的递归函数修改方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用函数递归的方法计算s=pow(x,n)

注意:用pow求次方时要加<math.h>头文件

代码如下:

结果如图:

注意:看上去结果并没有什么问题,但是在fun函数中并没有调用自身,也就是说并没用进行递归运算,只是单纯的进行了x与x的n-1次方相乘,所以上面代码并不正确。

下面只需要修改一个地方便能实现函数递归。

代码如下:

只是把递归函数内返回值x*pow(x,n-1)改为x*fun(x,n-1),结果一样正确。

结果如图:

 

 

<think>我们正在讨论如何优化非2的次方除数的余操作(例如对10余)。由于位运算通常只对2的次方除数直接有效,我们需要其他技巧来处理非2的次方的情况。以下是一些优化技术:###1.**利用乘法与移位近似除法(MagicNumber方法)**这是最常用的优化技术,通过将除法转换为乘法和移位操作。其原理是:对于除数d,存在一个魔术数M和移位量s,使得:$$a\modd=a-d\times\left\lfloor\frac{a}{d}\right\rfloor$$而$\left\lfloor\frac{a}{d}\right\rfloor$可以通过$(a\timesM)\ggs$来近似计算(其中$\gg$表示右移)。**步骤**:1.选择魔术数M和移位量s,使得对于一定范围内的a,有:$$\left\lfloor\frac{a}{d}\right\rfloor=\left\lfloor\frac{a\timesM}{2^{s}}\right\rfloor$$2.然后余操作可以表示为:$$a\modd=a-d\times\left((a\timesM)\ggs\right)$$**示例:对10余(32位无符号整数)**-魔术数$M=\lceil2^{s}/10\rceil$,通常s取35(经验值)-具体实现:```cuint32_tmod10(uint32_ta){uint32_tquotient=(a*(uint64_t)0xCCCCCCCD)>>35;//魔术数0xCCCCCCCD=3435973837returna-quotient*10;}```注:这里使用64位乘法防止溢出,魔术数0xCCCCCCCD是$\lceil2^{35}/10\rceil$的值。**优点**:速度快,尤其适合固定除数的重复运算。**缺点**:魔术数依赖数据位宽和除数,需要预先计算。###2.**利用周期性化简**如果被除数a有周期性出现的特点(如连续整数),可以利用同余性质逐步化简:$$a\modd=(a\modk\timesd)\modd$$其中k是选定的化简系数(通常取2的次方以便位运算)。**示例:对10余**由于$10\times2^8=2560<65536$,对于16位整数:```cuint16_tmod10(uint16_ta){//第一步:模2560(因为2560=10*256,且256是2^8)a=a%2560;//第二步:模10(此时a小于2560,可用查表法或乘法优化)returna%10;}```**优化**:第一步用位与运算(因为$2560=256\times10$,但2560不是2的,所以不能直接位与。但我们可以利用$2560=0xA00$,所以$a\mod2560=a\&0x9FF$并不正确,因为模运算需要处理余数。因此,这里实际上还是需要一条件判断或减法循环。所以这种方法可能不如魔术数高效。###3.**查表法**当输入范围较小时,可直接查表获取余数。**示例**:如果a是8位整数(0~255),可建立256字节的查找表:```cconstuint8_tmod10_table[256]={0,1,2,3,4,5,6,7,8,9,0,1,...};//预先计算uint8_tmod10(uint8_ta){returnmod10_table[a];}```**优点**:速度极快(O(1)时间)。**缺点**:表大小随输入范围指数增长,仅适用于小范围输入。###4.**分治与累加**将大整数分解为多个小段,每段分别余,再合并结果。利用公式:$$(a\times2^k+b)\modd=((a\modd)\times(2^k\modd)+b)\modd$$**示例**:对32位整数a余10:```cuint32_tmod10(uint32_ta){uint32_tresult=0;while(a){result=(result+(a&0xFF))%10;//处理最低8位a>>=8;//右移8位if(a){//2^8mod10=6,所以移位后乘6result=(result*6)%10;}}returnresult;}```**优化**:可并行处理多个字节(SIMD指令)或展开循环。###5.**利用特殊除数的性质**某些除数有特殊数学性质可简化运算:-**除数为10**:利用十进制特性,取最后一位数字(相当于模10):```ccharlast_digit='0'+(a%10);//转换为字符```但这不是位运算优化。对于整数,我们可以观察:$$a\mod10=(a\mod100)\mod10$$然后模100可用查表法(0-99)或魔术数优化。###性能对比|方法|适用场景|指令周期(估算)|内存占用||------------------|-------------------|---------------|----------||魔术数乘法|通用,大整数|10-20cycles|极小||周期性化简|特定范围|15-30cycles|小||查表法|小范围输入(如8位)|1-2cycles|256B||分治累加|超大整数|50+cycles|极小||特殊除数性质|除数为10,100等|5-10cycles|可变|###嵌入式应用建议-**资源丰富场景**:优先使用魔术数乘法(速度快,代码固定)。-**内存受限场景**:若输入范围小(如a<256),用查表法;否则用分治累加。-**除数为10的优化特例**:```c//32位整数模10优化uint32_tmod10_opt(uint32_ta){uint32_tlow=a&0xFFFF;//低16位uint32_thigh=a>>16;//高16位//分别计算模10:高16位乘6(因为2^16mod10=6),再与低16位相加return((high%10)*6+(low%10))%10;}```###注意事项1.**魔术数计算工具**:可使用在线工具(如[libdivide](https://libdivide.com/))生成魔术数。2.**有符号数处理**:先取绝对值,计算余数后再调整符号。3.**测试覆盖**:验证魔术数在输入范围内的正确性(边界值如0、最大值等)。>**关键参考**:在Linux内核的`do_div`函数中广泛使用魔术数优化除法[^1]。§§相关问题§§1.如何计算魔术数(MagicNumber)用于除法优化?2.在资源受限的嵌入式系统中,如何选择最优的余算法?3.除数为3、5、7等小质数时有哪些特殊优化方法?4.如何处理64位整数的非2次方余?5.魔术数方法在哪些情况下会失效?</think>## 非2的次方除数余优化技术 针对非2的次方除数(如10)的余操作优化,以下是几种高效的位运算和数学优化技术: --- ### 一、魔术数乘法优化法(Magic Number) 这是最高效的通用方法,通过乘法和位移替代除法运算。其数学原理基于: $$ a \mod d = a - d \times \left\lfloor \frac{a}{d} \right\rfloor $$ 其中 $\left\lfloor \frac{a}{d} \right\rfloor$ 可通过魔术数乘法近似计算。 **32位整数对10余实现**: ```c uint32_t mod10(uint32_t a) { // 魔术数 = ceil(2^35/10) = 3435973837 uint64_t magic = (uint64_t)a * 0xCCCCCCCD; uint32_t quotient = (uint32_t)(magic >> 35); // 右移35位 return a - quotient * 10; } ``` **优化原理**: 1. 魔术数 $M = \lceil 2^{35}/10 \rceil = 3435973837$ (0xCCCCCCCD) 2. 计算 $\left\lfloor \frac{a}{10} \right\rfloor \approx (a \times M) \gg 35$ 3. 余数 $= a - 10 \times quotient$ **性能**:仅需1乘法和1移位,比传统除法快5-10倍[^1] --- ### 二、分治累加法 适用于大整数或资源受限环境,将数字分解为高位和低位处理: $$ (H \times 2^k + L) \mod d = [(H \mod d) \times (2^k \mod d) + L] \mod d $$ **32位整数对10余**: ```c uint32_t mod10(uint32_t a) { uint32_t high = a >> 16; // 高16位 uint32_t low = a & 0xFFFF; // 低16位 // 2^16 mod 10 = 65536 % 10 = 6 uint32_t high_mod = (high % 10) * 6; uint32_t low_mod = low % 10; return (high_mod + low_mod) % 10; } ``` **优化点**: 1. 利用 $2^{16} \equiv 6 \pmod{10}$ 的数学性质 2. 递归处理可进一步分解高位 3. 适合无硬件乘法器的MCU --- ### 三、查表法(LUT) 当输入范围有限时,直接预计算余数表: ```c // 适用于8位输入(0-255) const uint8_t mod10_table[256] = { 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9, // 0-19 ... // 重复模式直到255 }; uint8_t fast_mod10(uint8_t a) { return mod10_table[a]; } ``` **适用场景**: - 输入范围小(如8位数据) - 内存充足的嵌入式系统 - 与魔术数结合处理高位数据 --- ### 四、周期性位运算优化 利用模运算的周期性进行位级优化: ```c // 对10余的位运算优化 uint32_t bitwise_mod10(uint32_t a) { while(a > 9) { // 计算二进制位和 (等效模9) uint32_t sum = 0; while(a) { sum += a & 0xF; // 每处理4位 a >>= 4; } a = sum; } return a == 10 ? 0 : a; // 处理边界 } ``` **数学原理**: $10^n \equiv 1 \pmod{9}$,但需额外处理余数10 --- ### 五、加减法移位法 通过加减和移位逼近结果: ```c uint32_t mod10(uint32_t a) { // 近似计算 a/10 ≈ (a * 13) >> 7 uint32_t q = (a * 13) >> 7; uint32_t result = a - q * 10; // 结果校正 if(result >= 10) result -= 10; return result; } ``` --- ### 性能对比表 | 方法 | 指令周期 | 内存占用 | 适用范围 | |------------------|----------|----------|----------------| | 魔术数乘法 | 3-5 | 4字节 | 通用 | | 分治累加 | 10-15 | 极小 | 无硬件乘法器 | | 查表法 | 1 | 256字节 | 小范围输入 | | 周期性位运算 | 15-30 | 极小 | 资源极度受限 | | 加减法移位 | 8-12 | 极小 | 中低速处理器 | > **嵌入式实践建议**: > - ARM Cortex-M系列优先使用魔术数法 > - 8位MCU(如AVR)推荐分治累加法 > - 内存充足时查表法最快 > - 周期性位运算适合ASIC设计 --- ### 六、特殊案例:除数为10的优化 利用10=2×5的特性进行分层处理: ```c uint32_t mod10_opt(uint32_t a) { // 先模5:a & 0x7 (仅当a<15时成立) uint32_t mod5 = a & 0x7; // 再模2:a & 0x1 uint32_t mod2 = a & 0x1; // 中国剩余定理组合结果 if(mod5 % 2 != mod2) mod5 += 5; return mod5; } ``` > **限制**:仅适用于 $a < 15$,需配合分治法扩展范围[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值