• Post Reply Bookmark Topic Watch Topic
  • New Topic

Java primitives and boundaries - long... infinity and beyond  RSS feed

 
Stephen Fitzsimmons
Greenhorn
Posts: 4
Java MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm new on here, and also new to posting on a forum.

I've grown up knowing it is good to ask why? And so, I seek some help here after several days of debugging.

Take a Java (Oracle SE 7 JVM) long, primitive or it's wrapper class... assign a variable with the value slightly less than 2^63-1 (the maximum value... i.e. infinity? for a long); keep adding 1. What happens?
You quite quickly get - minimum long, or minus infinity (?).

Infinity is my perspective from a Mathematics degree.

It is not behavior I expected, is there someone who can point me in the direction of an explanation? I am eager to know/learn

Stephen
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephen Fitzsimmons wrote:
Take a Java (Oracle SE 7 JVM) long, primitive or it's wrapper class... assign a variable with the value slightly less than 2^63-1 (the maximum value... i.e. infinity? for a long); keep adding 1. What happens?
You quite quickly get - minimum long, or minus infinity (?).

Infinity is my perspective from a Mathematics degree.

It is not behavior I expected, is there someone who can point me in the direction of an explanation? I am eager to know/learn


Welcome to the ranch !!

Java longs do not support the concept of infinity. If you need to have infinity then you need to use the floating point primitives -- either float or double.

As for the behavior of long, Java supports the Twos Complement format. And when you add one to the maximum value for long, it will roll around to the minimum value for long. This is simply how it works.


And BTW, adding one to Float.POSIVITY_INFINITY will yield an answer of Float.POSITIVE_INFINITY.

Henry
 
fred rosenberger
lowercase baba
Bartender
Posts: 12562
49
Chrome Java Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
here's a simplified example. Let's say an int used only 4 bytes for an int. we use one of the three bits to track the sign of the number...so a '0' in the left-most bit means non-negative (i.e. 0 or greater), and a 1 will mean negative.

So, lets start with zero, and start adding 1 to it..

0000 == 0
0001 == 1
0010 == 2
0011 == 3
0100 == 4
0101 == 5
0110 == 6
0111 == 7

so far, so good. now let's add one more:

1000

hmmm....now we have a problem. the leading '1' tells me the number is negative. Now I need to use "Two's Complement" to figure out what the value really is (you can google that to find out what exactly it is). Basically, you invert all the bits and add 1. So 1000 becomes 0111. Add 1, and you get 1000. that converts to 8. I know from before i need a negative number, so 1000 == -8 (again - I am assuming an int is only 4 bytes).

So the same thing happens with an int. once you get to 0111 1111 1111 1111 1111 1111 1111 1111 and add 1 to it, you 'roll over' from positive numbers into negative numbers, due to the binary addition.
 
Stephen Fitzsimmons
Greenhorn
Posts: 4
Java MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you Henry,

I was using the long primitive to get a big number, for my help in understanding the Fork-Join Framework (what is the biggest prime number less than 2^63-1 was my task; how about I split it into smaller pieces of work...).

I spent a day debugging and ignored the code with long.

I still don't understand why long will wrap over, and it feels a little bit 'dodgy/tricky'.

Something I will watch out for in the future, thanks.

Stephen
 
Stephen Fitzsimmons
Greenhorn
Posts: 4
Java MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you Fred, I understand the binary...

I had wrongly interrupted -2^63 as being minus infinity (in Java primitive long terms) and 2^63-1 as being positive infinity (in Java primitive long terms). The outer limits of Java primitive long

Thanks for your help
 
Henry Wong
author
Sheriff
Posts: 23295
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephen Fitzsimmons wrote:
I still don't understand why long will wrap over, and it feels a little bit 'dodgy/tricky'.


I'm afraid that is how it works. And this has nothing to do with Java. It pretty much works the same way on the majority of languages running on the majority of platforms. Whole number variables have to do something for overflow and underflow, and they all tend to simply wrap around.

If you don't want that, then I suggest you use something bigger than a long -- something like the BigInteger class.

Henry

 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The number formats are what people have agreed on over several decades in computing. They support things which are mathematically incorrect: for example floating‑point arithmetic supports −zero which doesn't actually exist. So you have to make do with a compromise to fit with the constraints of binary arithmetic.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephen Fitzsimmons wrote:I had wrongly interrupted -2^63 as being minus infinity (in Java primitive long terms) and 2^63-1 as being positive infinity (in Java primitive long terms). The outer limits of Java primitive long

It's possibly also worth mentioning that all primitive integers in Java (except char) are signed. The nice thing about 2s-compliment from an internal standpoint is that all addition/subtraction/increment operations work the same way, regardless of sign, so adding 1 to 346 works exactly the same way as adding 1 to -23 - ie, the sign only becomes significant when we want to extract (or display) the resulting value.

If you try something like:you'll notice that the "overflow" looks different. However, what's happening internally is identical (the two primitives are exactly the same size, and if you print out their hex values, you'll see that they're also identical before and after the '++' operation').

HIH

Winston

 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote: . . . all addition/subtraction/increment operations work the same way, regardless of sign, . . .
…and subtracting is the same as adding with the insertion of a carry bit and an XOR gate on every input. So you can do addition and subtraction on the same circuit for the cost of one extra input.
 
Stephen Fitzsimmons
Greenhorn
Posts: 4
Java MyEclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you all for your help, very much appreciated, Stephen.
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:...and if you print out their hex values, you'll see that they're also identical before and after the '++' operation').

Actually, that statement is wrong, since char's "MAX_VALUE" is 16 '1' bits and Short.MAX_VALUE is a 0 followed by 15 '1' bits.
You could, however, see different behaviour with the same values by setting 'c' to Short.MAX_VALUE initially.

Winston
 
Don't get me started about those stupid light bulbs.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!