Detecting overflow

Tim McDaniel mcdaniel at uicsrd.csrd.uiuc.edu
Sat May 20 05:33:28 AEST 1989


[My earlier article with the same title, <1067 at garcon.cso.uiuc.edu>,
was incomplete.  I intend to cancel it.  Sorry if you see both of
these.]

In article <455 at skye.ed.ac.uk> ken at aiai.UUCP (Ken Johnson) writes:
>Since I posted a C program which detects overflow in int multiplication
>at immense cost in time terms, I received the following solution
>by e-mail:
>
>	if ( b != 0 && (a * b)/b == a) { /* No overflow */ }

As I noted eariler, it doesn't work if overflow on multiply causes a
fatal trap.  (However, if it silently truncates, it's almost correct.
I should have made this a special case in MY immense-cost code.)  By
the way, Ken's code wasn't so bad.  It did have a loop, but it avoided
division, which can be slooooow.

>However, this is not always going to work. Consider the case of
>a = 512 (0x200), b = 64 (0x40). Then in 16-bit arithmetic,

... presumably, 2s-complement, and "*" silently left-truncates on
overflow ...

>	(a * b) = 0x8000 (overflowing)

Yes.  0x8000 == -32768 (where "overflow" means "the result is an
integer, but cannot be represented exactly in the storage provided")

> but 0x8000/0x40 = 0x200

No.  The ANSI C standard requires that -32768/64 == -512.  The
division here (0x8000/0x40 == 0x200) is correct for unsigned, but if
it was unsigned arithmetic, there was no overflow; in unsigned, 0x8000
represents 32768, which is the correct result.  So the test worked in
this case.

>A further example would be 521 * 63 (0x209 * 0x3f).
Same type of result.

>...so I don't think this is guaranteed to work either.

A problem case is actually a = 0x8000 = -32768, b = -1.
        a * b = 0x8000 = -32768
This has overflowed, since the correct answer, 32768, can't be stored
in 16 bits 2s-complement. Then
        -32768 / b = -32768 / -1 = -32768
for the same basic reason.

Here's another, less probable case: suppose that an overflow on "*"
generates INT_MAX (or INT_MIN, depending on the proper sign).  Then
        -1311 * 25 = -32775
This would be reduced to INT_MIN = -32768 (say).
        -32768 / 25 = -1310.72000 = uhhh ....

An ANSI C implementation is permitted to generate either -1310
(truncate) or -1311 (round to -infinity).  If it chooses the latter,
the test fails.

--
"6:20 O Timothy, keep that which is committed to thy trust, avoiding
profane and vain babblings, and oppositions of science falsely so
called: 6:21 Which some professing have erred concerning the faith."

Tim, the Bizarre and Oddly-Dressed Enchanter  |  mcdaniel at uicsrd.csrd.uiuc.edu
            {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
            mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet}



More information about the Comp.lang.c mailing list