martin
martin

Reputation: 13

INT_MAX does not behave right in an If-Statement

My C-Program performs a "Turmrechnung"(A predefined number("init_num" gets multiplied with a predefined range of numbers(init_num*2*3*4*5*6*7*8*9 in my case, defined by the variable "h"), and after that it is divided by those same numbers and the result should be the initial value of "init_num". My task is to integrate a way to stop the calculation if the value of init_num becomes larger than INT_MAX(from limits.h). But the If-Statement is always true, even if it is not, in case of a larger initial value of "init_num", which results in values bigger than INT_MAX along the way of the calculation.

It only works if i replace "INT_MAX" with a smaller number than INT_MAX like 200000000 in my If-Statement. Why?

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

int main() {
  int init_num = 1000000;
  int h = 9;

  for (int i = 2; i < h+1; ++i)
  {
    if (init_num * i < INT_MAX)
    {
      printf("%10i %s %i\n", init_num, "*", i);
      init_num *= i;
    }
    else
    {
      printf("%s\n","An overflow has occurred!");
      break;
    }
  }
  for (int i = 2; i < h+1; ++i)
  {
    printf("%10i %s %i\n", init_num, ":", i);
    init_num /= i;
  }
  printf("%10i\n", init_num);


}

Upvotes: 0

Views: 676

Answers (4)

ameyCU
ameyCU

Reputation: 16607

if (init_num * i < INT_MAX)

INT_MAX is the maximum value of int , therefore , this condition will never be false or in other words 0 (except when it is equal to INT_MAX).

If you want you can write your condition like this -

if (init_num < INT_MAX/i)

Upvotes: 5

too honest for this site
too honest for this site

Reputation: 12263

The problem is signed integer overflow is undefined behaviour. Concentrate on the "undefined" part and think about it. Briefly: avoid under all circumstances.

To avoid this, you can either use a devinitively wider type which is gauranteed to hold the result of the multiplication and then test:

// ensure the type we use for cast is large enough
_Static_assert(LLONG_MAX > INT_MAX, "LLONG too small.");

if ( (long long)init_num * i < (long long)INT_MAX )

This apparently does not work is you are already at the limit (i.e. use the largest data type). So you have to check in advance:

if ( init_num < (INT_MAX / i) ) {
    init_num *= i;

Although more time-consuming due to the extra division, this is in general the better approach, as it does not require a larger data type (where multiplication might be also more expensive).

Upvotes: 2

alk
alk

Reputation: 70931

init_num * int

results in an int and though cannot grow beyond a maximum possible int (INT_MAX) by defintion.

So provide "room" for calculations "larger" than an int by replacing

if (init_num * i < INT_MAX)

with

if ((long) init_num * i < (long) INT_MAX)

The casting to long leads to a long result.

(The above approach assumes long being wider then int.)

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234695

init_num * i < INT_MAX will only be 0 if int_num * i is INT_MAX. This is not particularly likely. Note that signed integer overflow is undefined behaviour in C, so do be particularly careful here.

You can rewrite your statement to init_num < INT_MAX / i in your particular case. Do note that integer division truncates though.

Upvotes: 2

Related Questions