Przekroczenie zakresu typu double

0

Witam!
Nie jestem pewien czy nazwa tematu jest odpowiednia, ale tak czy tak opiszę mój problem.

Mianowicie...

Rzecz w tym, że mam napisać program do liczenia kilku zagadnień matematycznych takich jak silnia i tak dalej. Weźmy tą silnię pod młotek. Licząc małe silnie, rzędu do 18! to wszystko gra. Problem pojawia się, gdy chce obliczyć 19! i więcej. Wtedy mój program kończy działanie(każde od 19! do x!) wynikiem 92233720368547760. Jak sprawić, żeby program prawidłowo liczył wyższe silnie? Pomoże ktoś? Nie chcę się tutaj "chwalić" kodem. Powiem tylko, że działam na typie double, bo tak mi zostało zlecone zadanie. BigDecimal czy BigInteger nie wchodzi w grę. Da się w ogóle coś takiego wykonać czy zostałem wpuszczony w maliny?

1

Jak sprawić, żeby program prawidłowo liczył wyższe silnie? Pomoże ktoś? Nie chcę się tutaj "chwalić" kodem.

Najpierw wyślij szklaną kulę. Względnie możesz po prostu napisać program poprawnie.

Z wikipedii:
max double = 1.7976931348623157 × 10^308

Spokojnie możesz policzyć np silnię ze stu. Tyle, że wynik będzie przybliżony.

0

Silnie liczę metodą rekurencyjną:

static public double Silnia(double ekran)
    {
        if (ekran == 0) 
            return 1;
        else 
            return ekran * Silnia(ekran - 1);
    }

Funkcję wywołuję z parametrem double i wtedy pakuję w okienko:
this.jTextField1.setText((String.valueOf(df.format(wynik))));

Wiem, może niezbyt profesjonalne. Bawiłem sie DecimalFormat, stąd tam df.format.

1

A zmienna wynik jaki ma typ? Zamień to setText(whatever) na setText(String.valueOf(wynik)) gdzie wynik ma typ double i nie ma żadnych konwersji na longi czy cokolwiek po drodze.

PS:
Z ciekawości wyguglałem liczbę która podałeś i znalazłem to: http://stackoverflow.com/questions/12200058/java-numeric-types-to-as3-types

PS2:
Parametr do silni powinien być typu int.

0

Korzystając z typu long dojedziesz do 20!, a korzystając z typu double dojedziesz do 21!. Dalsze wartości są już przybliżone.

0

Zamień to setText(whatever) na setText(String.valueOf(wynik)) gdzie wynik ma typ double i nie ma żadnych konwersji na longi czy cokolwiek po drodze.

Miałem tak na początku, to nawet 12! zapisywało w notacji wykładniczej, a tego nie potrzebuję.
Zmiana na int też nie pomogła w niczym.

1

A wynik w notacji wykładniczej był prawidłowy?

Jeszcze 15 postów i dowiemy się w którym miejscu jest błąd :]

Jaki jest typ zmiennej wynik? Jest gdzieś rzutowanie na longa (implicite lub explicite)? Jak wygląda ten decimalformat?

Zamiana parametru na int nie ma pomóc tylko ma sprawić że kod będzie mniej WTFowy. Silnię oblicza się z argumentu będącego liczbą naturalną, a nie rzeczywistą.

0

Dobra. wynik jest typu double. Wynik w postaci wykładniczej był ten sam tyle że po pierwszej dziewiątce miałem kropeczkę i na końcu Ex, gdzie x to liczba w zależności od wielkości silni. DF wygląda tak:

DecimalFormat df = new DecimalFormat("#");

A, i może jeszcze istotny fakt(może). Dane pobieram z TextFielda, przez parsowanie do double. Później żeby zapisać wynik w TextFieldzie, parsuję wynik do Stringa

0
DecimalFormat df = new DecimalFormat("#############################################################################");
setText(df.format(wynik));

Hashy może być trochę mniej.

0

Nie pomogło :<

0

Gdzieś coś pokopałeś z zamianą typów bo twoja silnia działa.

