Berechnung der Potenzen von ganzen Zahlen

76

Gibt es in Java eine andere Möglichkeit, die Potenz einer Ganzzahl zu berechnen?

Ich benutze Math.pow(a, b)jetzt, aber es gibt a zurück double, und das ist normalerweise viel Arbeit und sieht weniger sauber aus, wenn Sie nur ints verwenden möchten (eine Leistung führt dann auch immer zu einem int).

Gibt es etwas so Einfaches a**bwie in Python?

Versteckt
quelle
2
Dies ist ein mögliches Duplikat dieser Frage stackoverflow.com/questions/101439/…
bpgergo

Antworten:

45

Ganzzahlen sind nur 32 Bit. Dies bedeutet, dass sein Maximalwert ist 2^31 -1. Wie Sie sehen, haben Sie bei sehr kleinen Zahlen schnell ein Ergebnis, das nicht mehr durch eine Ganzzahl dargestellt werden kann. Deshalb Math.powverwendet double.

Wenn Sie eine beliebige Ganzzahlgenauigkeit wünschen, verwenden Sie BigInteger.pow. Aber es ist natürlich weniger effizient.

JB Nizet
quelle
42
+1, das stimmt. Aber ich würde es schön finden, wenn die JavaArchitekten hinzugefügt haben pow(int, int). Du weißt, manchmal willst du das einfach 5^6und kümmerst dich überhaupt nicht um Doppel.
Petar Minchev
3
Ich rate nur, aber ich denke, sie haben es nicht getan, weil eine solche Methode in den meisten Fällen zu völlig falschen Ergebnissen führen würde. Prinzip des geringsten Erstaunens.
JB Nizet
1
Ja, das ist ein guter Punkt. Aber wenn Sie ein Unwissender sind und mit dem Sie arbeiten int, hindert Sie nichts daran, in (int)einen übergelaufenen Wert umzuwandeln .
Petar Minchev
3
Ich meine, wenn Sie "die meisten Fälle" als "für den größten Wert der Eingaben" definiert haben, sollte Java den *Operator weder für intnoch longfür Eingaben anbieten, da für die meisten Eingaben die Multiplikation überläuft. In der Tat läuft sogar die Zugabe etwa die Hälfte der Zeit über!
BeeOnRope
Entschuldigung, wenn ich zu spät komme. Warum doppelt und nicht lang verwenden?
Blueriver
38

Am besten basiert der Algorithmus auf der rekursiven Potenzdefinition von 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

}

Die Laufzeit der Operation ist O (logb). Referenz: Weitere Informationen

Ruh-u Revan
quelle
2
Und was macht die isEven(b)Methode? Ist es dasselbe mit b % 2 == 0?
HendraWD
1
Ich frage mich auch ... Der Typ ist gegangen und hat uns gefragt ... Slipshod-Programmierer ...
Apostolos
Inexistent (isEven(b))' function -- meaning ((b & 1) == 0) `- und ein unnötig komplizierter Algorithmus! (
Apostolos
Besser behandeln Fall, wo b <0, um unendliche Rekursion zu vermeiden
Tzafrir
5
In meinen Benchmarks ist dies tatsächlich 2x bis 20x langsamer als der einfache Schleifenalgorithmus für den gesamten Wertebereich. Die Rekursion hier verursacht viel Aufwand.
Gumby The Green
33

Nein, es gibt nicht so kurz wie a**b

Hier ist eine einfache Schleife, wenn Sie Doppel vermeiden möchten:

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

Wenn Sie powdas Ergebnis verwenden und in eine Ganzzahl konvertieren möchten, wandeln Sie das Ergebnis wie folgt um:

