When I try to parse the following string into a float and into a double :
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 100);
System.out.println("Float Value: " + Float.parseFloat(abc) * 100);
I get two different results.
Double Value: 840.0
Float Value: 839.99994
But when I try the same code with multiplying the float and double by 10 or 1000 I get the similar results for both of them.
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 10);
System.out.println("Float Value: " + Float.parseFloat(abc) * 10);
I get two similar results.
Double Value: 84.0
Float Value: 84.0
And when I try this :
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 1000);
System.out.println("Float Value: " + Float.parseFloat(abc) * 1000);
I get two similar results.
Double Value: 8400.0
Float Value: 8400.0
This will work fine:
System.out.println("Float Value: "+Math.round((float)Float.parseFloat(abc)*100));
So, this happens because of different representation of double and float, or more precise, about IEEE-754 rounding for float. Read about it here.
float has a smaller range and precision, so double would be better when you have memory (which you do today). But, they are both evil! There is a better option in Java called BigDecimal and you should use it, since it doesn't have problem with size and today we have strong computers so we will not have problems with memory and speed when dealing with a large number of decimal numbers needing max precision. For example, if you work on software that deals with a lot of money transactions, its a must to use BigDecimal.
It is true that double has more precision than float, but both of them suffer from the same problem: their value may not be exact, and they both have some (small) rounding error in their Least Significant Bit (LSB). This is clear in the first result you got: float value is not accurate. But when you multiply by 10 or 1000, the LSB is discarded from the result, and so you get the right answer for both float and double.
Related
Help, I got a problem when adding double value with negative number
A sample program to show the problem:
double newX = 850.0;
double delta = -1.6994427191177073E12;
double total = delta + newX;
System.out.println("newX:" + newX);
System.out.println("delta:" + delta);
System.out.println("total:" + total);
but the given output is:
newX:850.0
delta:-1.6994427191177073E12
total:-1.6994427182677073E12
I would expect the total value to be around "848.30055729". How to handle this calculation?
Regards,
Dennis
The computation is correct.
Lets start by converting your number from scientific notation
-1.6994427191177073E12
to decimal fixed-point notation:
-1699442719117.7073
This is because E12 means that the number to the left of E is multiplied by 1012.
Once you perform the addition of that number and 850.0, you get the result
-1699442718267.7073
Once you convert it to scientific notation by bringing the decimal point all the way to the left, you get the result printed by your program.
I was trying to really learn more about floats, doubles and bigdecimals in Java. I wanted to know exactly how a floating point number gets represented in each type, for ex. floats use 2^, big decimals use 10^ plus scaled(32-bit) and unscaled values (arbitrary precision).
I put together simple calcs using all three types and did conversations for each, the result is rather confusing. I would appreciate some hints about why the only correct representation is for float, and why when converted into Double and BigDecimal there were trailing imprecisions. Is it to do with binary representation conversions? Anyhow here are the code and its output:
// Float - 32b
float a = 3.14f;
float b = 3.100004f;
float abAsAFloat = a + b;
double abAsADouble = a + b;
BigDecimal abAsABigDecimal = new BigDecimal(a + b);
System.out.println("a + b as a float: " + abAsAFloat);
System.out.println("a + b as a double: " + abAsADouble);
System.out.println("a + b as a BigDecimal: " + abAsABigDecimal);
// Double - 64b
double c = 3.14;
double d = 3.100004;
double cdAsADouble = c + d;
BigDecimal cdAsABigDecimal = new BigDecimal(c + d);
System.out.println("c + d as a double: " + cdAsADouble);
System.out.println("c + d as a BigDecimal: " + cdAsABigDecimal);
// BigDecimal, arbitrary-precision, signBit*unscaledValue × 10^-scale
BigDecimal e = new BigDecimal(3.14);
BigDecimal f = new BigDecimal(3.100004);
BigDecimal efAsABigDecimal = e.add(f);
System.out.println("e + f: " + efAsABigDecimal);
// Drawbacks. speed, memory, native value equality, no overloads for +/- et al
a + b as a float: 6.240004
a + b as a double: 6.240004062652588
a + b as a BigDecimal: 6.240004062652587890625
c + d as a double: 6.240004000000001
c + d as a BigDecimal:
6.2400040000000007722746886429376900196075439453125
e + f: 6.240004000000000328185478792875073850154876708984375
You're inadvertently mixing types. For example:
BigDecimal e = new BigDecimal(3.14);
BigDecimal f = new BigDecimal(3.100004);
In this case, you're providing doubles as inputs, so e and f will have double residues. Instead, use this:
BigDecimal e = new BigDecimal("3.14");
BigDecimal f = new BigDecimal("3.100004");
The float output is seemingly the most accurate because Java "knows" floats have a limited precision, so it won't print fifteen digits.
float may look correct for this particular case, but it will be just as wrong for other values. Note that when float and double are converted to strings, only as many digits are printed as are necessary to get the right value in that type; this means float may print "the correct answer" even when that representation conceals just as much rounding error as double.
The problem with BigDecimal is that you're not using it correctly: you should be writing new BigDecimal("3.14") instead of new BigDecimal(3.14), which allows double to "mess it up" before BigDecimal has the chance to "fix it."
For the details of representation, https://en.wikipedia.org/wiki/Double-precision_floating-point_format has a thorough explanation with useful diagrams, but the short explanation is that float and double represent numbers as +/- 1 * 1. * 2^, where float stores the mantissa with 22 bits and the exponent with 8 bits, and double uses 52 and 11 bits respectively.
When you convert to either double or BigDecimal it converts to the closest representable value. When you convert to BigDecimal you are actually converting to double first as there is no direct conversion from float.
Usually the you want to convert from double to BigDecimal using BigDecimal.valueOf(double) This method assumes a certain level of rounding to match what the double would look like if you printed it.
Read this: Java Language Specification. Chapter 5. Conversions and Promotions
Especially, 5.6. Numeric Promotions
i.e
float a = 3.14f;
float b = 3.100004f;
double abAsADouble = a + b;
in this case first a will be added to b, giving a float result, then float will be converted to double and assigned. So, it might have a loss of precision, when comparing to (double)a + b;
The same thing, when using sum result as parameter to the constructor
new BigDecimal(a + b)
first, float a added to float b, giving a float result, after that it is converted to double and then BigDecimal object begins being constructed.
Any numeric constants with decimal point, unless you specify f at the end, are considered to be a double, so, when passing constant to the constructor:
new BigDecimal(3.100004);
Number is stored as double and passed as double precision to the constructor. To achieve more precision, use String parameter constructor instead:
new BigDecimal("3.100004");
As I was trying to compute some very small simple precision and double precision floating numbers I encountered some issues.
Take a look at the following code sample:
public class FloatingLimits {
public static void doSimpleFloatingLimitDemo() {
float firstValue = 1.56F;
float newValue = 1.0F / ((float)Math.pow(2.0D, 150));
double doubleFirst = 2.56;
double doubleNew = 1.0F /Math.pow(2.0D, 150);
double doubleThird = 1.0F/Math.pow(2.0D, 589);
double doubleFourth = 1.0F/Math.pow(2.0, 1589);
System.out.println("float first value =" + firstValue);
System.out.println("float new value =" + newValue);
System.out.println("double first value =" + doubleFirst);
System.out.println("double new value =" + doubleNew);
System.out.println("double third value =" + doubleThird);
System.out.println("double fourth value =" + doubleFourth);
}
public static void main(String[] args) {
doSimpleFloatingLimitDemo();
}
}
It produces the following result:
There is therefore a representation issue or a display issue! Does this have anything to do with numbers precision? The very small numbers that I could not represent with a simple float precision type (32 bits), could be represented with double float precision numbers (64) bits, but the double float also is showing limits. So what would that limit be for very small numbers? Is there a workaround for this using float and double numbers or should I necessarily use BigDecimal to solve it. If I have to use BigDecimals, is there a certain limit to BigDecimal representation as well?
If you look at Double.MAX_VALUE
A constant holding the largest positive finite value of type double, (2-2-52).21023.
And if you run:
System.out.println(Math.pow(2.0, 1589));
You will see the expected result:
Infinity
If you need to represents decimal numbers with arbitrary precision you have to use BigDecimal.
Here is a link
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
The internal binary representation of float and double can introduce errors. Another possibility is to work with int or long multiply the values by a factor (10, 100, 1000 ...) and treat them as non decimal values.
This question already has answers here:
How do I get whole and fractional parts from double in JSP/Java?
(18 answers)
Closed 9 years ago.
double d = 4.321562;
Is there an easy way to extract the 0.321562 on it's own from d? I tried looking in the math class but no luck. If this can be done without converting to string or casting to anything else, even better.
Well, you can use:
double x = d - Math.floor(d);
Note that due to the way that binary floating point works, that won't give you exactly 0.321562, as the original value isn't exactly 4.321562. If you're really interested in exact digits, you should use BigDecimal instead.
Another way to get the fraction without using Math is to cast to a long.
double x = d - (long) d;
When you print a double the toString will perform a small amount of rounding so you don't see any rounding error. However, when you remove the integer part, the rounding is no longer enough and the rounding error becomes obvious.
The way around this is to do the rounding yourself or use BigDecimal which allows you to control the rounding.
double d = 4.321562;
System.out.println("Double value from toString " + d);
System.out.println("Exact representation " + new BigDecimal(d));
double x = d - (long) d;
System.out.println("Fraction from toString " + x);
System.out.println("Exact value of fraction " + new BigDecimal(x));
System.out.printf("Rounded to 6 places %.6f%n", x);
double x2 = Math.round(x * 1e9) / 1e9;
System.out.println("After rounding to 9 places toString " + x2);
System.out.println("After rounding to 9 places, exact value " + new BigDecimal(x2));
prints
Double value from toString 4.321562
Exact representation 4.321562000000000125510268844664096832275390625
Fraction from toString 0.3215620000000001
Exact value of fraction 0.321562000000000125510268844664096832275390625
Rounded to 6 places 0.321562
After rounding to 9 places toString 0.321562
After rounding to 9 places, exact value 0.32156200000000001448796638214844278991222381591796875
NOTE: double has limited precision and you can see representation issue creep in if you don't use appropriate rounding. This can happen in any calculation you use with double esp numbers which are not an exact sum of powers of 2.
Use modulo:
double d = 3.123 % 1;
assertEquals(0.123, d,0.000001);
I'm writing a program for my Java class and we were asked to design a program, using GUI, that accepts a temperature value and converts to others, such as from Fahrenheit to Celsius and Kelvin. I've run into a problem though:
if (event.getSource() == fahrText)
{
string = event.getActionCommand();
tempF = Double.parseDouble(string);
tempC = (tempF - 32) * (5/9);
tempK = tempC + 273.15;
resultF.setText("Fahr: " + tempF);
resultC.setText("Cels: " + tempC);
resultK.setText("Kelv: " + tempK);
}
No matter what number I enter into the "fahrText" JTextField I get Celsius as 0, while tempF shows the value I entered. Any suggestions as to why? I used Double.valueOf(string) with the same results.
Try 5.0/9.0 - 5/9 is integer division, and equal to 0. An integer division gives you an integer - regardless of which type you happen to assign the result to.
You could also keep a private final static double FToCFactor = 5.0/9.0; around and multiply with that.
The expression
5/9
represents an integer division. The result of that expression is 0.
What you want is a floating point division. It can be achieved with
5.0/9.0
Use double constants (e.g., 32.0d) instead of integers for all of your math. You're ending up doing integer math instead of floating point math.