2010-08-26 11 views
20

W moim małym projekcie muszę zrobić coś jak Math.pow (7777.66, 5555.44) tylko z BARDZO dużymi liczbami. Natknąłem się na kilka rozwiązań:Jak zrobić ułamkową moc na BigDecimal w Javie?

  • użycie podwójnie - ale numery są zbyt duże
  • Zastosowanie BigDecimal.pow ale brak wsparcia dla frakcyjnej
  • użytkowania X^(A + B) = X^A * Formuła X^B (B jest pozostałością drugiej liczby), ale znowu nie ma wsparcia dla dużego X lub dużego A, ponieważ wciąż konwertuję do podwójnego
  • Użyj jakiegoś algorytmu z serii Taylora lub czegoś podobnego - jestem niezbyt dobra z matematyki, więc ta ostatnia jest moją ostatnią opcją, jeśli nie znajdę żadnych rozwiązań (niektóre biblioteki lub formuła dla (A + B)^(C + D)).

Ktoś wie o bibliotece lub o łatwym rozwiązaniu? Pomyślałem, że wiele osób ma ten sam problem ...

p.s. Znalazłem bibliotekę o nazwie ApFloat, która twierdzi, że robi to w przybliżeniu, ale uzyskane wyniki były tak przybliżone, że nawet 8^2 dało mi 60 ...

+0

mógłbyś podać przykład tego, co chcesz osiągnąć, 8^2 = 64 dźwięki słabe i 2^100^100 musi zostać zmniejszone. – stacker

+0

Muszę powiedzieć, że wypróbowałem sztuczkę z formułą, która działa dobrze nawet z liczbami z milionami cyfr! (Wygląda na to, że nie wiem wszystkiego o podwójnym i wewnętrznym) ... Przykłady: 50!^10! = 12.50911317862076252364259 * 10^233996181 50!^0.06 = 7395.788659356498101260513 Kod jest trochę długi, aby zamieścić tutaj, ale masz pomysł X^(A + B) = X^A * X^B ... Teraz Próbuję zrozumieć, jak i dlaczego (a jeśli) to naprawdę działa z liczbami, które są ogromne. –

+0

Już podałem rozwiązanie tam http://stackoverflow.com/questions/11848887/bigdecimal-to-power-of-bigdecimal-on-java-android/22556217#22556217 –

Odpowiedz

21

Roztwór do argumentów pod 1.7976931348623157E308 (Double.MAX_VALUE), ale wyniki wspierające miliony cyfr:

Od numerów podwójnych obsługuje do MAX_VALUE (na przykład 100! w podwójnym wygląda tak: 9.332621544394415E157), nie ma problemu, aby użyć BigDecimal.doubleValue(). Ale nie powinieneś po prostu robić Math.pow (double, double), ponieważ jeśli wynik jest większy niż MAX_VALUE, otrzymasz nieskończoność. SO: użyj wzoru X^(A + B) = X^A * X^B, aby oddzielić obliczenia na DWIE moce, duże, używając BigDecimal.pow i małe (pozostałość drugiego argumentu), używając Math. pow, a następnie pomnóż. X zostanie skopiowany do DOUBLE - upewnij się, że nie jest większy niż MAX_VALUE, A będzie INT (maksymalnie 2147483647, ale BigDecimal.pow nie obsługuje liczb całkowitych więcej niż miliard), a B będzie podwójne, zawsze mniejsze niż 1. w ten sposób można wykonać następujące czynności (ignorować moje prywatne stałych itp):

int signOf2 = n2.signum(); 
    try { 
     // Perform X^(A+B)=X^A*X^B (B = remainder) 
     double dn1 = n1.doubleValue(); 
     // Compare the same row of digits according to context 
     if (!CalculatorUtils.isEqual(n1, dn1)) 
      throw new Exception(); // Cannot convert n1 to double 
     n2 = n2.multiply(new BigDecimal(signOf2)); // n2 is now positive 
     BigDecimal remainderOf2 = n2.remainder(BigDecimal.ONE); 
     BigDecimal n2IntPart = n2.subtract(remainderOf2); 
     // Calculate big part of the power using context - 
     // bigger range and performance but lower accuracy 
     BigDecimal intPow = n1.pow(n2IntPart.intValueExact(), 
       CalculatorConstants.DEFAULT_CONTEXT); 
     BigDecimal doublePow = 
      new BigDecimal(Math.pow(dn1, remainderOf2.doubleValue())); 
     result = intPow.multiply(doublePow); 
    } catch (Exception e) { 
     if (e instanceof CalculatorException) 
      throw (CalculatorException) e; 
     throw new CalculatorException(
      CalculatorConstants.Errors.UNSUPPORTED_NUMBER_ + 
       "power!"); 
    } 
    // Fix negative power 
    if (signOf2 == -1) 
     result = BigDecimal.ONE.divide(result, CalculatorConstants.BIG_SCALE, 
       RoundingMode.HALF_UP); 

Rezultaty przykładów:

50!^10! = 12.50911317862076252364259*10^233996181 

50!^0.06 = 7395.788659356498101260513 
+2

Nie jest to przydatne bez klas 'CalculatorUtils',' CalculatorConstants' lub 'CalculatorException' – Supuhstar

+0

Jeśli przykład nie jest użyteczny, nie używaj go, jest to przykład. Dlatego napisałem "ignorujcie moje prywatne stałe". W każdym razie możesz odgadnąć lub wymienić każdy z nich. –

0

Wykładniki = logarytmy.

Spójrz na Logarithm of a BigDecimal

+2

Eh? Z pewnością nie są synonimami, jeśli o to ci chodzi ... –

+0

Kod źródłowy odnoszący się do zaakceptowanej odpowiedzi na to pytanie ma więcej rozwiązań niż tylko dla logu naturalnego. – prunge

+1

@Prunge - Dzięki. Nigdy nie powiedziałem nic o dzienniku naturalnym.Naprawdę, jeśli spojrzysz na zaakceptowaną odpowiedź Gene Marina, to, co on opisuje, jest logarytmiczne. X^(A + B) = X^A * X^B jest odpowiednikiem wymowy log (podstawa X) A + log (podstawa X) B = log (podstawa X) (A * B). Powinno to umożliwić doprowadzenie liczb do możliwego do opanowania rzędu wielkości. –