Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In what range does incrementing and decrementing Java doubles work?

Tags:

java

double

limit

I'm writing a Java class that tracks a fractional number, but needs to be able to increment and decrement it. Using a double for this number seems to work fine for small values, but I'm trying to figure out its limits.

I was thinking that one way of determining it might be to run a program that incremented a double and a long until they were no longer equal. However this takes too long to run.

double x = 0;
long y = 0;
while ((long)x == y)
{
    x++;
    y++;
}
System.out.println("X: " + x);
System.out.println("Y: " + y);

What are double's limits where you can no longer increment a value and actually add one to it? I'd think that decrementing a double would have a similar problem with negative numbers at some point.

like image 805
Stephen Ostermiller Avatar asked Apr 22 '26 04:04

Stephen Ostermiller


1 Answers

You essentially want the largest positive number with the ulp of 1. This is the largest positive number where adding 1 will still change it.

From the Wikipedia page we can see that ulp for a normal number x between 2^e and 2^(e+1) is calculated as 2^(e-p+1), where p is the precision (number of bits in the mantissa).

enter image description here

For double, p is 53, so we want to find a value of e such that 2^(e-52) is 1. Obviously, e should be 52.

Then we can construct a double with the exponent 52, and the largest mantissa possible. You can write it as a long:

Double.longBitsToDouble(
        0x433FFFFFFFFFFFFFL
);

Due to how doubles are represented, we need to write "433" (1075 in decimal). This is the number from which subtracting 1023 will give you the desired exponent of 52.

This is the largest number where adding 1 will still change the number. nextUp of this number will remain unchanged when you add 1:

double x = Double.longBitsToDouble(
        0x433FFFFFFFFFFFFFL
);
double y = Math.nextUp(x);
System.out.println(x + 1 == x); // false
System.out.println(y + 1 == y); // true

Another way of writing x is 0x1p53 - 1 (credits to Holger in the comments), i.e. one less than the number with an exponent of 53.


The situation is symmetric for decrementing:

double x = -Double.longBitsToDouble(
        0x433FFFFFFFFFFFFFL
);
double y = Math.nextDown(x);
System.out.println(x - 1 == x); // false
System.out.println(y - 1 == y); // true
like image 96
Sweeper Avatar answered Apr 24 '26 19:04

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!