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
As @Benoit already said in a comment, to keep the full precision of your number, you need a BigDecimal:
BigDecimal hashValue = new BigDecimal("20790123833965.960938");
DecimalFormat formatter = new DecimalFormat("#0.000000");
System.out.println(formatter.format(hashValue));
Output:
20790123833965.960938
Use this code, it will work.
public class JavaFormatter {
public static void main(String args[]) {
BigDecimal hashValue = new BigDecimal("20790123833965.960938");
DecimalFormat formatter = new DecimalFormat("#.######");
System.out.println(formatter.format(hashValue));
}
}
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
Use setRoundingMode, set the RoundingMode explicitly to handle your issue with the half-even round, then use the format pattern for your required output.
Example:
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));
}
gives the output:
12
123.1235
0.23
0.1
2341234.2125
EDIT: The original answer does not address the accuracy of the double values. That is fine if you don't care much whether it rounds up or down. But if you want accurate rounding, then you need to take the expected accuracy of the values into account. Floating point values have a binary representation internally. That means that a value like 2.7735 does not actually have that exact value internally. It can be slightly larger or slightly smaller. If the internal value is slightly smaller, then it will not round up to 2.7740. To remedy that situation, you need to be aware of the accuracy of the values that you are working with, and add or subtract that value before rounding. For example, when you know that your values are accurate up to 6 digits, then to round half-way values up, add that accuracy to the value:
Double d = n.doubleValue() + 1e-6;
To round down, subtract the accuracy.
Assuming value is a double, you can do:
(double)Math.round(value * 100000d) / 100000d
That's for 5 digits precision. The number of zeros indicate the number of decimals.
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
@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.