int result = (int)Math.pow(a, b);
Petar Minchev
quelle
5
@DmitryGinzburg: Wenn a long64 Bit ist, hat O (n) 64 als Obergrenze. Ist das wirklich so schlimm?
Thomas Weller
1
@ Thomas nein, du liegst falsch; Wenn dies der Fall bist 2_000_000_000, müssen Sie 2e9Operationen ausführen, anstatt 31in einer anderen Lösung
Dmitry Ginzburg,
2
@DmitryGinzburg: In diesem Fall treten viele Überlaufprobleme auf. Der OP-Code enthält keine Argumentvalidierung. Die maximal zulässige Anzahl sollte 64 sein, falls a so klein wie 2 ist (und für a = 1 macht es keinen Sinn).
Thomas Weller
@Thomas Überlaufprobleme sind nicht Ihr Problem, sondern das Problem des Läufers.
Dmitry Ginzburg
1
In meinen Benchmarks ist dies tatsächlich 2x bis 20x schneller als der rekursive O-Algorithmus (log (b)) für den gesamten Wertebereich. Die Rekursion verursacht viel Aufwand.
Gumby The Green
32

Wenn es die Potenz von 2 ist. Denken Sie daran, dass Sie einen einfachen und schnellen Shift-Ausdruck verwenden können 1 << exponent

Beispiel:

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

Verwenden Sie für größere Exponenten (über 31) stattdessen long

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

Übrigens. in Kotlin haben Sie shlstattdessen <<so

(Java) 1L << 32= 1L shl 32(Kotlin)

Stanislaw Baranski
quelle
7

Google Guava verfügt über mathematische Dienstprogramme für Ganzzahlen. IntMath

Ameise
quelle
2

Die Mathematikbibliotheken von Guava bieten zwei Methoden, die bei der Berechnung der exakten ganzzahligen Potenzen hilfreich sind:

pow(int b, int k) berechnet b bis zur k-ten Leistung und umschließt den Überlauf

checkedPow(int b, int k)ist identisch, außer dass es ArithmeticExceptionauf Überlauf wirft

checkedPow()Erfüllt persönlich die meisten meiner Anforderungen an die Potenzierung von Ganzzahlen und ist sauberer und sicherer als die Verwendung von Doppelversionen und Rundungen usw. An fast allen Stellen, an denen ich eine Potenzfunktion möchte, ist ein Überlauf ein Fehler (oder unmöglich, aber ich möchte wissen, ob das Unmögliche wird jemals möglich).

Wenn Sie ein longErgebnis erhalten möchten , können Sie einfach die entsprechenden LongMathMethoden verwenden und intArgumente übergeben.

BeeOnRope
quelle
2

Nun, Sie können einfach Math.pow(a,b)wie zuvor verwenden und den Wert einfach konvertieren, indem Sie ihn (int)vorher verwenden. Das Folgende könnte als Beispiel dafür dienen.

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

wo aund bkönnte sein doubleoder intWerte wie Sie wollen. Dadurch wird die Ausgabe einfach nach Bedarf in einen ganzzahligen Wert konvertiert.

Shubham Srivastava
quelle
3
Ich bin anderer Meinung, wenn 3.0 ^ 1.0 = 2.999999...aufgrund von Rundungsfehlern die Antwort 2falsch ist.
Hidde
@Hidde Ja, du bist der richtige Freund, das hat sicherlich einen Nachteil, danke für die Erwähnung. Es kann ein falsches Ergebnis liefern, aber wahrscheinlich würde Ihr Beispiel hier das richtige Ergebnis als 3.0.Nur als Beispiel für einen Rundungsfehler für die Multiplikation geben 2.2*3.0 = 6.0000005und nicht 6.6.
Shubham Srivastava
2
@Hidde Ein Java doublekann alle Java intsgenau darstellen. Siehe die Java-Sprachspezifikation, Abschnitt 5.1.2, " Erweitern der primitiven Konvertierung ".
David Moles
3
@ David, danke, aber mein Argument oben gilt immer noch. Die Zahlen selbst sind exakte Darstellungen, das Ergebnis der Potenz jedoch möglicherweise nicht. Besonders für große Mächte.
Hidde
1
@Hidde Wenn das Ergebnis der Leistung in eine passt int, wird es genau sein. Wenn es nicht in eine passt int, ist die Dezimalerweiterung nicht Ihr Problem, Überläufe sind Ihr Problem.
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;
    }

}
Mark Lamban
quelle
Verbesserung der forSchleife:for (; b > 0; b --)
tckmn
7
ernsthafte Verbesserung:
Quadrieren Sie
1

