1

I input 179.9 in an EditText. When I retrieve it, the value is different if it's stored as a float.

final EditText valueInput = mEntryDialogView.getValueInput();
final CharSequence input = valueInput.getText();
final String inputAsString = input.toString().trim();
final float asFloat = Float.valueOf(inputAsString); //179.899994
final double asDouble = Double.valueOf(inputAsString); //179.9

Something fishy is going on here, could anyone explain to me why the float value is not correct? Even so if I convert the double value above to a float, it will be incorrect.

Moreover, is there anything that can be done to retrieve the value as a float in such a manner that it is equivalent to the actual inputted value?

zoltish
  • 2,122
  • 19
  • 37
  • 3
    Possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – tynn Feb 27 '16 at 17:37
  • Eventhough it's about double, the same counts for float even more. – tynn Feb 27 '16 at 17:38
  • It does answer the question partially, Id still like to know a solution that works in Android though. – zoltish Feb 27 '16 at 17:42
  • This behavior isn't going to change between Android or other platforms. It's just that a float doesn't have the exact precision you need. If you say what exactly you're trying to do with this value and why it has to be exactly what you want, then people can suggest alternatives that don't involve float. – Doug Stevenson Feb 27 '16 at 17:49
  • Have you tried casting to double/float BEFORE making a string of it? I think than converting to string and back (double -> string -> double or float -> string -> float) should work. This should solve the conversation problem. Basically, those rounding "problems" are normal as the link that has already been posted explains. – prom85 Feb 27 '16 at 18:45
  • I understand that, what I dont understand is that I have an app in production using this exact logic with no errors, but in my new project I can see that this actually causes a problem in that values will be incorrect by a small margin. I would still like to keep using floats but surely there must be some way around it; Im thinking that the error comes up in the conversion String -> Float? The string is supplied via an EditText so I cant change that part. – zoltish Feb 27 '16 at 19:09

3 Answers3

2

float and double don't allow to store decimal numbers exactly, because floating point numbers are stored in a binary form (mantissa + exponent) and not as a list of decimal digits, and there is no exact match between the two. You will always lose some precision, even if the system will try to round the values on display to compensate for that.

The maximum precision of a Float is approximately between 6 and 9 decimal digits.

If you want to store a decimal value without losing precision, for example amounts of money, either use BigDecimal or String.

Amounts of money can also be stored as an integer value representing cents, but make sure you use a BigDecimal or some String operations to do the conversion without losing precision.

BladeCoder
  • 12,779
  • 3
  • 59
  • 51
  • My understanding was that a float with such precision (6-9 decimals) is enough to store a number (e.g. 179.9 in this case) without it being changed at all, but I suppose I was wrong on that - so thanks for clarifying, your answer helped me resolve the issues on my end. – zoltish Feb 28 '16 at 10:26
  • It's not about _decimal_ precision, it's about _binary_ precision. 179.9 doesn't land well on binary representation — neither does double, but the latter is close enough to be rounded to 179.9 when formatting for output. p.s. sorry, just realized I essentially repeated the answer – Actine Feb 28 '16 at 12:41
1

Perhaps this you can be useful!!

As has told me a partner, java uses the IEEE754 standard that uses a float to 32 bits. Indeed, if we only have 32 bits, the first bit is sign, eight for the exponent, and the other 23 for the mantissa. We have 179 integer part from 179.9 is 10110011 in binary, which already fill 8 bits of the mantissa, when we calculate the 0.9 decimal in binary multiplying by two and extracting integer part, the first 15 bits are 11100110011, which are those that fit in the mantissa for a float (32 bits).   If now recalculated to decimal, the exponent of 2 positive, 0 or negative, these 15 bits of the decimal part becomes 0.82958984325, far from 0.9.

Regards from Tarragona(Spain) :-)

Santi Fri
  • 96
  • 3
0

You understand why there are these precision errors using floats or even doubles. If you don't care much about very fast performance, use BigDecimals instead of floats or doubles:

http://developer.android.com/intl/es/reference/java/math/BigDecimal.html

Streets Of Boston
  • 12,576
  • 2
  • 25
  • 28