# Overflow and range checking for mul/div

Show 80 post(s) from this thread on one page
Page 1 of 2 12 Last
• 06-04-2008
Elysia
Overflow and range checking for mul/div
I'm currently trying to implement range checking and overflow/underflow checking for multiplication and division, but... it's more complicated than addition and subtraction.

My current way is somewhat messy.
If we assume that a custom range is set to:
Min: 0
Max: 100 000

And we have the number 15 and want to multiply by 10 000, we would get 150 000, which is above > 100 000 and thus would result in overflow and a number that is 50 000 afterwards.
The problem is that checking if Result > upper bound is not always feasible, since for example, if the upper bound is the maximum range for a 64-bit integer. The result would be an overflow, so I can't do it that way. This suggests another way.
Using mathematics, I came up with:

Min: 0
Max: 100 000
Base: 15
Multiply By: 10 000

100 000 / 15 = 6666
(Divide upper range with the current number stored (m_Data). Basically see how many times we can multiply this number with until we hit the upper bound. Also truncate to integer.)

6666 >= 10 000
(Check if the number we can multiply with is larger or equal to the amount we want to multiply with. If the result is true, then we will have no overflow.)
If true, no overflow

(If no)
10 000 - 6666 = 3334
(Get the remaining amount to multiply with that would exceed the upper bound.)
15 * 6666 = 99 990
(Multiply the current number with the maximum number we can multiply by that does not exceed the upper bound.)
100 000 - 99 990 = 10
(Calculate the difference between the maximum number and the result of the current operation. This is to take into account the lost digits due to the integer truncation.)
15 * 3334 = 50 010
(Multiply the number by the amount that exceeded the upper bound.)
50 010 - 10 = 50 000
(Subtract the difference due to the integer truncation.)

Since floating point numbers aren't reliable, I chose to do integer math instead.
But this is a pretty long way of doing it and it doesn't even take into account negative numbers on either side!
There must a better way to do it (big precision library to handle bigger numbers?) or a way to modify the algorithm or whatever to call it to work with negative numbers.

This is only for multiplication, as well. Then I'd have to implement a similar method for division. So I'm looking for insight into the matter.
Anything that might help would be nice.
• 06-04-2008
phantomotap
Um... I didn't give this a lot of thought, but I don't think it will work. If the values more than double the maximum this will not work.

Also, the entire operation looks like an attempt to reproduce '%' without using '%'.

Soma

Code:

```unsigned long maximum(100000); unsigned long value(15); unsigned long multiple(10000); unsigned long overflow(multiple - (maximum / value)); unsigned long remainder(maximum % value); unsigned long result((overflow * value) - remainder);```
• 06-04-2008
cpjust
I'm not too familiar with assembly, but isn't there an assembly instruction (at least on x86) that can tell you if there was an overflow in the previous operation?
If so, that would help with the case of integer overflow.
• 06-04-2008
Sander
- Will your "custom ranges" always be within the range of an available integer type?
- Do you want to stick to integers?

--
Computer Programming: An Introduction for the Scientifically Inclined
• 06-04-2008
matsp
Quote:

Originally Posted by cpjust
I'm not too familiar with assembly, but isn't there an assembly instruction (at least on x86) that can tell you if there was an overflow in the previous operation?
If so, that would help with the case of integer overflow.

Sure, but that would require writing the math in assembler too, because the overflow flag is transient - it doesn't remain set if you do any other math operation (e.g. the compiler does some math to calculate the address of, say, a member variable). So you need to pair the calculation itself with a jump on overflow (or interrupt on overflow, but that's a bit excessive, I think).

And of course, that only applies if you overflow the actual hardware value. So if the calculation is artificially bounded (e.g 100000), then overflow flag in the processor won't work.

--
Mats
• 06-04-2008
Elysia
Quote:

Originally Posted by phantomotap
Also, the entire operation looks like an attempt to reproduce '&#37;' without using '%'.

Quote:

Originally Posted by cpjust
I'm not too familiar with assembly, but isn't there an assembly instruction (at least on x86) that can tell you if there was an overflow in the previous operation?
If so, that would help with the case of integer overflow.

Yes, as mats explained, it doesn't seem very feasible.

Quote:

Originally Posted by Sander
- Will your "custom ranges" always be within the range of an available integer type?
- Do you want to stick to integers?

