实现基于整数的幂函数的最有效方法 pow(int, int)

The most efficient way to implement an integer based power function pow(int, int)

提问人:Doug T. 提问时间:9/19/2008 最后编辑:durron597Doug T. 更新时间:5/19/2023 访问量:272621

问:

将一个整数提高到 C 中另一个整数的幂的最有效方法是什么?

// 2^3
pow(2,3) == 8

// 5^5
pow(5,5) == 3125
C 算法 数学

评论

0赞 jalf 5/30/2009
C 没有 pow() 函数吗?
27赞 Nathan Fellman 5/30/2009
是的,但这适用于浮点数或双精度值,不适用于整数
7赞 Andy Lester 10/3/2008
当你说“效率”时,你需要指定与什么相关的效率。速度?内存使用情况?代码大小?可维护性?
3赞 Adrian McCarthy 1/8/2016
如果你坚持使用实际的 s(而不是一些巨大的 int 类),那么对 ipow 的大量调用就会溢出。这让我想知道是否有一种聪明的方法来预先计算表并将所有非溢出组合简化为简单的表查找。这将比大多数一般答案占用更多的内存,但就速度而言可能更有效。int
1赞 EsmaeelE 10/29/2017
pow()不是一个安全的功能

答:

8赞 10 revs, 2 users 96%Doug T. #1

一个非常特殊的情况是,当你需要说 2^(-x 到 y) 时,其中 x,当然是负数,而 y 太大而无法对 int 进行移位。您仍然可以通过用浮子拧紧在恒定时间内执行 2^x。

struct IeeeFloat
{

    unsigned int base : 23;
    unsigned int exponent : 8;
    unsigned int signBit : 1;
};


union IeeeFloatUnion
{
    IeeeFloat brokenOut;
    float f;
};

inline float twoToThe(char exponent)
{
    // notice how the range checking is already done on the exponent var 
    static IeeeFloatUnion u;
    u.f = 2.0;
    // Change the exponent part of the float
    u.brokenOut.exponent += (exponent - 1);
    return (u.f);
}

通过使用替身作为基本类型,您可以获得 2 的更多幂。 (非常感谢评论者帮助解决这篇文章)。

还有一种可能性是,了解更多关于IEEE浮点数的信息,可能会出现其他特殊情况的幂。

评论

0赞 paxdiablo 9/19/2008
漂亮的解决方案,但不合时宜??
0赞 Drealmer 9/19/2008
IEEE 浮点数是以 x 2 ^ exp 为基数,更改指数值除了乘以 2 的幂之外不会导致任何其他结果,并且很有可能它会使浮点数非规范化......恕我直言,你的解决方案是错误的
0赞 Doug T. 9/19/2008
你们都是对的,我记错了我的解决方案最初是写的,哦,很久以前,明确地用于 2 的幂。我重写了我的答案,作为该问题的特殊情况解决方案。
0赞 freespace 9/19/2008
首先,代码被引用时损坏,需要编辑才能编译。其次,使用 gcc 在 core2d 上破解代码。看到这个转储 也许我做错了什么。然而,我认为这行不通,因为 IEEE 浮点指数是以 10 为基数。
3赞 Drealmer 9/19/2008
基数 10?呃,不,它是以 2 为基数,除非你的意思是二进制 10 :)
447赞 Elias Yarrkov 9/19/2008 #2

平方幂。

int ipow(int base, int exp)
{
    int result = 1;
    for (;;)
    {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        if (!exp)
            break;
        base *= base;
    }

    return result;
}

这是在非对称密码学中对大量数字进行模块化幂运算的标准方法。

评论

