2

I run the below program and I get an unexpected number in the output.

Enter the number to be checked

9999999999

1410065407 is a prime number

I get a different number in the output. I had entered 9999999999 and I see 1410065407 in the output. Can someone explain how this is coming? Looks like I am exceeding the range of integer domain.

#include<stdio.h>
#include<stdlib.h>
void main()
{

    int n,i;

    printf("Enter the number to be checked\n");

    scanf("%d",&n);

     i=2;

    while(i<n)
    {
        if(n%i==0)
        {
            printf("%d is not a prime number\n", n);
            exit(0);
        }

        i++;
    }

    printf("%d is a prime number\n", n);

}
Zack
  • 2,078
  • 10
  • 33
  • 58
  • 1
    `void main()` should be `int main(void)`. If you learned `void main()` from a book, get your money back and complain to the publisher. – Keith Thompson Jan 18 '15 at 12:26

1 Answers1

3

9,999,999,999 (ten 9s) is to big to fit into your int data type. If you work out the difference between that and 1,410,065,407, you'll see it's an exact power of two (233 to be exact), meaning that it wrapped around while you were scanning it in.

By "wrapped around", I refer to the property of integers to simply wrap around at their maximum value to become something unexpected.

For example, an eight-bit unsigned integer which can hold the values 0..255 will, when you add one to a variable holding 255, become zero (signed values tend to wrap from the largest positive value to the smallest negative value, smallest meaning furthest from zero in this case).

So let's say you're reading in a decimal number where the type has a range of 0..255 and the string representation of the number is 456. The following "code" would be roughly how it works:

def scanNum(s):
    result = 0
    for each character c in s:
        result = result * 10 + value(c)
    return result
  • When processing the 4 character, result is multiplied by ten, 0 * 10 = 0, and you then add four, giving 4.
  • When processing the 5 character, result is multiplied by ten, 4 * 10 = 40, and you then add five, giving 45.
  • When processing the 6 character, result is multiplied by ten, 45 * 10 = 450 but, because you can only represent 0..255, it wraps around, giving you 450 - 256 = 194. And you then add six, giving 200.

You can see there that the difference between what you want and what you get is very much related to the range as well: 456 - 200 = 256.

If you try it with nine 9s (or 999,999,999, keeping in mind the largest number representable with 32-bit two's complement is larger at 2,147,483,647), or use a data type able to hold larger numbers, you'll probably find it's okay:

#include <stdio.h>
#include <stdlib.h>
int main (void) {
    long long n;
    printf("Enter the number to be checked\n");
    scanf("%lld",&n);
    printf("%lld\n", n);
    return 0;
}

I originally thought this was wrong according to the standard since, as per C11 7.21.6.2 The fscanf function /12, it defers to the strtol function:

d Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument. The corresponding argument shall be a pointer to signed integer.

and the strtol function, C11 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions /8 states:

If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any).

But, in actuality, only the format defers to that function. The result for fscanf and its brethren is controlled by C11 7.21.6.2 The fscanf function /10:

If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.

So, the number you get back if it's out of range can be anything and, in fact, given the lack of limitations on the results of undefined behaviour, it could do anything rather than just returning a dodgy result, including formatting your disks and collapsing local space-time into a naked singularity :-)

In this case, it appears to simply wrap the value around as part of the scanning process, the simplest thing for the code to do.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Yes. The difference is 8589934592 which is exact power of 2. But I did not get the term "wrapped around". Do you mean that it goes back to beginning of the integer list once it hits the end limit? – Zack Jan 18 '15 at 05:12
  • @Zack, yes, that's essentially it. I've updated the answer with (substantially) more information. Hope that helps. – paxdiablo Jan 18 '15 at 05:40
  • The behavior is undefined, not just the result. – Keith Thompson Jan 18 '15 at 12:27