Currently I'm sticking with integers, native built-in types.
Although, however, since the class is templated, it is actually possible to supply a custom class as a wrapper for custom integers later.
• 06-05-2008
Sander
I don't think it will be easy to work out the specifications for your new type. I assume you're trying to make some kind of "wrapper" allowing you to do ordinary math operations, but keep the result within a (custom) range and set an overflow flag upon wrapping around.

But suppose you set a custom range of 10 .. 20 and add 7 to 15. The result would be 22, which is over the specified maximum so you set the overflow flag, but then what do you set the result to? You can't set it to 2 because that would also be out of the range, and yet no other choice makes sense...
• 06-05-2008
Elysia
Perhaps, but it's better to wrap twice in such case.
• 06-05-2008
cpjust
Quote:

Originally Posted by Sander
I don't think it will be easy to work out the specifications for your new type. I assume you're trying to make some kind of "wrapper" allowing you to do ordinary math operations, but keep the result within a (custom) range and set an overflow flag upon wrapping around.

But suppose you set a custom range of 10 .. 20 and add 7 to 15. The result would be 22, which is over the specified maximum so you set the overflow flag, but then what do you set the result to? You can't set it to 2 because that would also be out of the range, and yet no other choice makes sense...

Wouldn't it wrap around to 12 in that case?
Anyways, if it overflowed, what difference does it make what you set the value to? The result is out of range.
What about throwing an exception on underflow/overflow?
• 06-05-2008
Elysia
Quote:

Originally Posted by cpjust
What about throwing an exception on underflow/overflow?

That's part of the design too, but I decided to allow you to not throw an exception because exceptions are incredibly slow.
Traits struct:

Code:

```template<typename T> struct IntTraits {         const static bool bUnderflow = true;         const static bool bOverflow = true;         const static bool bThrow = false;         const static bool bLogging = false;         const static bool bShiftDataLost = true;         const static bool bAssert = true;         const static T RangeUpper = 2; //boost::integer_traits<T>::const_max;         const static T RangeLower = 1; //boost::integer_traits<T>::const_min; };```
• 06-05-2008
whiteflags
Quotients don't overflow. If the quotient would wrap around, then a and b should have wrapped around, meaning that you are dividing numerals in a type too small. I suppose you could downcast the result to a smaller type too, but that would be a construction exception, since you can't fit the number into the range without truncating bits.
• 06-05-2008
grumpy
The basic principles you need to remember come down to the causes of overflow and underflow (assuming an underflow is producing a result less than allowed minimum, and overflow is producing a value that wraps or exceeds allowed maximum).

Assume we have two positive (non-zero) values a and b that are constrained to in the range [minimum, maximum]. Overflow on multiplication will only occur if a*b exceeds the maximum allowed value. i.e. a*b > maximum. That can only occur if both values are greater than 1 (multiplying a value in range by a value < 1 cannot give overflow). So a test for overflow is "if (a > 1 && b > 1 && a *b > maximum)" which can be recast as "if (a > 1 && b > 1 && a > maximum/b)" [this can be simplified, obviously, if minimum exceeds 1].

It is possible to formulate similar tests for underflow on multiplication or overflow/underflow on division. I'll leave those as an exercise.

The key is remembering basic mathematical relationships between inequality relationships. If a, b and c are all positive, then a test "if (a*b > c)" is the same as "if (a > c/b)".
• 06-06-2008
iMalc
c = a * b overflows if c / b != a

Integer division cannot produce overflow. Divide by zero is a special case you already have to handle.
• 06-06-2008
grumpy
Quote:

Originally Posted by iMalc
c = a * b overflows if c / b != a

Integer division cannot produce overflow. Divide by zero is a special case you already have to handle.

For basic integral types in C/C++ that is true. It is not true for all integral types (eg other languages allow specification of integral types with values in specified ranges, and such things can be implemented as a class in C++).

If your acceptable range is [-10,-1] then overflow on division is possible. -10/-1 equals 10 which exceeds any value in the accepted range.
• 06-06-2008
Elysia
Quote:

Originally Posted by grumpy
It is possible to formulate similar tests for underflow on multiplication or overflow/underflow on division. I'll leave those as an exercise.

The key is remembering basic mathematical relationships between inequality relationships. If a, b and c are all positive, then a test "if (a*b > c)" is the same as "if (a > c/b)".

The problem with
(a * b > c) == (a > c / b)
That it would only work when the range was the maximum for the integer can hold. If I specify a custom range, that test will be useless.
Show 80 post(s) from this thread on one page
Page 1 of 2 12 Last