1

I'm playing around with https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test

I want to test if a uint64_t is prime or not. For that I need to compute pow(a, b) % n where a <= 37 but b and n can be large uint64_t values. I know I can compute pow(a, b) with the square-and-multiply algorithm doing % n in every step. But that still leaves 2 problematic operations: (x * x) % n and (x * a) % n.

I wonder if there is something better than splitting everything into low and high 32bit and doing long multiplication and long division for the remainder.

PS: don't assume there is a 128bit integer type

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42
  • 1
    No, there's not really anything significantly better if you don't have a 128-bit type. – President James K. Polk May 07 '22 at 19:59
  • How does this question differ from existing ones, e.g. https://stackoverflow.com/questions/10076011/calculate-aa-mod-n-without-overflow, https://stackoverflow.com/questions/28259832/how-can-i-avoid-overflow-in-modular-multiplication, https://stackoverflow.com/questions/13464745/is-there-a-way-to-do-ab-mod-m-without-overflow-for-unsigned-long-long-a-and-b, https://stackoverflow.com/questions/45918104/how-to-do-arithmetic-modulo-another-number-without-overflow – njuffa May 07 '22 at 20:13
  • And another is [Ways to do modulo multiplication with primitive types](https://stackoverflow.com/questions/12168348/ways-to-do-modulo-multiplication-with-primitive-types) although it's tagged C++. – Weather Vane May 07 '22 at 20:40
  • @njuffa it doesn't, I'm just bad at searching. But lets see: 10076011 does 64 shift+addmod for a multiplication, surely we can do better. 28259832 has no correct answer. 13464745 overflows for large n. 45918104 is rust and again 64 shifts + addmod. And Weather Vane's link again does 64 shifts+addmod or worse 2^64 addmods. So yeah, it's a duplicate but there is nothing I would call a solution. – Goswin von Brederlow May 07 '22 at 21:35
  • If you're using gcc on x86_64, you can use inline asm with the `mul` and `div` instructions to store the intermediate 128 bit value in the rdx:rax pair, but that it very target specific. – Chris Dodd May 08 '22 at 01:23
  • @ChrisDodd I tried __int128 on x86_64, which gets the `mul` right but doesn't use the `div`: https://godbolt.org/z/19esKx9x3 – Goswin von Brederlow May 08 '22 at 03:20
  • @PresidentJamesK.Polk https://godbolt.org/z/f4oondfMx sqrmod is with 128-bit type, sqrmod2 is what I think the code should be. But ARM doesn't have __int128 anyway. – Goswin von Brederlow May 08 '22 at 03:41
  • 1
    @GoswinvonBrederlow: yes, you need to use inline asm to use the rdx:rax pair: `asm("mul %2; div %3" : "+a"(a), "+d"(r) : "r"(b), "r"(m));` will compute r = (a*b)%m; (and incidentally clobber a, but its tough to avoid that -- the "clobber" spec is not useful for avoiding that problem as there are two instructions here and the clobber happens in the middle.) – Chris Dodd May 08 '22 at 05:03
  • @Useless 1) this does up to 64 or `1<<64 - 1` additions depending on which answer. Have fun waiting for the later to finish. 2) It overflows for values over `1 << 63`. So no, that doesn't answer the question. – Goswin von Brederlow May 20 '22 at 14:27

0 Answers0