Ceea ce aș dori este o metodă de a converti o cameră dublă la un șir de caractere care runde, folosind jumătate-metoda - de exemplu, dacă zecimal pentru a fi rotunjită este de 5, întotdeauna se rotunjește la numărul următor. Aceasta este metoda standard de rotunjire majoritatea oamenilor se așteaptă în cele mai multe situații.
De asemenea, am dori doar cifre semnificative pentru a fi afișate, adică nu ar trebui să fie orice zerouri la sfârșit.
Știu o metodă de a face acest lucru este de a utiliza Șir de caractere.format
metoda:
String.format("%.5g%n", 0.912385);
se întoarce:
0.91239
care este mare, cu toate acestea întotdeauna se afișează numerele cu 5 zecimale, chiar dacă acestea nu sunt semnificative:
String.format("%.5g%n", 0.912300);
se întoarce:
0.91230
O altă metodă este de a utiliza DecimalFormatter
:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
se întoarce:
0.91238
Cu toate acestea, după cum puteți vedea acest lucru foloseste jumătate-chiar rotunjire asupra sumelor. Care se va rotunji în jos în cazul în care anterior cifră este chiar. Ceea ce am'd ca este asta:
0.912385 -> 0.91239
0.912300 -> 0.9123
Ceea ce este cel mai bun mod de a realiza acest lucru în Java?
Folosi setRoundingMode
, setați RoundingMode
în mod explicit să se ocupe de problema ta cu jumătate-chiar rotund, apoi utilizați formatul model de ieșire necesare.
Exemplu:
DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
Double d = n.doubleValue();
System.out.println(df.format(d));
}
oferă ieșire:
12
123.1235
0.23
0.1
2341234.2125
EDIT: original răspuns nu se referă la precizia de dublu valori. Că este bine, dacă nu't pasă prea mult dacă runde în sus sau în jos. Dar dacă vrei exacte rotunjire, atunci ai nevoie să ia așteptat de precizie a valorilor în considerare. Valori în virgulă mobilă au un binar de reprezentare pe plan intern. Asta înseamnă că o valoare ca 2.77395 nu au exact valoarea pe plan intern. Acesta poate fi ușor mai mare sau puțin mai mică. Dacă valoarea internă este puțin mai mică, atunci nu se va rotunji la 2.7740. Pentru a remedia această situație, trebuie să fie conștienți de precizie a valorilor care lucrați cu, și de a adăuga sau scădea această valoare înainte de rotunjire. De exemplu, atunci când știi că valorile sunt corecte până la 6 cifre, apoi a rotunji jumătate valorile, se adaugă faptul că precizia cu valoarea:
Double d = n.doubleValue() + 1e-6;
Pentru a rotunji în jos, scade precizia.
new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);
veți obține o BigDecimal. Pentru a obține șirul de ieșire din ea, să-l numim
BigDecimal's
toStringmetoda, sau
toPlainString` metoda pentru Java 5+ pentru un simplu șir format.
Exemplu de program:
package trials;
import java.math.BigDecimal;
public class Trials {
public static void main(String[] args) {
int yourScale = 10;
System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
}
Ca alții s-au remarcat, răspunsul corect este să folosim fie DecimalFormat " sau " BigDecimal
. Floating-point nu't au zecimale deci nu poti rotund/truncate la un anumit număr dintre ei, în primul rând. Trebuie să lucreze într-un număr zecimal radix, și asta este ceea ce aceste două clase.
Am posta următorul cod ca un contra-exemplu pentru toate răspunsurile în acest thread și într-adevăr peste tot StackOverflow (și nu numai) care recomanda multiplicare urmat de trunchiere urmat de divizie. Este de datoria avocaților de aceasta tehnica pentru a explica de ce codul de mai jos produce la ieșire greșit în peste 92% din cazuri.
public class RoundingCounterExample
{
static float roundOff(float x, int position)
{
float a = x;
double temp = Math.pow(10.0, position);
a *= temp;
a = Math.round(a);
return (a / (float)temp);
}
public static void main(String[] args)
{
float a = roundOff(0.0009434f,3);
System.out.println("a="+a+" (a % .001)="+(a % 0.001));
int count = 0, errors = 0;
for (double x = 0.0; x < 1; x += 0.0001)
{
count++;
double d = x;
int scale = 2;
double factor = Math.pow(10, scale);
d = Math.round(d * factor) / factor;
if ((d % 0.01) != 0.0)
{
System.out.println(d + " " + (d % 0.01));
errors++;
}
}
System.out.println(count + " trials " + errors + " errors");
}
}
Ieșirea din acest program:
10001 trials 9251 errors
EDIT: Pentru a adresa unele comentarii de mai jos am refacut modulul face parte din test buclă folosind `BigDecimal " și " noi MathContext(16) pentru modul de operare, după cum urmează:
public static void main(String[] args)
{
int count = 0, errors = 0;
int scale = 2;
double factor = Math.pow(10, scale);
MathContext mc = new MathContext(16, RoundingMode.DOWN);
for (double x = 0.0; x < 1; x += 0.0001)
{
count++;
double d = x;
d = Math.round(d * factor) / factor;
BigDecimal bd = new BigDecimal(d, mc);
bd = bd.remainder(new BigDecimal("0.01"), mc);
if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
{
System.out.println(d + " " + bd);
errors++;
}
}
System.out.println(count + " trials " + errors + " errors");
}
Rezultatul:
10001 trials 4401 errors
Să presupunem că aveți
double d = 9232.129394d;
puteți utiliza BigDecimal
BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();
sau fără BigDecimal
d = Math.round(d*100)/100.0d;
cu ambele soluții d == 9232.13
Real's Java Cum să-mesaje această soluție, care este, de asemenea, compatibil pentru versiuni înainte de Java 1.6.
BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
@Milhous: în format zecimal de rotunjire este excelent:
puteți utiliza, de asemenea
DecimalFormat df = new DecimalFormat("#.00000"); df.format(0.912385);
pentru a asigurați-vă că aveți la final 0's.
Aș adăuga că această metodă este foarte bun la furnizarea de un real numeric, rotunjire mecanism - nu numai vizual, dar, de asemenea, atunci când de prelucrare.
Ipotetic: trebuie să pună în aplicare o rotunjire mecanism într-un GUI program. Pentru a modifica acuratețe / precizie de un rezultat de ieșire pur și simplu schimba caret format (de exemplu, în paranteze). Așa că:
DecimalFormat df = new DecimalFormat("#0.######");
df.format(0.912385);
se va întoarce cât de ieșire: 0.912385
DecimalFormat df = new DecimalFormat("#0.#####");
df.format(0.912385);
se va întoarce cât de ieșire: 0.91239
DecimalFormat df = new DecimalFormat("#0.####");
df.format(0.912385);
se va întoarce cât de ieșire: 0.9124
[EDIT: de asemenea, dacă caret format ca ("#0.############") si tu
introduceți un număr zecimal, de exemplu, 3.1415926, pentru argument's sake, DecimalFormat
nu produce nici un gunoi (de exemplu, la sfârșit de zerouri) și va reveni:
3.1415926
.. daca're așa de înclinat. Acordate, l's un pic verbose
pentru gustul unora dev's, dar hei, e's are o amprenta de memorie scăzută
în timpul prelucrării și este foarte ușor să pună în aplicare.]
Deci, în esență, frumusețea DecimalFormat este că simultan se ocupă de string aspectul, precum și nivelul de rotunjire precizie stabilit. Ergo: ai obține două avantaje pentru prețul de unul de implementare a codului. ;)
Ai putea folosi următoarele utilitate metodă-
public static double round(double valueToRound, int numberOfDecimalPlaces)
{
double multipicationFactor = Math.pow(10, numberOfDecimalPlaces);
double interestedInZeroDPs = valueToRound * multipicationFactor;
return Math.round(interestedInZeroDPs) / multipicationFactor;
}
Aici este un rezumat a ceea ce puteți utiliza, dacă doriți rezultatul ca Șir de caractere:
DecimalFormat df = new DecimalFormat("#.#####"); df.setRoundingMode(RoundingMode.HALF_UP); String str1 = df.format(0.912385)); // 0.91239
String str2 = new BigDecimal(0.912385) .setScale(5, BigDecimal.ROUND_HALF_UP) .toString();
Aici este o sugestie a ceea ce biblioteci puteți utiliza, dacă doriți "dublu" ca un rezultat. Am ar't recomanda pentru conversie șir, deși, ca dublu nu poate fi capabil de a reprezenta exact ce vrei (a se vedea de exemplu aici):
dublu rotunjit = Precizie.rotund(0.912385, 5, BigDecimal.ROUND_HALF_UP);
dublu rotunjit = Funcții.rotund(0.00001).aplica(0.912385)
dublu rotunjit = Utils.roundDouble(0.912385, 5)
Un succint soluția:
public static double round(double value, int precision) {
int scale = (int) Math.pow(10, precision);
return (double) Math.round(value * scale) / scale;
}
A se vedea, de asemenea, https://stackoverflow.com/a/22186845/212950 Datorită jpdymond pentru a oferi acest lucru.
Puteți utiliza BigDecimal
BigDecimal value = new BigDecimal("2.3");
value = value.setScale(0, RoundingMode.UP);
BigDecimal value1 = new BigDecimal("-2.3");
value1 = value1.setScale(0, RoundingMode.UP);
System.out.println(value + "n" + value1);
Consultați: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/
Dacă vrei într-adevăr numere zecimale pentru calcul (și nu numai de ieșire), nu utilizați un binar în virgulă mobilă în format, cum ar fi dublu.
Use BigDecimal or any other decimal-based format.
Eu nu folosesc BigDecimal pentru calcule, dar trebuie avut în vedere este dependentă de mărimea de numere're de-a face cu. În majoritatea implementărilor, am găsi parsarea de la dublu sau întreg Lung este suficientă pentru număr foarte mare de calcule.
De fapt, am've recent utilizate analizat-la-Timp pentru a obține o reprezentare precisă (spre deosebire de hex rezultate) într-un GUI pentru numere la fel de mare ca ################################# personajele (ca o exemplu).
De când am găsit nici un răspuns complet la această temă am'am pus împreună o clasă care ar trebui să se ocupe de acest lucru în mod corespunzător, cu suport pentru:
Utilizare este destul de simplu:
(Pentru motive de acest exemplu, eu sunt, folosind un custom locale)
public static final int DECIMAL_PLACES = 2;
NumberFormatter formatter = new NumberFormatter(DECIMAL_PLACES);
String value = formatter.format(9.319); // "9,32"
String value2 = formatter.format(0.0000005); // "5,00E-7"
String value3 = formatter.format(1324134123); // "1,32E9"
double parsedValue1 = formatter.parse("0,4E-2", 0); // 0.004
double parsedValue2 = formatter.parse("0,002", 0); // 0.002
double parsedValue3 = formatter.parse("3423,12345", 0); // 3423.12345
Aici este clasa:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;
public class NumberFormatter {
private static final String SYMBOL_INFINITE = "\u221e";
private static final char SYMBOL_MINUS = '-';
private static final char SYMBOL_ZERO = '0';
private static final int DECIMAL_LEADING_GROUPS = 10;
private static final int EXPONENTIAL_INT_THRESHOLD = 1000000000; // After this value switch to exponential notation
private static final double EXPONENTIAL_DEC_THRESHOLD = 0.0001; // Below this value switch to exponential notation
private DecimalFormat decimalFormat;
private DecimalFormat decimalFormatLong;
private DecimalFormat exponentialFormat;
private char groupSeparator;
public NumberFormatter(int decimalPlaces) {
configureDecimalPlaces(decimalPlaces);
}
public void configureDecimalPlaces(int decimalPlaces) {
if (decimalPlaces <= 0) {
throw new IllegalArgumentException("Invalid decimal places");
}
DecimalFormatSymbols separators = new DecimalFormatSymbols(Locale.getDefault());
separators.setMinusSign(SYMBOL_MINUS);
separators.setZeroDigit(SYMBOL_ZERO);
groupSeparator = separators.getGroupingSeparator();
StringBuilder decimal = new StringBuilder();
StringBuilder exponential = new StringBuilder("0.");
for (int i = 0; i < DECIMAL_LEADING_GROUPS; i++) {
decimal.append("###").append(i == DECIMAL_LEADING_GROUPS - 1 ? "." : ",");
}
for (int i = 0; i < decimalPlaces; i++) {
decimal.append("#");
exponential.append("0");
}
exponential.append("E0");
decimalFormat = new DecimalFormat(decimal.toString(), separators);
decimalFormatLong = new DecimalFormat(decimal.append("####").toString(), separators);
exponentialFormat = new DecimalFormat(exponential.toString(), separators);
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
decimalFormatLong.setRoundingMode(RoundingMode.HALF_UP);
exponentialFormat.setRoundingMode(RoundingMode.HALF_UP);
}
public String format(double value) {
String result;
if (Double.isNaN(value)) {
result = "";
} else if (Double.isInfinite(value)) {
result = String.valueOf(SYMBOL_INFINITE);
} else {
double absValue = Math.abs(value);
if (absValue >= 1) {
if (absValue >= EXPONENTIAL_INT_THRESHOLD) {
value = Math.floor(value);
result = exponentialFormat.format(value);
} else {
result = decimalFormat.format(value);
}
} else if (absValue < 1 && absValue > 0) {
if (absValue >= EXPONENTIAL_DEC_THRESHOLD) {
result = decimalFormat.format(value);
if (result.equalsIgnoreCase("0")) {
result = decimalFormatLong.format(value);
}
} else {
result = exponentialFormat.format(value);
}
} else {
result = "0";
}
}
return result;
}
public String formatWithoutGroupSeparators(double value) {
return removeGroupSeparators(format(value));
}
public double parse(String value, double defValue) {
try {
return decimalFormat.parse(value).doubleValue();
} catch (ParseException e) {
e.printStackTrace();
}
return defValue;
}
private String removeGroupSeparators(String number) {
return number.replace(String.valueOf(groupSeparator), "");
}
}
Încercați acest lucru: org.apache.commons.math3.util.Precizie.rotund(double x, int scară)
A se vedea: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
Apache Commons Matematică Bibliotecă pagina de pornire este: http://commons.apache.org/proper/commons-math/index.html
Interne implemetation al acestei metode este:
public static double round(double x, int scale) {
return round(x, scale, BigDecimal.ROUND_HALF_UP);
}
public static double round(double x, int scale, int roundingMethod) {
try {
return (new BigDecimal
(Double.toString(x))
.setScale(scale, roundingMethod))
.doubleValue();
} catch (NumberFormatException ex) {
if (Double.isInfinite(x)) {
return x;
} else {
return Double.NaN;
}
}
}
Doar în cazul în care cineva are nevoie de ajutor cu asta. Această soluție funcționează perfect pentru mine.
private String withNoTrailingZeros(final double value, final int nrOfDecimals) {
return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();
}
returnează o
Pentru a realiza acest lucru putem folosi această formatare:
DecimalFormat df = new DecimalFormat("#.00");
String resultado = df.format(valor)
sau:
DecimalFormat df = new DecimalFormat("0.00"); :
Utilizați această metodă pentru a obține întotdeauna două zecimale:
private static String getTwoDecimals(double value){
DecimalFormat df = new DecimalFormat("0.00");
return df.format(value);
}
Definirea acestei valori:
91.32
5.22
11.5
1.2
2.6
Folosind metoda putem obtine acest rezultat:
91.32
5.22
11.50
1.20
2.60
Sunt de acord cu răspunsul ales să folosesc DecimalFormat--- sau alternativ
BigDecimal`.
Vă rugăm să citiți Update de mai jos în primul rând!
Un similar, dar repede și-gunoi metodă este furnizat de `DoubleRounder utilitate în decimal4j bibliotecă:
double a = DoubleRounder.round(2.0/3.0, 3);
double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
double c = DoubleRounder.round(1000.0d, 17);
double d = DoubleRounder.round(90080070060.1d, 9);
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
Va ieșire
0.667
0.666
1000.0
9.00800700601E10
Vezi https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility
Disclaimer: sunt implicați în decimal4j proiect.
Actualizare:
Ca @iaforek subliniat DoubleRounder întoarce uneori rezultate contraintuitive. Motivul este că acesta îndeplinește matematic corect rotunjire asupra sumelor. De exemplu DoubleRounder.rotund(256.025 d, 2)
va fi rotunjit în jos la 256.02 deoarece valoarea dublă reprezentat ca 256.025 d este oarecum mai mică decât cea rațională valoare 256.025 și, prin urmare, vor fi rotunjite în jos.
Note:
BigDecimal(dublu)
constructor (dar nu a valueOf(dublu)
care foloseste string constructor).Pentru aceste motive și tot menționate mai sus în acest post am nu se poate recomanda să utilizați DoubleRounder.