C++ 计算C+中10的整数幂的速度比pow()快多少+;?

C++ 计算C+中10的整数幂的速度比pow()快多少+;?,c++,numerical,C++,Numerical,我知道2的幂可以使用实现,你可以使用查找表,这将是目前为止最快的 也可以考虑使用:---/P> 模板 expt(tp,无符号q) { tr(1); while(q!=0){ 如果(q%2==1){//q是奇数 r*=p; q--; } p*=p; q/=2; } 返回r; } 整数幂函数(不涉及浮点转换和计算)可能比pow()快得多。: 编辑:基准测试-朴素的整数求幂方法似乎比浮点方法的性能高出大约两倍: h2co3-macbook:~ h2co3$ cat quirk.c #include &

我知道2的幂可以使用实现,你可以使用查找表,这将是目前为止最快的

也可以考虑使用:---/P>

模板
expt(tp,无符号q)
{
tr(1);
while(q!=0){
如果(q%2==1){//q是奇数
r*=p;
q--;
}
p*=p;
q/=2;
}
返回r;
}
整数幂函数(不涉及浮点转换和计算)可能比
pow()快得多。

编辑:基准测试-朴素的整数求幂方法似乎比浮点方法的性能高出大约两倍:

h2co3-macbook:~ h2co3$ cat quirk.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <math.h>

int integer_pow(int x, int n)
{
    int r = 1;
    while (n--)
    r *= x;

    return r; 
}

int main(int argc, char *argv[])
{
    int x = 0;

    for (int i = 0; i < 100000000; i++) {
        x += powerfunc(i, 5);
    }

    printf("x = %d\n", x);

    return 0;
}
h2co3-macbook:~ h2co3$ clang -Wall -o quirk quirk.c -Dpowerfunc=integer_pow
h2co3-macbook:~ h2co3$ time ./quirk
x = -1945812992

real    0m1.169s
user    0m1.164s
sys 0m0.003s
h2co3-macbook:~ h2co3$ clang -Wall -o quirk quirk.c -Dpowerfunc=pow
h2co3-macbook:~ h2co3$ time ./quirk
x = -2147483648

real    0m2.898s
user    0m2.891s
sys 0m0.004s
h2co3-macbook:~ h2co3$ 
h2co3 macbook:~h2co3$cat quirk.c
#包括
#包括
#包括
#包括
#包括
#包括
整数功率(整数x,整数n)
{
int r=1;
而(n--)
r*=x;
返回r;
}
int main(int argc,char*argv[])
{
int x=0;
对于(int i=0;i<100000000;i++){
x+=powerfunc(i,5);
}
printf(“x=%d\n”,x);
返回0;
}
h2co3 macbook:~h2co3$铿锵-Wall-o怪癖怪癖.c-Dpowerfunc=integer\u pow
h2co3 macbook:~h2co3$time./quirk
x=-1945812992
实0m1.169s
用户0m1.164s
sys 0m0.003s
h2co3 macbook:~h2co3$铿锵-Wall-o怪癖怪癖.c-Dpowerfunc=pow
h2co3 macbook:~h2co3$time./quirk
x=-2147483648
实际0m2.898s
用户0m2.891s
系统0m0.004s
h2co3 macbook:~h2co3美元

计算10的积分幂肯定有比使用
std::pow()更快的方法。
!第一个实现是
pow(x,n)
可以在O(logn)时间内实现。下一个实现是
pow(x,10)
(x类似:

int quick_pow10(int n)
{
    static int pow10[10] = {
        1, 10, 100, 1000, 10000, 
        100000, 1000000, 10000000, 100000000, 1000000000
    };

    return pow10[n]; 
}
显然,您可以对
long
执行相同的操作

这应该比任何竞争方法快好几倍。但是,如果你有很多基数(尽管基数越大,值的数量会急剧下降),那么如果没有大量的组合,这仍然是可行的

作为比较:

#include <iostream>
#include <cstdlib>
#include <cmath>

static int quick_pow10(int n)
{
    static int pow10[10] = {
        1, 10, 100, 1000, 10000, 
        100000, 1000000, 10000000, 100000000, 1000000000
    };

    return pow10[n]; 
}

static int integer_pow(int x, int n)
{
    int r = 1;
    while (n--)
       r *= x;

    return r; 
}

static int opt_int_pow(int n)
{
    int r = 1;
    const int x = 10;
    while (n)
    {
        if (n & 1) 
        {
           r *= x;
           n--;
        }
        else
        {
            r *= x * x;
            n -= 2;
        }
    }

    return r; 
}


int main(int argc, char **argv)
{
    long long sum = 0;
    int n = strtol(argv[1], 0, 0);
    const long outer_loops = 1000000000;

    if (argv[2][0] == 'a')
    {
        for(long i = 0; i < outer_loops / n; i++)
        {
            for(int j = 1; j < n+1; j++)
            {
                sum += quick_pow10(n);
            }
        }
    }
    if (argv[2][0] == 'b')
    {
        for(long i = 0; i < outer_loops / n; i++)
        {
            for(int j = 1; j < n+1; j++)
            {
                sum += integer_pow(10,n);
            }
        }
    }

    if (argv[2][0] == 'c')
    {
        for(long i = 0; i < outer_loops / n; i++)
        {
            for(int j = 1; j < n+1; j++)
            {
                sum += opt_int_pow(n);
            }
        }
    }

    std::cout << "sum=" << sum << std::endl;
    return 0;
}
(我也可以选择使用
pow
,但我第一次尝试它时需要1m22.56秒,所以当我决定优化循环变量时,我删除了它)

这里是一个尝试:

// specialize if you have a bignum integer like type you want to work with:
template<typename T> struct is_integer_like:std::is_integral<T> {};
template<typename T> struct make_unsigned_like:std::make_unsigned<T> {};

template<typename T, typename U>
T powT( T base, U exponent ) {
  static_assert( is_integer_like<U>::value, "exponent must be integer-like" );
  static_assert( std::is_same< U, typename make_unsigned_like<U>::type >::value, "exponent must be unsigned" );

  T retval = 1;
  T& multiplicand = base;
  if (exponent) {
    while (true) {
      // branch prediction will be awful here, you may have to micro-optimize:
      retval *= (exponent&1)?multiplicand:1;
      // or /2, whatever -- `>>1` is probably faster, esp for bignums:
      exponent = exponent>>1;
      if (!exponent)
        break;
      multiplicand *= multiplicand;
    }
  }
  return retval;
}
//如果要使用类似bignum integer的类型,请进行专门化:
模板结构类似于:std::is_integral{};
模板结构make_unsigned_like:std::make_unsigned{};
模板
T功率(T基,U指数){
静态断言(是类似整数的::值,“指数必须是类似整数的”);
静态断言(std::is_same::值,“指数必须无符号”);
T retval=1;
T&被乘数=基数;
if(指数){
while(true){
//分支预测在这里会很糟糕,您可能需要进行微观优化:
retval*=(指数&1)?被乘数:1;
//或者/2,不管怎样--`>>1`可能更快,尤其是对于大块头:
指数=指数>>1;
如果(!指数)
打破
被乘数*=被乘数;
}
}
返回返回;
}
上面发生的是一些事情

首先,BigNum支持很便宜,它是
模板化的。它支持任何支持
*=own_type
的基类型,并且可以隐式转换为
int
,或者
int
可以隐式转换为它(如果两者都是真的,就会出现问题),并且您需要专门化一些
模板
s,以指示所涉及的指数类型是无符号的和类整数的

在这种情况下,类整数和无符号意味着它支持
&1
返回
bool
>1
返回可以从中构造并最终(在重复
>1
s之后)的内容当在
bool
上下文中对其进行评估时,返回
false
。我使用traits类来表示限制,因为像
-1
这样的值的简单使用会编译并(在某些平台上)永远循环,而(在其他平台上)不会


假设乘法为O(1),则此算法的执行时间为O(lg(指数)),其中lg(指数)是使用模板元编程对任何基进行
求解所需的次数:

template<int E, int N>
struct pow {
    enum { value = E * pow<E, N - 1>::value };
};

template <int E>
struct pow<E, 0> {
    enum { value = 1 };
};
模板
结构功率{
枚举{value=E*pow::value};
};
模板
结构功率{
枚举{值=1};
};
然后,它可用于生成可在运行时使用的查找表:

template<int E>
long long quick_pow(unsigned int n) {
    static long long lookupTable[] = {
        pow<E, 0>::value, pow<E, 1>::value, pow<E, 2>::value,
        pow<E, 3>::value, pow<E, 4>::value, pow<E, 5>::value,
        pow<E, 6>::value, pow<E, 7>::value, pow<E, 8>::value,
        pow<E, 9>::value
    };

    return lookupTable[n];
}
模板
长-长-快-波(无符号整数n){
静态长可查找[]={
pow::value,pow::value,pow::value,
pow::value,pow::value,pow::value,
pow::value,pow::value,pow::value,
pow::值
};
返回可查找的[n];
}
这必须与正确的编译器标志一起使用,以便检测可能的溢出

用法示例:

for(unsigned int n = 0; n < 10; ++n) {
    std::cout << quick_pow<10>(n) << std::endl;
}
for(无符号整数n=0;n<10;++n){
std::cout基于方法,但编译时生成缓存

#include <iostream>
#include <limits>
#include <array>

// digits

template <typename T>
constexpr T digits(T number) {    
  return number == 0 ? 0 
                     : 1 + digits<T>(number / 10);
}

// pow

// https://stackoverflow.com/questions/24656212/why-does-gcc-complain-error-type-intt-of-template-argument-0-depends-on-a
// unfortunatly we can't write `template <typename T, T N>` because of partial specialization `PowerOfTen<T, 1>`

template <typename T, uintmax_t N>
struct PowerOfTen {
  enum { value = 10 * PowerOfTen<T, N - 1>::value };
};

template <typename T>
struct PowerOfTen<T, 1> {
  enum { value = 1 };
};

// sequence

template<typename T, T...>
struct pow10_sequence { };

template<typename T, T From, T N, T... Is>
struct make_pow10_sequence_from 
: make_pow10_sequence_from<T, From, N - 1, N - 1, Is...> { 
  //  
};

template<typename T, T From, T... Is>
struct make_pow10_sequence_from<T, From, From, Is...> 
: pow10_sequence<T, Is...> { 
  //
};

// base10list

template <typename T, T N, T... Is>
constexpr std::array<T, N> base10list(pow10_sequence<T, Is...>) {
  return {{ PowerOfTen<T, Is>::value... }};
}

template <typename T, T N>
constexpr std::array<T, N> base10list() {    
  return base10list<T, N>(make_pow10_sequence_from<T, 1, N+1>());
}

template <typename T>
constexpr std::array<T, digits(std::numeric_limits<T>::max())> base10list() {    
  return base10list<T, digits(std::numeric_limits<T>::max())>();    
};

// main pow function

template <typename T>
static T template_quick_pow10(T n) {

  static auto values = base10list<T>();
  return values[n]; 
}

// client code

int main(int argc, char **argv) {

  long long sum = 0;
  int n = strtol(argv[1], 0, 0);
  const long outer_loops = 1000000000;

  if (argv[2][0] == 't') {

    for(long i = 0; i < outer_loops / n; i++) {

      for(int j = 1; j < n+1; j++) {

        sum += template_quick_pow10(n);
      }
    }
  }

  std::cout << "sum=" << sum << std::endl;
  return 0;
}

没有乘法和表版本:

//Nx10^n
int Npow10(int N, int n){
  N <<= n;
  while(n--) N += N << 2;
  return N;
}
//Nx10^n
int Npow10(int N,int N){

N如果是整数值,此函数计算x^y的速度将比计算pow快得多

int pot(int x, int y){
int solution = 1;
while(y){
    if(y&1)
        solution*= x;
    x *= x;
    y >>= 1;
}
return solution;

}

现在,使用
constexpr
,您可以这样做:

constexpr int pow10(int n) {
    int result = 1;
    for (int i = 1; i<=n; ++i)
        result *= 10;
    return result;
}

int main () {
    int i = pow10(5);
}

如果要计算,例如10^5,则可以:

int main() {
   cout << (int)1e5 << endl; // will print 100000
   cout << (int)1e3 << endl; // will print 1000
   return 0;
} 
intmain(){

cout
result*=10
也可以写成
result=(结果使用查寻表?查寻表只有在提升到整数值或十进制数值的幂并可缩放为整数时才有用。如果它可以是任意浮点,则必须使用
pow
或等效库。如果一边总是10,另一边总是整数,则可以编写自己的t能够并完成它。没有比这更快的了-它实际上是一个内存读取和一个或多个
//Nx10^n
int Npow10(int N, int n){
  N <<= n;
  while(n--) N += N << 2;
  return N;
}
int pot(int x, int y){
int solution = 1;
while(y){
    if(y&1)
        solution*= x;
    x *= x;
    y >>= 1;
}
return solution;
constexpr int pow10(int n) {
    int result = 1;
    for (int i = 1; i<=n; ++i)
        result *= 10;
    return result;
}

int main () {
    int i = pow10(5);
}
main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 100000
        mov     eax, 0
        pop     rbp
        ret
int main() {
   cout << (int)1e5 << endl; // will print 100000
   cout << (int)1e3 << endl; // will print 1000
   return 0;
} 
constexpr int pow10(int n) {
  int result = 1;
  for (int i = 0; i < n; i++) {
    result = (result << 3) + (result << 1);
  }
  return result;
}