diff --git a/src/macfloat.c b/src/macfloat.c index 0bfbd414cc..b4daa4f0b9 100644 --- a/src/macfloat.c +++ b/src/macfloat.c @@ -443,11 +443,6 @@ Obj FuncSTRING_DIGITS_MACFLOAT( Obj self, Obj gapprec, Obj f) return str; } -Obj FuncSTRING_MACFLOAT( Obj self, Obj f) /* backwards compatibility */ -{ - return FuncSTRING_DIGITS_MACFLOAT(self,INTOBJ_INT(PRINTFDIGITS),f); -} - Obj FuncLDEXP_MACFLOAT( Obj self, Obj f, Obj i) { return NEW_MACFLOAT(ldexp(VAL_MACFLOAT(f),INT_INTOBJ(i))); @@ -517,7 +512,6 @@ static StructGVarFunc GVarFuncs [] = { GVAR_FUNC(ABS_MACFLOAT, 1, "macfloat"), GVAR_FUNC(SIGN_MACFLOAT, 1, "macfloat"), GVAR_FUNC(SIGNBIT_MACFLOAT, 1, "macfloat"), - GVAR_FUNC(STRING_MACFLOAT, 1, "macfloat"), GVAR_FUNC(STRING_DIGITS_MACFLOAT, 2, "digits, macfloat"), GVAR_FUNC(EQ_MACFLOAT, 2, "x, y"), diff --git a/src/opers.c b/src/opers.c index b585fbbd93..f6dbf1cf08 100644 --- a/src/opers.c +++ b/src/opers.c @@ -2561,7 +2561,7 @@ Obj DoAttribute ( val = DoOperation1Args( self, obj ); while (val == (Obj) 0) { val = ErrorReturnObj("Method for an attribute must return a value", - 0L, 0L, + 0L, 0L, "you can supply a value via 'return ;'"); } val = CopyObj( val, 0 ); @@ -2614,6 +2614,11 @@ Obj DoVerboseAttribute ( /* call the operation to compute the value */ val = DoVerboseOperation1Args( self, obj ); + while (val == (Obj) 0) { + val = ErrorReturnObj("Method for an attribute must return a value", + 0L, 0L, + "you can supply a value via 'return ;'"); + } val = CopyObj( val, 0 ); /* set the value (but not for internal objects) */ @@ -2983,12 +2988,12 @@ Obj DoProperty ( /* call the operation to compute the value */ val = DoOperation1Args( self, obj ); while ( val != True && val != False ) { - val = ErrorReturnObj( + val = ErrorReturnObj( "Method for a property did not return true or false", - 0L, 0L, + 0L, 0L, "you can 'return true;' or 'return false;'"); } - + /* set the value (but not for internal objects) */ if ( ENABLED_ATTR(self) == 1 && ! IS_MUTABLE_OBJ(obj) ) { switch ( TNUM_OBJ( obj ) ) { @@ -3038,7 +3043,13 @@ Obj DoVerboseProperty ( /* call the operation to compute the value */ val = DoVerboseOperation1Args( self, obj ); - + while ( val != True && val != False ) { + val = ErrorReturnObj( + "Method for a property did not return true or false", + 0L, 0L, + "you can 'return true;' or 'return false;'"); + } + /* set the value (but not for internal objects) */ if ( ENABLED_ATTR(self) == 1 && ! IS_MUTABLE_OBJ(obj) ) { switch ( TNUM_OBJ( obj ) ) { diff --git a/tst/testinstall/float.tst b/tst/testinstall/float.tst index a82b083f8b..1ac87caffe 100644 --- a/tst/testinstall/float.tst +++ b/tst/testinstall/float.tst @@ -73,10 +73,24 @@ gap> 355/113.0 = 355.0/113; true # -# convert floats to other types +gap> 2.0^2; +4. +gap> 2.0^-2; +0.25 +gap> 2.0^2.; +4. +gap> 2.0^-2.; +0.25 + +# +gap> LeftQuotient(1.0, 2.0); +2. +gap> LeftQuotient(2.0, 1.0); +0.5 + +# +# convert floats to ints # -gap> Rat(355.0/113.0); -355/113 gap> Int(1.0); 1 gap> Int(1.5); @@ -85,11 +99,33 @@ gap> Int(-1.0); -1 gap> Int(-1.5); -1 +gap> Int(1.e22); +10000000000000000000000 +gap> Int(-1.e22); +-10000000000000000000000 + +# +# convert floats to rationals +# +gap> Rat(355.0/113.0); +355/113 gap> Rat(0.5); 1/2 gap> Rat(0.0); 0 +# +# Print / View / Display for floats +# +gap> l := [ 0.0, -0.0, 1.0, Sqrt(2.0), posinf, neginf, nan ]; +[ 0., -0., 1., 1.41421, inf, -inf, nan ] +gap> ViewObj(l); Print("\n"); +[ 0., -0., 1., 1.41421, inf, -inf, nan ] +gap> PrintObj(l); Print("\n"); +[ 0, -0, 1, 1.414213562373095, inf, -inf, nan ] +gap> Display(l); +[ 0, -0, 1, 1.414213562373095, inf, -inf, nan ] + # # # @@ -286,6 +322,76 @@ function ( ) return 23.0; end +# +# +# +gap> Cos(0.); +1. +gap> Sin(0.); +0. +gap> Tan(0.); +0. +gap> Acos(1.); +0. +gap> Asin(0.); +0. +gap> Log(1.); +0. +gap> Exp(0.); +1. +gap> if IsBound(Log2) then Assert(0, Log2(1.) = 0.); fi; +gap> if IsBound(Log10) then Assert(0, Log10(1.) = 0.); fi; +gap> if IsBound(Log1p) then Assert(0, Log1p(0.) = 0.); fi; +gap> if IsBound(Exp2) then Assert(0, Exp2(0.) = 1.); fi; +gap> if IsBound(Exp10) then Assert(0, Exp10(0.) = 1.); fi; +gap> if IsBound(Expm1) then Assert(0, Expm1(0.) = 0.); fi; + +# +gap> Round(1.3); +1. +gap> Round(1.9); +2. +gap> Round(-1.9); +-2. +gap> Round(-1.3); +-1. + +# +gap> Floor(1.3); +1. +gap> Floor(1.9); +1. +gap> Floor(-1.9); +-2. +gap> Floor(-1.3); +-2. + +# +gap> Ceil(1.3); +2. +gap> Ceil(1.9); +2. +gap> Ceil(-1.9); +-1. +gap> Ceil(-1.3); +-1. + +# +gap> AbsoluteValue(1.3); +1.3 +gap> AbsoluteValue(1.9); +1.9 +gap> AbsoluteValue(-1.9); +1.9 +gap> AbsoluteValue(-1.3); +1.3 + +# +gap> Atan2(0.,0.); +0. +gap> Hypothenuse(3.,4.); +5. + # gap> STOP_TEST( "float.tst", 1); diff --git a/tst/testinstall/kernel/ariths.tst b/tst/testinstall/kernel/ariths.tst new file mode 100644 index 0000000000..b80443d954 --- /dev/null +++ b/tst/testinstall/kernel/ariths.tst @@ -0,0 +1,306 @@ +# +# Tests for functions defined in src/ariths.c +# +gap> START_TEST("kernel/ariths.tst"); + +# InUndefined +gap> 1 in 2; +Error, operations: IN of integer and integer is not defined + +# +# Test the various "VerboseFOO" handlers; to this end, create a mock family, +# category and type, and two instances of that, so that we can safely test all +# involved unary and binary operations +# +gap> fam := NewFamily("MockFamily");; +gap> cat := NewCategory("IsMockObj", +> IsMultiplicativeElementWithInverse and +> IsAdditiveElementWithInverse and +> IsCommutativeElement and +> IsAssociativeElement and +> IsAdditivelyCommutativeElement);; +gap> type := NewType(fam, cat and IsPositionalObjectRep);; +gap> a := Objectify(type,[2]);; +gap> b := Objectify(type,[3]);; + +# unary +gap> unary := [ +> Zero, +> ZeroMutable, +> AdditiveInverse, +> AdditiveInverseMutable, +> One, +> OneMutable, +> Inverse, +> InverseMutable, +> ];; + +# binary +gap> binary := [ +> \=, +> \<, +> \in, +> \+, +> \-, +> \*, +> \/, +> LeftQuotient, +> \^, +> Comm, +> \mod, +> ];; + +# +# test with regular methods +# +gap> for m in unary do InstallMethod(m, [cat], ReturnTrue); od; +gap> for m in binary do InstallMethod(m, [cat, cat], ReturnTrue); od; +gap> InstallMethod(SetZeroImmutable, [cat, IsObject], ReturnNothing); +gap> InstallMethod(SetAdditiveInverseImmutable, [cat, IsObject], ReturnNothing); +gap> InstallMethod(SetOneImmutable, [cat, IsObject], ReturnNothing); +gap> InstallMethod(SetInverseImmutable, [cat, IsObject], ReturnNothing); + +# ... and also involving TryNextMethod +gap> for m in unary do InstallMethod(m, [cat], 1, function(x) TryNextMethod(); end); od; +gap> for m in binary do InstallMethod(m, [cat, cat], 1, function(x,y) TryNextMethod(); end); od; + +# +gap> Zero(a); +true +gap> ZeroMutable(a); +true +gap> -a; +true +gap> AdditiveInverseMutable(a); +true +gap> One(a); +true +gap> OneMutable(a); +true +gap> Inverse(a); +true +gap> InverseMutable(a); +true +gap> a = b; +true +gap> a < b; +true +gap> a in b; +true +gap> a + b; +true +gap> a - b; +true +gap> a * b; +true +gap> a / b; +true +gap> LeftQuotient(a, b); +true +gap> a ^ b; +true +gap> Comm(a, b); +true +gap> a mod b; +true + +# +gap> meths := Concatenation(unary, binary);; +gap> TraceMethods(meths); + +# +gap> Zero(a); +#I ZeroImmutable at stream:1 +#I Trying next: ZeroImmutable at stream:1 +#I SetZeroImmutable at stream:1 +true +gap> ZeroMutable(a); +#I ZeroMutable at stream:1 +#I Trying next: ZeroMutable at stream:1 +true +gap> -a; +#I AdditiveInverseImmutable at stream:1 +#I Trying next: AdditiveInverseImmutable at stream:1 +#I SetAdditiveInverseImmutable at stream:1 +true +gap> AdditiveInverseMutable(a); +#I AdditiveInverseMutable at stream:1 +#I Trying next: AdditiveInverseMutable at stream:1 +true +gap> One(a); +#I OneImmutable at stream:1 +#I Trying next: OneImmutable at stream:1 +#I SetOneImmutable at stream:1 +true +gap> OneMutable(a); +#I OneMutable at stream:1 +#I Trying next: OneMutable at stream:1 +true +gap> Inverse(a); +#I InverseImmutable at stream:1 +#I Trying next: InverseImmutable at stream:1 +#I SetInverseImmutable at stream:1 +true +gap> InverseMutable(a); +#I InverseMutable at stream:1 +#I Trying next: InverseMutable at stream:1 +true +gap> a = b; +#I = at stream:1 +#I Trying next: = at stream:1 +true +gap> a < b; +#I < at stream:1 +#I Trying next: < at stream:1 +true +gap> a in b; +#I in at stream:1 +#I Trying next: in at stream:1 +true +gap> a + b; +#I + at stream:1 +#I Trying next: + at stream:1 +true +gap> a - b; +#I - at stream:1 +#I Trying next: - at stream:1 +true +gap> a * b; +#I * at stream:1 +#I Trying next: * at stream:1 +true +gap> a / b; +#I / at stream:1 +#I Trying next: / at stream:1 +true +gap> LeftQuotient(a, b); +true +gap> a ^ b; +#I ^ at stream:1 +#I Trying next: ^ at stream:1 +true +gap> Comm(a, b); +#I Comm at stream:1 +#I Trying next: Comm at stream:1 +true +gap> a mod b; +#I mod at stream:1 +#I Trying next: mod at stream:1 +true + +# +gap> UntraceMethods(meths); + +# +# test "method should have returned a value" checks +# +gap> for m in unary do InstallMethod(m, [cat], 2, ReturnNothing); od; +gap> for m in binary do InstallMethod(m, [cat, cat], 2, ReturnNothing); od; + +# +gap> Zero(a); +Error, Method for an attribute must return a value +gap> ZeroMutable(a); +Error, ZeroOp: method should have returned a value +gap> -a; +Error, Method for an attribute must return a value +gap> AdditiveInverseMutable(a); +Error, AdditiveInverseOp: method should have returned a value +gap> One(a); +Error, Method for an attribute must return a value +gap> OneMutable(a); +Error, OneOp: method should have returned a value +gap> Inverse(a); +Error, Method for an attribute must return a value +gap> InverseMutable(a); +Error, InvOp: method should have returned a value +gap> a = b; +false +gap> a < b; +false +gap> a in b; +false +gap> a + b; +Error, SUM: method should have returned a value +gap> a - b; +Error, DIFF: method should have returned a value +gap> a * b; +Error, PROD: method should have returned a value +gap> a / b; +Error, QUO: method should have returned a value +gap> LeftQuotient(a, b); +Error, LeftQuotient: method should have returned a value +gap> a ^ b; +Error, POW: method should have returned a value +gap> Comm(a, b); +Error, Comm: method should have returned a value +gap> a mod b; +Error, mod: method should have returned a value + +# +gap> meths := Concatenation(unary, binary);; +gap> TraceMethods(meths); + +# +gap> Zero(a); +#I ZeroImmutable at stream:1 +Error, Method for an attribute must return a value +gap> ZeroMutable(a); +#I ZeroMutable at stream:1 +Error, ZeroOp: method should have returned a value +gap> -a; +#I AdditiveInverseImmutable at stream:1 +Error, Method for an attribute must return a value +gap> AdditiveInverseMutable(a); +#I AdditiveInverseMutable at stream:1 +Error, AdditiveInverseOp: method should have returned a value +gap> One(a); +#I OneImmutable at stream:1 +Error, Method for an attribute must return a value +gap> OneMutable(a); +#I OneMutable at stream:1 +Error, OneOp: method should have returned a value +gap> Inverse(a); +#I InverseImmutable at stream:1 +Error, Method for an attribute must return a value +gap> InverseMutable(a); +#I InverseMutable at stream:1 +Error, InvOp: method should have returned a value +gap> a = b; +#I = at stream:1 +false +gap> a < b; +#I < at stream:1 +false +gap> a in b; +#I in at stream:1 +false +gap> a + b; +#I + at stream:1 +Error, SUM: method should have returned a value +gap> a - b; +#I - at stream:1 +Error, DIFF: method should have returned a value +gap> a * b; +#I * at stream:1 +Error, PROD: method should have returned a value +gap> a / b; +#I / at stream:1 +Error, QUO: method should have returned a value +gap> LeftQuotient(a, b); +Error, LeftQuotient: method should have returned a value +gap> a ^ b; +#I ^ at stream:1 +Error, POW: method should have returned a value +gap> Comm(a, b); +#I Comm at stream:1 +Error, Comm: method should have returned a value +gap> a mod b; +#I mod at stream:1 +Error, mod: method should have returned a value + +# +gap> UntraceMethods(meths); + +# +gap> STOP_TEST("kernel/ariths.tst", 1); diff --git a/tst/testinstall/kernel/macfloat.tst b/tst/testinstall/kernel/macfloat.tst new file mode 100644 index 0000000000..2add667282 --- /dev/null +++ b/tst/testinstall/kernel/macfloat.tst @@ -0,0 +1,44 @@ +# +# Tests for functions defined in src/macfloat.c +# +gap> START_TEST("kernel/macfloat.tst"); + +# +gap> MACFLOAT_INT(fail); +fail + +# +gap> MACFLOAT_STRING(fail); +Error, MACFLOAT_STRING: object to be converted must be a string not a boolean \ +or fail + +# +gap> pi := 3.1415926535897932384626433; +3.14159 +gap> STRING_DIGITS_MACFLOAT(10, pi); +"3.141592654" +gap> STRING_DIGITS_MACFLOAT(20, pi); +"3.141592653589793116" +gap> STRING_DIGITS_MACFLOAT(40, pi); +"3.141592653589793115997963468544185161591" +gap> STRING_DIGITS_MACFLOAT(50, pi); +"3.141592653589793115997963468544185161591" + +# +gap> LDEXP_MACFLOAT(pi,1); +6.28319 +gap> LDEXP_MACFLOAT(pi,-1); +1.5708 +gap> LDEXP_MACFLOAT(pi,0); +3.14159 + +# +gap> FREXP_MACFLOAT(0.); +[ 0., 0 ] +gap> FREXP_MACFLOAT(1.); +[ 0.5, 1 ] +gap> FREXP_MACFLOAT(pi); +[ 0.785398, 2 ] + +# +gap> STOP_TEST("kernel/macfloat.tst", 1); diff --git a/tst/testinstall/kernel/records.tst b/tst/testinstall/kernel/records.tst new file mode 100644 index 0000000000..d84952362a --- /dev/null +++ b/tst/testinstall/kernel/records.tst @@ -0,0 +1,92 @@ +# +# Tests for functions defined in src/records.c +# +gap> START_TEST("kernel/records.tst"); + +# +# setup: a precord, and a custom record object +# +gap> r:=rec(1:=2); +rec( 1 := 2 ) +gap> fam := NewFamily("MockFamily");; +gap> cat := NewCategory("IsMockRecord", IsRecord);; +gap> type := NewType(fam, cat and IsPositionalObjectRep);; +gap> mockRec := Objectify(type,["myName"]);; + +# RNamIntg, RNamObj +gap> ForAll([1,-1,"abc"], x -> IsInt(RNamObj(x))); +true +gap> RNamObj(fail); +Error, Record: '.()' must be a string or an integer + +# NameRNam +gap> ForAll([1,-1,"abc"], x -> NameRNam(RNamObj(x)) = String(x)); +true +gap> NameRNam(-1); +Error, NameRName: must be a record name (not a integer) +gap> NameRNam(fail); +Error, NameRName: must be a record name (not a boolean or fail) + +# ElmRecHandler +gap> ELM_REC(r, RNamObj(1)); +2 +gap> ELM_REC(r, RNamObj(2)); +Error, Record Element: '.2' must have an assigned value + +# ElmRecError +gap> fail.1; +Error, Record Element: must be a record (not a boolean or fail) + +# ElmRecObject +gap> InstallMethod(\., [cat, IsPosInt], function(x,i) end); +gap> mockRec.1; +Error, Record access method must return a value +gap> InstallMethod(\., [cat, IsPosInt], function(x,i) return 42; end); +gap> mockRec.1; +42 + +# IsbRecHandler +gap> ISB_REC(r, RNamObj(1)); +true +gap> ISB_REC(r, RNamObj(2)); +false + +# IsbRecError +gap> IsBound(fail.1); +Error, Record IsBound: must be a record (not a boolean or fail) + +# IsbRecObject +gap> InstallMethod(IsBound\., [cat, IsPosInt], {x,i} -> (i = RNamObj(1))); +gap> IsBound(mockRec.1); +true +gap> IsBound(mockRec.2); +false + +# AssRecHandler +gap> ASS_REC(r, RNamObj(3), 42); +gap> r; +rec( 1 := 2, 3 := 42 ) + +# AssRecError +gap> fail.1 := 2; +Error, Record Assignment: must be a record (not a boolean or fail) + +# AssRecObject +gap> InstallMethod(\.\:\=, [cat, IsPosInt, IsObject], function(x,i,v) end); +gap> ASS_REC(mockRec, RNamObj(1), 2); +gap> mockRec.1 := 2; +2 + +# UnbRecHandler +gap> UNB_REC(r, RNamObj(2)); + +# UnbRecError +gap> Unbind(fail.1); +Error, Record Unbind: must be a record (not a boolean or fail) + +# UnbRecObject +gap> InstallMethod(Unbind\., [cat, IsPosInt], function(x,i) end); +gap> Unbind(mockRec.1); + +# +gap> STOP_TEST("kernel/records.tst", 1);