Not sure if this helps. I would say bitshifting/masking would be a good approach, but your values are too big, but you can do a slower bitshift /mask with #:
a =: #:<:2^48x b=: 23456789123451x*2112345x bigMod =: #.@:|.@:*./@:([ ,: |.@:#:@:]) a bigMod b timespacex 'a bigMod b' 0.000168 109952 -------------------------------------------- On Mon, 5/8/17, 'Mike Day' via Programming <[email protected]> wrote: Subject: [Jprogramming] Precision of modular multiplication of quite large numbers To: [email protected] Date: Monday, May 8, 2017, 5:43 PM Using extended integers is the obvious answer to this, but I'd like to avoid the memory and performance hits. I'm using J806 (with avx if that's relevant) under Windows 10 on a 64-bit machine. I wish to multiply integers modulo 2^48 . We can assume that inputs are < 2^48. Set M =: 2 <.@^ 48 The "standard" way to do this is to define, say, by =: M&|@* For comparison, define a verb to multiply under x:, byx =: by &. x: " 0 So consider these verbs applied to inputs whose product before taking its modulus exceeds 2^64, such as 2112345 23456789123451: <.2^.2112345 23456789123451 21 44 For these I get: (;datatype) 2112345 <.@(by,byx) 23456789123451 +-------------------------------+-------+ |228120645902336 228120645905603|integer| +-------------------------------+-------+ The type of the result of by on its own on these args is floating. I was surprised when I spotted this. I had assumed that M&|@v forced the operation to preserve integer type! Anyway, byx is slower and uses more space than by: ts' $a by/ b' [ a =. 100#2112345 [ b =. 100#23456789123451 0.0148233 275328 ts' $a byx/ b' [ a =. 100#2112345 [ b =. 100#23456789123451 0.085672 353792 I attempted to get round this by writing my own verb, highprod. It splits the arguments into low and high parts. In non-J notation, x = a + b%:M, y = c + d%:M: xy == M| (ac + M|(ad + bc)%:M) + O(M) rtM =: 2 <.@^ 24 highprod =: 3 : 0 " 0 : a =. rtM | x [ b =. _24 (33 b.) M|x =. <.x c =. rtM | y [ d =. _24 (33 b.) M|y =. <.y (a<.@*c) (M| <.@ +) 24 (33 b.) mask (17 b.) +/ (a,b)<.@*d,c ) (;datatype) 2112345 <.@(highprod,byx) 23456789123451 +-------------------------------+-------+ |228120645905603 228120645905603|integer| +-------------------------------+-------+ But it's even worse in terms of speed though using less space than byx: ts' $a highprod/ b' [ a =. 100#2112345 [ b =. 100#23456789123451 0.148359 279296 No doubt "highprod" could be tweaked to make it somewhat faster, possibly with a tacit form, but I doubt it would ever be as fast as "by" I suppose byx or the like could be applied conditionally, testing the size of the inputs, though the test would consume some time. Is there a better way to do modulus multiply with largish arguments? Thanks for any ideas, Mike --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
