计算整数的幂


76

Java中还有其他方法可以计算整数的幂吗?

Math.pow(a, b)现在使用,但是它返回一个double,这通常是很多工作,并且在您只想使用ints时看起来不太干净(那么幂也会总是产生int)。

有没有a**b像Python一样简单的东西?


2
这是这个问题的一个可能重复stackoverflow.com/questions/101439/...
bpgergo

Answers:


45

整数只有32位。这意味着其最大值为2^31 -1。如您所见,对于非常小的数字,您很快就会得到不能再用整数表示的结果。这就是Math.pow使用的原因double

如果要任意整数精度,请使用BigInteger.pow。但这当然效率较低。


42
+1,是的。但是如果Java建筑师加上的话,我认为很好pow(int, int)。您知道有时候您只是想要那个5^6,根本不在乎双打。
Petar Minchev

3
我只是在猜测,但我认为他们没有这样做,因为在大多数情况下,这种方法会导致完全错误的结果。最少惊讶的原则。
JB Nizet

1
是的,这很不错。但是,当您是一个愚昧无知的人并与之合作时int,没有什么能阻止您转换为(int)溢出值。
Petar Minchev

3
我的意思是,如果你定义“大多数情况下”作为“的投入最大的价值”,那么Java的当然不应该提供的*运营商无论是对intlong输入,因为大多数输入的乘法会溢出。实际上,即使加法也溢出了大约一半的时间!
BeeOnRope

对不起,我迟到了。为什么要使用double而不是long?
Blueriver

38

最好的算法是基于a ^ b的递归能力定义。

long pow (long a, int b)
{
    if ( b == 0)        return 1;
    if ( b == 1)        return a;
    if (isEven( b ))    return     pow ( a * a, b/2); //even a=(a^2)^b/2
    else                return a * pow ( a * a, b/2); //odd  a=a*(a^2)^b/2

}

该操作的运行时间为O(logb)。参考:更多信息


2
什么是isEven(b)方法做?一样b % 2 == 0吗?
HendraWD

1
我也想知道...那家伙走了,让我们想知道...溜溜的程序员...
Apostolos

不存在(isEven(b))' function -- meaning ((b&1)== 0)`-和不必要的复杂算法!(
阿波斯托洛斯

更好地处理b <0以避免无限递归的情况
Tzafrir

5
在我的基准测试中,对于整个值范围,这实际上比简单循环算法慢2到20倍。这里的递归会带来很多开销。
Gumby The Green

33

不,没有那么短的东西 a**b

如果您想避免出现重复,这是一个简单的循环:

long result = 1;
for (int i = 1; i <= b; i++) {
   result *= a;
}

如果要使用pow并将结果转换为整数,请按如下所示转换结果:

int result = (int)Math.pow(a, b);

5
@DmitryGinzburg:给定along为64位,则O(n)的上限为64。真的那么糟糕吗?
托马斯·韦勒2015年

1
@托马斯不,你错了;如果b2_000_000_000,那么您将不得不执行2e9操作而不是31使用其他解决方案
Dmitry Ginzburg 2015年

2
@DmitryGinzburg:在这种情况下,您会遇到很多溢出问题。OP的代码不包含参数验证。如果a小于2,则允许的最大数量应为64(对于a = 1,则没有意义)。
Thomas Weller

@Thomas溢出问题不是您的问题,而是跑步者的问题。
德米特里·金茨堡

1
在我的基准测试中,对于整个值范围,这实际上比递归O(log(b))算法快2到20倍。递归会带来很多开销。
Gumby The Green

32

当它是2的幂时。请记住,您可以使用简单快速的shift表达式 1 << exponent

例:

2 2 = 1 << 2= (int) Math.pow(2, 2)
2 10 = 1 << 10=(int) Math.pow(2, 10)

对于较大的指数(超过31),请改用long

2 32 = 1L << 32=(long) Math.pow(2, 32)