http://ideone.com/T33feD
Wiki podaje 100! = 9.332621544×10^157
Program wypluwa 9.33262154439441E157 czyli 9.33262154439441 * 10^157

Wynik który otrzymujesz można wygenerować tym programem: http://ideone.com/Iolywr
Ale równie dobrze można też w taki sposób: http://ideone.com/RUXPnA
I wydaje mi się, że w twoim programie robisz tę drugą rzecz (co jest oczywistym błędem).

DecimalFormat dobrze też sobie radzi z dużym double: http://ideone.com/pjk3jz

0

Z tym, że nie mam żadnego rzutowania w programie :<
Ekran jest parsowany na double
ekran = Double.parseDouble(this.jTextField1.getText());
ekran jest typu double, wiadomka.
Później ta zmienna leci jako argument metody, która zwraca wartość przypisywaną do zmiennej wynik.
Metoda ma postać jak wyżej w poście podałem.
No i wynik jest wypisywany na ekran, ale to wszystko w piiz...
Bo jest jeszcze jedna rzecz o której nie wspomniałem. Mianowicie...
Mój program poza takimi silniami ma liczyć takie rzeczy jak tangensy i sinusy, a dodatkowo ma je podawać z dokładnością ustaloną przez użytkownika. I tutaj leżał cały problem, bo tą dokładność miałem póki co zrobioną tak żeby jakoś działała i to w niej lezał cały problem. Po zakomentowaniu wszystko działa. Poza dokładnością. Kod metody dokładności:

static public double Dokladnosc(double wynik, double dokladnosc)
    {
        wynik=wynik*Math.pow(10,dokladnosc);
        wynik=Math.round(wynik);
        wynik=wynik/Math.pow(10,dokladnosc);
        return wynik;
    }

wiem wiem, naiwne. Jeśli ktoś ma pomysł na realizację dokładności to proszę o pomoc, póki co dziękuję za pomoc z Wynikiem silnii. Super jesteście.

0

Coś takiego

String pattern = "#########";
if(dokladnosc>0)
{
    pattern+=".";
    for(int i=0;i<dokladnosc;i++)
    {
        pattern+="#";
    }
}
DecimalFormat df = new DecimalFormat(pattern);
...
df.format(wynik);
0

Czyli tak jak pisałem. Math.round zwraca longa, a potem dzielisz go przez 100 i w międzyczasie rzutujesz implicite pomiędzy longiem a doublem. Nie wiem co ta funkcja ma robić, ale jeśli chcesz uniknąć rzutowania na longa to użyj Math.rint zamiast Math.round.

0

Ok, fajne, z tym, że jak to ostatecznie wyświetlam na ekranie, to podaje mi z przecinkiem a nie z kropeczką, a gdy np, chcę wykonac kolejne działanie i naciskam przycisk to nagle wynik zmienia się na wynik z kropeczką, ale na końcu dodaje się kilka zer i 2, np

128,1 -> 128.1000000000000002

Ale jakoś sobie może z tym poradzę. Dziękuję

Wibowit - Twoją metodę też wypróbuję, ale już raczej nie dzisiaj, bo mam już małe zamieszanko w głowie z tym projektem i czas zrobić przerwę. Niemniej, dziękuję serdecznie za całą pomoc :>

0

Wykorzystaj kod od bogdans do wyświetlania w postaci zaokrąglonej. Wyników pośrednich nie zaokrąglaj, a więc najlepiej wywal metodę Dokladnosc.

0

Wywaliłem, znaczy, zastąpiłem wnętrzności mojej metody bogdans'owym kodem. Ale mam problem taki jak opisałem wyżej.

0

Bo kolejne działanie pewnie obsługujesz zupełnie innym kodem i nie wykorzystujesz w nim kodu bogdansa do wyświetlania, ani nie wyrzuciłeś metody Dokladnosc w diabły.

0

Dobra. To jest koniec na dziś moich prac, bo nawet coś tak oczywistego nie wpadło mi do głowy. Jeśli jednak nie w tym tkwi problem to jeszcze tutaj zgłoszę problem. Na razie dziękuję wszystkim.

1 użytkowników online, w tym zalogowanych: 0, gości: 1