Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you calculate a factor if you have the other factor and the product with overflows?

Tags:

c++

c

x86

dword

a * x = b

I have a seemingly rather complicated multiplication / imul problem: if I have a and I have b, how can I calculate x if they're all 32-bit dwords (e.g. 0-1 = FFFFFFFF, FFFFFFFF+1 = 0)? For example:

0xcb9102df * x = 0x4d243a5d

In that case, x is 0x1908c643. I found a similar question but the premises were different and I'm hoping there's a simpler solution than those given.

like image 699
Lupe Avatar asked Apr 11 '16 00:04

Lupe


1 Answers

Numbers have a modular multiplicative inverse modulo a power of two precisely iff they are odd. Everything else is a bit-shifted odd number (even zero, which might be anything, with all bits shifted out). So there are a couple of cases:

Given a * x = b

  • tzcnt(a) > tzcnt(b) no solution
  • tzcnt(a) <= tzcnt(b) solvable, with 2tzcnt(a) solutions

The second case has a special case with 1 solution, for odd a, namely x = inverse(a) * b

More generally, x = inverse(a >> tzcnt(a)) * (b >> tzcnt(a)) is a solution, because you write a as (a >> tzcnt(a)) * (1 << tzcnt(a)), so we cancel the left factor with its inverse, we leave the right factor as part of the result (cannot be cancelled anyway) and then multiply by what remains to get it up to b. Still only works in the second case, obviously. If you wanted, you could enumerate all solutions by filling in all possibilities for the top tzcnt(a) bits.

The only thing that remains is getting the inverse, you've probably seen it in the other answer, whatever it was, but for completeness you can compute it as follows: (not tested)

; input x
dword y = (x * x) + x - 1;
dword t = y * x;
y *= 2 - t;
t = y * x;
y *= 2 - t;
t = y * x;
y *= 2 - t;
; result y
like image 174
harold Avatar answered Sep 23 '22 02:09

harold