From e81afc21e1665937027711a1924906d1bea6ef7b Mon Sep 17 00:00:00 2001 From: Markus Pfeiffer Date: Fri, 24 Nov 2017 23:44:29 +0000 Subject: [PATCH 1/2] Introduce kernel-level LCM_INT This is done using the gmp function mpz_lcm. --- hpcgap/lib/integer.gi | 8 +--- lib/integer.gi | 8 +--- src/integer.c | 86 +++++++++++++++++++++++++++++++------------ 3 files changed, 65 insertions(+), 37 deletions(-) diff --git a/hpcgap/lib/integer.gi b/hpcgap/lib/integer.gi index b4bc6c316c..ae854359e4 100644 --- a/hpcgap/lib/integer.gi +++ b/hpcgap/lib/integer.gi @@ -1105,13 +1105,7 @@ InstallGlobalFunction( IsPrimePowerInt, ## #F LcmInt( , ) . . . . . . . . . . least common multiple of integers ## -InstallGlobalFunction(LcmInt,function ( n, m ) - if m = 0 and n = 0 then - return 0; - else - return AbsInt( m / GcdInt( m, n ) * n ); - fi; -end); +InstallGlobalFunction(LcmInt, LCM_INT); ############################################################################# diff --git a/lib/integer.gi b/lib/integer.gi index 459ffceaf5..ec684b8875 100644 --- a/lib/integer.gi +++ b/lib/integer.gi @@ -1078,13 +1078,7 @@ InstallGlobalFunction( IsPrimePowerInt, ## #F LcmInt( , ) . . . . . . . . . . least common multiple of integers ## -InstallGlobalFunction(LcmInt,function ( n, m ) - if m = 0 and n = 0 then - return 0; - else - return AbsInt( m / GcdInt( m, n ) * n ); - fi; -end); +InstallGlobalFunction(LcmInt, LCM_INT); ############################################################################# diff --git a/src/integer.c b/src/integer.c index 9e857ee1ee..7e1d26b3bb 100644 --- a/src/integer.c +++ b/src/integer.c @@ -2202,6 +2202,45 @@ Obj FuncGCD_INT ( Obj self, Obj opL, Obj opR ) return GcdInt( opL, opR ); } +Obj LcmInt(Obj opL, Obj opR) +{ + UInt sizeL, sizeR; + fake_mpz_t mpzL, mpzR, mpzResult; + Obj result; + + CHECK_INT(opL); + CHECK_INT(opR); + + if (opL == INTOBJ_INT(0)) + return AbsInt(opR); + if (opR == INTOBJ_INT(0)) + return AbsInt(opL); + + sizeL = SIZE_INT_OR_INTOBJ(opL); + sizeR = SIZE_INT_OR_INTOBJ(opR); + + NEW_FAKEMPZ(mpzResult, sizeL + sizeR); + FAKEMPZ_GMPorINTOBJ(mpzL, opL); + FAKEMPZ_GMPorINTOBJ(mpzR, opR); + + /* compute the gcd */ + mpz_lcm(MPZ_FAKEMPZ(mpzResult), MPZ_FAKEMPZ(mpzL), MPZ_FAKEMPZ(mpzR)); + + /* convert result to GAP object and return it */ + CHECK_FAKEMPZ(mpzResult); + CHECK_FAKEMPZ(mpzL); + CHECK_FAKEMPZ(mpzR); + result = GMPorINTOBJ_FAKEMPZ(mpzResult); + CHECK_INT(result); + return result; +} + +Obj FuncLCM_INT(Obj self, Obj opL, Obj opR) +{ + REQUIRE_INT_ARG("LcmInt", "left", opL); + REQUIRE_INT_ARG("LcmInt", "right", opR); + return LcmInt(opL, opR); +} /**************************************************************************** ** @@ -2614,29 +2653,30 @@ static StructGVarFilt GVarFilts [] = { ** *V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export */ -static StructGVarFunc GVarFuncs [] = { - - GVAR_FUNC(QUO_INT, 2, "gmp1, gmp2"), - GVAR_FUNC(ABS_INT, 1, "x"), - GVAR_FUNC(SIGN_INT, 1, "x"), - GVAR_FUNC(REM_INT, 2, "gmp1, gmp2"), - GVAR_FUNC(GCD_INT, 2, "gmp1, gmp2"), - GVAR_FUNC(PROD_INT_OBJ, 2, "gmp, obj"), - GVAR_FUNC(POW_OBJ_INT, 2, "obj, gmp"), - GVAR_FUNC(JACOBI_INT, 2, "n, m"), - GVAR_FUNC(FACTORIAL_INT, 1, "n"), - GVAR_FUNC(BINOMIAL_INT, 2, "n, k"), - GVAR_FUNC(PVALUATION_INT, 2, "n, p"), - GVAR_FUNC(POWERMODINT, 3, "base, exp, mod"), - GVAR_FUNC(IS_PROBAB_PRIME_INT, 2, "n, reps"), - GVAR_FUNC(INVMODINT, 2, "base, mod"), - GVAR_FUNC(HexStringInt, 1, "gmp"), - GVAR_FUNC(IntHexString, 1, "string"), - GVAR_FUNC(Log2Int, 1, "gmp"), - GVAR_FUNC(STRING_INT, 1, "gmp"), - GVAR_FUNC(INT_STRING, 1, "string"), - GVAR_FUNC(RandomIntegerMT, 2, "mtstr, nrbits"), - { 0, 0, 0, 0, 0 } +static StructGVarFunc GVarFuncs[] = { + + GVAR_FUNC(QUO_INT, 2, "gmp1, gmp2"), + GVAR_FUNC(ABS_INT, 1, "x"), + GVAR_FUNC(SIGN_INT, 1, "x"), + GVAR_FUNC(REM_INT, 2, "gmp1, gmp2"), + GVAR_FUNC(GCD_INT, 2, "gmp1, gmp2"), + GVAR_FUNC(LCM_INT, 2, "gmp1, gmp2"), + GVAR_FUNC(PROD_INT_OBJ, 2, "gmp, obj"), + GVAR_FUNC(POW_OBJ_INT, 2, "obj, gmp"), + GVAR_FUNC(JACOBI_INT, 2, "n, m"), + GVAR_FUNC(FACTORIAL_INT, 1, "n"), + GVAR_FUNC(BINOMIAL_INT, 2, "n, k"), + GVAR_FUNC(PVALUATION_INT, 2, "n, p"), + GVAR_FUNC(POWERMODINT, 3, "base, exp, mod"), + GVAR_FUNC(IS_PROBAB_PRIME_INT, 2, "n, reps"), + GVAR_FUNC(INVMODINT, 2, "base, mod"), + GVAR_FUNC(HexStringInt, 1, "gmp"), + GVAR_FUNC(IntHexString, 1, "string"), + GVAR_FUNC(Log2Int, 1, "gmp"), + GVAR_FUNC(STRING_INT, 1, "gmp"), + GVAR_FUNC(INT_STRING, 1, "string"), + GVAR_FUNC(RandomIntegerMT, 2, "mtstr, nrbits"), + { 0, 0, 0, 0, 0 } }; From 13118fea92787076f8212d2e9fc0edffca9061ce Mon Sep 17 00:00:00 2001 From: Markus Pfeiffer Date: Wed, 13 Dec 2017 21:27:58 +0000 Subject: [PATCH 2/2] Add some tests for LcmInt --- tst/testinstall/intarith.tst | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tst/testinstall/intarith.tst b/tst/testinstall/intarith.tst index b1cb05d557..d2f7c41d96 100644 --- a/tst/testinstall/intarith.tst +++ b/tst/testinstall/intarith.tst @@ -444,6 +444,51 @@ gap> GcdInt(-2^60, -2^60); gap> GcdInt(-2^28, -2^28); 268435456 +# +# LcmInt +# +gap> List(dataNonZero, x -> LcmInt(bigNeg, x)); +[ 10000000000000000000100000000000000000000, 100000000000000000000, + 100000000000000000000, 100000000000000000000, 100000000000000000000, + 100000000000000000000, 100000000000000000000, + 10000000000000000000100000000000000000000 ] +gap> List(dataNonZero, x -> LcmInt(smlNeg, x)); +[ 1000000000000000000010000, 100000000000000000000, 10000, 10000, 10000, + 10000, 100000000000000000000, 1000000000000000000010000 ] +gap> List(dataNonZero, x -> LcmInt(smlPos, x)); +[ 1000000000000000000010000, 100000000000000000000, 10000, 10000, 10000, + 10000, 100000000000000000000, 1000000000000000000010000 ] +gap> List(dataNonZero, x -> LcmInt(bigPos, x)); +[ 10000000000000000000100000000000000000000, 100000000000000000000, + 100000000000000000000, 100000000000000000000, 100000000000000000000, + 100000000000000000000, 100000000000000000000, + 10000000000000000000100000000000000000000 ] + +# +gap> g:=3^10*257;; a:=g*991;; b:=g*1601;; +gap> LcmInt(2^20*a, 2^30*b) = 2^30*3^10*257*991*1601; +true +gap> LcmInt(2^80*a, 2^40*b) = 2^80*3^10*257*991*1601; +true +gap> LcmInt(2^80*a, 2^90*b) = 2^90*3^10*257*991*1601; +true + +# check symmetry +gap> ForAll(data, x -> ForAll(data, y -> LcmInt(x,y) = LcmInt(y,x))); +true + +# +gap> LcmInt(fail,1); +Error, LcmInt: must be an integer (not a boolean or fail) +gap> LcmInt(1,fail); +Error, LcmInt: must be an integer (not a boolean or fail) + +# corner cases +gap> LcmInt(-2^60, -2^60); +1152921504606846976 +gap> LcmInt(-2^28, -2^28); +268435456 + # # AInvInt #