顺便说一句 在科特林你shl不是<<这样

(java)1L << 32= 1L shl 32(kotlin)



2

番石榴的数学库提供了两种在计算精确整数幂时有用的方法:

pow(int b, int k) 计算b到k的幂,并在溢出时自动换行

checkedPow(int b, int k)相同,除了它会ArithmeticException溢出

个人checkedPow()满足我对整数乘幂的大多数需求,并且比使用双精度版本和舍入等更干净,更混乱。在几乎所有需要幂函数的地方,溢出都是错误(或不可能,但是我想知道是否不可能的事成为可能)。

如果要获得long结果,则可以使用相应的LongMath方法并传递int参数。


2

好吧,您可以Math.pow(a,b)像以前使用的那样简单地使用它,而只需(int)先使用它即可转换其值。下面可以作为一个例子。

int x = (int) Math.pow(a,b);

您想要的位置ab位置doubleint值。这将根据需要将其输出简单地转换为整数值。


3
我不同意,如果3.0 ^ 1.0 = 2.999999...由于四舍五入的错误,答案将2是错误的。
隐藏

@Hidde是的,您是对的朋友,这肯定有一个缺点,感谢您的提及。它可能会导致错误的结果,但可能在这里你的例子会给出正确的结果3.0。只是作为一个例子来舍入误差为乘法2.2*3.0 = 6.0000005,而不是6.6
Shubham Srivastava

2
@Hidde Javadouble可以ints完全代表所有Java 。请参见Java语言规范,第5.1.2节“扩展基本转换”。
大卫·摩尔

3
@David,谢谢,但是我上面的论点仍然成立。数字本身将是精确的表示形式,但功效的结果可能并非如此。特别是对于大国。
隐藏

1
@Hidde如果幂的结果适合int,则将是正确的。如果不适合int,则十进制扩展不是您的问题,溢出是您的问题。
David Moles

2
import java.util.*;

public class Power {

    public static void main(String args[])
    {
        Scanner sc=new Scanner(System.in);
        int num = 0;
        int pow = 0;
        int power = 0;

        System.out.print("Enter number: ");
        num = sc.nextInt();

        System.out.print("Enter power: ");
        pow = sc.nextInt();

        System.out.print(power(num,pow));
    }

    public static int power(int a, int b)
    {
        int power = 1;

        for(int c = 0; c < b; c++)
            power *= a;

        return power;
    }

}

for循环的改进:for (; b > 0; b --)
tckmn 2013年

7
重大改进:将基数平方并在每一步将指数减半
凯文·克莱恩

1

我设法修改(边界,甚至检查,负数检查)Qx__答案。使用风险自负。0 ^ -1、0 ^ -2等。返回0。

private static int pow(int x, int n) {
        if (n == 0)
            return 1;
        if (n == 1)
            return x;
        if (n < 0) { // always 1^xx = 1 && 2^-1 (=0.5 --> ~ 1 )
            if (x == 1 || (x == 2 && n == -1))
                return 1;
            else
                return 0;
        }
        if ((n & 1) == 0) { //is even 
            long num = pow(x * x, n / 2);
            if (num > Integer.MAX_VALUE) //check bounds
                return Integer.MAX_VALUE; 
            return (int) num;
        } else {
            long num = x * pow(x * x, n / 2);
            if (num > Integer.MAX_VALUE) //check bounds
                return Integer.MAX_VALUE;
            return (int) num;
        }
    }

1

用于计算功率的重复平方算法的简单(不检查溢出或参数的有效性)实现:

/** Compute a**p, assume result fits in a 32-bit signed integer */ 
int pow(int a, int p)
{
    int res = 1;
    int i1 = 31 - Integer.numberOfLeadingZeros(p); // highest bit index
    for (int i = i1; i >= 0; --i) {
        res *= res;
        if ((p & (1<<i)) > 0)
            res *= a;
    }
    return res;
}

