2015-11-10 11 views
13

So che java.lang.Math fornisce un insieme di metodi statici per eseguire alcune operazioni (sum, difference, multiply, increment, decrement, negate, toInt), lanciando un ArithmeticException su overflow.Come rilevare trabocco sul potere in Java

C'è qualcosa di simile per il potere?

risposta

9

No, non esiste nulla di equivalente per pow integrato in Java. (Le uniche pow metodi integrate in Java sono Math.pow, che accoglie raddoppia e non trabocchi nella stessa maniera interi fanno, e BigInteger.pow, evitando di troppo pieno perché BigInteger s possono essere arbitrariamente grande.)

caso le librerie di terze parti sono accettabili, però, Guava ha eg IntMath.checkedPow, che fa quello che stai cercando.

+0

Penso che dovresti menzionare anche "LongMath.checkedPow". Penso che (anche se potrei sbagliarmi) è banale per 'int' perché ogni' int' può essere rappresentato come un double, quindi devi solo fare 'Math.pow (a, b)' e confrontare con 'Integer.MAX_VALUE '. –

+0

@Louis Se utilizzo il 'BigInteger' non posso preoccuparmi della dimensione del numero ottenuto? – Claudia

+1

@Claudia [BigInteger] (https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html): "numeri interi arbitrari di precisione ... Tutti i dettagli nella Specifica relativa l'overflow viene ignorato, dato che i BigInteger sono grandi quanto necessario per adattarsi ai risultati di un'operazione. " –

0

I numeri interi sono solo 32 bit. quindi il valore massimo è 2^31 -1. (Se si utilizza BigInteger.pow. È meno efficiente.) Quindi è possibile controllare manualmente e lanciare Eccezione se necessario altrimenti utilizzare Math.pow che utilizza il doppio.

+3

Questa non è una risposta. La domanda è se esiste un tale metodo (presumo all'interno dell'API Java 8). – Turing85

+0

Quello che sto cercando di dire è che possiamo scrivere il nostro codice e naturalmente non esiste un'eccezione. Grazie. – Chirag

+0

Java è completo, quindi si presume che sia possibile scrivere qualsiasi algoritmo all'interno di Java. – Turing85

4

Come detto Chirag, i numeri interi generano eccezioni quando superano mentre i doppi non lo fanno. Non per diventare troppo specifici ma, fondamentalmente, i doppi in memoria sono memorizzati in modo molto simile alla notazione scientifica, in quanto sono alcuni interi * 2^(un po 'di potenza), e quindi non eccedono davvero ma moltiplicano per un 2^grande o piccolo (un po 'di potere) che perdono completamente la loro precisione. Quindi puoi pensare al doppio overflow come quando perdono completamente la loro precisione e vengono stampati come Infinity o -Infinity.

Quindi, è necessario verificare manualmente che si sia verificato un overflow verificando se il valore risultante è Double.POSITIVE_INFINITY o Double.NEGATIVE_INFINITY.

Ecco alcuni esempi di codice per mostrare quello che voglio dire:

public static void main(String[] args) throws Exception 
{ 
    double a = Double.MAX_VALUE; // highest possible double 
    double b = Double.MAX_VALUE; // highest possible double 

    if (Math.pow(a, b) == Double.POSITIVE_INFINITY || Math.pow(a, b) == Double.NEGATIVE_INFINITY) 
    { 
     throw new ArithmeticException("Double Overflow"); 
    } 
} 
1

Se è bene avere una propria implementazione, si potrebbe fare qualcosa di simile:

private static final int[] maxBaseForExponent = IntStream.range(0, 30) 
     .map(e -> (int) Math.pow(Integer.MAX_VALUE, 1d/e)).toArray(); 

public static int powExact(int base, int exponent) { 
    if (exponent < 0) { 
     throw new ArithmeticException("Negative exponent"); 
    } 
    if ((base < -1 || base > 1) && (exponent > 30 || base > maxBaseForExponent[exponent]) 
      && !(base == -2 && exponent == 31)) { 
     throw new ArithmeticException("Overflow"); 
    } 
    switch (base) { 
    case -2: 
     return (exponent & 1) == 0 ? 1 << exponent : -1 << exponent; 
    case -1: 
     return (exponent & 1) == 0 ? 1 : -1; 
    case 0: 
     return exponent == 0 ? 1 : 0; 
    case 1: 
     return 1; 
    case 2: 
     return 1 << exponent; 
    default: 
    } 
    int result = 1; 
    while (exponent != 0) { 
     if ((exponent & 1) != 0) { 
      result *= base; 
     } 
     exponent >>= 1; 
     base *= base; 
    } 
    return result; 
} 

Ha preso l'algoritmo da here e modificato per verificare l'overflow utilizzando un array che contiene la base massima per ciascun esponente da 0 a 30.

Problemi correlati