-- Copyright 1993-1998, by the Cecil Project -- Department of Computer Science and Engineering, University of Washington -- See the LICENSE file for license information. (--DOC Numbers support the standard arithmetic operations, plus the protocol of totally-ordered objects `(=', `<', `min', etc.). This contract implies that all subclasses of `number' are freely mixable at run-time. --) module Number extends Ordered, Hashable { abstract object num isa ordered_hashable[num]; signature as_int(num):integer; method as_float(n@:num):float { n.as_single_float } signature as_single_float(num):single_float; signature as_double_float(num):double_float; -- mixed int/float arithmetic behavior method =(l@:num,r@:num):bool { l.as_float = r.as_float } method <(l@:num,r@:num):bool { l.as_float < r.as_float } --DOCSHORT standard arithmetic signature +(`T <= num, T):T; signature -(`T <= num, T):T; signature *(`T <= num, T):T; signature /(`T <= num, T):T; signature /_float(`T <= num, T):T & float; -- this avoids truncation -- default implementations; coerce to floats implementation +(l@:num,r@:num):num { l.as_float + r.as_float } implementation -(l@:num,r@:num):num { l.as_float - r.as_float } implementation *(l@:num,r@:num):num { l.as_float * r.as_float } implementation /(l@:num,r@:num):num { l.as_float / r.as_float } implementation /_float(l@:num,r@:num):float { l.as_float / r.as_float } --some signatures to explain the results of mixed integer/float arithmetic signature +(integer, float):float; signature +(float, integer):float; signature -(integer, float):float; signature -(float, integer):float; signature *(integer, float):float; signature *(float, integer):float; signature /(integer, float):float; signature /(float, integer):float; signature /_float(integer, float):float; signature /_float(float, integer):float; method negate(n:`T <= num):T { -n } method -(n:`T <= num):T { cast[T](0 - n) } --DOCSHORT same as `negate' method +(n:`T <= num):T { n } -- assume no special behavior for overflows, by default -- (overridden for small_ints) method -_ov(l@:num):num { -l } method +_ov(l@:num,r@:num):num { l + r } method -_ov(l@:num,r@:num):num { l - r } method *_ov(l@:num,r@:num):num { l * r } method /_ov(l@:num,r@:num):num { l / r } method /_float_ov(l@:num,r@:num):num { l /_float r } precedence *, /, /_float left_associative; precedence +, - left_associative below *, / above =; method pred(i@num:`T <= num):T { cast[T](i - 1) } --DOCSHORT i-1 method succ(i@num:`T <= num):T { cast[T](i + 1) } --DOCSHORT i+1 method square(n:`T <= num):T { n * n } --DOCSHORT n^2 method cube(n:`T <= num):T { n * n * n } --DOCSHORT n^3 --DOCSHORT absolute value method abs(n:`T <= num):T { if(n < 0, { -n }, { n }) } --DOCSHORT return -1, 0, or 1 depending on sign of argument method sign(x:num):int { compare(x, 0, { -1 }, { 0 }, { 1 }) } --DOCSHORT arithmetic average: (n1+n2)/2 method average(n1:num, n2:num):num { (n1 + n2) / 2 } --DOCSHORT exponentiation method power(x@num:`T <= num, power:integer):S where signature *_ov(T,T):`S, S <= T { assert(power >= 0, "negative powers not implemented"); if(power = 0, { ^ cast[S](1) }); if(power.is_even, { ^ power(x *_ov x, power/2); }); x *_ov power(x *_ov x, power/2) } --DOCSHORT same as `power' method **(x@num:`T <= num, power:integer):S where signature *_ov(T,T):`S, S <= T { x.power(power) } precedence ** right_associative above *, /; method sqrt(x@num:`T <= num):T { error("sorry, not yet implemented for this kind of num"); } };