Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce kernel-level LCM_INT #2019

Merged
merged 2 commits into from
Dec 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions hpcgap/lib/integer.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1105,13 +1105,7 @@ InstallGlobalFunction( IsPrimePowerInt,
##
#F LcmInt( <m>, <n> ) . . . . . . . . . . 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);


#############################################################################
Expand Down
8 changes: 1 addition & 7 deletions lib/integer.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1078,13 +1078,7 @@ InstallGlobalFunction( IsPrimePowerInt,
##
#F LcmInt( <m>, <n> ) . . . . . . . . . . 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);


#############################################################################
Expand Down
86 changes: 63 additions & 23 deletions src/integer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/****************************************************************************
**
Expand Down Expand Up @@ -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 }

};

Expand Down
45 changes: 45 additions & 0 deletions tst/testinstall/intarith.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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: <left> must be an integer (not a boolean or fail)
gap> LcmInt(1,fail);
Error, LcmInt: <right> 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
#
Expand Down