If you're following along the Free Java Online Course,
Tricky Java Number Stuff is good topic to hit when we've covered primitives
and operators. One lesson I tell everyone when they are learning about computers is
"Computers do what you tell them to, not what you want them to".
Too often you'll say I know what will happen,
and you'll be surprised by the outcome. Once you think about it a bit more,
you'll realize your mistake and say "Oh yeah".
Here's a few "Oh yeah" moments for you.
If you're new to programming in Java, and this video shocks you,
There are programmers out there who have many years of experience,
and this some of this video will still blow their mind!
So let's start!
Every programmer
from the day they start to learn programming, you're taught "don't divide by zero".
It's bad. Computers die. Don't do it! Let's do it!
What happens when we divide 1 by 0? So what happens when we divide
1 by 0? What will this code do? Boom!
Java dies. ArithmeticException: / by zero.
I guess that was expected.
Wanna do it again? Let's try with floating-point numbers!
What does this print? If you’re not sure what changed,
I changed the integer literals to double literals.
Huh. It prints "infinity".
No error. So can you verify if an answer is infinity?
If you tested the value against POSITIVE_INFINITY,
you'd get... well what would you get?
Well let's run it. And the numbers are equal,
because 1 divided by 0 does equal infinity. What about
0 divided by 0? What would that print? Well
that doesn't really make sense, and Java agrees.
Not a number (NaN). Now what happens if we compared
0 divided by 0 and 0 divided by 0?
Are these two equal? Nope.
The numbers are not equal. You can't compare
not a numbers (NaN). They always returns false when using equality operator.
If need to check for not a numbers (NaNs) you need to use the Float method
isNaN(). Let's play with floating point numbers more.
Let's see if you know what minimum values are.
What happens in this code? What gets printed?
Your first thought might be, well this is a trick question so it has to be the min
value.
Or is the trick that it's zero? Many programmers outsmart themself with this
question.
Negative numbers are smaller than 0, so
this code prints -2.147483648E9
Not all that surprising,
but some people are tripped up on it. Let's double down with Doubles!
What does this print? Again if you're not sure what I changed, I'm now using the Double class
for the minimum value.
We already saw that. This is just with Doubles.
So we're going to double down and say that it's some bigger negative number, right?
And it prints 0.
Min values for Doubles are the smallest positive minimum value you can represent
in a double. The smallest without actually being 0.
The minimum value for Integer is negative, and the minimum value for
Double
and Floats is positive. If you guessed 0,
gold star!
What if you wanted to the store 1? We can define our byte. This is the bit pattern for
1.
How do we define -1 using bits?
Well since it's a 2's compliment number, let's try that.
-1 as bits is all one's.
And it won't even compile. So how do you represent
-1? Just add a minus sign.
That's it. Literals are literals, not
2's complement numbers. So you need to use the sign operator
with the binary literals to define negative numbers.
Alright. If I
gave you a byte, are the three statements equal?
That is after we declare b to be equal to 0,
do the following three statements do the same thing?
Nope. In the first two cases
b will evaluate to 2 after the execution. The first two
insert a cast back to a byte when you compile. And the third?
Won't even compile. The third won't compile since
1 is an integer literal. The one causes a widening
conversion and the addition returns an integer not a byte.
Well what happens when you add two bytes?
Neither an integer. Like the literal before this won't even compile.
Addition returns integers. It doesn't matter if it's a byte, or even if your answer
fits into a byte. Oh. Well what happens when you use the unary operator
and add something that clearly will not fit into a byte? Let's go do it.
Okay, will it compile? Will it even run?
Yes it compiles and runs.
It prints out -122?!? You can even add something that's clearly not
a byte like 50,000. That prints
80. The result you're getting is the number that is modulo congruent
to the number the you're trying to calculate. If that surprises you,
you may want to take a look at the "How computers store numbers"
lessons on DeegeU.com.
OK. Last one for now. Let's play with the
Integer class and autoboxing. If we have an Integer
and set it to 1, then create another Integer and set that to 1,
are the two Integers equal using the equality operator?
Remember, the Integers are classes and the equality operator will test to see
if the two variable references reference the same
Integer instance. This is not looking at the value.
And they're equal! Did that surprise you?
That means that a and b point to the same
instance. Okay let's do the exact same thing, but in this case
with 128. The only change here is
a and b now equal 128. And they're not
equal. These do not point to the same Integer
instance. If we use 1 and 1, they are equal.
If we use 128 and 128, they're not equal.
The reason is Java doesn't like creating objects it
doesn't need to. For numbers less than 127,
Java creates a cache o Integer instances.
Anything within the range of a byte. That's -128 to 127.
You can verify this in the valueOf() method in the Integer class.
So
We've seen that we can divide by zero using floating-point numbers,
we can not compare not a numbers (NaNs), integers and doubles have minimum values
that different sign,
literals are literals, it
sucks doing math with bytes, and number classes are not always created when you
create one.
Know of any other crazy number behavior in core Java?
Let me know in the comments below. Till next time.