You can try BigDecimal for this purpose
Double toBeTruncated = new Double("3.5789055");
Double truncatedDouble = BigDecimal.valueOf(toBeTruncated)
.setScale(3, RoundingMode.HALF_UP)
.doubleValue();
Answer from Neel on Stack OverflowYou 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.
Videos
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
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
I came across a piece of code in a legacy Java 8 application at work which adds two doubles and gives out a double. I observed that the resulting doubles for various inputs had variable number of digits after the decimal point. Some were very precise with 12 digits after the decimal point and some had merely a digit after the decimal point.
I’m curious to know what factors affect certain doubles to be so very precise and certain doubles not as much.
Examples:
double one = 3880.95; double two = 380.9; Result: 4261.849999999999
double one = 1293.65; double two = 1293.6; Result: 2587.25
The Wikipedia page on it is a good place to start.
To sum up:
floatis represented in 32 bits, with 1 sign bit, 8 bits of exponent, and 23 bits of the significand (or what follows from a scientific-notation number: 2.33728*1012; 33728 is the significand).doubleis represented in 64 bits, with 1 sign bit, 11 bits of exponent, and 52 bits of significand.
By default, Java uses double to represent its floating-point numerals (so a literal 3.14 is typed double). It's also the data type that will give you a much larger number range, so I would strongly encourage its use over float.
There may be certain libraries that actually force your usage of float, but in general - unless you can guarantee that your result will be small enough to fit in float's prescribed range, then it's best to opt with double.
If you require accuracy - for instance, you can't have a decimal value that is inaccurate (like 1/10 + 2/10), or you're doing anything with currency (for example, representing $10.33 in the system), then use a BigDecimal, which can support an arbitrary amount of precision and handle situations like that elegantly.
A float gives you approx. 6-7 decimal digits precision while a double gives you approx. 15-16. Also the range of numbers is larger for double.
A double needs 8 bytes of storage space while a float needs just 4 bytes.
@PeterLawrey states max precision in 15.
That's actually not what he stated at all. What he stated was:
double has 15 decimal places of accuracy
and he is wrong. They have 15 decimal digits of accuracy.
The number of decimal digits in any number is given by its log to the base 10. 15 is the floor value of log10(253-1), where 53 is the number of bits of mantissa (including the implied bit), as described in the Javadoc and IEEE 754, and 253-1 is therefore the maximum possible mantissa value. The actual value is 15.954589770191003298111788092734 to the limits of the Windows calculator.
He is quite wrong to describe it as 'decimal places of accuracy'. A double has 15 decimal digits of accuracy if they are all before the decimal point. For numbers with fractional parts you can get many more than 15 digits in the decimal representation, because of the incommensurability of decimal and binary fractions.
Run this code, and see where it stops
public class FindPrecisionDouble {
static public void main(String[] args) {
double x = 1.0;
double y = 0.5;
double epsilon = 0;
int nb_iter = 0;
while ((nb_iter < 1000) && (x != y)) {
System.out.println(x-y);
epsilon = Math.abs(x-y);
y = ( x + y ) * 0.5;
}
final double prec_decimal = - Math.log(epsilon) / Math.log(10.0);
final double prec_binary = - Math.log(epsilon) / Math.log(2.0);
System.out.print("On this machine, for the 'double' type, ");
System.out.print("epsilon = " );
System.out.println( epsilon );
System.out.print("The decimal precision is " );
System.out.print( prec_decimal );
System.out.println(" digits" );
System.out.print("The binary precision is " );
System.out.print( prec_binary );
System.out.println(" bits" );
}
}
Variable y becomes the smallest value different than 1.0. On my computer (Mac Intel Core i5), it stops at 1.1102...E-16. It then prints the precision (in decimal and in binary).
As stated in https://en.wikipedia.org/wiki/Machine_epsilon, floating-point precision can be estimated with the epsilon value. It is "the smallest number that, when added to one, yields a result different from one" (I did a small variation: 1-e instead of 1+e, but the logic is the same)
I'll explain in decimal: if you have a 4-decimals precision, you can express 1.0000 - 0.0001, but you cannot express the number 1.00000-0.00001 (you lack the 5th decimal). In this example, with a 4-decimals precision, the epsilon is 0.0001. The epsilon directly measures the floating-point precision. Just transpose to binary.
Edit Your question asked "How to determine...". The answer you were searching were more an explanation of than a way to determine precision (with the answer you accepted). Anyways, for other people, running this code on a machine will determine the precision for the "double" type.
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);
This is a cheap hack that works (and does not introduce any rounding issues):
String string = String.format("%.6f", d).replaceAll("(\\.\\d+?)0*$", "$1");