51赞 user9876 7/29/2009
您可能应该添加一个检查,以检查“exp”不是负数。目前,此函数要么给出错误的答案,要么永远循环。(取决于 >>= 在有符号的 int 上是执行零填充还是符号扩展 - 允许 C 编译器选择其中任何一种行为)。
32赞 orlp 8/31/2012
我写了一个更优化的版本,可以在这里免费下载: gist.github.com/3551590 在我的机器上,它的速度大约快了 2.5 倍。
13赞 Ilmari Karonen 4/9/2013
@AkhilJain:C语言非常好;要使其在 Java 中也有效,请分别替换 和 with 和。while (exp)if (exp & 1)while (exp != 0)if ((exp & 1) != 0)
5赞 Craig McQueen 8/21/2013
您的函数可能应该有 ,否则可以正确处理负数。unsigned expexp
8赞 bames53 10/12/2015
@ZinanXing 乘以 n 次会导致更多的乘法,并且速度较慢。这种方法通过有效地重用乘法来节省乘法。例如,要计算 n^8,使用 7 次乘法的朴素方法。该算法仅计算三次乘法,然后计算 ,然后计算 ,然后计算 ,其中 = n^8。对于较大的指数,性能差异很大。n*n*n*n*n*n*n*nm=n*no=m*mp=o*op
6赞 Chris Cudmore 9/19/2008 #3
int pow( int base, int exponent)

{   // Does not work for negative exponents. (But that would be leaving the range of int) 
    if (exponent == 0) return 1;  // base case;
    int temp = pow(base, exponent/2);
    if (exponent % 2 == 0)
        return temp * temp; 
    else
        return (base * temp * temp);
}

评论

0赞 MSalters 8/13/2015
不是我的投票,但尽管有负指数,但不会离开 int 的范围。现在一个人是偶然工作的,就像.pow(1, -1)pow(-1, -1)
1赞 bartgol 8/15/2017
唯一可能不会让您离开 int 范围的负指数是 -1。它仅在基数为 1 或 -1 时才有效。因此,只有两对 exp<0 的 exp不会导致非整数幂。虽然我是一个材料学家,我喜欢量词,但我认为在这种情况下,在实践中,可以说负指数会让你离开整数领域......
91赞 Pramod 9/21/2008 #4

请注意,平方幂不是最优化的方法。作为适用于所有指数值的通用方法,这可能是您能做的最好的方法,但对于特定的指数值,可能有一个更好的序列,需要更少的乘法。

例如,如果你想计算 x^15,通过平方进行幂的方法将给你:

x^15 = (x^7)*(x^7)*x 
x^7 = (x^3)*(x^3)*x 
x^3 = x*x*x

这总共是 6 次乘法。

事实证明,这可以通过加法链幂使用“仅”5 次乘法来完成。

n*n = n^2
n^2*n = n^3
n^3*n^3 = n^6
n^6*n^6 = n^12
n^12*n^3 = n^15

没有有效的算法来找到这种最佳乘法序列。来自维基百科

寻找最短加法链的问题不能通过动态规划来解决,因为它不满足最优子结构的假设。也就是说,将幂分解为更小的幂是不够的,每个幂都以最小度计算,因为较小幂的加法链可能是相关的(共享计算)。例如,在上面 a¹⁵ 的最短加法链中,a⁶ 的子问题必须计算为 (a³)²,因为 a³ 被重用(而不是 a⁶ = a²(a²)²,后者也需要三次乘法)。

评论

6赞 Eric Postpischil 12/28/2013
@JeremySalwen:正如这个答案所述,二进制幂通常不是最优化的方法。目前还没有已知的有效算法来寻找最小的乘法序列。
3赞 Pacerier 9/16/2014
@EricPostpischil,这取决于您的应用程序。通常我们不需要通用算法来处理所有数字。参见《计算机编程的艺术》,第 2 卷:半数值算法
3赞 Toby Speight 10/19/2015
Alexander Stepanov 和 Daniel Rose 合著的《从数学到通用编程》一书中对这个问题进行了很好的阐述。恕我直言,这本书应该放在每个软件从业者的书架上。
2赞 lhf 4/14/2016
另请参阅 en.wikipedia.org/wiki/...
0赞 Josiah Yoder 8/18/2018
这可以针对整数进行优化,因为整数的幂远低于 255,不会导致 32 位整数溢出。您可以为每个 int 缓存最佳乘法结构。我想代码+数据仍然比简单地缓存所有权力要小......
4赞 Jason Z 10/3/2008 #5

作为对平方幂效率的评论的后续。

这种方法的优点是它在 log(n) 时间内运行。例如,如果你要计算一些巨大的东西,比如 x^1048575 (2^20 - 1),你只需要通过循环 20 次,而不是使用朴素的方法计算 100 万+。

此外,就代码复杂性而言,这比试图找到最优化的乘法序列更简单,就像 Pramod 的建议一样。

编辑:

