0

I have a Java programt o display the limits of primitive integer datatypes which is as follows:

import static java.lang.Math.*;

class HelloWorld {
    public static void main(String[] args) {
        System.out.println((byte)(pow(2,8-1));
        System.out.println((byte)(pow(2,8-1)-1));
        System.out.println((short)(pow(2,16-1)));
        System.out.println((short)(pow(2,16-1)-1));
        System.out.println((int)(pow(2,32-1)));
        System.out.println((int)(pow(2,32-1)-1));
        System.out.println((long)(pow(2,64-1)));
        System.out.println((long)(pow(2,64-1)-1));
    }
}

Its output is as follows:

-128
127
-32768
32767
2147483647
2147483647
9223372036854775807
9223372036854775807

Can you please explain why the output for int and long typecasting?

I was expecting something like

-128
127
-32768
32767
-2147483648
2147483647
-9223372036854775808
9223372036854775807
3
  • Math.pow() returns double, which can’t hold all the bits of long. Use shifts. Commented Nov 19, 2023 at 20:15
  • It can't even hold all the bits of int? Commented Nov 19, 2023 at 20:17
  • 1
    Off-topic: The primitives have wrapper classes. The wrapper classes have static fields for the limits of the primitives. For integer primitives, you can use MAX_VALUE and MIN_VALUE. For example, Short.MIN_VALUE. Commented Nov 19, 2023 at 20:30

3 Answers 3

3

The behaviour is specified in the Java Language Specification 5.1.3 Narrowing Primitive Conversion:

A narrowing conversion of a floating-point number to an integral type T takes two steps:

  1. In the first step, the floating-point number is converted either to a long, if T is long, or to an int, if T is byte, short, char, or int, as follows:

    • [...]

    • [...]

    • [...]

      b. The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.

  2. In the second step:

    • If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T (§5.1.3) of the result of the first step.
  • for (int)(pow(2,32-1)) the value of pow(2,32-1) is too large and that clause applies, i.e. the result is Integer.MAX_VALUE.

  • for (int)(pow(2,32-1)-1) the value of pow(2,32-1)-1 is a double with Integer.MAX_VALUE and the result is Integer.MAX_VALUE.

  • for (long)(pow(2,64-1)) the value of pow(2,64-1) is too large and that clause applies, i.e. the result is Long.MAX_VALUE.

