Re: Integer promotion and overflow
Neo wrote:[color=blue]
> "Michael Mair" <Michael.Mair@i nvalid.invalid> wrote in message
> news:33s645F40i 738U1@individua l.net...
>[color=green]
>>
>>Neo wrote:
>>[color=darkred]
>>>"Keith Thompson" <kst-u@mib.org> wrote in message
>>>news:ln8y7bm pvu.fsf@nuthaus .mib.org...
>>>
>>>
>>>>Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> writes:
>>>>
>>>>
>>>>>I'm using gcc-3.4.3 on a linux pc. The ints and long ints are 32 bits
>>>>>and long long ints are 64 bits.
>>>>>
>>>>>When i have:
>>>>>
>>>>> int num=9600;
>>>>> long long int reg=(long long)8000000000 00/(5000000*num);
>>>>>
>>>>>the denominator overflows and gives an incorrect answer: reg=1059
>>>>>
>>>>>With an extra cast:
>>>>>
>>>>> long long int reg=(long long)8000000000 00/((long long)5000000*nu m);
>>>>>
>>>>>i get: reg=16
>>>>>
>>>>>If the numerator is a long long int, should the denominator be
>>>>>automatica lly promoted to a long long int?
>>>>
>>>>The evaluation of an expression is not affected by the context in
>>>>which it appears. Think of expressions, including their
>>>>subexpressi ons, as being evaluated bottom-up, not top-down.
>>>>
>>>>The right operand of the "/" operator is:
>>>>
>>>> (5000000*num)
>>>>
>>>>Each operand of the "*" is of type int, so it's an int-by-int
>>>>multiplicat ion yielding an int result. (It overflows, which invokes
>>>>undefined behavior, which most likely shows up as discarding the
>>>>high-order bits.) That int result then becomes the right operand of
>>>>the "/" operator. The left operand of the "/" operator is (long
>>>>long)800000 000000, which is of type long long, so the right operand is
>>>>promoted to long long -- but that promotion (to 64 bits) is done
>>>>*after* the 32-bit multiplication.
>>>>
>>>>Since the overflow invokes undefined behavior, I suppose a
>>>>sufficientl y clever compiler could let the context affect the
>>>>evaluatio n of (5000000*num), so the whole expression yields a
>>>>mathematica lly correct result. But such cleverness doesn't really do
>>>>you any favors, it merely masks your error.
>>>>
>>>>(There are languages in which the context of an expression affects its
>>>>evaluatio n. C is not such a language.)
>>>>
>>>>You might prefer to use a suffix on the integer constants rather than
>>>>casting them to long long:
>>>>
>>>> long long int reg=80000000000 0LL/(5000000LL*num) ;
>>>
>>>
>>>Hi Keith,
>>>
>>>I used the following form :
>>>
>>>int num = 9600;
>>>long long int i = (long long)8000000000 00/(5000000LL * num);
>>>printf("%ld\ n", i);
>>>
>>>on my Win XP machine (gcc 3.3.1) gcc flash out the following warning :
>>>longlong.c : In function `main':
>>>longlong.c:7 : warning: integer constant is too large for "long" type
>>>output : 16
>>>
>>>and to more surprise when compiling the same code on Solaris Workstation
>>>with gcc 3.3 warning was the same as above but the result :
>>>output : 0
>>>
>>>WHY IT IS SO??????[/color]
>>
>>RTFmanpage (printf):
>>
>>The length modifier l specifies _long_, not _long_long_.
>>If you want to print a long long, use ll:
>>printf("%lld\ n", i);
>>
>>Depending on the byte representation of the number in memory, we may
>>well arrive at 16 (korrekt) or 0, if erroneously reading only a part
>>of the bytes belonging to the argument.[/color]
>
> Michael, thanks for the correction. It should be obviously "%lld\n".
> But why the warning??? its still there.[/color]
I do not know which is "line 7", so I can only guess.
Probably, you do not invoke gcc in C99 mode -- C89/90 does not
know the type long long.
Please post your complete code or try what the compiler does for
gcc -Wall -O -std=c99 -pedantic
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.
Neo wrote:[color=blue]
> "Michael Mair" <Michael.Mair@i nvalid.invalid> wrote in message
> news:33s645F40i 738U1@individua l.net...
>[color=green]
>>
>>Neo wrote:
>>[color=darkred]
>>>"Keith Thompson" <kst-u@mib.org> wrote in message
>>>news:ln8y7bm pvu.fsf@nuthaus .mib.org...
>>>
>>>
>>>>Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> writes:
>>>>
>>>>
>>>>>I'm using gcc-3.4.3 on a linux pc. The ints and long ints are 32 bits
>>>>>and long long ints are 64 bits.
>>>>>
>>>>>When i have:
>>>>>
>>>>> int num=9600;
>>>>> long long int reg=(long long)8000000000 00/(5000000*num);
>>>>>
>>>>>the denominator overflows and gives an incorrect answer: reg=1059
>>>>>
>>>>>With an extra cast:
>>>>>
>>>>> long long int reg=(long long)8000000000 00/((long long)5000000*nu m);
>>>>>
>>>>>i get: reg=16
>>>>>
>>>>>If the numerator is a long long int, should the denominator be
>>>>>automatica lly promoted to a long long int?
>>>>
>>>>The evaluation of an expression is not affected by the context in
>>>>which it appears. Think of expressions, including their
>>>>subexpressi ons, as being evaluated bottom-up, not top-down.
>>>>
>>>>The right operand of the "/" operator is:
>>>>
>>>> (5000000*num)
>>>>
>>>>Each operand of the "*" is of type int, so it's an int-by-int
>>>>multiplicat ion yielding an int result. (It overflows, which invokes
>>>>undefined behavior, which most likely shows up as discarding the
>>>>high-order bits.) That int result then becomes the right operand of
>>>>the "/" operator. The left operand of the "/" operator is (long
>>>>long)800000 000000, which is of type long long, so the right operand is
>>>>promoted to long long -- but that promotion (to 64 bits) is done
>>>>*after* the 32-bit multiplication.
>>>>
>>>>Since the overflow invokes undefined behavior, I suppose a
>>>>sufficientl y clever compiler could let the context affect the
>>>>evaluatio n of (5000000*num), so the whole expression yields a
>>>>mathematica lly correct result. But such cleverness doesn't really do
>>>>you any favors, it merely masks your error.
>>>>
>>>>(There are languages in which the context of an expression affects its
>>>>evaluatio n. C is not such a language.)
>>>>
>>>>You might prefer to use a suffix on the integer constants rather than
>>>>casting them to long long:
>>>>
>>>> long long int reg=80000000000 0LL/(5000000LL*num) ;
>>>
>>>
>>>Hi Keith,
>>>
>>>I used the following form :
>>>
>>>int num = 9600;
>>>long long int i = (long long)8000000000 00/(5000000LL * num);
>>>printf("%ld\ n", i);
>>>
>>>on my Win XP machine (gcc 3.3.1) gcc flash out the following warning :
>>>longlong.c : In function `main':
>>>longlong.c:7 : warning: integer constant is too large for "long" type
>>>output : 16
>>>
>>>and to more surprise when compiling the same code on Solaris Workstation
>>>with gcc 3.3 warning was the same as above but the result :
>>>output : 0
>>>
>>>WHY IT IS SO??????[/color]
>>
>>RTFmanpage (printf):
>>
>>The length modifier l specifies _long_, not _long_long_.
>>If you want to print a long long, use ll:
>>printf("%lld\ n", i);
>>
>>Depending on the byte representation of the number in memory, we may
>>well arrive at 16 (korrekt) or 0, if erroneously reading only a part
>>of the bytes belonging to the argument.[/color]
>
> Michael, thanks for the correction. It should be obviously "%lld\n".
> But why the warning??? its still there.[/color]
I do not know which is "line 7", so I can only guess.
Probably, you do not invoke gcc in C99 mode -- C89/90 does not
know the type long long.
Please post your complete code or try what the compiler does for
gcc -Wall -O -std=c99 -pedantic
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.
Comment