我想我应该在有人标记我溢出的可能性之前澄清一下。这种方法假设你有某种巨大的库。

32赞 Jake 3/18/2011 #6

如果您需要将 2 提高到幂。最快的方法是通过功率进行位移。

2 ** 3 == 1 << 3 == 8
2 ** 30 == 1 << 30 == 1073741824 (A Gigabyte)

评论

0赞 Rob Smallshire 11/24/2011
有没有一种优雅的方法可以做到这一点,使 2 ** 0 == 1 ?
0赞 Déjà vu 5/6/2021
@RobSmallshire 也许(因为 1<<0 是 1,你必须检查它是否在 C 标准中,或者它是否依赖于平台,但你也可以注意它在 C 中有意义,这不是功率:)2 ** x = 1 << x2 ** x = x ? (1 << x) : 12 ** x
12赞 user1067920 5/9/2012 #7

这是 Java 中的方法

private int ipow(int base, int exp)
{
    int result = 1;
    while (exp != 0)
    {
        if ((exp & 1) == 1)
            result *= base;
        exp >>= 1;
        base *= base;
    }

    return result;
}

评论

0赞 Anushree Acharjee 7/10/2015
不适用于大容量,例如 POW(71045970,41535484)
23赞 David Etler 9/5/2015
@AnushreeAcharjee当然不是。计算这样的数字需要任意精度的算术。
1赞 Raman Yelianevich 11/25/2015
对于大数字,请使用 BigInteger#modPow 或 Biginteger#pow,已经实现了基于参数大小的适当算法
1赞 alx - recommends codidact 4/26/2021
一方面,该问题被 OP 标记为 C,因此它显然是一个 C 问题。此外,这种微优化通常不会在如此高级的语言中完成(如果你使用 Java,我猜性能不是你所追求的)。另一方面,如果这个问题在搜索引擎中很高,那么将其扩展到其他语言也可能很有趣。所以,不要介意我的旧评论:)
0赞 RARE Kpop Manifesto 5/18/2023
@AnushreeAcharjee : 是的,你也忘记了十进制的数字71045970 ^ 41535484326mn
6赞 aditya 5/14/2012 #8

如果你想得到一个整数 2 的值,提高到某物的幂,最好使用 shift 选项:

pow(2,5)可以替换为1<<5

这效率要高得多。

0赞 Vaibhav Fouzdar 12/28/2013 #9

另一个实现(在 Java 中)。可能不是最有效的解决方案,但 # 次迭代与指数解相同。

public static long pow(long base, long exp){        
    if(exp ==0){
        return 1;
    }
    if(exp ==1){
        return base;
    }

    if(exp % 2 == 0){
        long half = pow(base, exp/2);
        return half * half;
    }else{
        long half = pow(base, (exp -1)/2);
        return base * half * half;
    }       
}

评论

0赞 alx - recommends codidact 3/18/2019
不是 Java 问题!
1赞 Abhijit Gaikwad 6/19/2014 #10

考虑负 exponenet 的更通用的解决方案

private static int pow(int base, int exponent) {

    int result = 1;
    if (exponent == 0)
        return result; // base case;

    if (exponent < 0)
        return 1 / pow(base, -exponent);
    int temp = pow(base, exponent / 2);
    if (exponent % 2 == 0)
        return temp * temp;
    else
        return (base * temp * temp);
}

评论

1赞 jswolf19 8/29/2014
整数除法的结果为整数,因此负指数的效率可能要高得多,因为它只会返回 0、1 或 -1......
0赞 chux - Reinstate Monica 4/2/2015
pow(i, INT_MIN)可能是一个无限循环。
1赞 MSalters 8/13/2015
@chux:它可能会格式化您的硬盘:整数溢出是 UB。
0赞 chux - Reinstate Monica 8/13/2015
@MSalters不是整数溢出。将该结果分配给当然可能会溢出,可能导致时间的结束,但我会满足于一个看似随机的值。:-)pow(i, INT_MIN)temp
0赞 kyorilys 2/3/2015 #11

我使用递归,如果 exp 是偶数,5^10 =25^5。

int pow(float base,float exp){
   if (exp==0)return 1;
   else if(exp>0&&exp%2==0){
      return pow(base*base,exp/2);
   }else if (exp>0&&exp%2!=0){
      return base*pow(base,exp-1);
   }
}
2赞 chux - Reinstate Monica 4/2/2015 #12

