Recent

Author Topic: (a * b) mod c with int64  (Read 27733 times)

BeniBela

  • Hero Member
  • *****
  • Posts: 958
    • homepage
(a * b) mod c with int64
« on: June 16, 2012, 05:47:55 pm »
Is there a function to calculate (a*b) mod c, when a,b,c are int64?

The result fits nicely in a int64, but the a*b calculation overflows

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: (a * b) mod c with int64
« Reply #1 on: June 16, 2012, 06:14:15 pm »
Can you use some workaround, like:
var a, b, c: Extended;

Result:=trunc(a*(b/c));

where Result is int64.

Integer part of Extended is ~62bits.

Also, here was some threads about 128-bit integers in past, so try search the forum.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

BeniBela

  • Hero Member
  • *****
  • Posts: 958
    • homepage
Re: (a * b) mod c with int64
« Reply #2 on: June 16, 2012, 07:49:35 pm »
Can you use some workaround, like:
var a, b, c: Extended;

Result:=trunc(a*(b/c));


I need an exact 50-bit remainder, so i think the intermediate result needs at least 100 bit and  extended is too unprecise


Also, here was some threads about 128-bit integers in past, so try search the forum.

I searched before, but didn't find anything

circular

  • Hero Member
  • *****
  • Posts: 4468
    • Personal webpage
Re: (a * b) mod c with int64
« Reply #3 on: June 16, 2012, 07:54:13 pm »
Maybe you can find some bigint library.
Conscience is the debugger of the mind

Laksen

  • Hero Member
  • *****
  • Posts: 802
    • J-Software
Re: (a * b) mod c with int64
« Reply #4 on: June 16, 2012, 07:55:43 pm »
The only way to do that is probably to disable range and overflow detection in that part of the code. Sort of something like this:

Code: [Select]
   {$PUSH}
   {$Q-}
   writeln((a*b) mod c);
   {$POP}

circular

  • Hero Member
  • *****
  • Posts: 4468
    • Personal webpage
Re: (a * b) mod c with int64
« Reply #5 on: June 16, 2012, 08:03:43 pm »
Yes but no, the result will no be correct if a*b is bigger than max int64 value.
Conscience is the debugger of the mind

BeniBela

  • Hero Member
  • *****
  • Posts: 958
    • homepage
Re: (a * b) mod c with int64
« Reply #6 on: June 16, 2012, 08:35:54 pm »
Maybe you can find some bigint library.

I think that is overkill for just one 128 bit multiplication/modulo.


Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: (a * b) mod c with int64
« Reply #7 on: June 16, 2012, 11:25:09 pm »
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12202
  • Debugger - SynEdit - and more
    • wiki
Re: (a * b) mod c with int64
« Reply #8 on: June 16, 2012, 11:33:20 pm »
Bit late, but if I am not mistaken:

Well if you first take the modulo of  "a mod c"

d = a div c
m = a mod c

a = d * c + m
(a*b) =  d*b * c + m*b

To get the modulo of "(a*b) mod c" you can also say you wan the modulo of
   ( d*b*c + m*b ) mod c
since
  d*b*c
is dividable by c (c is a factor), you are looking for
   (m*b ) mod c
and since "m = a mod c", that means you need

  ((a mod c) * b) mod c

of course that can still overflow.

But since the above shows that
   m2 = (a*b) mod c
can be replaced by
  m2 = ((a mod c) * b) mod c

of course, instead of a, we could have replaced b. Lets replace b, the same way in
  m2 = ((a mod c) * b) mod c

and we get
  m = ((a mod c) * (b mod c)) mod c

It can still overflow. But maybe it is enough in your case
« Last Edit: June 16, 2012, 11:35:25 pm by Martin_fr »

BeniBela

  • Hero Member
  • *****
  • Posts: 958
    • homepage
Re: (a * b) mod c with int64
« Reply #9 on: June 16, 2012, 11:53:25 pm »
There are many links in this thread: http://www.lazarus.freepascal.org/index.php/topic,9375.msg45964.html#msg45964

Oh, there it is.

But still, I don't want to use a new library for such a simple division



and we get
  m = ((a mod c) * (b mod c)) mod c

It can still overflow. But maybe it is enough in your case

No, c is around 10**50




Now I have looked in the amd64 instruction manual, and it turned out that a 64 bit processor always calculates multiplication/division with 128 bit, so in assembler it is no problem.

Code: [Select]

//result := (a * b) mod m
function intMulMod64(a_rdi,b_rsi,m_rdx: int64): int64; assembler; nostackframe; inline;
asm
  mov rax, a_rdi
  mov rcx, m_rdx
  mul b_rsi
  div rcx
  mov rax, rdx
end;


But it would be nice to have a platform independent way


[edit]: and is there are way to change the calling convention to have the first parameter in eax and the last one not in edx?
« Last Edit: June 17, 2012, 12:23:41 am by BeniBela »

Laksen

  • Hero Member
  • *****
  • Posts: 802
    • J-Software
Re: (a * b) mod c with int64
« Reply #10 on: June 17, 2012, 01:09:23 am »
But it would be nice to have a platform independent way

Doesn't this work?
Code: [Select]
function intMulMod64(a,b,c: int64): int64;
begin
   {$PUSH}
   {$Q-}
   result := (a*b) mod c;
   {$POP}
end

BeniBela

  • Hero Member
  • *****
  • Posts: 958
    • homepage
Re: (a * b) mod c with int64
« Reply #11 on: June 17, 2012, 01:25:32 am »
But it would be nice to have a platform independent way

Doesn't this work?
Code: [Select]
function intMulMod64(a,b,c: int64): int64;
begin
   {$PUSH}
   {$Q-}
   result := (a*b) mod c;
   {$POP}
end


No, it becomes

Code: [Select]
...
000000000040024C 480fafc2                 imul   %rdx,%rax
0000000000400250 4899                     cqto   
0000000000400252 48f77de8                 idivq  -0x18(%rbp)
...

and cqto kills the register with the higher 64-bit word

circular

  • Hero Member
  • *****
  • Posts: 4468
    • Personal webpage
Re: (a * b) mod c with int64
« Reply #12 on: June 18, 2012, 07:28:13 pm »
Maybe you can find some bigint library.

I think that is overkill for just one 128 bit multiplication/modulo.
Well if there is no other way. You cannot rely on pure asm if you want it to be cross platform.
Conscience is the debugger of the mind

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12715
  • FPC developer.
Re: (a * b) mod c with int64
« Reply #13 on: June 18, 2012, 11:28:28 pm »

Well if there is no other way. You cannot rely on pure asm if you want it to be cross platform.

Stronger even, while (some?) CPUs might support int128 in 64-bit mode, most architectures don't.

KpjComp

  • Hero Member
  • *****
  • Posts: 680
Re: (a * b) mod c with int64
« Reply #14 on: June 19, 2012, 01:29:42 am »
Quote
But it would be nice to have a platform independent way

Is speed important?

As one way would be to roll your own binary multiple / divide without ASM, it would involve a fair bit of Bit Anding and Bit shifting, but it would be possible to code totally in Pascal.  One advantage here is that you could have as many bit's as you wish.   4096bit multiply anyone.  :)

 

TinyPortal © 2005-2018