473,657 Members | 2,432 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Integer promotion and overflow

Hi,
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
automatically promoted to a long long int?
Nov 14 '05 #1
20 2356
Russell Shaw wrote:
Hi,
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
automatically promoted to a long long int?


lcc-win32 gives the same answer as gcc. The problem is
that the denomitar *is* converted to long long. The
compiler does:

long long int reg=(long long)8000000000 00/(long long)(5000000*n um);

Neither gcc nor lcc-win32 realize that the denominator is an
expression, converting each member to the highest rank type.

Maybe there are compilers that clever, but I would not rely
on it, and would add the cast.

jacob
Nov 14 '05 #2
Russell Shaw wrote:
Hi,
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
automatically promoted to a long long int?


Yes. But the denominator (in the first form) is itself
the product of two factors of type `int', so it is calculated
in `int' arithmetic. The product is too large for an `int',
so it overflows and is chopped down to 32 bits (on your system;
C itself doesn't guarantee what happens). Then the already-
damaged value is promoted to `long long' for the division, but
it's too late: the denominator is much smaller than intended,
so the quotient comes out much too large.

In the second form, the 5000000 term is converted to `long
long' by the cast operator. The denominator is then the product
of a `long long' and an `int', so `num' is converted to `long
long' and the multiplication is carried out in `long long'
arithmetic and does not overflow. Then the division takes
place, and everything comes out as expected.

A better way to write this would be to make the constants
`long long' to begin with:

long long int reg = 800000000000LL / (5000000LL * num);

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 14 '05 #3
On Sun, 02 Jan 2005 17:26:27 +0100, jacob navia
<ja***@jacob.re mcomp.fr> wrote:
lcc-win32 gives the same answer as gcc. The problem is
that the denomitar *is* converted to long long. The
compiler does:

long long int reg=(long long)8000000000 00/(long long)(5000000*n um);

Neither gcc nor lcc-win32 realize that the denominator is an
expression, converting each member to the highest rank type.
Nor should they, C is specified such that conversions occur only when
they are forced because the types are dissimilar (or when forced with a
cast). For instance:

long long denom = 5000000 * num;

will give the same overflow, because it is specified that 5000000*num is
calculated and only then converted to a long long.
Maybe there are compilers that clever, but I would not rely
on it, and would add the cast.


It would not be 'clever', it would be against the standard. There are
other /languages/ which have the semantics the other way round, so that
expression type is propagated left to right (Algol and Pascal, I
believe, do that), but any C compiler must do the sub-expressions first
and promote the types only when it is necessary because the other
operand is a higher type.

Chris C
Nov 14 '05 #4
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
automatically 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
subexpressions, 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
multiplication 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)8000000000 00, 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
sufficiently clever compiler could let the context affect the
evaluation of (5000000*num), so the whole expression yields a
mathematically 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
evaluation. 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) ;

On the other hand, the cast uses the type name explicitly, so it might
be considered clearer.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #5
Chris Croughton <ch***@keristor .net> writes:
On Sun, 02 Jan 2005 17:26:27 +0100, jacob navia
<ja***@jacob.re mcomp.fr> wrote:

[...]
Maybe there are compilers that clever, but I would not rely
on it, and would add the cast.


It would not be 'clever', it would be against the standard.

[...]

As I mentioned in another thread, it wouldn't be against the standard
if it affected the visible behavior of the program only when it
invokes undefined behavior. But such "cleverness " would not be a good
idea, since it would tend to mask errors.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #6
Keith Thompson <ks***@mib.or g> writes:
Chris Croughton <ch***@keristor .net> writes:
On Sun, 02 Jan 2005 17:26:27 +0100, jacob navia
<ja***@jacob.re mcomp.fr> wrote:

[...]
Maybe there are compilers that clever, but I would not rely
on it, and would add the cast.


It would not be 'clever', it would be against the standard.

[...]

As I mentioned in another thread, it wouldn't be against the standard
if it affected the visible behavior of the program only when it
invokes undefined behavior. But such "cleverness " would not be a good
idea, since it would tend to mask errors.


Sorry, I meant to say "As I mentioned elsewhere in this thread ...".

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #7
On Sun, 02 Jan 2005 23:03:44 GMT, Keith Thompson <ks***@mib.or g> wrote
in comp.lang.c:
Chris Croughton <ch***@keristor .net> writes:
On Sun, 02 Jan 2005 17:26:27 +0100, jacob navia
<ja***@jacob.re mcomp.fr> wrote:

[...]
Maybe there are compilers that clever, but I would not rely
on it, and would add the cast.


It would not be 'clever', it would be against the standard.

[...]

As I mentioned in another thread, it wouldn't be against the standard
if it affected the visible behavior of the program only when it
invokes undefined behavior. But such "cleverness " would not be a good
idea, since it would tend to mask errors.


True. But if either of the operands in the calculation of the
denominator were unsigned, such 'early promotion' would be
non-conforming.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #8
Neo

"Keith Thompson" <ks***@mib.or g> wrote in message
news:ln******** ****@nuthaus.mi b.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
automatically 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
subexpressions, 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
multiplication 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)8000000000 00, 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
sufficiently clever compiler could let the context affect the
evaluation of (5000000*num), so the whole expression yields a
mathematically 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
evaluation. 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??????

Thanks n Regards
-Neo

On the other hand, the cast uses the type name explicitly, so it might
be considered clearer.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org
<http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*>
<http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Nov 14 '05 #9


Neo wrote:
"Keith Thompson" <ks***@mib.or g> wrote in message
news:ln******** ****@nuthaus.mi b.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
automaticall y 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
subexpression s, 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
multiplicatio n 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)80000000 0000, 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
evaluation of (5000000*num), so the whole expression yields a
mathematicall y 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
evaluation. 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??????


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.
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

112
4355
by: Carsten Hansen | last post by:
Suppose I'm using an implementation where an int is 16 bits. In the program below, what function is called in the first case, and what is called in the second case? Also, if there is a difference between C89 and C99, I would like to know. I have tried with different compilers, and I see some differences. Before I file a bug report with my C vendor, I would like to know what the correct behavior is. struct S
16
5117
by: TTroy | last post by:
Hello, I'm relatively new to C and have gone through more than 4 books on it. None mentioned anything about integral promotion, arithmetic conversion, value preserving and unsigned preserving. And K&R2 mentions "signed extension" everywhere. Reading some old clc posts, I've beginning to realize that these books are over-generalizing the topic. I am just wondering what the difference between the following pairs of terms are: 1)...
3
1959
by: shmartonak | last post by:
I have the following program. Under linux I've compiled it with gcc and in DOS I've compiled it with TURBOC 2.01. I get different outputs when I run it. /* start of program */ #include <stdio.h> int main() { unsigned char u1=200, u2=200; unsigned long l1 = 0;
21
4107
by: Frederick Gotham | last post by:
I set about trying to find a portable way to set the value of UCHAR_MAX. At first, I thought the following would work: #define UCHAR_MAX ~( (unsigned char)0 ) However, it didn't work for me. Could someone please explain to me what's going on? I would have thought that the following happens: (1) The literal, 0, whose type is int, gets converted to an unsigned char.
4
1933
by: spibou | last post by:
On 6.3.1.1 of N1124 we read: If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. A few lines above that we read: The following may be used in an expres-
6
13815
by: sarathy | last post by:
Hi, What is integer promotion? How is it different from arithmetic conversion? Regards, Sarathy
1
3773
by: charles_gero | last post by:
Hi all, I had a question about the topics in the subject and posted to comp.std.c, but feel it may also be appropriate here. Please excuse this crosspost if it is in bad form. I have a question about whether or not I am interpreting a nuance of the standard correctly, and the implications of said nuance. The sections in the C99 standard (and possibly older standards) that I will reference are as follows (typed out hopefully to avoid...
2
1675
by: Sune | last post by:
Hi all, there are several situations where integer promotion is performed in C and I need to confirm my understanding of it. Let's contain the discussion to workstation/server CPUs of 32/64 bits, I'm afraid 8/16 bits CPUs may add details I'm not interested in. Hopefully someone here can help out: - As long as I use function prototypes there will be no argument integer promotions (unless they are variadic)
42
7001
by: thomas.mertes | last post by:
Is it possible to use some C or compiler extension to catch integer overflow? The situation is as follows: I use C as target language for compiled Seed7 programs. For integer computions the C type 'long' is used. That way native C speed can be reached. Now I want to experiment with raising a Seed7 exception (which is emulated with setjmp(), longjmp() in C) for integer
0
8395
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8826
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8503
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7330
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6166
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5632
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4306
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2726
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
1615
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.