迟到:

下面是一个解决方案,也可以尽可能地处理。y < 0

  1. 它使用 的结果 for maximum range。没有规定不适合的答案。intmax_tintmax_t
  2. powjii(0, 0) --> 1这是这种情况的常见结果
  3. pow(0,negative),另一个未定义的结果,返回INTMAX_MAX

    intmax_t powjii(int x, int y) {
      if (y < 0) {
        switch (x) {
          case 0:
            return INTMAX_MAX;
          case 1:
            return 1;
          case -1:
            return y % 2 ? -1 : 1;
        }
        return 0;
      }
      intmax_t z = 1;
      intmax_t base = x;
      for (;;) {
        if (y % 2) {
          z *= base;
        }
        y /= 2;
        if (y == 0) {
          break; 
        }
        base *= base;
      }
      return z;
    }
    

此代码使用永久循环来避免其他循环解决方案中的最终通用。该乘法是 1) 不需要的,2) 可能是溢出的,即 UB。for(;;)base *= baseint*int

评论

0赞 alx - recommends codidact 3/18/2019
powjii(INT_MAX, 63)导致 UB 中。考虑检查您是否可以乘以,或者移动到无符号并让它环绕。base *= base
0赞 alx - recommends codidact 3/18/2019
没有理由签字。它使代码复杂化,因为 where 是有效的奇怪情况,并且 any 将用于 的负值,因此最好将其取消签名并保存该代码。exp(-1) ** (-N)abs(base) > 10exp
1赞 chux - Reinstate Monica 3/18/2019
@CacahueteFrito 诚然,签署的内容并不是真正需要的,并且会带来您评论的复杂性,但 OP 的要求是具体的。因此,这些好的评论属于OP的问题。由于 OP 没有指定如何处理溢出,因此定义明确的错误答案仅比 UB 好一点。鉴于“最有效的方式”,我怀疑 OP 是否关心 OF。ypow(int, int)
0赞 rank1 8/13/2015 #13

