convert float to double losing precision [duplicate] - java

I've been trying to find out the reason, but I couldn't.
Can anybody help me?
Look at the following example.
float f = 125.32f;
System.out.println("value of f = " + f);
double d = (double) 125.32f;
System.out.println("value of d = " + d);
This is the output:
value of f = 125.32
value of d = 125.31999969482422

The value of a float does not change when converted to a double. There is a difference in the displayed numerals because more digits are required to distinguish a double value from its neighbors, which is required by the Java documentation. That is the documentation for toString, which is referred (through several links) from the documentation for println.
The exact value for 125.32f is 125.31999969482421875. The two neighboring float values are 125.3199920654296875 and 125.32000732421875. Observe that 125.32 is closer to 125.31999969482421875 than to either of the neighbors. Therefore, by displaying “125.32”, Java has displayed enough digits so that conversion back from the decimal numeral to float reproduces the value of the float passed to println.
The two neighboring double values of 125.31999969482421875 are 125.3199996948242045391452847979962825775146484375 and 125.3199996948242329608547152020037174224853515625.
Observe that 125.32 is closer to the latter neighbor than to the original value (125.31999969482421875). Therefore, printing “125.32” does not contain enough digits to distinguish the original value. Java must print more digits in order to ensure that a conversion from the displayed numeral back to double reproduces the value of the double passed to println.

When you convert a float into a double, there is no loss of information. Every float can be represented exactly as a double.
On the other hand, neither decimal representation printed by System.out.println is the exact value for the number. An exact decimal representation could require up to about 760 decimal digits. Instead, System.out.println prints exactly the number of decimal digits that allow to parse the decimal representation back into the original float or double. There are more doubles, so when printing one, System.out.println needs to print more digits before the representation becomes unambiguous.

The conversion from float to double is a widening conversion, as specified by the JLS. A widening conversion is defined as an injective mapping of a smaller set into its superset. Therefore the number being represented does not change after a conversion from float to double.
More information regarding your updated question
In your update you added an example which is supposed to demonstrate that the number has changed. However, it only shows that the string representation of the number has changed, which indeed it has due to the additional precision acquired through the conversion to double. Note that your first output is just a rounding of the second output. As specified by Double.toString,
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.
Since the adjacent values in the type double are much closer than in float, more digits are needed to comply with that ruling.

The 32bit IEEE-754 floating point number closest to 125.32 is in fact 125.31999969482421875. Pretty close, but not quite there (that's because 0.32 is repeating in binary).
When you cast that to a double, it's the value 125.31999969482421875 that will be made into a double (125.32 is nowhere to be found at this point, the information that it should really end in .32 is completely lost) and of course can be represented exactly by a double. When you print that double, the print routine thinks it has more significant digits than it really has (but of course it can't know that), so it prints to 125.31999969482422, which is the shortest decimal that rounds to that exact double (and of all decimals of that length, it is the closest).

The issue of the precision of floating-point numbers is really language-agnostic, so I'll be using MATLAB in my explanation.
The reason you see a difference is that certain numbers are not exactly representable in fixed number of bits. Take 0.1 for example:
>> format hex
>> double(0.1)
ans =
3fb999999999999a
>> double(single(0.1))
ans =
3fb99999a0000000
So the error in the approximation of 0.1 in single-precision gets bigger when you cast it as double-precision floating-point number. The result is different from its approximation if you started directly in double-precision.
>> double(single(0.1)) - double(0.1)
ans =
1.490116113833651e-09

As already explained, all floats can be exactly represented as a double and the reason for your issue is that System.out.println performs some rounding when displaying the value of a float or double but the rounding methodology is not the same in both cases.
To see the exact value of the float, you can use a BigDecimal:
float f = 125.32f;
System.out.println("value of f = " + new BigDecimal(f));
double d = (double) 125.32f;
System.out.println("value of d = " + new BigDecimal(d));
which outputs:
value of f = 125.31999969482421875
value of d = 125.31999969482421875