  • for (long)(pow(2,64-1)) the value of pow(2,64-1)-1 is still too large (double doesn't have the precision to subtract 1 from pow(2,64-1) and that expression result in pow(2,64-1)) and that clause applies, i.e. the result is Long.MAX_VALUE.

For the other datatypes (byte and short) the value fits into an int and the second step (description not copied) casts the int value into the target type.

Sign up to request clarification or add additional context in comments.

Comments

2

You are converting to the "Integer" types after you subtract 1. For integers and longs, the floating point value is adjusted for the subtraction of 1 beyond the precision that those types can hold. So the conversion to int or long does not include that particular difference.

Here is an example for the long conversion.

double result1 = Math.pow(2,64-1);
double result2 = Math.pow(2,64-1)-1;

System.out.println(result1);
System.out.println(result2);
long bits = Double.doubleToRawLongBits(result1);
System.out.println(bits);
System.out.println(Long.toBinaryString(bits));
bits = Double.doubleToRawLongBits(result2);
System.out.println(bits);
System.out.println(Long.toBinaryString(bits));

prints

9.223372036854776E18
9.223372036854776E18
4890909195324358656
100001111100000000000000000000000000000000000000000000000000000
4890909195324358656
100001111100000000000000000000000000000000000000000000000000000

Notice the values are the same. The subtraction made no difference due to loss of precision. The is true for ints. This precision difference was such that it did not affect the shorter width types.

Comments

0

"... I have a Java programt o display the limits of primitive integer datatypes ..."

You have a miscalculation.

If x is 2 × 10 n−1 − 1, you should not expect a negative value, and rather, 1 subtracted from the product.
You most-likely meant, −2, or, multiplied by −1.

In other words, the values would be, 128 and 127, and then, 32,768 and 32,767, etc.
And not, the minimum and maximum values, −128 and 127, −32,768 and 32,767, etc.

Nevertheless, the values would not be correct; as, your bounds are met.
Doing so will produce a set of bits that cannot be correctly expressed.
Wikipedia – Signed number representations – Two's complement.
Wikipedia – Integer_overflow.

If the MSb is reserved for a signum, then the printed value would not be a valid representation.
Here is a list of, x + n.

   x       bits
----------------
 124  01111100
 125  01111101
 126  01111110
 127  01111111
-128  10000000
-127  10000001
-126  10000010
-125  10000011
-124  10000100
-123  10000101
-122  10000110
-128
-128
-32768
-32768
2147483647
-2147483648
9223372036854775807
-9223372036854775808

Here is an example, to provide a comparison.

The first row, for each, is the unadulterated, double value; the result of Math#pow.
The second row, is the result after the cast, of this value.
And finally, the third row, is the minimum, and maximum value, from the corresponding wrapper class.

  type              x | min              y | max
--------------------------------------------------
  byte                  127                  128
                        127                 -128
                       -128                  127
 short                32767                32768
                      32767               -32768
                     -32768                32767
   int           2147483647           2147483648
                 2147483647           2147483647
                -2147483648           2147483647
  long  9223372036854776000  9223372036854776000
        9223372036854775807  9223372036854775807
       -9223372036854775808  9223372036854775807

Here is the code.

public static void main(String[] args) {
    Value[] a = {
        new Value(byte.class),
        new Value(short.class),
        new Value(int.class),
        new Value(long.class)
    };
    System.out.printf("%6s %20s %20s%n", "type", "x | min", "y | max");
    System.out.println("-".repeat(50));
    for (Value v : a) {
        System.out.println(v);
        System.out.printf("%48s%n", v.cast());
        System.out.printf("%48s%n", v.bounds());
    }
}

static class Value {
    Class<?> t;
    double x, y;

    Value(Class<?> t) {
        this.t = t;
        int b = 0;
        if (t == byte.class) b = 8;
        else if (t == short.class) b = 16;
        else if (t == int.class) b = 32;
        else if (t == long.class) b = 64;
        x = (y = Math.pow(2, --b)) - 1;
    }

    String cast() {
        if (t == byte.class)
            return "%20s %20s".formatted((byte) x, (byte) y);
        else if (t == short.class)
            return "%20s %20s".formatted((short) x, (short) y);
        else if (t == int.class)
            return "%20s %20s".formatted((int) x, (int) y);
        else
            return "%20s %20s".formatted((long) x, (long) y);
    }

    String bounds() {
        if (t == byte.class)
            return "%20s %20s".formatted(Byte.MIN_VALUE, Byte.MAX_VALUE);
        else if (t == short.class)
            return "%20s %20s".formatted(Short.MIN_VALUE, Short.MAX_VALUE);
        else if (t == int.class)
            return "%20s %20s".formatted(Integer.MIN_VALUE, Integer.MAX_VALUE);
        else
            return "%20s %20s".formatted(Long.MIN_VALUE, Long.MAX_VALUE);
    }

    @Override
    public String toString() {
        return "%6s %20.0f %20.0f".formatted(t.getSimpleName(), x, y);
    }
}

1 Comment

First, why do you say, 2x(10^(n-1))? It is simply 2^(n-1). And I would expect a negative value. The first two examples the op's output are the expected values of -128, 127, -32768, 32767. So (byte)(Math.pow(2,8-1)) or (byte)(128) shows the minimum value for a byte as -128 and (byte)(Math.pow(2,8-1)-1) or (byte)(127) shows the maximum value as 127.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.