You're running into a key problem here. It's not 'in java, if
does not work'. Of course it does. It's a tool used by millions, and you're a beginner - anytime you think 'The tool must be broken', trust the millions. It isn't.
The problem you're running into is that double
math doesn't do what you think it does.
double A=0, J=1;
.... A == 1.0 ....
Stop. You lost the game. You can't use ==
with doubles unless you really, really, really know what you are doing.
double
does not work that way. doubles are imprecise. Computers are finite constructs. Quick, grab me a piece of paper and write out 1 divided by 3, in decimal, exactly.
Of course, you can't. 0.333333 - it never ends. Computers like binary instead of decimal, and they'd be very slow indeed if they had to emulate decimal (after all, 10 is not a power of 2, so it's not so easy to emulate base-10 math, considering!) - so, double
does two things:
Because computers aren't infinite, just like your piece of paper isn't, doubles silently lop off anything beyond 52 digits (counting both before and after the comma). It's as if you wrote 0.3333 (52 threes), and then handed it back to me and went: Here you go! - you might think that is annoying, but consider how else it should work.
... and because computers like binary, that's 52 binary digits. zeroes and ones, only.
Here's the thing: If I ask you to write 1/5th on a piece of paper, you can do that. 0.2. There. Exact perfection. That's because 1/5th is easy to 'do' in base-10 math. But in base-2 math it is as impossible as 1/3rd is! - a computer CANNOT perfectly represent 0.2 and has to round it.
Imagine I asked you to write that note for 1/3, and then I ask you to write 2 more notes, also with 1/3. You hand me back a note with 0.(52 threes) three times. I then give you those notes right back and ask you to 'please add these numbers up'.
Guess what?
You will mess it up. Because you will give me 0.(52 nines). Because that is indeed the correct sum of all the 3 notes you handed me. So, in this 'write it on a note' system (which is, exactly, what computers do, of course), 1/3 + 1/3 + 1/3
results in a broken result.
This is part of the double
spec - this is really how it works.
As a consequence, doubles have errors, and given that they have errors, you need to think about any double
value as merely 'near' what the actual number is you wanted. Once you get real good at this you'll know exactly how 'far' near can get (if you do a lot of math at very large magnitude, or do loads of ops, that error gets quite large. But, even if you don't, there's some error, even if only a very small one). Point is, given that the number is merely 'near' what you think it is, ==
is broken with doubles. It just doesn't work. That explains for example why A == 2
is never true
. For the same reason first writing down 1/3 three times lopping off any digits after the 52nd one, then adding those up, isn't fully 1.0 either.
Because of this, you have the wrong idea about which of the if
s is being triggered. You get straight integers when an if
triggers that uses %.0f
format, and you get the 5.0
style prints when a %.1f
is being triggered.
%.1f
does what you ask it to: it rounds. So, if your actual number is 0.999999999 (because of that rounding issue), and you toss that at printf("%.1f")
it dutifully prints 1.0, because 1.0 is indeed the closest number to 0.99999999 that you can print with only one digit after the comma.
So how do I fix this?
There are various strategies; your code is not clear about what it is actually trying to do, so I can't advise you on what the right answer is here. But there is a right answer to all scenarios. A small selection of common solutions:
int/long instead
Many systems have a universally agreed upon unit of atomicity. Trying to operate sub-atomic is problematic and doesn't integrate. For example, for euros, the atomic unit is cents. You can ask a bank to transfer 1 cent. You cannot ask a bank to transfer half of a cent.
In such systems its generally a smarter plan to store the atomic unit and not the de facto unit. So, store cents, not euros. If you have a class representing an item stocked in a store and you need to track price, do NOT do double price = 1.23;
for something costing 1 dollar and 23 cents. Instead fo int price = 123;
.
BigDecimal
BD emulates decimal math to whatever precision you want (with the one and only limitation your system's memory). It can perfectly do the math you are trying to do. But note that it comes with a bevy of caveats - it's slow as molasses and hard to use. Also, you still don't solve the division problem. Just like you can't write the exact result of 1 divided by 3 on a piece of paper, if you ask BD to divide 1 by 3 it will throw an exception instead; you have to tell it how to deal with the rounding that it has to do, and once you do that, rounding is back in and we're stick with that 'actually all doubles are more like a nebulous cloud that is merely near what it really should be' thing.
delta
Instead of using ==
, instead you want to know if the result is merely NEAR what you are looking for. So, instead of A == 1.0
, you'd do: Math.abs(A - 1.0) < 0.00001
which checks if A is really really close to 1.0.