Use DecimalFormat: new DecimalFormat("#.0#####").format(d).
This will produce numbers with 1 to 6 decimal digits.
Since DecimalFormat will use the symbols of the default locale, you might want to provide which symbols to use:
//Format using english symbols, e.g. 100.0 instead of 100,0
new DecimalFormat("#.0#####", DecimalFormatSymbols.getInstance( Locale.ENGLISH )).format(d)
In order to format 100.0 to 100, use the format string #.######.
Note that DecimalFormat will round by default, e.g. if you pass in 0.9999999 you'll get the output 1. If you want to get 0.999999 instead, provide a different rounding mode:
DecimalFormat formatter = new DecimalFormat("#.######", DecimalFormatSymbols.getInstance( Locale.ENGLISH ));
formatter.setRoundingMode( RoundingMode.DOWN );
String s = formatter.format(d);
Answer from Thomas on Stack OverflowUse DecimalFormat: new DecimalFormat("#.0#####").format(d).
This will produce numbers with 1 to 6 decimal digits.
Since DecimalFormat will use the symbols of the default locale, you might want to provide which symbols to use:
//Format using english symbols, e.g. 100.0 instead of 100,0
new DecimalFormat("#.0#####", DecimalFormatSymbols.getInstance( Locale.ENGLISH )).format(d)
In order to format 100.0 to 100, use the format string #.######.
Note that DecimalFormat will round by default, e.g. if you pass in 0.9999999 you'll get the output 1. If you want to get 0.999999 instead, provide a different rounding mode:
DecimalFormat formatter = new DecimalFormat("#.######", DecimalFormatSymbols.getInstance( Locale.ENGLISH ));
formatter.setRoundingMode( RoundingMode.DOWN );
String s = formatter.format(d);
This is a cheap hack that works (and does not introduce any rounding issues):
String string = String.format("%.6f", d).replaceAll("(\\.\\d+?)0*
1");
You can try BigDecimal for this purpose
Double toBeTruncated = new Double("3.5789055");
Double truncatedDouble = BigDecimal.valueOf(toBeTruncated)
.setScale(3, RoundingMode.HALF_UP)
.doubleValue();
You can't set the precision of a double (or Double) to a specified number of decimal digits, because floating-point values don't have decimal digits. They have binary digits.
You will have to convert into a decimal radix, either via BigDecimal or DecimalFormat, depending on what you want to do with the value later.
See also my answer to this question for a refutation of the inevitable *100/100 answers.
DecimalFormat will allow you to define how many digits you want to display. A '0' will force an output of digits even if the value is zero, whereas a '#' will omit zeros.
System.out.print(new DecimalFormat("#0.0000").format(value)+" kg\n"); should to the trick.
See the documentation
Note: if used frequently, for performance reasons you should instantiate the formatter only once and store the reference: final DecimalFormat df = new DecimalFormat("#0.0000");. Then use df.format(value).
add this instance of DecimalFormat to the top of your method:
DecimalFormat four = new DecimalFormat("#0.0000"); // will round and display the number to four decimal places. No more, no less.
// the four zeros after the decimal point above specify how many decimal places to be accurate to.
// the zero to the left of the decimal place above makes it so that numbers that start with "0." will display "0.____" vs just ".____" If you don't want the "0.", replace that 0 to the left of the decimal point with "#"
then, call the instance "four" and pass your double value when displaying:
double value = 0;
System.out.print(four.format(value) + " kg/n"); // displays 0.0000
Use BigDecimal Instead of a double:
String d = "12.00"; // No need for `new String("12.00")` here
BigDecimal decimal = new BigDecimal(d);
This works because BigDecimal maintains a "precision," and the BigDecimal(String) constructor sets that from the number of digits to the right of the ., and uses it in toString. So if you just dump it out with System.out.println(decimal);, it prints out 12.00.
Your problem is not a loss of precision, but the output format of your number and its number of decimals. You can use DecimalFormat to solve your problem.
DecimalFormat formatter = new DecimalFormat("#0.00");
String d = new String("12.00");
Double dble = new Double(d.valueOf(d));
System.out.println(formatter.format(dble));
I will also add that you can use DecimalFormatSymbols to choose which decimal separator to use. For example, a point :
DecimalFormatSymbols separator = new DecimalFormatSymbols();
separator.setDecimalSeparator('.');
Then, while declaring your DecimalFormat :
DecimalFormat formatter = new DecimalFormat("#0.00", separator);
As others have mentioned, you'll probably want to use the BigDecimal class, if you want to have an exact representation of 11.4.
Now, a little explanation into why this is happening:
The float and double primitive types in Java are floating point numbers, where the number is stored as a binary representation of a fraction and a exponent.
More specifically, a double-precision floating point value such as the double type is a 64-bit value, where:
- 1 bit denotes the sign (positive or negative).
- 11 bits for the exponent.
- 52 bits for the significant digits (the fractional part as a binary).
These parts are combined to produce a double representation of a value.
(Source: Wikipedia: Double precision)
For a detailed description of how floating point values are handled in Java, see the Section 4.2.3: Floating-Point Types, Formats, and Values of the Java Language Specification.
The byte, char, int, long types are fixed-point numbers, which are exact representions of numbers. Unlike fixed point numbers, floating point numbers will some times (safe to assume "most of the time") not be able to return an exact representation of a number. This is the reason why you end up with 11.399999999999 as the result of 5.6 + 5.8.
When requiring a value that is exact, such as 1.5 or 150.1005, you'll want to use one of the fixed-point types, which will be able to represent the number exactly.
As has been mentioned several times already, Java has a BigDecimal class which will handle very large numbers and very small numbers.
From the Java API Reference for the BigDecimal class:
Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. The value of the number represented by the BigDecimal is therefore (unscaledValue × 10^-scale).
There has been many questions on Stack Overflow relating to the matter of floating point numbers and its precision. Here is a list of related questions that may be of interest:
- Why do I see a double variable initialized to some value like 21.4 as 21.399999618530273?
- How to print really big numbers in C++
- How is floating point stored? When does it matter?
- Use float or decimal for accounting application dollar amount?
If you really want to get down to the nitty gritty details of floating point numbers, take a look at What Every Computer Scientist Should Know About Floating-Point Arithmetic.
When you input a double number, for example, 33.33333333333333, the value you get is actually the closest representable double-precision value, which is exactly:
33.3333333333333285963817615993320941925048828125
Dividing that by 100 gives:
0.333333333333333285963817615993320941925048828125
which also isn't representable as a double-precision number, so again it is rounded to the nearest representable value, which is exactly:
0.3333333333333332593184650249895639717578887939453125
When you print this value out, it gets rounded yet again to 17 decimal digits, giving:
0.33333333333333326
You sort of answered your own question - build your format string dynamically... valid format strings follow the conventions outlined here: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax.
If you want a formatted decimal that occupies 8 total characters (including the decimal point) and you wanted 4 digits after the decimal point, your format string should look like "%8.4f"...
To my knowledge there is no "native support" in Java beyond format strings being flexible.
You can use the DecimalFormat class.
double d1 = 3.14159;
double d2 = 1.235;
DecimalFormat df = new DecimalFormat("#.##");
double roundedD1 = df.format(d); // 3.14
double roundedD2 = df.format(d); // 1.24
If you want to set the precision at run time call:
df.setMaximumFractionDigits(precision)
Disclaimer: I only recommend that you use this if speed is an absolute requirement.
On my machine, the following can do 1 million conversions in about 130ms:
private static final int POW10[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
public static String format(double val, int precision) {
StringBuilder sb = new StringBuilder();
if (val < 0) {
sb.append('-');
val = -val;
}
int exp = POW10[precision];
long lval = (long)(val * exp + 0.5);
sb.append(lval / exp).append('.');
long fval = lval % exp;
for (int p = precision - 1; p > 0 && fval < POW10[p]; p--) {
sb.append('0');
}
sb.append(fval);
return sb.toString();
}
The code as presented has several shortcomings: it can only handle a limited range of doubles, and it doesn't handle NaNs. The former can be addressed (but only partially) by extending the POW10 array. The latter can be explicitly handled in the code.
If you don't need thread-safe code, you can re-use the buffer for a little more speed (to avoid recreating a new object each time), such as:
private static final int[] POW10 = {1, 10, 100, 1000, 10000, 100000, 1000000};
private static final StringBuilder BUFFER = new StringBuilder();
public String format( double value, final int precision ) {
final var sb = BUFFER;
sb.setLength( 0 );
if( value < 0 ) {
sb.append( '-' );
value = -value;
}
final int exp = POW10[ precision ];
final long lval = (long) (value * exp + 0.5);
sb.append( lval / exp ).append( '.' );
final long fval = lval % exp;
for( int p = precision - 1; p > 0 && fval < POW10[ p ]; p-- ) {
sb.append( '0' );
}
sb.append( fval );
return sb.toString();
}
If you need both speed and precision, I've developed a fast DoubleFormatUtil class at xmlgraphics-commons: http://xmlgraphics.apache.org/commons/changes.html#version_1.5rc1
You can see the code there: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/util/DoubleFormatUtil.java?view=markup
It's faster than both DecimalFormat/BigDecimal, as fast as Double.toString, it's precise, it's well tested. It's licensed under Apache License 2.0, so you can use it as you want.
Just using Double.parseDouble() and Double.toString() should work without losing data, I believe. In particular, from the docs for Double.toString():
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
Another alternative, if you want to preserve the exact string representation (which isn't quite the same thing) is to use BigDecimal in Java.
Do you need the string representation for any purpose, or it is merely for a textual data transport (e.g., SOAP/REST message)?
For the latter, you can convert the double value into a long using java.lang.Double.doubleToRawLongBits(double value) and back into a double using java.lang.Double.longBitsToDouble(long value). You can transport the long value as a hex-encoded string.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Double.html#doubleToRawLongBits(double) http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Double.html#longBitsToDouble(long)
This will preserve the exact 64-bit double value that you have, but it won't be human readable (for most! ;) ).