简体   繁体   中英

Java math.pow() returning wrong answer

I was using the Math.pow() method, and the results I get differ from the result I got from a calculator.

The code I used:

public static int getSum(int a, int b, int c, int d){
    return (int)(d*Math.pow(16.0,6.0)+c*Math.pow(16.0,4.0)+b*Math.pow(16.0,2.0)+a);
}

Printing

 getSum(0,0,128,191)

prints out 2147483647 while google calculator shows 3212836864.

What causes this?

Just to add an explanation to the existing answers (if eg someone wonders why there is no integer overflow):

The spec says under 5.1.3. Narrowing Primitive Conversion

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:

  • If the floating-point number is NaN (§4.2.3), the result of the first step of the conversion is an int or long 0.

  • Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, rounding
    toward zero using IEEE 754 round-toward-zero mode (§4.2.3). Then
    there are two cases:

    • If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V.

    • Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.

  • Otherwise, one of the following two cases must be true:

    • The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of type int or long.

    • 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.

So your double value returned from Math.pow is converted to the largest representable int (ie Integer.MAX_VALUE ).

Note that this part is specific to floating-point number conversions. If your method was eg defined as (note the additional cast to long )

public static int getSum(int a, int b, int c, int d){
    // Casting twice doesn't make sense. It's just here for demonstration.
    return (int)(long)(d*Math.pow(16.0,6.0)+c*Math.pow(16.0,4.0)+b*Math.pow(16.0,2.0)+a);
}

The corresponding part in spec would be

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

And your method would return -1082130422 (aka integer overflow).

Java int has capability of store 2^32 , which if it is signed, half is used by negative numbers. For positive numbers, can store up to 2^31 -1 = 2147483647 . You need a bigger type for this task, use long and it can store up to 9 223 372 036 854 775 807 when it is signed.

2,147,483,647 is the max value an int can hold. If you need larger numbers, like in this case, make your function return a long instead.

The maximum value of an integer in java is 2,147,483,647. You should keep it a double value and Math.ceil() or Math.floor() . You can also cast it into a long value because that is a 64 bit two's compliment integer.

change your code to following: int --> 32 bit (2^32 -1) Easy way to test max length is System.out.println(Integer.MAX_VALUE); ==> 2147483647

public static Long getSum(int a, int b, int c, int d) {
    return (long) (d * Math.pow(16.0, 6.0) + c * Math.pow(16.0, 4.0) + b * Math.pow(16.0, 2.0) + a);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM