2

I was learning computer architecture and decided to experiment with multiplication overflow. An overflow is observed for INT_MAX * INT_MAX, but I am not sure why this gives the product 1 in C/C++.

#include <stdio.h>
#include <limits.h>

int main()
{
    int num = INT_MAX;
    printf("%0x\n", num);       //stdout is 0x7fffffff
    printf("%d\n", num * num);  //stdout is 1
    return 0;
}
user438383
  • 5,716
  • 8
  • 28
  • 43

2 Answers2

6

Note: your code is invalid. Overflowing int * int is undefined behavior, and you should not write such code. The result will be unpredictable. This is a toy example where a compiler chooses to act in a specific way - but generally, the compiler is allowed to do anything with your code. If you want signed overflow to be defined, see for exmaple Is signed overflow still undefined behaviour in gcc when -fwrapv is used? .


For example, let's assume int on your platform has 32-bits and is twos-complement. The result is calculated, and then truncated to 32-bits.

INT_MAX = 0x7fffffff = 2147483647
2147483647 * 2147483647 = 4611686014132420609
4611686014132420609     = 0x3fffffff00000001
32-bits from 0x3fffffff00000001 = 0x00000001 = 1
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 4
    It remains astounding that people write “The result will be unpredictable” when the result is, in fact, predicted. – Eric Postpischil Jan 11 '22 at 12:54
  • 2
    @EricPostpischil it is in a particular implementation. It can be different if you compile using a different compiler or target other hardware. – 0___________ Jan 11 '22 at 12:56
  • @EricPostpischil maybe someone computer's doesn't use twos-complement, but something else? – justANewb stands with Ukraine Jan 11 '22 at 12:58
  • @EricPostpischil It’s unpredictable because it is not guaranteed by the standard. Even if all major vendors might decide to implement the result in the same way right now, there’s nothing stopping them from changing the result for the next patch – Ranoiaetep Jan 11 '22 at 13:01
  • 2
    @Ranoiaetep: “Not guaranteed by the standard” is a different thing from “unpredictable.” – Eric Postpischil Jan 11 '22 at 13:03
  • Most (all?) things in the world are not guaranteed, but many are predictable. – Paul Hankin Jan 11 '22 at 13:04
  • @0___________: Which simply means the prediction would rely on data such as what implementation is used. – Eric Postpischil Jan 11 '22 at 13:04
  • 2
    @EricPostpischil IMO nitpick. Simply wrong wording was used. Most UBs results can be predicted assuming a particular implementation. – 0___________ Jan 11 '22 at 13:14
  • 1
    @0___________ It’s unpredictable from source code alone, and often cannot be reliably predicted even when given more information. – user3840170 Jan 11 '22 at 13:42
  • 2
    @EricPostpischil: It's *explainable*, but I wouldn't have put much money on a *prediction* for what that code would print without trying it, even if I knew it was going to be compiled by a specific compiler like GCC. I didn't really expect GCC to treat `INT_MAX * INT_MAX` as `__builtin_unreachable()` when compiling without `-fwrapv` to make this well-defined, but it certainly could have. And obviously any other compiler could choose differently. `gcc -fsanitize=undefined` is also a conforming C implementation.. although it does print `1` after printing the error. – Peter Cordes Jan 11 '22 at 14:23
0

In different machine, the size of data type "int" may be different. It may be 32 bits or 64 bits which depends on what machine you use. The typical ranges for "int" for 32 bit programs is from -2^31(minimum) to 2^31-1(maximum). The typical ranges for "int" for 64 bit programs is from -2^63(minimum) to 2^63-1(maximum).

If your program is 32 bits, the result is (2^31-1)(2^31-1) = 2^62-2^32+1. Since 2^62-2^32 will only be represented in the upper 32 bits of binary result, the overflow result you will get is 1. Otherwise, if your program is 64 bits, then (2^63-1)(2^63-1) = 2^126-2^64+1 will also lead to same result by truncating the upper 64 bits.

Harry Lu
  • 34
  • 5
  • Your answer is assuming you compiled with `gcc -fwrapv` to make signed-integer overflow well-defined. Otherwise, it's only by the compiler's choice that it happened to wrap / truncate, instead of doing something else. – Peter Cordes Jan 11 '22 at 14:28