it won`t work in java because in java by default it will take real values as double and if we declare a float value without float representation
like
123.45f
by default it will take it as double and it will cause an error as loss of precision

The representation of the values changes due to contracts of the methods that convert numerical values to a String, correspondingly java.lang.Float#toString(float) and java.lang.Double#toString(double), while the actual value remains the same. There is a common part in Javadoc of both aforementioned methods that elaborates requirements to values' String representation:
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
To illustrate the similarity of significant parts for values of both types, the following snippet can be run:
package com.my.sandbox.numbers;
public class FloatToDoubleConversion {
public static void main(String[] args) {
float f = 125.32f;
floatToBits(f);
double d = (double) f;
doubleToBits(d);
}
private static void floatToBits(float floatValue) {
System.out.println();
System.out.println("Float.");
System.out.println("String representation of float: " + floatValue);
int bits = Float.floatToIntBits(floatValue);
int sign = bits >>> 31;
int exponent = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
System.out.println("Bytes: " + Long.toBinaryString(Float.floatToIntBits(floatValue)));
System.out.println("Sign: " + Long.toBinaryString(sign));
System.out.println("Exponent: " + Long.toBinaryString(exponent));
System.out.println("Mantissa: " + Long.toBinaryString(mantissa));
System.out.println("Back from parts: " + Float.intBitsToFloat((sign << 31) | (exponent + ((1 << 7) - 1)) << 23 | mantissa));
System.out.println(10D);
}
private static void doubleToBits(double doubleValue) {
System.out.println();
System.out.println("Double.");
System.out.println("String representation of double: " + doubleValue);
long bits = Double.doubleToLongBits(doubleValue);
long sign = bits >>> 63;
long exponent = (bits >>> 52 & ((1 << 11) - 1)) - ((1 << 10) - 1);
long mantissa = bits & ((1L << 52) - 1);
System.out.println("Bytes: " + Long.toBinaryString(Double.doubleToLongBits(doubleValue)));
System.out.println("Sign: " + Long.toBinaryString(sign));
System.out.println("Exponent: " + Long.toBinaryString(exponent));
System.out.println("Mantissa: " + Long.toBinaryString(mantissa));
System.out.println("Back from parts: " + Double.longBitsToDouble((sign << 63) | (exponent + ((1 << 10) - 1)) << 52 | mantissa));
}
}
In my environment, the output is:
Float.
String representation of float: 125.32
Bytes: 1000010111110101010001111010111
Sign: 0
Exponent: 110
Mantissa: 11110101010001111010111
Back from parts: 125.32
Double.
String representation of double: 125.31999969482422
Bytes: 100000001011111010101000111101011100000000000000000000000000000
Sign: 0
Exponent: 110
Mantissa: 1111010101000111101011100000000000000000000000000000
Back from parts: 125.31999969482422
This way, you can see that values' sign, exponent are the same, while its mantissa was extended retained its significant part (11110101010001111010111) exactly the same.
The used extraction logic of floating point number parts: 1 and 2.

Both are what Microsoft refers to as "approximate number data types."
There's a reason. A float has a precision of 7 digits, and a double 15. But I have seen it happen many times that 8.0 - 1.0 - 6.999999999. This is because they are not guaranteed to represent a decimal number fraction exactly.
If you need absolute, invariable precision, go with a decimal, or integral type.

Related

Why `2.0 - 1.1` and `2.0F - 1.1F` produce different results?

I am working on a code where I am comparing Double and float values:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 1.1); // 0.8999999999999999
System.out.println(2.0 - 1.1 == 0.9); // false
System.out.println(2.0F - 1.1F); // 0.9
System.out.println(2.0F - 1.1F == 0.9F); // true
System.out.println(2.0F - 1.1F == 0.9); // false
}
}
Output is given below:
0.8999999999999999
false
0.9
true
false
I believe the Double value can save more precision than the float.
Please explain this, looks like the float value is not lose precision but the double one lose?
Edit:
#goodvibration I'm aware of that 0.9 can not be exactly saved in any computer language, i'm just confused how java works with this in detail, why 2.0F - 1.1F == 0.9F, but 2.0 - 1.1 != 0.9, another interesting found may help:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 0.9); // 1.1
System.out.println(2.0 - 0.9 == 1.1); // true
System.out.println(2.0F - 0.9F); // 1.1
System.out.println(2.0F - 0.9F == 1.1F); // true
System.out.println(2.0F - 0.9F == 1.1); // false
}
}
I know I can't count on the float or double precision, just.. can't figure it out drive me crazy, whats the real deal behind this? Why 2.0 - 0.9 == 1.1 but 2.0 - 1.1 != 0.9 ??
The difference between float and double:
IEEE 754 single-precision binary floating-point format
IEEE 754 double-precision binary floating-point format
Let's run your numbers in a simple C program, in order to get their binary representations:
#include <stdio.h>
typedef union {
float val;
struct {
unsigned int fraction : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} bits;
} F;
typedef union {
double val;
struct {
unsigned long long fraction : 52;
unsigned long long exponent : 11;
unsigned long long sign : 1;
} bits;
} D;
int main() {
F f = {(float )(2.0 - 1.1)};
D d = {(double)(2.0 - 1.1)};
printf("%d %d %d\n" , f.bits.sign, f.bits.exponent, f.bits.fraction);
printf("%lld %lld %lld\n", d.bits.sign, d.bits.exponent, d.bits.fraction);
return 0;
}
The printout of this code is:
0 126 6710886
0 1022 3602879701896396
Based on the two format specifications above, let's convert these numbers to rational values.
In order to achieve high accuracy, let's do this in a simple Python program:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 100
TWO = Decimal(2)
def convert(sign, exponent, fraction, e_len, f_len):
return (-1) ** sign * TWO ** (exponent - 2 ** (e_len - 1) + 1) * (1 + fraction / TWO ** f_len)
def toFloat(sign, exponent, fraction):
return convert(sign, exponent, fraction, 8, 23)
def toDouble(sign, exponent, fraction):
return convert(sign, exponent, fraction, 11, 52)
f = toFloat(0, 126, 6710886)
d = toDouble(0, 1022, 3602879701896396)
print('{:.40f}'.format(f))
print('{:.40f}'.format(d))
The printout of this code is:
0.8999999761581420898437500000000000000000
0.8999999999999999111821580299874767661094
If we print these two values while specifying between 8 and 15 decimal digits, then we shall experience the same thing that you have observed (the double value printed as 0.9, while the float value printed as close to 0.9):
In other words, this code:
for n in range(8, 15 + 1):
string = '{:.' + str(n) + 'f}';
print(string.format(f))
print(string.format(d))
Gives this printout:
0.89999998
0.90000000
0.899999976
0.900000000
0.8999999762
0.9000000000
0.89999997616
0.90000000000
0.899999976158
0.900000000000
0.8999999761581
0.9000000000000
0.89999997615814
0.90000000000000
0.899999976158142
0.900000000000000
Our conclusion is therefore that Java prints decimals with a precision of between 8 and 15 digits by default.
Nice question BTW...
Pop quiz: Represent 1/3rd, in decimal.
Answer: You can't; not precisely.
Computers count in binary. There are many more numbers that 'cannot be completely represented'. Just like, in the decimal question, if you have only a small piece of paper to write it on, you may simply go with 0.3333333 and call it a day, and you'd then have a number that is quite close to, but not entirely the same as, 1 / 3, so do computers represent fractions.
Or, think about it this way: a float occupies 32-bits; a double occupies 64. There are only 2^32 (about 4 billion) different numbers that a 32-bit value can represent. And yet, even between 0 and 1 there are an infinite amount of numbers. So, given that there are at most 2^32 specific, concrete numbers that are 'representable precisely' as a float, any number that isn't in that blessed set of about 4 billion values, is not representable. Instead of just erroring out, you simply get the one in this pool of 4 billion values that IS representable, and is the closest number to the one you wanted.
In addition, because computers count in binary and not decimal, your sense of what is 'representable' and what isn't, is off. You may think that 1/3 is a big problem, but surely 1/10 is easy, right? That's simply 0.1 and that is a precise representation. Ah, but, a tenth works well in decimal. After all, decimal is based around the number 10, no surprise there. But in binary? a half, a fourth, an eighth, a sixteenth: Easy in binary. A tenth? That is as difficult as a third: NOT REPRESENTABLE.
0.9 is, itself, not a representable number. And yet, when you printed your float, that's what you got.
The reason is, printing floats/doubles is an art, more than a science. Given that only a few numbers are representable, and given that these numbers don't feel 'natural' to humans due to the binary v. decimal thing, you really need to add a 'rounding' strategy to the number or it'll look crazy (nobody wants to read 0.899999999999999999765). And that is precisely what System.out.println and co do.
But you really should take control of the rounding function: Never use System.out.println to print doubles and floats. Use System.out.printf("%.6f", yourDouble); instead, and in this case, BOTH would print 0.9. Because whilst neither can actually represent 0.9 precisely, the number that is closest to it in floats (or rather, the number you get when you take the number closest to 2.0 (which is 2.0), and the number closest to 1.1 (which is not 1.1 precisely), subtract them, and then find the number closest to that result) – prints as 0.9 even though it isn't for floats, and does not print as 0.9 in double.

Java - Numbers aren't subtracting correctly? [duplicate]

public class doublePrecision {
public static void main(String[] args) {
double total = 0;
total += 5.6;
total += 5.8;
System.out.println(total);
}
}
The above code prints:
11.399999999999
How would I get this to just print (or be able to use it as) 11.4?
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
If you just want to process values as fractions, you can create a Fraction class which holds a numerator and denominator field.
Write methods for add, subtract, multiply and divide as well as a toDouble method. This way you can avoid floats during calculations.
EDIT: Quick implementation,
public class Fraction {
private int numerator;
private int denominator;
public Fraction(int n, int d){
numerator = n;
denominator = d;
}
public double toDouble(){
return ((double)numerator)/((double)denominator);
}
public static Fraction add(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop + bTop, a.denominator * b.denominator);
}
else{
return new Fraction(a.numerator + b.numerator, a.denominator);
}
}
public static Fraction divide(Fraction a, Fraction b){
return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}
public static Fraction multiply(Fraction a, Fraction b){
return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}
public static Fraction subtract(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop-bTop, a.denominator*b.denominator);
}
else{
return new Fraction(a.numerator - b.numerator, a.denominator);
}
}
}
Observe that you'd have the same problem if you used limited-precision decimal arithmetic, and wanted to deal with 1/3: 0.333333333 * 3 is 0.999999999, not 1.00000000.
Unfortunately, 5.6, 5.8 and 11.4 just aren't round numbers in binary, because they involve fifths. So the float representation of them isn't exact, just as 0.3333 isn't exactly 1/3.
If all the numbers you use are non-recurring decimals, and you want exact results, use BigDecimal. Or as others have said, if your values are like money in the sense that they're all a multiple of 0.01, or 0.001, or something, then multiply everything by a fixed power of 10 and use int or long (addition and subtraction are trivial: watch out for multiplication).
However, if you are happy with binary for the calculation, but you just want to print things out in a slightly friendlier format, try java.util.Formatter or String.format. In the format string specify a precision less than the full precision of a double. To 10 significant figures, say, 11.399999999999 is 11.4, so the result will be almost as accurate and more human-readable in cases where the binary result is very close to a value requiring only a few decimal places.
The precision to specify depends a bit on how much maths you've done with your numbers - in general the more you do, the more error will accumulate, but some algorithms accumulate it much faster than others (they're called "unstable" as opposed to "stable" with respect to rounding errors). If all you're doing is adding a few values, then I'd guess that dropping just one decimal place of precision will sort things out. Experiment.
You may want to look into using java's java.math.BigDecimal class if you really need precision math. Here is a good article from Oracle/Sun on the case for BigDecimal. While you can never represent 1/3 as someone mentioned, you can have the power to decide exactly how precise you want the result to be. setScale() is your friend.. :)
Ok, because I have way too much time on my hands at the moment here is a code example that relates to your question:
import java.math.BigDecimal;
/**
* Created by a wonderful programmer known as:
* Vincent Stoessel
* xaymaca#gmail.com
* on Mar 17, 2010 at 11:05:16 PM
*/
public class BigUp {
public static void main(String[] args) {
BigDecimal first, second, result ;
first = new BigDecimal("33.33333333333333") ;
second = new BigDecimal("100") ;
result = first.divide(second);
System.out.println("result is " + result);
//will print : result is 0.3333333333333333
}
}
and to plug my new favorite language, Groovy, here is a neater example of the same thing:
import java.math.BigDecimal
def first = new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")
println "result is " + first/second // will print: result is 0.33333333333333
Pretty sure you could've made that into a three line example. :)
If you want exact precision, use BigDecimal. Otherwise, you can use ints multiplied by 10 ^ whatever precision you want.
As others have noted, not all decimal values can be represented as binary since decimal is based on powers of 10 and binary is based on powers of two.
If precision matters, use BigDecimal, but if you just want friendly output:
System.out.printf("%.2f\n", total);
Will give you:
11.40
You're running up against the precision limitation of type double.
Java.Math has some arbitrary-precision arithmetic facilities.
You can't, because 7.3 doesn't have a finite representation in binary. The closest you can get is 2054767329987789/2**48 = 7.3+1/1407374883553280.
Take a look at http://docs.python.org/tutorial/floatingpoint.html for a further explanation. (It's on the Python website, but Java and C++ have the same "problem".)
The solution depends on what exactly your problem is:
If it's that you just don't like seeing all those noise digits, then fix your string formatting. Don't display more than 15 significant digits (or 7 for float).
If it's that the inexactness of your numbers is breaking things like "if" statements, then you should write if (abs(x - 7.3) < TOLERANCE) instead of if (x == 7.3).
If you're working with money, then what you probably really want is decimal fixed point. Store an integer number of cents or whatever the smallest unit of your currency is.
(VERY UNLIKELY) If you need more than 53 significant bits (15-16 significant digits) of precision, then use a high-precision floating-point type, like BigDecimal.
private void getRound() {
// this is very simple and interesting
double a = 5, b = 3, c;
c = a / b;
System.out.println(" round val is " + c);
// round val is : 1.6666666666666667
// if you want to only two precision point with double we
// can use formate option in String
// which takes 2 parameters one is formte specifier which
// shows dicimal places another double value
String s = String.format("%.2f", c);
double val = Double.parseDouble(s);
System.out.println(" val is :" + val);
// now out put will be : val is :1.67
}
Use java.math.BigDecimal
Doubles are binary fractions internally, so they sometimes cannot represent decimal fractions to the exact decimal.
/*
0.8 1.2
0.7 1.3
0.7000000000000002 2.3
0.7999999999999998 4.2
*/
double adjust = fToInt + 1.0 - orgV;
// The following two lines works for me.
String s = String.format("%.2f", adjust);
double val = Double.parseDouble(s);
System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
Doubles are approximations of the decimal numbers in your Java source. You're seeing the consequence of the mismatch between the double (which is a binary-coded value) and your source (which is decimal-coded).
Java's producing the closest binary approximation. You can use the java.text.DecimalFormat to display a better-looking decimal value.
Short answer: Always use BigDecimal and make sure you are using the constructor with String argument, not the double one.
Back to your example, the following code will print 11.4, as you wish.
public class doublePrecision {
public static void main(String[] args) {
BigDecimal total = new BigDecimal("0");
total = total.add(new BigDecimal("5.6"));
total = total.add(new BigDecimal("5.8"));
System.out.println(total);
}
}
Multiply everything by 100 and store it in a long as cents.
Computers store numbers in binary and can't actually represent numbers such as 33.333333333 or 100.0 exactly. This is one of the tricky things about using doubles. You will have to just round the answer before showing it to a user. Luckily in most applications, you don't need that many decimal places anyhow.
Floating point numbers differ from real numbers in that for any given floating point number there is a next higher floating point number. Same as integers. There's no integer between 1 and 2.
There's no way to represent 1/3 as a float. There's a float below it and there's a float above it, and there's a certain distance between them. And 1/3 is in that space.
Apfloat for Java claims to work with arbitrary precision floating point numbers, but I've never used it. Probably worth a look.
http://www.apfloat.org/apfloat_java/
A similar question was asked here before
Java floating point high precision library
Use a BigDecimal. It even lets you specify rounding rules (like ROUND_HALF_EVEN, which will minimize statistical error by rounding to the even neighbor if both are the same distance; i.e. both 1.5 and 2.5 round to 2).
Why not use the round() method from Math class?
// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4
Check out BigDecimal, it handles problems dealing with floating point arithmetic like that.
The new call would look like this:
term[number].coefficient.add(co);
Use setScale() to set the number of decimal place precision to be used.
If you have no choice other than using double values, can use the below code.
public static double sumDouble(double value1, double value2) {
double sum = 0.0;
String value1Str = Double.toString(value1);
int decimalIndex = value1Str.indexOf(".");
int value1Precision = 0;
if (decimalIndex != -1) {
value1Precision = (value1Str.length() - 1) - decimalIndex;
}
String value2Str = Double.toString(value2);
decimalIndex = value2Str.indexOf(".");
int value2Precision = 0;
if (decimalIndex != -1) {
value2Precision = (value2Str.length() - 1) - decimalIndex;
}
int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
sum = value1 + value2;
String s = String.format("%." + maxPrecision + "f", sum);
sum = Double.parseDouble(s);
return sum;
}
You can Do the Following!
System.out.println(String.format("%.12f", total));
if you change the decimal value here %.12f
So far I understand it as main goal to get correct double from wrong double.
Look for my solution how to get correct value from "approximate" wrong value - if it is real floating point it rounds last digit - counted from all digits - counting before dot and try to keep max possible digits after dot - hope that it is enough precision for most cases:
public static double roundError(double value) {
BigDecimal valueBigDecimal = new BigDecimal(Double.toString(value));
String valueString = valueBigDecimal.toPlainString();
if (!valueString.contains(".")) return value;
String[] valueArray = valueString.split("[.]");
int places = 16;
places -= valueArray[0].length();
if ("56789".contains("" + valueArray[0].charAt(valueArray[0].length() - 1))) places--;
//System.out.println("Rounding " + value + "(" + valueString + ") to " + places + " places");
return valueBigDecimal.setScale(places, RoundingMode.HALF_UP).doubleValue();
}
I know it is long code, sure not best, maybe someone can fix it to be more elegant. Anyway it is working, see examples:
roundError(5.6+5.8) = 11.399999999999999 = 11.4
roundError(0.4-0.3) = 0.10000000000000003 = 0.1
roundError(37235.137567000005) = 37235.137567
roundError(1/3) 0.3333333333333333 = 0.333333333333333
roundError(3723513756.7000005) = 3.7235137567E9 (3723513756.7)
roundError(3723513756123.7000005) = 3.7235137561237E12 (3723513756123.7)
roundError(372351375612.7000005) = 3.723513756127E11 (372351375612.7)
roundError(1.7976931348623157) = 1.797693134862316
Do not waste your efford using BigDecimal. In 99.99999% cases you don't need it. java double type is of cource approximate but in almost all cases, it is sufficiently precise. Mind that your have an error at 14th significant digit. This is really negligible!
To get nice output use:
System.out.printf("%.2f\n", total);

Java - Equation issues [duplicate]

public class doublePrecision {
public static void main(String[] args) {
double total = 0;
total += 5.6;
total += 5.8;
System.out.println(total);
}
}
The above code prints:
11.399999999999
How would I get this to just print (or be able to use it as) 11.4?
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
If you just want to process values as fractions, you can create a Fraction class which holds a numerator and denominator field.
Write methods for add, subtract, multiply and divide as well as a toDouble method. This way you can avoid floats during calculations.
EDIT: Quick implementation,
public class Fraction {
private int numerator;
private int denominator;
public Fraction(int n, int d){
numerator = n;
denominator = d;
}
public double toDouble(){
return ((double)numerator)/((double)denominator);
}
public static Fraction add(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop + bTop, a.denominator * b.denominator);
}
else{
return new Fraction(a.numerator + b.numerator, a.denominator);
}
}
public static Fraction divide(Fraction a, Fraction b){
return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}
public static Fraction multiply(Fraction a, Fraction b){
return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}
public static Fraction subtract(Fraction a, Fraction b){
if(a.denominator != b.denominator){
double aTop = b.denominator * a.numerator;
double bTop = a.denominator * b.numerator;
return new Fraction(aTop-bTop, a.denominator*b.denominator);
}
else{
return new Fraction(a.numerator - b.numerator, a.denominator);
}
}
}
Observe that you'd have the same problem if you used limited-precision decimal arithmetic, and wanted to deal with 1/3: 0.333333333 * 3 is 0.999999999, not 1.00000000.
Unfortunately, 5.6, 5.8 and 11.4 just aren't round numbers in binary, because they involve fifths. So the float representation of them isn't exact, just as 0.3333 isn't exactly 1/3.
If all the numbers you use are non-recurring decimals, and you want exact results, use BigDecimal. Or as others have said, if your values are like money in the sense that they're all a multiple of 0.01, or 0.001, or something, then multiply everything by a fixed power of 10 and use int or long (addition and subtraction are trivial: watch out for multiplication).
However, if you are happy with binary for the calculation, but you just want to print things out in a slightly friendlier format, try java.util.Formatter or String.format. In the format string specify a precision less than the full precision of a double. To 10 significant figures, say, 11.399999999999 is 11.4, so the result will be almost as accurate and more human-readable in cases where the binary result is very close to a value requiring only a few decimal places.
The precision to specify depends a bit on how much maths you've done with your numbers - in general the more you do, the more error will accumulate, but some algorithms accumulate it much faster than others (they're called "unstable" as opposed to "stable" with respect to rounding errors). If all you're doing is adding a few values, then I'd guess that dropping just one decimal place of precision will sort things out. Experiment.
You may want to look into using java's java.math.BigDecimal class if you really need precision math. Here is a good article from Oracle/Sun on the case for BigDecimal. While you can never represent 1/3 as someone mentioned, you can have the power to decide exactly how precise you want the result to be. setScale() is your friend.. :)
Ok, because I have way too much time on my hands at the moment here is a code example that relates to your question:
import java.math.BigDecimal;
/**
* Created by a wonderful programmer known as:
* Vincent Stoessel
* xaymaca#gmail.com
* on Mar 17, 2010 at 11:05:16 PM
*/
public class BigUp {
public static void main(String[] args) {
BigDecimal first, second, result ;
first = new BigDecimal("33.33333333333333") ;
second = new BigDecimal("100") ;
result = first.divide(second);
System.out.println("result is " + result);
//will print : result is 0.3333333333333333
}
}
and to plug my new favorite language, Groovy, here is a neater example of the same thing:
import java.math.BigDecimal
def first = new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")
println "result is " + first/second // will print: result is 0.33333333333333
Pretty sure you could've made that into a three line example. :)
If you want exact precision, use BigDecimal. Otherwise, you can use ints multiplied by 10 ^ whatever precision you want.
As others have noted, not all decimal values can be represented as binary since decimal is based on powers of 10 and binary is based on powers of two.
If precision matters, use BigDecimal, but if you just want friendly output:
System.out.printf("%.2f\n", total);
Will give you:
11.40
You're running up against the precision limitation of type double.
Java.Math has some arbitrary-precision arithmetic facilities.
You can't, because 7.3 doesn't have a finite representation in binary. The closest you can get is 2054767329987789/2**48 = 7.3+1/1407374883553280.
Take a look at http://docs.python.org/tutorial/floatingpoint.html for a further explanation. (It's on the Python website, but Java and C++ have the same "problem".)
The solution depends on what exactly your problem is:
If it's that you just don't like seeing all those noise digits, then fix your string formatting. Don't display more than 15 significant digits (or 7 for float).
If it's that the inexactness of your numbers is breaking things like "if" statements, then you should write if (abs(x - 7.3) < TOLERANCE) instead of if (x == 7.3).
If you're working with money, then what you probably really want is decimal fixed point. Store an integer number of cents or whatever the smallest unit of your currency is.
(VERY UNLIKELY) If you need more than 53 significant bits (15-16 significant digits) of precision, then use a high-precision floating-point type, like BigDecimal.
private void getRound() {
// this is very simple and interesting
double a = 5, b = 3, c;
c = a / b;
System.out.println(" round val is " + c);
// round val is : 1.6666666666666667
// if you want to only two precision point with double we
// can use formate option in String
// which takes 2 parameters one is formte specifier which
// shows dicimal places another double value
String s = String.format("%.2f", c);
double val = Double.parseDouble(s);
System.out.println(" val is :" + val);
// now out put will be : val is :1.67
}
Use java.math.BigDecimal
Doubles are binary fractions internally, so they sometimes cannot represent decimal fractions to the exact decimal.
/*
0.8 1.2
0.7 1.3
0.7000000000000002 2.3
0.7999999999999998 4.2
*/
double adjust = fToInt + 1.0 - orgV;
// The following two lines works for me.
String s = String.format("%.2f", adjust);
double val = Double.parseDouble(s);
System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
Doubles are approximations of the decimal numbers in your Java source. You're seeing the consequence of the mismatch between the double (which is a binary-coded value) and your source (which is decimal-coded).
Java's producing the closest binary approximation. You can use the java.text.DecimalFormat to display a better-looking decimal value.
Short answer: Always use BigDecimal and make sure you are using the constructor with String argument, not the double one.
Back to your example, the following code will print 11.4, as you wish.
public class doublePrecision {
public static void main(String[] args) {
BigDecimal total = new BigDecimal("0");
total = total.add(new BigDecimal("5.6"));
total = total.add(new BigDecimal("5.8"));
System.out.println(total);
}
}
Multiply everything by 100 and store it in a long as cents.
Computers store numbers in binary and can't actually represent numbers such as 33.333333333 or 100.0 exactly. This is one of the tricky things about using doubles. You will have to just round the answer before showing it to a user. Luckily in most applications, you don't need that many decimal places anyhow.
Floating point numbers differ from real numbers in that for any given floating point number there is a next higher floating point number. Same as integers. There's no integer between 1 and 2.
There's no way to represent 1/3 as a float. There's a float below it and there's a float above it, and there's a certain distance between them. And 1/3 is in that space.
Apfloat for Java claims to work with arbitrary precision floating point numbers, but I've never used it. Probably worth a look.
http://www.apfloat.org/apfloat_java/
A similar question was asked here before
Java floating point high precision library
Use a BigDecimal. It even lets you specify rounding rules (like ROUND_HALF_EVEN, which will minimize statistical error by rounding to the even neighbor if both are the same distance; i.e. both 1.5 and 2.5 round to 2).
Why not use the round() method from Math class?
// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4
Check out BigDecimal, it handles problems dealing with floating point arithmetic like that.
The new call would look like this:
term[number].coefficient.add(co);
Use setScale() to set the number of decimal place precision to be used.
If you have no choice other than using double values, can use the below code.
public static double sumDouble(double value1, double value2) {
double sum = 0.0;
String value1Str = Double.toString(value1);
int decimalIndex = value1Str.indexOf(".");
int value1Precision = 0;
if (decimalIndex != -1) {
value1Precision = (value1Str.length() - 1) - decimalIndex;
}
String value2Str = Double.toString(value2);
decimalIndex = value2Str.indexOf(".");
int value2Precision = 0;
if (decimalIndex != -1) {
value2Precision = (value2Str.length() - 1) - decimalIndex;
}
int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
sum = value1 + value2;
String s = String.format("%." + maxPrecision + "f", sum);
sum = Double.parseDouble(s);
return sum;
}
You can Do the Following!
System.out.println(String.format("%.12f", total));
if you change the decimal value here %.12f
So far I understand it as main goal to get correct double from wrong double.
Look for my solution how to get correct value from "approximate" wrong value - if it is real floating point it rounds last digit - counted from all digits - counting before dot and try to keep max possible digits after dot - hope that it is enough precision for most cases:
public static double roundError(double value) {
BigDecimal valueBigDecimal = new BigDecimal(Double.toString(value));
String valueString = valueBigDecimal.toPlainString();
if (!valueString.contains(".")) return value;
String[] valueArray = valueString.split("[.]");
int places = 16;
places -= valueArray[0].length();
if ("56789".contains("" + valueArray[0].charAt(valueArray[0].length() - 1))) places--;
//System.out.println("Rounding " + value + "(" + valueString + ") to " + places + " places");
return valueBigDecimal.setScale(places, RoundingMode.HALF_UP).doubleValue();
}
I know it is long code, sure not best, maybe someone can fix it to be more elegant. Anyway it is working, see examples:
roundError(5.6+5.8) = 11.399999999999999 = 11.4
roundError(0.4-0.3) = 0.10000000000000003 = 0.1
roundError(37235.137567000005) = 37235.137567
roundError(1/3) 0.3333333333333333 = 0.333333333333333
roundError(3723513756.7000005) = 3.7235137567E9 (3723513756.7)
roundError(3723513756123.7000005) = 3.7235137561237E12 (3723513756123.7)
roundError(372351375612.7000005) = 3.723513756127E11 (372351375612.7)
roundError(1.7976931348623157) = 1.797693134862316
Do not waste your efford using BigDecimal. In 99.99999% cases you don't need it. java double type is of cource approximate but in almost all cases, it is sufficiently precise. Mind that your have an error at 14th significant digit. This is really negligible!
To get nice output use:
System.out.printf("%.2f\n", total);

Float and double datatype in Java

The float data type is a single-precision 32-bit IEEE 754 floating point and the double data type is a double-precision 64-bit IEEE 754 floating point.
What does it mean? And when should I use float instead of double or vice-versa?
The Wikipedia page on it is a good place to start.
To sum up:
float is 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).
double is 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.
Floating-point numbers, also known as real numbers, are used when evaluating expressions that require fractional precision. For example, calculations such as square root, or transcendentals such as sine and cosine, result in a value whose precision requires a floating-point type. Java implements the standard (IEEE–754) set of floatingpoint types and operators. There are two kinds of floating-point types, float and double, which represent single- and double-precision numbers, respectively. Their width and ranges are shown here:
Name Width in Bits Range
double 64 1 .7e–308 to 1.7e+308
float 32 3 .4e–038 to 3.4e+038
float
The type float specifies a single-precision value that uses 32 bits of storage. Single precision is faster on some processors and takes half as much space as double precision, but will become imprecise when the values are either very large or very small. Variables of type float are useful when you need a fractional component, but don't require a large degree of precision.
Here are some example float variable declarations:
float hightemp, lowtemp;
double
Double precision, as denoted by the double keyword, uses 64 bits to store a value. Double precision is actually faster than single precision on some modern processors that have been optimized for high-speed mathematical calculations. All transcendental math functions, such as sin( ), cos( ), and sqrt( ), return double values. When you need to maintain accuracy over many iterative calculations, or are manipulating large-valued numbers, double is the best choice.
This will give error:
public class MyClass {
public static void main(String args[]) {
float a = 0.5;
}
}
/MyClass.java:3: error: incompatible types: possible lossy conversion from double to float
float a = 0.5;
This will work perfectly fine
public class MyClass {
public static void main(String args[]) {
double a = 0.5;
}
}
This will also work perfectly fine
public class MyClass {
public static void main(String args[]) {
float a = (float)0.5;
}
}
Reason : Java by default stores real numbers as double to ensure higher precision.
Double takes more space but more precise during computation and float takes less space but less precise.
Java seems to have a bias towards using double for computations nonetheless:
Case in point the program I wrote earlier today, the methods didn't work when I used float, but now work great when I substituted float with double (in the NetBeans IDE):
package palettedos;
import java.util.*;
class Palettedos{
private static Scanner Z = new Scanner(System.in);
public static final double pi = 3.142;
public static void main(String[]args){
Palettedos A = new Palettedos();
System.out.println("Enter the base and height of the triangle respectively");
int base = Z.nextInt();
int height = Z.nextInt();
System.out.println("Enter the radius of the circle");
int radius = Z.nextInt();
System.out.println("Enter the length of the square");
long length = Z.nextInt();
double tArea = A.calculateArea(base, height);
double cArea = A.calculateArea(radius);
long sqArea = A.calculateArea(length);
System.out.println("The area of the triangle is\t" + tArea);
System.out.println("The area of the circle is\t" + cArea);
System.out.println("The area of the square is\t" + sqArea);
}
double calculateArea(int base, int height){
double triArea = 0.5*base*height;
return triArea;
}
double calculateArea(int radius){
double circArea = pi*radius*radius;
return circArea;
}
long calculateArea(long length){
long squaArea = length*length;
return squaArea;
}
}
According to the IEEE standards, float is a 32 bit representation of a real number while double is a 64 bit representation.
In Java programs we normally mostly see the use of double data type. It's just to avoid overflows as the range of numbers that can be accommodated using the double data type is more that the range when float is used.
Also when high precision is required, the use of double is encouraged. Few library methods that were implemented a long time ago still requires the use of float data type as a must (that is only because it was implemented using float, nothing else!).
But if you are certain that your program requires small numbers and an overflow won't occur with your use of float, then the use of float will largely improve your space complexity as floats require half the memory as required by double.
This example illustrates how to extract the sign (the leftmost bit), exponent (the 8 following bits) and mantissa (the 23 rightmost bits) from a float in Java.
int bits = Float.floatToIntBits(-0.005f);
int sign = bits >>> 31;
int exp = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
Float.intBitsToFloat((sign << 31) | (exp + ((1 << 7) - 1)) << 23 | mantissa));
The same approach can be used for double’s (11 bit exponent and 52 bit mantissa).
long bits = Double.doubleToLongBits(-0.005);
long sign = bits >>> 63;
long exp = (bits >>> 52 & ((1 << 11) - 1)) - ((1 << 10) - 1);
long mantissa = bits & ((1L << 52) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
Double.longBitsToDouble((sign << 63) | (exp + ((1 << 10) - 1)) << 52 | mantissa));
Credit: http://s-j.github.io/java-float/
You should use double instead of float for precise calculations, and float instead of double when using less accurate calculations. Float contains only decimal numbers, but double contains an IEEE754 double-precision floating point number, making it easier to contain and computate numbers more accurately. Hope this helps.
In regular programming calculations, we don’t use float. If we ensure that the result range is within the range of float data type then we can choose a float data type for saving memory. Generally, we use double because of two reasons:-
If we want to use the floating-point number as float data type then method caller must explicitly suffix F or f, because by default every floating-point number is treated as double. It increases the burden to the programmer. If we use a floating-point number as double data type then we don’t need to add any suffix.
Float is a single-precision data type means it occupies 4 bytes. Hence in large computations, we will not get a complete result. If we choose double data type, it occupies 8 bytes and we will get complete results.
Both float and double data types were designed especially for scientific calculations, where approximation errors are acceptable. If accuracy is the most prior concern then, it is recommended to use BigDecimal class instead of float or double data types. Source:- Float and double datatypes in Java

NumberFormat Parse Issue

I am quite confused about this peculiar 'error' I am getting when parsing a String to a Double.
I've already set up the NumberFormat properties and symbols.
When passing a String with 15 digits and 2 decimals (ex. str = "333333333333333,33")
and parsing it with Number num = NumberFormat.parse(str) the result is omitting a digit.
The actual value of num is 3.333333333333333E14.
It seems to be working with Strings with all 1's, 2's and 4's though...
Anyone can enlighten me?
Cheers
Enrico
The short answer; due to round error
(double) 111111111111111.11 != (double) 111111111111111.1
but
(double) 333333333333333.33 == (double) 333333333333333.3
If you want more precision, use setParseBigDecimal and parse will return a BigDecimal.
Why does this happen? This is because you are at the limit of the precision of double. The 17 ones is fine as it can just be represented. The 2's is just double this and as double stores powers of two, every power of two of all 17 ones, so 17 fours and 17 eights is fine.
However, 17 threes takes one more bit than double has to represent the value and this last bit is truncated. Similarly 17 fives, sixes and nines also have rounding errors.
double[] ds = {
111111111111111.11,
222222222222222.22,
333333333333333.33,
444444444444444.44,
555555555555555.55,
666666666666666.66,
777777777777777.77,
888888888888888.88,
999999999999999.99};
for (double d : ds) {
System.out.println(d + " - " + new BigDecimal(d));
}
prints the following. The double is rounded slightly before printing and the BigDecimal shows you the exact values the double represents.
1.1111111111111111E14 - 111111111111111.109375
2.2222222222222222E14 - 222222222222222.21875
3.333333333333333E14 - 333333333333333.3125
4.4444444444444444E14 - 444444444444444.4375
5.5555555555555556E14 - 555555555555555.5625
6.666666666666666E14 - 666666666666666.625
7.777777777777778E14 - 777777777777777.75
8.888888888888889E14 - 888888888888888.875
1.0E15 - 1000000000000000
The DecimalFormat.parse method will in this case return a Double, which has limited precision.
You can't expect it to always be able to return a Number that represents the input exactly.
You can use BigDecimal.setParseBigDecimal to allow the number format to return a BigDecimal from the parse method. This Number is capable of representing your values with arbitrary precision. (Thanks #Peter Lawrey for pointing that out!)

Categories