时间复杂度与指数p是对数的(即与表示p所需的位数成线性关系)。


1

pow方法存在一些问题:

  1. 我们可以替换(y&1)== 0; y%2 == 0时,
    按位运算总是更快。

您的代码总是将y减1并执行额外的乘法运算,包括y为偶数的情况。最好将这部分放在else子句中。

public static long pow(long x, int y) {
        long result = 1;
        while (y > 0) {
            if ((y & 1) == 0) {
                x *= x;
                y >>>= 1;
            } else {
                result *= x;
                y--;
            }
        }
        return result;
    }

0

与Python(幂可以通过a ** b来计算)不同,JAVA没有这种完成两个数字幂的结果的捷径。Java在Math类中具有名为pow的函数,该函数返回Double值

double pow(double base, double exponent)

但是您也可以使用相同的函数来计算整数的幂。在下面的程序中,我执行了相同的操作,最后将结果转换为整数(类型转换)。根据例子:

import java.util.*;
import java.lang.*; // CONTAINS THE Math library
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n= sc.nextInt(); // Accept integer n
        int m = sc.nextInt(); // Accept integer m
        int ans = (int) Math.pow(n,m); // Calculates n ^ m
        System.out.println(ans); // prints answers
    }
}

或者,Thejava.math.BigInteger.pow(int exponent)返回一个BigInteger,其值为(this ^ exponent)。指数是整数,而不是BigInteger。例:

import java.math.*;
public class BigIntegerDemo {
public static void main(String[] args) {
      BigInteger bi1, bi2; // create 2 BigInteger objects          
      int exponent = 2; // create and assign value to exponent
      // assign value to bi1
      bi1 = new BigInteger("6");
      // perform pow operation on bi1 using exponent
      bi2 = bi1.pow(exponent);
      String str = "Result is " + bi1 + "^" +exponent+ " = " +bi2;
      // print bi2 value
      System.out.println( str );
   }
}

0

使用以下逻辑来计算a的n次方。

通常,如果我们要计算n的幂次。我们将'a'乘以n次,这种方法的时间复杂度为O(n)将n乘以2,计算幂指数=仅将'a'乘以n / 2。将值加倍。现在,时间复杂度降低为O(n / 2)。

public  int calculatePower1(int a, int b) {
    if (b == 0) {
        return 1;
    }

    int val = (b % 2 == 0) ? (b / 2) : (b - 1) / 2;

    int temp = 1;
    for (int i = 1; i <= val; i++) {
        temp *= a;
    }

    if (b % 2 == 0) {
        return temp * temp;
    } else {
        return a * temp * temp;
    }
}

谢谢,但是我正在寻找一种内置在语言中且简短的方法。我确实知道计算功效的算法。
隐藏

0

base是要加电的数字,n是功率,如果n为0,则返回1;如果n为1,则返回基数;如果不满足条件,则使用公式base *(powerN (base,n-1))例如:升为使用该公式的2是:2(base)* 2(powerN(base,n-1))。

public int power(int base, int n){
   return n == 0 ? 1 : (n == 1 ? base : base*(power(base,n-1)));
}


0
import java.util.Scanner;

class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();

        for (int i = 0; i < t; i++) {

            try {
                long x = sc.nextLong();
                System.out.println(x + " can be fitted in:");
                if (x >= -128 && x <= 127) {
                    System.out.println("* byte");
                }
                if (x >= -32768 && x <= 32767) {
                    //Complete the code
                    System.out.println("* short");
                    System.out.println("* int");
                    System.out.println("* long");
                } else if (x >= -Math.pow(2, 31) && x <= Math.pow(2, 31) - 1) {
                    System.out.println("* int");
                    System.out.println("* long");
                } else {
                    System.out.println("* long");
                }
            } catch (Exception e) {
                System.out.println(sc.next() + " can't be fitted anywhere.");
            }

        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.