> Note, in case someone blindly takes this as advice: This method of expressing it in C doesn't work for multiplication (you could wrap more than once).
Yeah, you're absolutely right.
> I'm not sure you can express an overflow check for multiplication purely in portable C (without library or intrinsic support), actually. Well, I guess you could break the multiplication into checked additions manually, but that's probably not a great idea.
I've never tried to implement this, but couldn't you look at the position of the most significant bit in the multiplicands to guess if the multiply will overflow? You'd have to be okay with false positives I suppose? Naively it would be slow, but if you have a hardware CLZ instruction it could be pretty fast.
I did find this on SO:
x = a * b;
if (a != 0 && x / a != b) {
// overflow handling
}
That makes sense, but of course it would be
HORRENDOUSLY expensive.
If you're willing to not be non-portable, you could just do expanding multiplies and check the high word:
struct exmulres {
unsigned long hi;
unsigned long lo;
};
static inline __attribute__((always_inline)) struct exmulres do_one_expanding_multiply(unsigned long a, unsigned long b)
{
struct exmulres res;
#if defined(__x86_64__)
asm ("movq %0,%%rax; mulq %1; movq %%rdx,%1; movq %%rax,%0"
: "=r" (res.lo), "=r" (res.hi) : "0" (a), "1" (b) : "%rax","%rdx");
#elif defined(__i386__)
asm ("movl %0,%%eax; mull %1; movl %%edx,%1; movl %%eax,%0"
: "=r" (res.lo), "=r" (res.hi) : "0" (a), "1" (b) : "%eax","%edx");
#elif defined(__arm__)
asm ("umull %0,%1,%2,%3"
: "=r" (res.lo), "=r" (res.hi) : "r" (a), "r" (b) :);
#else
#error "No expanding multiply assembly has been written for your architecture"
#endif
return res;
}
It probably wouldn't be very difficult to fill that out for all the CPU architectures Linux supports, which would cover all your bases unless you're doing super embedded stuff.
EDIT: Typo