Ich habe es geschafft, die Qx__-Antwort zu ändern (Grenzen, sogar prüfen, negative Zahlen prüfen). Benutzung auf eigene Gefahr. 0 ^ -1, 0 ^ -2 etc .. gibt 0 zurück.

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;
        }
    }
Smarty77
quelle
1

Eine einfache Implementierung (keine Überprüfung auf Überlauf oder auf Gültigkeit von Argumenten) für den Algorithmus für wiederholtes Quadrieren zur Berechnung der Leistung:

/** 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;
}

Die zeitliche Komplexität ist logarithmisch zum Exponenten p (dh linear zu der Anzahl von Bits, die zur Darstellung von p erforderlich sind).

Michail Alexakis
quelle
1

Es gibt einige Probleme mit der Pow-Methode:

  1. Wir können (y & 1) ersetzen == 0; mit y% 2 == 0 sind
    bitweise Operationen immer schneller.

Ihr Code dekrementiert immer y und führt eine zusätzliche Multiplikation durch, einschließlich der Fälle, in denen y gerade ist. Es ist besser, diesen Teil in die else-Klausel aufzunehmen.

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;
    }
Erasyl Abenov
quelle
0

Im Gegensatz zu Python (wo Potenzen durch a ** b berechnet werden können) hat JAVA keine solche Abkürzung, um das Ergebnis der Potenz zweier Zahlen zu erzielen. Java hat eine Funktion namens pow in der Math-Klasse, die einen Double-Wert zurückgibt

double pow(double base, double exponent)

Mit derselben Funktion können Sie aber auch Potenzen von Ganzzahlen berechnen. Im folgenden Programm habe ich dasselbe getan und schließlich konvertiere ich das Ergebnis in eine Ganzzahl (Typumwandlung). Folge dem Beispiel:

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
    }
}

Alternativ gibt The java.math.BigInteger.pow(int exponent)eine BigInteger zurück, deren Wert (this ^ exponent) ist. Der Exponent ist eher eine Ganzzahl als eine BigInteger. Beispiel:

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 );
   }
}
Pritam Mullick
quelle
0

Verwenden Sie die folgende Logik, um die n-Potenz von a zu berechnen.

Normalerweise, wenn wir n Potenzen von a berechnen wollen. Wir werden 'a' mit n multiplizieren. Die zeitliche Komplexität dieses Ansatzes wird O (n) sein. Teilen Sie die Potenz n mit 2, berechnen Sie Exponentattion = multiplizieren Sie 'a' nur mit n / 2. Verdoppeln Sie den Wert. Jetzt wird die Zeitkomplexität auf O (n / 2) reduziert.

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;
    }
}
Yuvaraj Ram
quelle
Danke, aber ich suche einen Weg, der in die Sprache eingebaut und kurz ist. Ich kenne den Algorithmus zur Berechnung von Leistungen.
Versteckte
0

base ist die Zahl, die Sie einschalten möchten, n ist die Leistung, wir geben 1 zurück, wenn n 0 ist, und wir geben die Basis zurück, wenn n 1 ist. Wenn die Bedingungen nicht erfüllt sind, verwenden wir die Formel base * (powerN) (Basis, n-1)) zB: 2 zur Verwendung dieser Formel angehoben ist: 2 (Basis) * 2 (PotenzN (Basis, n-1)).

public int power(int base, int n){
   return n == 0 ? 1 : (n == 1 ? base : base*(power(base,n-1)));
}
Milch
quelle
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.");
            }

        }
    }
}
Sudarshan Padale
quelle