2015-02-25 25 views
7

Czy ktoś może wyjaśnić, dlaczego otrzymuję 0 jako wynik dla pierwszej linii?BigDecimal 1.0E + 8/100000000 z ROUND_HALF_UP jest 0

System.out.println((new BigDecimal("1.0E+8")).divide(new BigDecimal(100000000), BigDecimal.ROUND_HALF_UP)); 
System.out.println((new BigDecimal("1.0E+8")).subtract(BigDecimal.ONE).divide(new BigDecimal(100000000), BigDecimal.ROUND_HALF_UP)); 

0E+7 
1 
+1

Dlaczego to jest "0E + 7", a nie "0"? – user2864740

+0

@ user2864740 To * jest * wynikiem, ale myślę, że OP oczekiwał '1'. – tnw

Odpowiedz

13

To wszystko ma do czynienia z łusek z BigDecimal s zaangażowanych .

Po określeniu formatu wykładniczego w constructor that takes a String, skala może być ujemna. Oznacza to, że cyfry znaczące nie rozciągają się aż do jedności.

BigDecimal oneEPlus8 = new BigDecimal("1.0E+8"); 
System.out.println(oneEPlus8.scale()); 

Powoduje to wyprowadzenie -7.

Korzystanie z constructor that takes an int daje skalę 0.

BigDecimal oneHundredMillion = new BigDecimal(100000000); 
System.out.println(oneHundredMillion.scale()); 

Powoduje to wyprowadzenie 0.

Po uzyskaniu divideBigDecimals iloraz przyjmuje skalę obiektu, na który jest wywoływana divide. Skala ilorazu jest więc również -7. Wynik został obliczony na 1, ale w skali -7, zaokrąglenia tylko daje dwie możliwości: 0 lub 10000000, więc ROUND_HALF_UP rundy do 0, dając wyjście 0E+7.

Po przyjęciu subtractBigDecimals różnica przyjmuje maksimum skali odejmowanych liczb. Skala różnicy wynosi 0. Wynik obliczany jest na 1, a skala 0 nie wymusza tutaj zaokrąglenia. Dane wyjściowe to 1.

Aby uzyskać wynik 1 bez konieczności odejmowania 1 można odjąć 0, czy można nazwać setScale(0) na oneEPlus8.

oneEPlus8 = oneEPlus8.setScale(0); 
System.out.println(oneEPlus8.divide(oneHundredMillion, BigDecimal.ROUND_HALF_UP)); 

This wyjścia:

1 

Tak na marginesie, można użyć divide(BigDecimal, RoundingMode) podzielić określając RoundingMode enum zamiast starszych int stałych.