9

I need to calculate

result = (dividend * factor) / divisor

where

dividend: full range of int64_t values
factor: either a full range of uint32_t values or as a special case 2^32
divisor: positive values of int64_t
result: is guaranteed to fit in a int32_t

I need to do this in plain C/C++ without any libraries on a microcontroller. The compiler supports int64_t and uint64_t types; most likely no hardware implementation for multiply or divide. Currently I have a workaround for the uint32_t factor but I need a solution for factor 2^32.

11
  • What architecture are you going to run this on? Commented Dec 28, 2015 at 18:38
  • What type is factor. int64_t? Commented Dec 28, 2015 at 18:39
  • 1
    If you "have a workaround" for 32-bit factor, for 2**32 can you tolerate using 2**31 and either doubling the dividend or halving the divisor? Commented Dec 28, 2015 at 19:06
  • 3
    (Please share your workaround for the uint32_t factor.) Commented Dec 28, 2015 at 19:40
  • 1
    result = (int32_t)((dividend / divisor) * factor + ((dividend % divisor) * factor) / divisor);? (Can the OP please include the assembly generated for the existing work-around?) Commented Dec 28, 2015 at 22:29

1 Answer 1

1

OP: "Currently I have a workaround for the uint32_t factor"

The factor == 2^32 is a corner case and is all that is needed to be solved here as OP's "workaround" can handle factors [0 ... 2^32-1].

If the dividend can be doubled without overflow, simple use factor == 2^31 with a doubled dividend.

If the divisor is even, use factor == 2^31 with a halved divisor. @Weather Vane

Else the dividend is large. Recall that the quotient is in [-2^31 ... 2^31-1] range. In general, the product of the large dividend and factor == 2^32 dividend by the divisor will out of the int32_t range, so those out-of-range combinations are not of concern as "result: is guaranteed to fit in a int32_t".

The acceptable edge conditions occur with a final quotient near the edge of the int32_t range.

 pow(2,63) == 9223372036854775808
 pow(2,62) == 4611686018427387904
 pow(2,32) == 4294967296
 pow(2,31) == 2147483648

 Smallest Dividends   Factor      Largest Divisors       Smallest Quotients 
-4611686018427387905  4294967296  -9223372036854775807   2147483648.00+
-4611686018427387905  4294967296   9223372036854775807  -2147483648.00+  OK
 4611686018427387904  4294967296  -9223372036854775807  -2147483648.00+  OK
 4611686018427387904  4294967296   9223372036854775807   2147483648.00+

After testing, dividend and divisor, the only representable answer in INT32_MIN.


Sample Code:

int32_t muldiv64(int64_t dividend, uint64_t factor, int64_t divisor) {
  if (factor >= 0x100000000) {
    assert(factor == 0x100000000);
    factor /= 2;
    if (dividend >= INT64_MIN/2 && dividend <= INT64_MAX/2) {
      dividend *= 2;
    } else if (divisor %2 == 0) {
      divisor /= 2;
    } else {
      return INT32_MIN;
    }
  }
  return  workaround_for_the_uint32_t_factor(dividend, factor, divisor);
}

The original problem is to detect this edge condition and how to handle it.. The workaround_for_the_uint32_t_factor() may not have been coded yet, thus it was not posted.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.