我已经实现了一种算法,可以记住所有计算能力,然后在需要时使用它们。因此,例如,x^13 等于 (x^2)^2^2 * x^2^2 * x,其中 x^2^2 是从表中获取的,而不是再次计算它。这基本上是@Pramod答案的实现(但在 C# 中)。 所需的乘法次数为 Ceil(Log n)

public static int Power(int base, int exp)
{
    int tab[] = new int[exp + 1];
    tab[0] = 1;
    tab[1] = base;
    return Power(base, exp, tab);
}

public static int Power(int base, int exp, int tab[])
    {
         if(exp == 0) return 1;
         if(exp == 1) return base;
         int i = 1;
         while(i < exp/2)
         {  
            if(tab[2 * i] <= 0)
                tab[2 * i] = tab[i] * tab[i];
            i = i << 1;
          }
    if(exp <=  i)
        return tab[i];
     else return tab[i] * Power(base, exp - i, tab);
}

评论

1赞 alx - recommends codidact 3/18/2019
public?2个函数命名相同?这是一个C问题。
7赞 roottraveller 1/8/2016 #14

power()仅适用于整数的函数

int power(int base, unsigned int exp){

    if (exp == 0)
        return 1;
    int temp = power(base, exp/2);
    if (exp%2 == 0)
        return temp*temp;
    else
        return base*temp*temp;

}

复杂度 = O(log(exp))

power()函数用于负 EXP 和浮点基数。

float power(float base, int exp) {

    if( exp == 0)
       return 1;
    float temp = power(base, exp/2);       
    if (exp%2 == 0)
        return temp*temp;
    else {
        if(exp > 0)
            return base*temp*temp;
        else
            return (temp*temp)/base; //negative exponent computation 
    }

} 

复杂度 = O(log(exp))

评论

0赞 greybeard 1/8/2016
这与 Abhijit Gaikwadchux 的答案有何不同?请论证在呈现的第二个代码块中的用法(考虑展示如何计算)。floatpower(2.0, -3)
0赞 roottraveller 1/8/2016
@greybeard我已经提到了一些评论。可能是可以解决您的查询
1赞 alx - recommends codidact 3/18/2019
GNU 科学库已经有了第二个功能:gnu.org/software/gsl/manual/html_node/Small-integer-powers.html
0赞 Leon 3/24/2020
@roottraveller您能解释一下解决方案吗?为什么我们使用 temp,将 exp 除以 2 并检查 exp(偶数/奇数)?谢谢!negative exp and float base
-1赞 MarcusJ 8/17/2016 #15

我的情况有点不同,我正在尝试用一种力量创建一个面具,但我想无论如何我都会分享我找到的解决方案。

显然,它仅适用于 2 的幂。

Mask1 = 1 << (Exponent - 1);
Mask2 = Mask1 - 1;
return Mask1 + Mask2;

评论

0赞 MarcusJ 6/17/2017
我试过了,它不适用于 64 位,它被移开永远不会返回,在这种特定情况下,我尝试将所有位都设置为低于 X,包括 X。
0赞 Michaël Roy 6/17/2017
那是 1 << 64 吗?这是一个溢出。最大的整数正好低于该整数:(1 << 64) - 1。
0赞 Michaël Roy 6/17/2017
1 << 64 == 0,这就是原因。也许你的表示最适合你的应用。我更喜欢可以放在宏中的东西,而没有额外的变量,比如 ,这样就可以在编译时进行计算#define MASK(e) (((e) >= 64) ? -1 :( (1 << (e)) - 1))
0赞 MarcusJ 6/18/2017
是的,我知道什么是溢出。仅仅因为我没有使用这个词,并不是邀请我不必要地居高临下。正如我所说,这对我有用,花了一点努力才发现,因此分享它。就是这么简单。
0赞 Michaël Roy 6/18/2017
如果我冒犯了你,我很抱歉。我真的不是故意的。
-1赞 Johannes Blaschke 4/8/2018 #16

如果您在编译时知道指数(并且它是一个整数),则可以使用模板来展开循环。这可以提高效率,但我想在这里演示一下基本原理:

#include <iostream>

template<unsigned long N>
unsigned long inline exp_unroll(unsigned base) {
    return base * exp_unroll<N-1>(base);
}

我们使用模板专用化终止递归:

template<>
unsigned long inline exp_unroll<1>(unsigned base) {
    return base;
}

指数需要在运行时已知,

int main(int argc, char * argv[]) {
    std::cout << argv[1] <<"**5= " << exp_unroll<5>(atoi(argv[1])) << ;std::endl;
}

评论

4赞 alx - recommends codidact 3/18/2019
这显然不是 C++ 的问题。(c != c++) == 1
1赞 alx - recommends codidact 3/18/2019 #17

除了 Elias 的回答之外,当使用有符号整数实现时会导致未定义的行为,以及使用无符号整数实现时高输入值不正确,

以下是平方幂的修改版本,它也适用于有符号整数类型,并且不会给出不正确的值:

#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;

我使用了 ,但任何宽度(有符号或无符号)都可以使用,只需稍作修改。但是,如果需要使用非固定宽度的整数类型,则需要更改(在使用 )或类似的东西,这应该进行优化,但它更丑陋,而不是 C 常量表达式。此外,由于在完美正方形的情况下浮点精度,将结果转换为不是很好,但由于我不知道任何实现 - 或任何类型的最大值 - 是完美正方形,你可以接受它。int64_tSQRT_INT64_MAX(int)sqrt(INT_MAX)intsqrt()intINT_MAX

1赞 ToxicAbe 5/4/2021 #18

Swift 中的 O(log N) 解决方案...

// Time complexity is O(log N)
func power(_ base: Int, _ exp: Int) -> Int { 

    // 1. If the exponent is 1 then return the number (e.g a^1 == a)
    //Time complexity O(1)
    if exp == 1 { 
        return base
    }

    // 2. Calculate the value of the number raised to half of the exponent. This will be used to calculate the final answer by squaring the result (e.g a^2n == (a^n)^2 == a^n * a^n). The idea is that we can do half the amount of work by obtaining a^n and multiplying the result by itself to get a^2n
    //Time complexity O(log N)
    let tempVal = power(base, exp/2) 

    // 3. If the exponent was odd then decompose the result in such a way that it allows you to divide the exponent in two (e.g. a^(2n+1) == a^1 * a^2n == a^1 * a^n * a^n). If the eponent is even then the result must be the base raised to half the exponent squared (e.g. a^2n == a^n * a^n = (a^n)^2).
    //Time complexity O(1)
    return (exp % 2 == 1 ? base : 1) * tempVal * tempVal 

}
2赞 user1095108 5/6/2021 #19
int pow(int const x, unsigned const e) noexcept
{
  return !e ? 1 : 1 == e ? x : (e % 2 ? x : 1) * pow(x * x, e / 2);
  //return !e ? 1 : 1 == e ? x : (((x ^ 1) & -(e % 2)) ^ 1) * pow(x * x, e / 2);
}

是的,它是递归的,但一个好的优化编译器会优化递归。

评论

0赞 Andy 5/19/2021
Clang 确实优化了尾递归,但 gcc 不会,除非您替换乘法顺序,即 godbolt.org/z/EoWbfx5nc(e % 2 ? x : 1) * pow(x * x, e / 2)
0赞 user1095108 5/19/2021
@Andy我确实注意到正在挣扎,但我不介意,因为我正在将这个函数用作函数。gccconstexpr
0赞 anatolyg 7/8/2022 #20

这是一个用于计算的 O(1) 算法,受此注释的启发。它适用于 32 位签名。x ** yint

对于较小的值,它使用平方求幂。对于较大的值,只有少数值 的结果不会溢出。此实现使用查找表来读取结果,而无需进行计算。yyx

在溢出时,C 标准允许任何行为,包括崩溃。但是,我决定对 LUT 索引进行边界检查,以防止内存访问冲突,这可能是令人惊讶和不可取的。

伪代码:

If `x` is between -2 and 2, use special-case formulas.
Otherwise, if `y` is between 0 and 8, use special-case formulas.
Otherwise:
    Set x = abs(x); remember if x was negative
    If x <= 10 and y <= 19:
        Load precomputed result from a lookup table
    Otherwise:
        Set result to 0 (overflow)
    If x was negative and y is odd, negate the result

C代码:

#define POW9(x) x * x * x * x * x * x * x * x * x
#define POW10(x) POW9(x) * x
#define POW11(x) POW10(x) * x
#define POW12(x) POW11(x) * x
#define POW13(x) POW12(x) * x
#define POW14(x) POW13(x) * x
#define POW15(x) POW14(x) * x
#define POW16(x) POW15(x) * x
#define POW17(x) POW16(x) * x
#define POW18(x) POW17(x) * x
#define POW19(x) POW18(x) * x

int mypow(int x, unsigned y)
{
    static int table[8][11] = {
        {POW9(3), POW10(3), POW11(3), POW12(3), POW13(3), POW14(3), POW15(3), POW16(3), POW17(3), POW18(3), POW19(3)},
        {POW9(4), POW10(4), POW11(4), POW12(4), POW13(4), POW14(4), POW15(4), 0, 0, 0, 0},
        {POW9(5), POW10(5), POW11(5), POW12(5), POW13(5), 0, 0, 0, 0, 0, 0},
        {POW9(6), POW10(6), POW11(6), 0, 0, 0, 0, 0, 0, 0, 0},
        {POW9(7), POW10(7), POW11(7), 0, 0, 0, 0, 0, 0, 0, 0},
        {POW9(8), POW10(8), 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {POW9(9), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {POW9(10), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    };

    int is_neg;
    int r;

    switch (x)
    {
    case 0:
        return y == 0 ? 1 : 0;
    case 1:
        return 1;
    case -1:
        return y % 2 == 0 ? 1 : -1;
    case 2:
        return 1 << y;
    case -2:
        return (y % 2 == 0 ? 1 : -1) << y;
    default:
        switch (y)
        {
        case 0:
            return 1;
        case 1:
            return x;
        case 2:
            return x * x;
        case 3:
            return x * x * x;
        case 4:
            r = x * x;
            return r * r;
        case 5:
            r = x * x;
            return r * r * x;
        case 6:
            r = x * x;
            return r * r * r;
        case 7:
            r = x * x;
            return r * r * r * x;
        case 8:
            r = x * x;
            r = r * r;
            return r * r;
        default:
            is_neg = x < 0;
            if (is_neg)
                x = -x;
            if (x <= 10 && y <= 19)
                r = table[x - 3][y - 9];
            else
                r = 0;
            if (is_neg && y % 2 == 1)
                r = -r;
            return r;
        }
    }
}