C++在不使用pow或循环的情况下计算一个数字的幂
C++ calculate the power of a number without using pow or loop
我是一名C++初学者,有一项任务是编写一个计算数字幂的函数,但我们不允许使用pow函数或循环。
函数的用户必须在命令窗口中输入基数和指数。
从什么地方开始?
pow(x, y)
可以写成exp(y * log(x))
。据我所知,这满足了问题的限制。
对于真正的x
和y
,任何替代方案都是困难的。当然,对积分y
使用递归有一些愚蠢的选择,但对线性问题使用递归从来都不是一个特别好的方法。
void start_here(unsigned int n) {
if (n > 0)
start_here(n - 1);
}
start_here(2019);
然后你写:
double pow(double x, unsigned int exp) {
if (exp > 0)
return x * pow(x, exp - 1);
else
return 1;
}
然后你会改进:
double pow(double x, unsigned int exp) {
if (exp > 0) {
const auto p2 = pow(x, exp / 2);
return p2 * p2 * ((exp & 1) ? x : 1);
}
else
return 1;
}
最后一种算法被称为二进制幂运算。
最后你学习了模板:
template<unsigned int exp>
constexpr double pow(double x) {
if constexpr (exp > 0) {
const auto p2 = pow<exp / 2>(x);
return p2 * p2 * ((exp & 1) ? x : 1);
}
else
return 1;
}
编辑尾部递归优化。让我们来看看为的第一个版本生成的程序集代码无优化的pow()
(-O0
(:
pow(double, unsigned int):
push rbp
mov rbp, rsp
sub rsp, 16
movsd QWORD PTR [rbp-8], xmm0
mov DWORD PTR [rbp-12], edi
cmp DWORD PTR [rbp-12], 0
je .L2
mov eax, DWORD PTR [rbp-12]
lea edx, [rax-1]
mov rax, QWORD PTR [rbp-8]
mov edi, edx
movq xmm0, rax
call pow(double, unsigned int)
mulsd xmm0, QWORD PTR [rbp-8]
jmp .L3
.L2:
movsd xmm0, QWORD PTR .LC0[rip]
.L3:
leave
ret
.LC0:
.long 0
.long 1072693248
我们看到一个递归CCD_ 8。
现在让我们添加一些优化(-O2 -ffast-math
(:
pow(double, unsigned int):
movapd xmm1, xmm0
movsd xmm0, QWORD PTR .LC0[rip]
test edi, edi
je .L4
.L3:
mulsd xmm0, xmm1
sub edi, 1
jne .L3
ret
.L4:
ret
.LC0:
.long 0
.long 1072693248
递归调用在哪里?它不见了!编译器采用尾调用优化,并将递归调用转换为简单循环。这个汇编代码相当于这个C++代码:
double pow(double x, unsigned int exp) {
double p = 1;
if (exp == 0)
return p;
loop:
p *= x;
if (--exp > 0)
goto loop;
return p;
}
由于浮点乘法的非结合性,如果没有-ffast-math
选项,这种优化是不可能的。
最后,1.d
在内存中用8个字节表示:
3F F0 00 00 | 00 00 00 00 (base 16)
转换成两个long
数字后,它们变为:
1072693248 | 0 (base 10)
这是两个可以在汇编代码中发现的神奇数字。
以下是您的操作方法。
int exponent(int , int );
int main()
{
cout<<exponent(3,8);
return 0;
}
int exponent(int x , int y )
{
if(y==0)
return 1;
return (x*exponent(x,y-1));
}
如果你觉得难以消化,请告诉我。
使用递归的解决方案:
double power(double x, double n, double product = 1) {
if (n <= 0) return product;
product *= x;
return power(x, n - 1, product);
}
int main()
{
cout << power(10, 2);
}
假设基数和指数为整数,为什么不直接进行循环展开呢。假设sizeof(int(=4字节=32位。
long long power (int base, int exponent)
{
long long result = 1;
long long powOf2 = base;
if (exponent%2)
result *= powOf2;
exponent >>= 1;
powOf2 *= powOf2;
if (exponent%2)
result *= powOf2;
exponent >>= 1;
powOf2 *= powOf2;
(copy paste 30 more times)
return result;
}
如果sizeof(int(=8,则复制粘贴62次,而不是30次。
相关文章:
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何获取一个数字的前3位
- 以C++输出一个数字三角形
- 反转一个数字程序不起作用,为什么?
- 如何让用户在 c++ 中选择一个数字
- 输出一个数字,该数字可能是三种类型之一
- C++在不使用pow或循环的情况下计算一个数字的幂
- 我必须更改我的数字最后一个数字和第一个数字,但不要使用仅带有整数或循环的函数.例如从 12345 到 52341
- 找到所有与自己求和的数字X的快速方法,去掉一个数字得到N
- C++[递归]将一个数字写成2的升序之和
- 试图找到一个数字的平方根,但代码不起作用。C++
- 我没有得到一个数字作为输出,而是一个表情符号
- 我的代码应该接受一个数字,并返回字母等级或"Grade is not valid"但 else 语句不起作用
- 将一个数字拆分为多个数字,每个数字只有一个有效位
- 你怎么编码,如果x不等于一个数字,程序就会退出
- 如何将整数数组相乘得到一个数字?
- 为无符号字符* 分配一个数字
- 如何以更有效的方式检查一个数字是否是素数?
- C++显示两个区间之间的数字的程序检查一个数字是否可以表示为两个素数的总和
- 字符串和双精度的麻烦,等值后再得到一个数字