module IntMod()
option object;
local base := 1;
local value := 0;
# implement a ModuleApply and ModuleCopy routine
# to use IntMod() as a object constructor
export ModuleApply::static := proc()
Object( IntMod, _passed );
end;
export ModuleCopy::Static := proc( self::IntMod, proto::IntMod,
v::integer, b::integer, $ )
if ( _npassed < 3 ) then
# if a value was not given, copy the prototype
self:-value := proto:-value;
else
# use the given value
self:-value := v;
end;
if ( _npassed < 4 ) then
# if a base was not given, opy the prototype
self:-base := proto:-base;
else
# use the given base
self:-base := b;
end;
# apply the mod
self:-value := self:-value mod self:-base;
end;
# implement ModulePrint to make the display nice
export ModulePrint::static := proc( self::IntMod )
nprintf( "%d mod %d", self:-value, self:-base );
end;
# Implement Module type to enable type checking with
# with a specified base
export ModuleType::static := proc( self, type, b, $ )
if ( _npassed = 2 ) then
true;
else
evalb( self:-base = b );
end;
end;
# accessor to get the stored value
export getValue::static := proc( self::IntMod )
self:-value;
end;
# implement the + operator to allow IntMods to work properly
# in sum statements. We assume that the modular arthemetic is
# contagious and the entire addition become modular
export `+`::static := proc( )
local ints, imods, total, base, other;
# remove the stuff we aren't going to manipulate
( ints, other ) := selectremove( type, [_passed],
{ 'IntMod', 'integer' } );
( imods, ints ) := selectremove( type, ints, 'IntMod' );
base := imods[1]:-base;
if ( not andmap( type, imods, 'IntMod'( base ) ) ) then
error "all IntMods must be of the same base"
end;
#Add the IntMods and the integer constant, if one exists
total := ( `if`( numelems(ints) > 0, ints[1], 0 ) +
add( getValue(i), i in imods ) ) mod base;
# return a sequence
IntMod( total, base ), op( other );
end;
# implement the * operator
export `*`::static := proc( )
local ints, imods, total, base, other;
# remove the stuff we aren't going to manipulate
( ints, other ) := selectremove( type, [_passed],
{ 'IntMod', 'integer' } );
( imods, ints ) := selectremove( type, ints, 'IntMod' );
base := imods[1]:-base;
if ( not andmap( type, imods, 'IntMod'( base ) ) ) then
error "all IntMods must be of the same base"
end;
# remove the stuff we aren't going to manipulate
total := ( `if`( numelems(ints) > 0, ints[1], 1 ) *
add( getValue(i), i in imods ) ) mod base;
# return a sequence
IntMod( total, base ), op( other );
end;
# implement the ^ operator
export `^`::static := proc( self::IntMod, exponent::integer, $ )
IntMod( self:-value^exponent, self:-base );
end;
# implement the basic comparison operators
export `=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value = other:-value )
end;
export `<`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value < other:-value )
end;
export `<=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value <= other:-value )
end;
export `>`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value > other:-value )
end;
export `>=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value >= other:-value )
end;
# override the convert routine to allow IntMods to be converted
# to integers. The inverse does not work because we con't know
# which base to use
export convert::static := proc( v, toType, $ )
if ( v::IntMod ) then
if ( toType = ':-integer' ) then
v:-value;
else
error "cannot convert from IntMod to %1", toType;
end;
else
error "cannot convert into IntMod from %1", v
end;
end;
end: |