Recent am încercat să înțeleg folosirea java.math.MathContext , dar nu am reușit să înțeleg corect. Se folosește pentru rotunjirea în java.math.BigDecimal
, dacă da, de ce nu este rotundă cifrele zecimale, dar chiar și partea mentesa.
Din documentele API, am aflat că respectă specificațiile specificate în specificațiile ANSI X3.274-1996
și ANSI X3.274-1996 / AM 1-2000
, dar I nu le-au făcut să citească online.
Te rog să-mi spui dacă ai vreo idee despre asta.
Dacă vă înțeleg corect, suna ca și cum ați aștepta MathContext pentru a controla câte cifre ar trebui păstrate după punctul zecimal. Nu este pentru asta. Specifică câte cifre trebuie păstrate, total . Deci, dacă specificați că doriți 3 cifre semnificative, asta e tot ce veți obține.
De exemplu, aceasta:
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)));
va produce:
1234567890.123456789
1234567890
1.2346E+9
Nu este pentru distracție. De fapt, am găsit un exemplu online, care a indicat utilizarea MathContext
pentru a răsfoi sumele / numerele stocate în BigDecimal.
De exemplu,
If MathContext
is configured to have precision = 2
and rounding mode = ROUND_HALF_EVEN
BigDecimal Number = 0.5294
, is rounded to 0.53
Așa că am crezut că este o tehnică mai nouă și o folosește pentru scopuri de rotunjire. Cu toate acestea, sa transformat în coșmar, deoarece a început să rotunjim chiar o parte a numerelor.
De exemplu,
Number = 1.5294
is rounded to 1.5
Number = 10.5294
is rounded to 10
Number = 101.5294
is rounded to 100
.... si asa mai departe
Deci, acesta nu este comportamentul pe care l-am așteptat pentru rotunjire (ca precizie = 2).
Se pare că are o anumită logică, deoarece de la patter pot să spun că este nevoie de primele două cifre (ca fiind de 2 cifre de număr) și apoi se adaugă 0 până la nr. din cifre devin identice cu suma neincluse (a se vedea exemplul din 101.5294 ...)
@jatan
Vă mulțumim pentru răspuns. Are sens. Îmi puteți explica MathContext în contextul metodei rotunde BigDecimal #.
Nu este nimic special în ceea ce privește BigDecimal.round ()
vs orice altă metodă BigDecimal
. În toate cazurile, MathContext
specifică numărul de cifre semnificative și tehnica de rotunjire. Practic, există două părți ale fiecărui MathContext
. Există o precizie și există și RoundingMode
.
Precizia specifică din nou numărul de cifre semnificative. Deci, dacă specificați 123
ca număr și cereți 2 cifre semnificative, veți obține 120
. Ar putea fi mai clară dacă gândiți în termeni de notație științifică.
123
would be 1.23e2
in scientific notation. If you only keep 2 significant digits, then you get 1.2e2
, or 120
. By reducing the number of significant digits, we reduce the precision with which we can specify a number.
Partea RoundingMode
specifică modul în care ar trebui să rezolvăm pierderea de precizie. Pentru a reutiliza exemplul, dacă utilizați 123
ca număr și solicitați 2 cifre semnificative, v-ați redus precizia. Cu RoundingMode
din HALF_UP
(modul implicit), 123
va deveni 120
. Cu RoundingMode
de CEILING
, veți primi 130
.
De exemplu:
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)));
ieşiri:
123.4
1.2E+2
1.3E+2
2E+2
Puteți vedea că atât precizia, cât și modul de rotunjire afectează ieșirea.
Pentru a rotunji doar partea fracționată a unui BigDecimal, verificați metoda BigDecimal.setScale (int newScale, int roundingMode)
.
De exemplu. pentru a schimba un număr cu trei cifre după punct zecimal la unul cu două cifre și rotunjire în sus:
BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);
Rezultatul este un BigDecimal cu valoarea 1.24 (din cauza regulii de rotunjire)
Aș adăuga aici câteva exemple. Nu le-am găsit în răspunsurile anterioare, dar le consider util pentru cei care pot induce în eroare cifrele semnificative cu numărul de zecimale . Să presupunem că avem un astfel de context:
MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
Pentru acest cod:
BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);
este clar că rezultatul dvs. este 1.23E + 3
așa cum spuneau mai sus băieții. Primele cifre semnificative sunt 123 ...
Dar ceea ce în acest caz:
BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);
numărul dvs. nu va fi rotunjit la 3 locuri după virgulă - pentru cineva care nu poate fi intuitivă și merită subliniată. În schimb, acesta va fi rotunjit la primele 3 cifre semnificative , care în acest caz sunt "4 5 4". Deci, codurile de mai sus rezultă în 4.55E-7
și nu în 0.000
după cum se poate aștepta cineva.
Exemple similare:
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
Sper că acest exemplu evident, dar relevant ar fi de ajutor ...