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.
Related
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.
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.
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.
I have a class that has a double 'sizeinMegs' variable and whenever the value is tiny, say 0.00025 megs, it simply stores 0.0 as seen in the debug watch.
How do I save it in all its decimal glory?
Here's my code:
thePdf.setFileSizeInMegaBytes((theFile.length() / 1000000)); //that's a double
double size = theFile.length(); // this returns say 12345
size = size / 1000000; this returns 0.012345
double storedValue = thePdf.getFileSizeInMegaBytes(); // this shows 0.0 in the watch window
String value;
value = fmt(size); //this shows the right value in the string
lblTest.setText("Size: " + value + " MB");
....
public static String fmt(double d)
{
if(d == (int) d)
return String.format("%d",(int)d);
else
return String.format("%s",d);
}
It's hard to tell here, because i can't see the declaration of "theFile", but if the length() method is returning a long or int value, then the very first line of your program is doing integer/long division, and thus any value < 1 becomes 0.
If that's the case here, cast the length to a double first.
THe reason the second part works is that this declaration has an implicit cast from int/long to double, and thus any subsequent calculations results in doubles.
double size = theFile.length();
Your problem is integer division. Instead of
theFile.length() / 1000000
which will always round downwards, you could write
theFile.length() / 1000000.0
which forces this to be a non-integer division.
Whenever you place / between two expressions of int type, the result will be an int too, and it will be rounded.
You should use BigDecimal instead of double, that way you won't lose precision.
Can you show code in:
thePdf.setFileSizeInMegaBytes()
and
thePdf.getFileSizeInMegaBytes()
I have the following code :
Double x = 17.0;
Double y = 0.1;
double remainder = x.doubleValue() % y.doubleValue();
When I run this I get remainder = 0.09999999999999906
Any idea why??
I basically need to check that x is fully divisible by y. Can you suggest alternative ways to do that in java.
Thanks
Because of how floating-point numbers are represented.
If you want exact values, use BigDecimal:
BigDecimal remainder = BigDecimal.valueOf(x).remainder(BigDecimal.valueOf(y));
Another way to to that is to multiple each value by 10 (or 100, 1000), cast to int, and then use %.
You need to compare your result which allows for rounding error.
if (remainder < ERROR || remainder > 0.1 - ERROR)
Also, don't use Double when you mean to use double
Expecting precise results from double arithmetic is problematic on computers. The basic culprit is that us humans use base 10 mostly, whereas computers normally store numbers in base 2. There are conversion problems between the two.
This code will do what you want:
public static void main(String[] args) {
BigDecimal x = BigDecimal.valueOf(17.0);
BigDecimal y = BigDecimal.valueOf(0.1);
BigDecimal remainder = x.remainder(y);
System.out.println("remainder = " + remainder);
final boolean divisible = remainder.equals(BigDecimal.valueOf(0.0));
System.out.println("divisible = " + divisible);
}