Muszę obliczyć niektóre zmienne zmiennoprzecinkowe, a mój kolega sugeruje, żebym użył BigDecimal
zamiast tego, double
ponieważ będzie to bardziej precyzyjne. Ale chcę wiedzieć, co to jest i jak najlepiej wykorzystać BigDecimal
?
java
floating-point
double
bigdecimal
Truong Ha
źródło
źródło
Odpowiedzi:
A
BigDecimal
jest dokładnym sposobem przedstawiania liczb. ADouble
ma pewną precyzję. Praca z podwójnymi o różnych wielkościach (powiedzmyd1=1000.0
id2=0.001
) może spowodować całkowite0.001
odrzucenie podczas sumowania, ponieważ różnica wielkości jest tak duża. ZBigDecimal
tym by się nie stało.Wadą
BigDecimal
jest to, że jest wolniejszy i nieco trudniej jest zaprogramować algorytmy w ten sposób (z powodu przeciążenia+
-
*
i/
bez przeciążenia).Jeśli masz do czynienia z pieniędzmi lub precyzja jest koniecznością, użyj
BigDecimal
. W przeciwnym razieDoubles
są wystarczająco dobre.Polecam czytanie javadoc z
BigDecimal
jak robią to wyjaśnić rzeczy lepiej niż ja tutaj :)źródło
if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
BigDecimal
”, Double miałoby więcej „precyzji” (więcej cyfr).Mój angielski nie jest dobry, więc napiszę tutaj prosty przykład.
Wyjście programu:
Ktoś nadal chce używać podwójnie? ;)
źródło
System.out.println(0.003f - 0.002f);
BigDecimal jest dokładny:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
Istnieją dwie główne różnice od podwójnych:
Powodem, dla którego powinieneś używać BigDecimal do obliczeń pieniężnych, nie jest to, że może on reprezentować dowolną liczbę, ale że może reprezentować wszystkie liczby, które mogą być reprezentowane w postaci dziesiętnej i które obejmują praktycznie wszystkie liczby w świecie monetarnym (nigdy nie przenosisz 1/3 $ do kogoś).
źródło
Jeśli zapiszesz wartość ułamkową, taką
1 / 7
jak wartość dziesiętna, otrzymaszz nieskończoną sekwencją
142857
. Ponieważ możesz wpisać tylko skończoną liczbę cyfr, nieuchronnie wprowadzisz błąd zaokrąglania (lub obcięcia).Liczby takie jak
1/10
lub1/100
wyrażone jako liczby binarne z częścią ułamkową mają również nieskończoną liczbę cyfr po przecinku:Doubles
przechowuj wartości jako binarne i dlatego może wprowadzić błąd wyłącznie poprzez konwersję liczby dziesiętnej na liczbę binarną, nawet bez wykonywania arytmetyki.BigDecimal
Z drugiej strony liczby dziesiętne (jak ) przechowują każdą cyfrę dziesiętną taką, jaka jest. Oznacza to, że typ dziesiętny nie jest bardziej precyzyjny niż binarny zmiennoprzecinkowy lub typ punktu stałego w sensie ogólnym (tzn. Nie może przechowywać1/7
bez utraty precyzji), ale jest bardziej dokładny w przypadku liczb, które mają skończoną liczbę cyfr dziesiętnych jako często dotyczy to kalkulacji pieniężnych.BigDecimal
Dodatkową zaletą Javy jest to, że może mieć dowolną (ale skończoną) liczbę cyfr po obu stronach przecinka, ograniczoną tylko dostępną pamięcią.źródło
BigDecimal to biblioteka numeryczna Oracle o dowolnej precyzji. BigDecimal jest częścią języka Java i jest użyteczny w różnych aplikacjach, od finansowych po naukowe (tam gdzie jestem).
Nie ma nic złego w stosowaniu podwójnych metod do niektórych obliczeń. Załóżmy jednak, że chcesz obliczyć Math.Pi * Math.Pi / 6, czyli wartość funkcji Riemann Zeta dla prawdziwego argumentu dwóch (projekt, nad którym obecnie pracuję). Podział zmiennoprzecinkowy przedstawia bolesny problem błędu zaokrąglania.
Z drugiej strony BigDecimal zawiera wiele opcji obliczania wyrażeń z dowolną dokładnością. Metody dodawania, mnożenia i dzielenia opisane w dokumentacji Oracle poniżej „zajmują miejsce +, * i / w BigDecimal Java World:
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
Metoda CompareTo jest szczególnie przydatna w pętli while i for.
Należy jednak zachować ostrożność podczas korzystania z konstruktorów dla BigDecimal. Konstruktor ciągów jest bardzo przydatny w wielu przypadkach. Na przykład kod
BigDecimal onethird = nowy BigDecimal („0.33333333333”);
wykorzystuje reprezentację ciągu 1/3 do reprezentowania tej nieskończenie powtarzającej się liczby z określonym stopniem dokładności. Błąd zaokrąglenia jest najprawdopodobniej gdzieś tak głęboko w JVM, że błędy zaokrąglenia nie zakłócają większości twoich praktycznych obliczeń. Jednak z własnego doświadczenia widziałem, jak zaokrągla się w górę. Metoda setScale jest ważna pod tym względem, jak widać w dokumentacji Oracle.
źródło
/* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
Jeśli masz do czynienia z obliczeniami, istnieją przepisy dotyczące sposobu obliczania i jakiej precyzji należy użyć. Jeśli ci się nie uda, zrobisz coś nielegalnego. Jedynym prawdziwym powodem jest to, że reprezentacja bitowa przypadków dziesiętnych nie jest precyzyjna. Jak to ujął Basil, przykład jest najlepszym wytłumaczeniem. Aby uzupełnić jego przykład, oto co się dzieje:
Wynik:
Mamy też to:
Daje nam wynik:
Ale:
Ma wynik:
źródło