Korzystanie z Javy.matematyka.MathContext
Ostatnio próbowałem zrozumieć użycie Javy.matematyka.MathContext ale nie zrozumiał poprawnie. Jest używany do zaokrąglania w java.math.BigDecimal
. Jeśli tak, dlaczego nie zaokrągla cyfry dziesiętne, ale nawet część mantissa.
Z API docs dowiedziałem się, że jest zgodny ze standardem określonym w specyfikacjach ANSI X3.274-1996
i ANSI X3.274-1996/AM 1-2000
, ale nie udało mi się ich odczytać online.
5 answers
@jatan
Dzięki za odpowiedź. To ma sens. Czy możesz mi wyjaśnić MathContext w kontekście metody BigDecimal # round.
Nie ma nic specjalnego w BigDecimal.round()
vs. każda inna metoda BigDecimal
. We wszystkich przypadkach MathContext
określa liczbę cyfr znaczących i technikę zaokrąglania. Zasadniczo istnieją dwie części każdego MathContext
. Jest precyzja, jest też RoundingMode
.
Precyzja ponownie określa liczbę cyfr znaczących. Jeśli więc podasz 123
jako liczbę i poprosisz o 2 znaczące cyfry, otrzymasz 120
. To może być jaśniejsze, jeśli myślisz w kategoriach notacji naukowej.
123
będzie 1.23e2
w notacji naukowej. Jeśli zachowasz tylko 2 znaczące cyfry, otrzymasz 1.2e2
lub 120
. Zmniejszając liczbę cyfr znaczących, zmniejszamy precyzję, z jaką możemy określić liczbę.
Część RoundingMode
określa jak powinien poradzić sobie z utratą precyzji. Aby ponownie użyć przykładu, jeśli użyjesz 123
jako liczby i poprosisz o 2 znaczące cyfry, zmniejszysz swoją precyzję. Z RoundingMode
z HALF_UP
(tryb domyślny), 123
stanie się 120
. Z RoundingMode
z CEILING
, otrzymasz 130
.
Na przykład:
System.out.println(new BigDecimal("123.4",
new MathContext(4,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
new MathContext(2,RoundingMode.CEILING)));
System.out.println(new BigDecimal("123.4",
new MathContext(1,RoundingMode.CEILING)));
Wyjścia:
123.4
1.2E+2
1.3E+2
2E+2
Widać, że zarówno precyzja, jak i tryb zaokrąglania wpływają na wyjście.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-11 06:06:48
Aby zaokrąglać tylko część ułamkową bigdecimalu, sprawdź metodę BigDecimal.setScale(int newScale, int roundingMode)
.
Np. zmiana liczby z trzema cyframi po przecinku na jedną z dwoma cyframi i zaokrąglenie w górę:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
Wynikiem tego jest BigDecimal o wartości 1.24 (ze względu na regułę zaokrąglania)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 12:55:27
Dodałbym tu kilka przykładów. Nie znalazłem ich w poprzednich odpowiedziach, ale uważam je za przydatne dla tych, którzy mogą wprowadzić w błąd znaczące cyfryz liczbą miejsc dziesiętnych. Załóżmy, że mamy taki kontekst:
MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Dla tego kodu:
BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
Jest całkowicie jasne, że Twój wynik jest 1.23E+3
, jak chłopaki powiedzieli powyżej. Pierwsze cyfry znaczące to 123...
Ale co w tym przypadku:
BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
Twoja liczba nie będzie zaokrąglona do 3 miejsca po przecinku - dla kogoś może to nie być intuicyjne i warte podkreślenia. Zamiast tego zostanie zaokrąglona do pierwszych 3 znaczących cyfr , które w tym przypadku są "4 5 4". Tak więc powyższy kod daje 4.55E-7
a nie 0.000
Jak ktoś mógł się spodziewać.
Podobne przykłady:
BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX);
System.out.println(d3); // 0.00100
BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX);
System.out.println(d4); // 0.200
BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX);
System.out.println(d5); //4.00E-9
Mam nadzieję, że ten oczywisty, ale istotny przykład będzie pomocny...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-11 08:05:46
Jeśli dobrze cię rozumiem, wygląda na to, że oczekujesz, że MathContext będzie kontrolował, ile cyfr powinno być zachowanych po przecinku. Nie po to to jest. Określa liczbę cyfr do zachowania, Razem . Więc jeśli określisz, że chcesz 3 znaczące cyfry, to wszystko, co dostaniesz.
Na przykład to:
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(20)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(10)));
System.out.println(new BigDecimal("1234567890.123456789",
new MathContext(5)));
Wyświetli:
1234567890.123456789
1234567890
1.2346E+9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-11 05:44:00
To nie dla Zabawy. W zasadzie znalazłem jakiś przykład online, który mówi o użyciu MathContext
do zaokrąglania ilości/liczb przechowywanych w BigDecimal.
Na przykład,
Jeśli MathContext
jest skonfigurowane na precision = 2
i rounding mode = ROUND_HALF_EVEN
BigDecimal Number = 0.5294
, jest zaokrąglone do 0.53
Więc pomyślałem, że to nowsza technika i użyłem jej do zaokrąglania. Jednak przerodziło się to w koszmar, ponieważ zaczęło zaokrąglać nawet część liczby.
Dla przykład,
Number = 1.5294
jest zaokrąglone do 1.5
Number = 10.5294
jest zaokrąglone do 10
Number = 101.5294
jest zaokrąglone do 100
.... i tak dalej
Więc nie jest to zachowanie oczekiwałem dla zaokrąglania(jako precyzja = 2).
Wydaje się mieć jakąś logikę, ponieważ z pattera mogę powiedzieć, że pobiera pierwsze dwie cyfry (ponieważ precyzja to 2) liczby, a następnie dodaje 0 do no. cyfr stają się takie same jak kwota nieograniczona (sprawdź przykład 101.5294 ...)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-23 10:09:10