/* Pure math routines. Also defines complex and rational numbers. */ /* Copyright (c) 2008 by Albert Graef . This file is part of the Pure programming language and system. Pure is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Pure is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Random number generator. This uses the Mersenne twister, in order to avoid bad generators present in some C libraries. Returns pseudo random ints in the range -0x80000000..0x7fffffff. */ extern int pure_random() = random, void pure_srandom(int) = srandom; /* The sqrt function. */ extern double sqrt(double); sqrt x::int | sqrt x::bigint = sqrt (double x); /* Exponential function and logarithms. */ private c_log; extern double exp(double), double log(double) = c_log; ln x::double = c_log x; log x::double = c_log x/c_log 10.0; exp x::int | exp x::bigint = exp (double x); ln x::int | ln x::bigint = ln (double x); log x::int | log x::bigint = log (double x); /* Euler's number. */ const e = exp 1.0; /* Trigonometric functions. */ extern double sin(double), double cos(double), double tan(double); extern double asin(double), double acos(double), double atan(double); extern double atan2(double,double); sin x::int | sin x::bigint = sin (double x); cos x::int | cos x::bigint = cos (double x); tan x::int | tan x::bigint = tan (double x); asin x::int | asin x::bigint = asin (double x); acos x::int | acos x::bigint = acos (double x); atan x::int | atan x::bigint = atan (double x); atan2 x::int y::int | atan2 x::bigint y::bigint | atan2 x::bigint y::int | atan2 x::int y::bigint = atan2 (double x) (double y); atan2 x::int y::double | atan2 x::bigint y::double = atan2 (double x) y; atan2 x::double y::int | atan2 x::double y::bigint = atan2 x (double y); /* Ludolph's number. */ const pi = 4.0*atan 1.0; /* Hyperbolic functions. */ extern double sinh(double), double cosh(double), double tanh(double); extern double __asinh(double) = asinh, double __acosh(double) = acosh, double __atanh(double) = atanh; sinh x::int | sinh x::bigint = sinh (double x); cosh x::int | cosh x::bigint = cosh (double x); tanh x::int | tanh x::bigint = tanh (double x); asinh x::int | asinh x::bigint = asinh (double x); acosh x::int | acosh x::bigint = acosh (double x); atanh x::int | atanh x::bigint = atanh (double x); /* Complex numbers. We provide both rectangular (x+:y) and polar (r<:a) representations, where (x,y) are the Cartesian coordinates and (r,t) the radius (absolute value) and angle (in radians) of a complex number, respectively. The +: and <: constructors bind weaker than all other arithmetic operators and are non-associative. */ infix 5 +: <: ; /* Constructor equations to normalize the polar representation r<:t so that r is always nonnegative and t falls in the range -pipi; = r <: pi if t==-pi; /* The imaginary unit. */ const i = 0+:1; /* The following operations all work with both the rectangular and the polar representation, promoting real inputs to complex where appropriate. When the result of an operation is again a complex number, it generally uses the same representation as the input (except for explicit conversions). */ /* We mostly follow Bronstein/Semendjajew here. Please mail me if you know better formulas for any of these. */ /* Convert any kind of number to a complex value. */ complex z@(x+:y) | complex z@(r<:t) = z; complex x::int | complex x::bigint = x+:0; complex x::double = x+:0.0; /* Convert between polar and rectangular representations. */ polar (x+:y) = sqrt (x*x+y*y) <: atan2 y x; rect (r<:t) = r*cos t +: r*sin t; polar z@(_<:_) = z; rect z@(_+:_) = z; /* For convenience, make these work with real values, too. */ polar x::int | polar x::bigint = x<:0; polar x::double = x<:0.0; rect x::int | rect x::bigint = x+:0; rect x::double = x+:0.0; /* Create complex values on the unit circle. Note: To quickly compute exp (x+:y) in polar form, use exp x <: y. */ cis t::int | cis t::bigint | cis t::double = rect (1<:t); /* Modulus (absolute value) and argument (angle). Note that you can also find both of these in one go by converting to polar form. */ abs (x+:y) = sqrt (x*x+y*y); abs (r<:t) = r; arg (x+:y) = atan2 y x; arg (r<:t) = t; arg x::int | arg x::bigint | arg x::double = atan2 0 x; /* Real and imaginary part. */ re (x+:y) = x; re (r<:t) = r*sin t; re x::int | re x::bigint | re x::double = x; im (x+:y) = y; im (r<:t) = r*cos t; im x::int = 0; im x::bigint = 0L; im x::double = 0.0; /* Complex conjugate. */ conj (x+:y) = x +: -y; conj (r<:t) = r <: -t; conj x::int | conj x::bigint | conj x::double = x; /* Complex sqrt. */ sqrt (x+:y) = sqrt r*(cos t +: sin t) when r = sqrt (x*x+y*y); t = atan2 y x/2 end; sqrt (r<:t) = sqrt r <: t/2; /* Complex exponential and logarithms. */ exp (x+:y) = exp x * (cos y +: sin y); exp (r<:t) = exp (r*cos t) <: r*sin t; ln z@(x+:y) = ln (abs z) +: arg z; ln (r<:t) = polar (ln r +: t); log z@(x+:y) | log z@(r<:t) = ln z / ln 10; /* Complex trig functions. */ sin (x+:y) = sin x*cosh y +: cos x*sinh y; cos (x+:y) = cos x*cosh y +: -sin x*sinh y; tan (x+:y) = (sin (2*x) +: sinh (2*y)) / (cos (2*x)+cosh (2*y)); // These are best computed in rect and then converted back to polar. sin z@(r<:t) = polar (sin (rect z)); cos z@(r<:t) = polar (cos (rect z)); tan z@(r<:t) = polar (tan (rect z)); // Use complex logarithms for the inverses. asin z@(x+:y) | asin z@(r<:t) = -i*ln (i*z+sqrt (1-z*z)); acos z@(x+:y) | acos z@(r<:t) = -i*ln (z+i*sqrt (1-z*z)); atan z@(x+:y) | atan z@(r<:t) = (ln (1+i*z)-ln (1-i*z))/(2*i); /* Complex hyperbolic functions. */ sinh (x+:y) = sinh x*cos y +: cosh x*sin y; cosh (x+:y) = cosh x*cos y +: sinh x*sin y; tanh (x+:y) = (sinh (2*x) +: sin (2*y)) / (cosh (2*x)+cos (2*y)); sinh z@(r<:t) = polar (sinh (rect z)); cosh z@(r<:t) = polar (cosh (rect z)); tanh z@(r<:t) = polar (tanh (rect z)); asinh z@(x+:y) | asinh z@(r<:t) = ln (z+sqrt (z*z+1)); acosh z@(x+:y) | acosh z@(r<:t) = ln (z+sqrt (z-1)*sqrt (z+1)); // Alternative definition by Kahan. Any reason to prefer that one? // acosh z@(x+:y) | // acosh z@(r<:t) = 2*ln (sqrt ((z+1)/2)+sqrt ((z-1)/2)); atanh z@(x+:y) | atanh z@(r<:t) = (ln (1+z)-ln (1-z))/2; /* Complex arithmetic. */ -(x+:y) = -x +: -y; -(r<:t) = r <: t+pi; (x1+:y1) + (x2+:y2) = x1+x2 +: y1+y2; z1@(r1<:t1)+z2@(r2<:t2) = polar (rect z1 + rect z2); (x1+:y1) - (x2+:y2) = x1-x2 +: y1-y2; z1@(r1<:t1)-z2@(r2<:t2) = polar (rect z1 - rect z2); // TODO: Review ISO/IEC9899 Annex G recommendations for * and / to fix up // nan+:nan results in rectangular representation. (x1+:y1) * (x2+:y2) = x1*x2-y1*y2 +: x1*y2+y1*x2; (r1<:t1) * (r2<:t2) = r1*r2 <: t1+t2; (x1+:y1) / (x2+:y2) = (x1*x2+y1*y2)/d +: (y1*x2-x1*y2)/d when d = x2*x2+y2*y2 end; (r1<:t1) / (r2<:t2) = r1/r2 <: t1-t2; /* Mixed rect/polar and polar/rect forms always return a rect result. */ z1@(x1+:y1)+z2@(r2<:t2) = z1 + rect z2; z1@(r1<:t1)+z2@(x2+:y2) = rect z1 + z2; z1@(x1+:y1)-z2@(r2<:t2) = z1 - rect z2; z1@(r1<:t1)-z2@(x2+:y2) = rect z1 - z2; z1@(x1+:y1)*z2@(r2<:t2) = z1 * rect z2; z1@(r1<:t1)*z2@(x2+:y2) = rect z1 * z2; z1@(x1+:y1)/z2@(r2<:t2) = z1 / rect z2; z1@(r1<:t1)/z2@(x2+:y2) = rect z1 / z2; /* Mixed complex/real and real/complex forms yield a rect or polar result, depending on what the complex input was. */ (x1+:y1)+x2 = x1+x2 +: y1 if realp x2; x1+(x2+:y2) = x1+x2 +: y2 if realp x1; z1@(r1<:t1)+x2 = z1 + polar x2 if realp x2; x1+z2@(r2<:t2) = polar x1 + z2 if realp x1; (x1+:y1)-x2 = x1-x2 +: y1 if realp x2; x1-(x2+:y2) = x1-x2 +: -y2 if realp x1; z1@(r1<:t1)-x2 = z1 - polar x2 if realp x2; x1-z2@(r2<:t2) = polar x1 - z2 if realp x1; z1@(x1+:y1)*x2 = z1 * rect x2 if realp x2; x1*z2@(x2+:y2) = rect x1 * z2 if realp x1; (r1<:t1)*x2 = r1*x2 <: t1 if realp x2; x1*(r2<:t2) = x1*r2 <: t2 if realp x1; z1@(x1+:y1)/x2 = z1 / rect x2 if realp x2; x1/z2@(x2+:y2) = rect x1 / z2 if realp x1; (r1<:t1)/x2 = r1/x2 <: t1 if realp x2; x1/(r2<:t2) = x1/r2 <: -t2 if realp x1; /* Complex powers. */ z1@(_+:_)^x2 | z1@(_<:_)^x2 = exp (ln z1*x2) if numberp x2; x1^z2@(_+:_) = exp (ln (rect x1)*z2) if realp x1; x1^z2@(_<:_) = exp (ln (polar x1)*z2) if realp x1; /* Equality. */ (x1+:y1) == (x2+:y2) = x1==x2 && y1==y2; (r1<:t1) == (r2<:t2) = r1==r2 && t1==t2; (x1+:y1) != (x2+:y2) = x1!=x2 || y1!=y2; (r1<:t1) != (r2<:t2) = r1!=r2 || t1!=t2; z1@(_+:_)==z2@(_<:_) = z1 == rect z2; z1@(_<:_)==z2@(_+:_) = rect z1 == z2; z1@(_+:_)!=z2@(_<:_) = z1 != rect z2; z1@(_<:_)!=z2@(_+:_) = rect z1 != z2; (x1+:y1)==x2 = x1==x2 && y1==0 if realp x2; x1==(x2+:y2) = x1==x2 && y2==0 if realp x1; z1@(r1<:t1)==x2 = z1 == (x2<:0) if realp x2; x1==z2@(r2<:t2) = (x1<:0) == z2 if realp x1; (x1+:y1)!=x2 = x1!=x2 || y1!=0 if realp x2; x1!=(x2+:y2) = x1!=x2 || y2!=0 if realp x1; z1@(r1<:t1)!=x2 = z1 != (x2<:0) if realp x2; x1!=z2@(r2<:t2) = (x1<:0) != z2 if realp x1; /* Rational numbers. These are constructed with the exact division operator '%' which has the same precedence and fixity as the other division operators declared in the prelude. */ infixl 7 % ; /* The '%' operator returns a rational or complex rational for any combination of integer, rational and complex integer/rational arguments, provided that the denominator is nonzero (otherwise it behaves like x div 0, which will raise an exception). Machine int operands are always promoted to bigints. For other numeric operands '%' works just like '/'. Rational results are normalized so that the sign is always in the numerator and numerator and denominator are relatively prime. Hence a rational zero is always represented as 0L%1L. */ x::bigint % 0L = x div 0L; x::bigint % y::bigint = (-x)%(-y) if y<0; = (x div d) % (y div d) when d = gcd x y end if gcd x y > 1; // int/bigint operands x::int % y::bigint = bigint x % y; x::bigint % y::int = x % bigint y; x::int % y::int = bigint x % bigint y; // rational operands (x1%y1)%(x2%y2) = (x1*y2)%(y1*x2); (x1%y1)%x2::int | (x1%y1)%x2::bigint = x1%(y1*x2); x1::int%(x2%y2) | x1::bigint%(x2%y2) = (x1*y2)%x2; // complex operands (these must both use the same representation, otherwise // the result won't be exact) z1@(_+:_)%z2@(_<:_) | z1@(_<:_)%z2@(_+:_) = z1/z2; (x1+:y1)%(x2+:y2) = (x1*x2+y1*y2)%d +: (y1*x2-x1*y2)%d when d = x2*x2+y2*y2 end; (r1<:t1)%(r2<:t2) = r1%r2 <: t1-t2; // mixed complex/real cases (x1+:y1)%x2 = (x1*x2)%d +: (y1*x2)%d when d = x2*x2 end if realp x2; x1%(x2+:y2) = (x1*x2)%d +: (-x1*y2)%d when d = x2*x2+y2*y2 end if realp x1; (r1<:t1)%x2 = r1%x2 <: t1 if realp x2; x1%(r2<:t2) = x1%r2 <: -t2 if realp x1; // fall back to ordinary inexact division in all other cases x::double%y = x/y if numberp y; x%y::double = x/y if numberp x; /* Conversions. */ rational x@(_%_) = x; rational x::int | rational x::bigint = x%1; /* The conversion from double doesn't do any rounding, so it is guaranteed that converting the resulting rational back to double reconstructs the original value. */ private pure_rational; extern expr* pure_rational(double); rational x::double = n%d when n,d = pure_rational x end; rational (x+:y) = rational x +: rational y; rational (x<:y) = rational x <: rational y; int x@(_%_) = int (bigint x); bigint x@(_%_) = trunc x; double (x%y) = x/y; complex (x%y) = x%y +: 0L%1L; rect (x%y) = x%y +: 0L%1L; polar (x%y) = x%y <: 0L%1L; /* Note that these normalization rules will yield inexact results when triggered. Thus you have to take care that your polar representations stay normalized if you want to do computations with exact complex rationals in polar notation. */ r@(_%_)<:t = -r <: t+pi if r<0; r<:t@(_%_) = r <: atan2 (sin t) (cos t) if t<-pi || t>pi; = r <: pi if t==-pi; cis (x%y) = rect (1<:x/y); /* Numerator and denominator. */ num (x%y) = x; den (x%y) = y; num x::int | num x::bigint = bigint x; num x::double = if frac x==0.0 then bigint x else num (rational x); den x::int | den x::bigint = 1L; den x::double = if frac x==0.0 then 1L else den (rational x); /* Absolute value and sign. */ abs (x%y) = abs x % y; sgn (x%y) = sgn x; /* Complex functions. */ arg (x%y) = atan2 0 (x/y); re x@(_%_) = x; im (_%_) = 0L%1L; conj x@(_%_) = x; /* Rounding functions. These return exact results here. */ floor x@(_%_) = if n<=x then n else n-1 when n::bigint = trunc x end; ceil x@(_%_) = -floor (-x); round (x%y) = -round ((-x)%y) if x<0; = x div 2 + 1 if y==2; = (2*x+y) div (2*y) otherwise; trunc (x%y) = x div y; frac x@(_%_) = x-trunc x; /* The pow function. Returns exact powers of integers and rationals for all integer exponents. */ pow (x%y) n::int | pow (x%y) n::bigint = pow x n % pow y n if n>0; = pow y (-n) % pow x (-n) if n<0; = 1L%1L otherwise; // Negative powers of integers. pow x::int n::int | pow x::int n::bigint | pow x::bigint n::int | pow x::bigint n::bigint = 1 % pow x (-n) if n<0; /* Fallback rules for other functions (inexact results). */ sqrt (x%y) = sqrt (x/y); exp (x%y) = exp (x/y); ln (x%y) = ln (x/y); log (x%y) = log (x/y); sin (x%y) = sin (x/y); cos (x%y) = cos (x/y); tan (x%y) = tan (x/y); asin (x%y) = asin (x/y); acos (x%y) = acos (x/y); atan (x%y) = atan (x/y); atan2 (x%y) z = atan2 (x/y) z if realp z; atan2 x (y%z) = atan2 x (y/z) if realp x; sinh (x%y) = sinh (x/y); cosh (x%y) = cosh (x/y); tanh (x%y) = tanh (x/y); asinh (x%y) = asinh (x/y); acosh (x%y) = acosh (x/y); atanh (x%y) = atanh (x/y); /* Rational arithmetic. */ -(x%y) = (-x)%y; (x1%y1)+(x2%y2) = (x1*y2+x2*y1) % (y1*y2); (x1%y1)-(x2%y2) = (x1*y2-x2*y1) % (y1*y2); (x1%y1)*(x2%y2) = (x1*x2) % (y1*y2); (x1%y1)+x2::int | (x1%y1)+x2::bigint = (x1+x2*y1) % y1; (x1%y1)-x2::int | (x1%y1)-x2::bigint = (x1-x2*y1) % y1; (x1%y1)*x2::int | (x1%y1)*x2::bigint = (x1*x2) % y1; x1::int+(x2%y2) | x1::bigint+(x2%y2) = (x1*y2+x2) % y2; x1::int-(x2%y2) | x1::bigint-(x2%y2) = (x1*y2-x2) % y2; x1::int*(x2%y2) | x1::bigint*(x2%y2) = (x1*x2) % y2; /* Fallback rules. */ // / and ^ always yield inexact results. (x1%y1)/(x2%y2) = (x1/y1) / (x2/y2); (x1%y1)^(x2%y2) = (x1/y1) ^ (x2/y2); (x1%y1)+x2 = (x1/y1)+x2 if numberp x2; (x1%y1)-x2 = (x1/y1)-x2 if numberp x2; (x1%y1)*x2 = (x1/y1)*x2 if numberp x2; (x1%y1)/x2 = (x1/y1)/x2 if numberp x2; (x1%y1)^x2 = (x1/y1)^x2 if numberp x2; x1+(x2%y2) = x1+(x2/y2) if numberp x1; x1-(x2%y2) = x1-(x2/y2) if numberp x1; x1*(x2%y2) = x1*(x2/y2) if numberp x1; x1/(x2%y2) = x1/(x2/y2) if numberp x1; x1^(x2%y2) = x1^(x2/y2) if numberp x1; /* Comparisons. */ x1%y1 == x2%y2 = x1*y2 == x2*y1; x1%y1 != x2%y2 = x1*y2 != x2*y1; x1%y1 < x2%y2 = x1*y2 < x2*y1; x1%y1 <= x2%y2 = x1*y2 <= x2*y1; x1%y1 > x2%y2 = x1*y2 > x2*y1; x1%y1 >= x2%y2 = x1*y2 >= x2*y1; x1%y1 == x2 = x1 == x2*y1 if numberp x2; x1%y1 != x2 = x1 != x2*y1 if numberp x2; x1%y1 < x2 = x1 < x2*y1 if realp x2; x1%y1 <= x2 = x1 <= x2*y1 if realp x2; x1%y1 > x2 = x1 > x2*y1 if realp x2; x1%y1 >= x2 = x1 >= x2*y1 if realp x2; x1 == x2%y2 = x1*y2 == x2 if numberp x2; x1 != x2%y2 = x1*y2 != x2 if numberp x2; x1 < x2%y2 = x1*y2 < x2 if realp x2; x1 <= x2%y2 = x1*y2 <= x2 if realp x2; x1 > x2%y2 = x1*y2 > x2 if realp x2; x1 >= x2%y2 = x1*y2 >= x2 if realp x2; /* Additional number predicates. */ complexp x = case x of x+:y | x<:y = realp x && realp y; _ = 0 end; realp x = case x of _::int | _::bigint | _::double | _::bigint%_::bigint = 1; _ = 0 end; rationalp x = case x of _::bigint%_::bigint = 1; _ = 0 end; numberp x = realp x || complexp x; /* Semantic number predicates. In difference to the syntactic predicates in primitives.pure and above, these check whether the given value can be represented as an object of the given target type (up to rounding errors). Note that if x is of syntactic type X, then it is also of semantic type X. Moreover, intvalp x => bigintvalp x => ratvalp x => realvalp x => compvalp x <=> numberp x. */ compvalp x = numberp x; realvalp x = compvalp x && im x==0; ratvalp x = realvalp x && re (x-x)!==nan; bigintvalp x = ratvalp x && den (re x)==1; intvalp x = bigintvalp x && int (re x)==x; /* Check whether a number is exact (i.e., doesn't contain any double components. */ exactp x = numberp x && not (doublep x || doublep (re x) || doublep (im x)); inexactp x = numberp x && (doublep x || doublep (re x) || doublep (im x));