2
0

MathRe.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. (* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
  2. (* Version 1, Update 2 *)
  3. MODULE MathRe; (** AUTHOR "adf"; PURPOSE "Real math functions"; *)
  4. IMPORT NbrInt, NbrRe, DataErrors, MathInt, MathRat, MathReSeries;
  5. VAR
  6. MaxFactorial-, maxIterations: NbrInt.Integer;
  7. delta, expInfinity, expNegligible, expZero, ln2, ln2Inv, ln10, ln10Inv, sqrtInfinity: NbrRe.Real;
  8. TYPE
  9. ArcSinA = OBJECT (MathReSeries.Coefficient)
  10. PROCEDURE Evaluate*;
  11. VAR i, k, index: NbrInt.Integer; den, num: NbrRe.Real;
  12. BEGIN {EXCLUSIVE}
  13. IF NbrInt.Odd( n ) THEN
  14. num := 1; den := 1; k := n;
  15. FOR i := k - 2 TO 1 BY -2 DO index := i; num := num * index; den := den * (index + 1) END;
  16. coef := num / (n * den)
  17. ELSE coef := 0
  18. END;
  19. IF n > maxIterations THEN eos := TRUE; DataErrors.ReWarning( x, "Did not converge - timed out." ) END
  20. END Evaluate;
  21. END ArcSinA;
  22. ArcSinhA = OBJECT (MathReSeries.Coefficient)
  23. PROCEDURE Evaluate*;
  24. VAR index: NbrInt.Integer;
  25. BEGIN {EXCLUSIVE}
  26. IF n = 0 THEN coef := 0
  27. ELSIF n = 1 THEN coef := 1 / x
  28. ELSE
  29. IF NbrInt.Odd( n ) THEN index := ((n - 2) * (n - 1)) ELSE index := (n * (n - 1)) END;
  30. coef := index * x
  31. END;
  32. IF n > maxIterations THEN eos := TRUE; DataErrors.ReWarning( x, "Did not converge - timed out." ) END
  33. END Evaluate;
  34. END ArcSinhA;
  35. ArcSinhB = OBJECT (MathReSeries.Coefficient)
  36. PROCEDURE Evaluate*;
  37. BEGIN {EXCLUSIVE}
  38. IF n = 0 THEN coef := 0 ELSE coef := (2 * n - 1) END
  39. END Evaluate;
  40. END ArcSinhB;
  41. ArcTanhA = OBJECT (MathReSeries.Coefficient)
  42. PROCEDURE Evaluate*;
  43. VAR index: NbrInt.Integer;
  44. BEGIN {EXCLUSIVE}
  45. IF n = 0 THEN coef := 0
  46. ELSIF n = 1 THEN coef := 1 / x
  47. ELSE index := (-(n - 1) * (n - 1)); coef := index * x
  48. END;
  49. IF n > maxIterations THEN eos := TRUE; DataErrors.ReWarning( x, "Did not converge - timed out." ) END
  50. END Evaluate;
  51. END ArcTanhA;
  52. ArcTanhB = OBJECT (MathReSeries.Coefficient)
  53. PROCEDURE Evaluate*;
  54. BEGIN {EXCLUSIVE}
  55. IF n = 0 THEN coef := 0 ELSE coef := (2 * n - 1) END
  56. END Evaluate;
  57. END ArcTanhB;
  58. TanA = OBJECT (MathReSeries.Coefficient)
  59. PROCEDURE Evaluate*;
  60. BEGIN {EXCLUSIVE}
  61. IF n = 0 THEN coef := 0
  62. ELSIF n = 1 THEN coef := 1
  63. ELSE coef := -x
  64. END;
  65. IF n > maxIterations THEN eos := TRUE; DataErrors.ReWarning( x, "Did not converge - timed out." ) END
  66. END Evaluate;
  67. END TanA;
  68. TanB = OBJECT (MathReSeries.Coefficient)
  69. PROCEDURE Evaluate*;
  70. BEGIN {EXCLUSIVE}
  71. IF n = 0 THEN coef := 0 ELSE coef := (2 * n - 1) END
  72. END Evaluate;
  73. END TanB;
  74. (** h n i G(n+1)
  75. | | = ---------- , m 3 0
  76. j m k m!G(n-m+1)
  77. *)
  78. PROCEDURE Binomial*( top: NbrRe.Real; bottom: NbrInt.Integer ): NbrRe.Real;
  79. (* Formula 6:3:1 of: J. Spanier and K. B. Oldham, An Atlas of Functions, Hemisphere Publishing Corp., Washington DC, 1987. *)
  80. VAR i: NbrInt.Integer; coef, prod: NbrRe.Real;
  81. BEGIN
  82. IF bottom < 0 THEN DataErrors.IntError( bottom, "Bottom parameter cannot be negative" ); prod := 0
  83. ELSIF bottom = 0 THEN prod := 1
  84. ELSE
  85. i := bottom; prod := 1;
  86. REPEAT coef := (top - (bottom - i)) / i; prod := coef * prod; NbrInt.Dec( i ) UNTIL i = 0
  87. END;
  88. RETURN prod
  89. END Binomial;
  90. (** Computes n! = n * (n - 1) * (n - 2) * ... * 1, MaxFactorial 3 n 3 0. *)
  91. PROCEDURE Factorial*( n: NbrInt.Integer ): NbrRe.Real;
  92. VAR x, n2, n4, n6, n8, nR: NbrRe.Real;
  93. BEGIN
  94. IF n < 0 THEN DataErrors.IntError( n, "Negative arguments are inadmissible." ); x := 0
  95. ELSIF n <= MathInt.MaxFactorial THEN x := MathInt.Factorial( n )
  96. ELSIF n <= MathRat.MaxFactorial THEN x := MathRat.Factorial( n )
  97. ELSIF n <= MaxFactorial THEN
  98. (* Use Stirling's approximation. *)
  99. nR := n; n2 := nR * nR; n4 := n2 * n2; n6 := n2 * n4; n8 := n4 * n4;
  100. x := (1 - 1 / (30 * n2) + 1 / (105 * n4) - 1 / (140 * n6) + 1 / (99 * n8)) / (12 * nR);
  101. x := Exp( x + nR * (Ln( nR ) - 1) ); x := x * Sqrt( 2 * NbrRe.Pi * nR )
  102. ELSE DataErrors.IntError( n, "Argument is too large - overflow." ); x := 0
  103. END;
  104. RETURN x
  105. END Factorial;
  106. (** Returns a pseudo-random number r uniformly distributed over the unit interval, i.e., r N (0, 1). *)
  107. PROCEDURE Random*( ): NbrRe.Real;
  108. VAR x: NbrRe.Real;
  109. BEGIN
  110. x := MathRat.Random(); RETURN x
  111. END Random;
  112. (** Returns the Heaviside step function: 0 if x < x0, 1/2 if x = x0, and 1 if x > x0. *)
  113. PROCEDURE Step*( x, x0: NbrRe.Real ): NbrRe.Real;
  114. VAR step: NbrRe.Real;
  115. BEGIN
  116. IF x < x0 THEN step := 0
  117. ELSIF x = x0 THEN step := 0.5
  118. ELSE step := 1
  119. END;
  120. RETURN step
  121. END Step;
  122. (** Computes the square root. *)
  123. PROCEDURE Sqrt*( x: NbrRe.Real ): NbrRe.Real;
  124. VAR sqrt: NbrRe.Real;
  125. BEGIN
  126. IF x < 0 THEN DataErrors.ReError( x, "Argument cannot be negative." ); sqrt := 0
  127. ELSIF x = 0 THEN sqrt := 0
  128. ELSE sqrt := NbrRe.Sqrt( x )
  129. END;
  130. RETURN sqrt
  131. END Sqrt;
  132. (** Computes the Pythagorean distance: V(x2 + y2). *)
  133. PROCEDURE Pythag*( x, y: NbrRe.Real ): NbrRe.Real;
  134. VAR absx, absy, dist, ratio: NbrRe.Real;
  135. BEGIN
  136. absx := NbrRe.Abs( x ); absy := NbrRe.Abs( y );
  137. IF absx > absy THEN ratio := absy / absx; dist := absx * Sqrt( 1 + ratio * ratio )
  138. ELSIF absy = 0 THEN dist := 0
  139. ELSE ratio := absx / absy; dist := absy * Sqrt( 1 + ratio * ratio )
  140. END;
  141. RETURN dist
  142. END Pythag;
  143. (** Computes xn, {x,n} 9 {0,0}. *)
  144. PROCEDURE IntPower*( x: NbrRe.Real; n: NbrInt.Integer ): NbrRe.Real;
  145. VAR sign: NbrInt.Integer; max, power: NbrRe.Real;
  146. BEGIN
  147. sign := 1;
  148. IF n = 0 THEN
  149. IF x # 0 THEN power := 1 ELSE DataErrors.Error( "Both argument and exponent cannot be zero." ); power := 1
  150. (* Sending an error message is ok, but if without stopping people in most cases do expect 0^0 =1 *)
  151. END
  152. ELSIF x = 0 THEN
  153. IF n > 0 THEN power := 0
  154. ELSE DataErrors.IntError( n, "Exponent cannot be negative when argument is zero." ); power := 0;
  155. END
  156. ELSE
  157. IF x < 0 THEN
  158. x := NbrRe.Abs( x );
  159. IF NbrInt.Odd( n ) THEN sign := -1 END
  160. END;
  161. IF n < 0 THEN x := 1 / x; n := NbrInt.Abs( n ) END;
  162. power := 1;
  163. WHILE n > 0 DO
  164. WHILE ~NbrInt.Odd( n ) & (n > 0) DO
  165. max := NbrRe.MaxNbr / x;
  166. IF x > max THEN x := max; n := 2; DataErrors.Error( "Arithmatic overflow." ) END;
  167. x := x * x; n := n DIV 2
  168. END;
  169. max := NbrRe.MaxNbr / power;
  170. IF x > max THEN x := max; n := 1; DataErrors.Error( "Arithmatic overflow." ) END;
  171. power := power * x; NbrInt.Dec( n )
  172. END
  173. END;
  174. RETURN sign * power
  175. END IntPower;
  176. (** Computes xy, x 3 0, {x,y} 9 {0,0} . *)
  177. PROCEDURE Power*( x: NbrRe.Real; y: NbrRe.Real ): NbrRe.Real;
  178. VAR arg, power: NbrRe.Real;
  179. BEGIN
  180. IF x < 0 THEN DataErrors.ReError( x, "Argument cannot be negative." ); power := 0
  181. ELSIF x = 0 THEN
  182. power := 0;
  183. IF y <= 0 THEN DataErrors.Error( "Exponent must be positive when argument is zero." ) END
  184. ELSIF ( x = 1 ) OR ( y = 0 ) THEN power := 1
  185. ELSE arg := y * Ln( x ); power := Exp( arg )
  186. END;
  187. RETURN power
  188. END Power;
  189. (** Computes ex *)
  190. PROCEDURE Exp*( x: NbrRe.Real ): NbrRe.Real;
  191. VAR exp: NbrRe.Real;
  192. BEGIN
  193. IF x > expInfinity THEN DataErrors.ReError( x, "Argument is too large." ); exp := NbrRe.MaxNbr
  194. ELSIF x < expZero THEN exp := 0
  195. ELSE exp := NbrRe.Exp( x )
  196. END;
  197. RETURN exp
  198. END Exp;
  199. (** Computes 2x *)
  200. PROCEDURE Exp2*( x: NbrRe.Real ): NbrRe.Real;
  201. VAR exp, xLn2: NbrRe.Real;
  202. BEGIN
  203. xLn2 := x * ln2;
  204. IF xLn2 > expInfinity THEN DataErrors.ReError( x, "Argument is too large." ); exp := NbrRe.MaxNbr
  205. ELSIF xLn2 < expZero THEN exp := 0
  206. ELSE exp := NbrRe.Exp( xLn2 )
  207. END;
  208. RETURN exp
  209. END Exp2;
  210. (** Computes 10x *)
  211. PROCEDURE Exp10*( x: NbrRe.Real ): NbrRe.Real;
  212. VAR exp, xLn10: NbrRe.Real;
  213. BEGIN
  214. xLn10 := x * ln10;
  215. IF xLn10 > expInfinity THEN DataErrors.ReError( x, "Argument is too large." ); exp := NbrRe.MaxNbr
  216. ELSIF xLn10 < expZero THEN exp := 0
  217. ELSE exp := NbrRe.Exp( xLn10 )
  218. END;
  219. RETURN exp
  220. END Exp10;
  221. (** Computes Loge(x) - the natural log. *)
  222. PROCEDURE Ln*( x: NbrRe.Real ): NbrRe.Real;
  223. VAR ln: NbrRe.Real;
  224. BEGIN
  225. IF x > 0 THEN ln := NbrRe.Ln( x ) ELSE DataErrors.ReError( x, "Argument must be positive." ); ln := 0 END;
  226. RETURN ln
  227. END Ln;
  228. (** Computes Log2(x) - log base 2. *)
  229. PROCEDURE Log2*( x: NbrRe.Real ): NbrRe.Real;
  230. VAR ln, log: NbrRe.Real;
  231. BEGIN
  232. IF x > 0 THEN ln := NbrRe.Ln( x ); log := ln2Inv * ln
  233. ELSE DataErrors.ReError( x, "Argument must be positive." ); log := 0
  234. END;
  235. RETURN log
  236. END Log2;
  237. (** Computes Log10(x) - log base 10. *)
  238. PROCEDURE Log*( x: NbrRe.Real ): NbrRe.Real;
  239. VAR ln, log: NbrRe.Real;
  240. BEGIN
  241. IF x > 0 THEN ln := NbrRe.Ln( x ); log := ln10Inv * ln
  242. ELSE DataErrors.ReError( x, "Argument must be positive." ); log := 0
  243. END;
  244. RETURN log
  245. END Log;
  246. (** Triganometric Functions *)
  247. PROCEDURE Sin*( x: NbrRe.Real ): NbrRe.Real;
  248. BEGIN
  249. RETURN NbrRe.Sin( x )
  250. END Sin;
  251. PROCEDURE Cos*( x: NbrRe.Real ): NbrRe.Real;
  252. BEGIN
  253. RETURN NbrRe.Cos( x )
  254. END Cos;
  255. PROCEDURE Tan*( x: NbrRe.Real ): NbrRe.Real;
  256. VAR cos, sin, tan: NbrRe.Real; a: TanA; b: TanB;
  257. BEGIN
  258. IF NbrRe.Abs( x ) < delta THEN NEW( a ); NEW( b ); tan := MathReSeries.ContinuedFraction( a, b, x )
  259. ELSE
  260. cos := Cos( x ); sin := Sin( x );
  261. IF cos # 0 THEN tan := sin / cos
  262. ELSE
  263. DataErrors.ReError( x, "Division by zero, i.e., the cos(x) = 0." );
  264. IF sin > 0 THEN tan := NbrRe.MaxNbr ELSE tan := NbrRe.MinNbr END
  265. END
  266. END;
  267. RETURN tan
  268. END Tan;
  269. PROCEDURE ArcSin*( x: NbrRe.Real ): NbrRe.Real;
  270. (* Returns the arcus sine of 'x' in the range [-p/2, p/2] where -1 <= x <= 1 *)
  271. VAR a: ArcSinA; n, d, abs, arcsin: NbrRe.Real;
  272. BEGIN
  273. abs := NbrRe.Abs( x );
  274. IF abs > 1 THEN DataErrors.ReError( x, "Argument is outside the admissible range: -1 <= x <= 1." ); arcsin := 0
  275. ELSIF abs = 1 THEN n := x; d := 0; arcsin := ArcTan2( n, d )
  276. ELSIF abs > delta THEN n := x; d := Sqrt( 1 - x * x ); arcsin := ArcTan2( n, d )
  277. ELSE NEW( a ); arcsin := MathReSeries.PowerSeries( a, x )
  278. END;
  279. RETURN arcsin
  280. END ArcSin;
  281. PROCEDURE ArcCos*( x: NbrRe.Real ): NbrRe.Real;
  282. (* Returns the arcus cosine of 'x' in the range [0, p] where -1 <= x <= 1 *)
  283. VAR n, d, abs, arccos: NbrRe.Real;
  284. BEGIN
  285. abs := NbrRe.Abs( x );
  286. IF abs > 1 THEN DataErrors.ReError( x, "Argument is outside the admissible range: -1 <= x <= 1." ); arccos := 0
  287. ELSIF abs = 1 THEN n := 0; d := x; arccos := ArcTan2( n, d )
  288. ELSE n := Sqrt( 1 - x * x ); d := x; arccos := ArcTan2( n, d )
  289. END;
  290. RETURN arccos
  291. END ArcCos;
  292. PROCEDURE ArcTan*( x: NbrRe.Real ): NbrRe.Real;
  293. BEGIN
  294. RETURN NbrRe.ArcTan( x )
  295. END ArcTan;
  296. PROCEDURE ArcTan2*( xn, xd: NbrRe.Real ): NbrRe.Real; (** Quadrant-correct arcus tangent: atan(xn/xd). *)
  297. VAR atan: NbrRe.Real;
  298. BEGIN
  299. IF xd = 0 THEN
  300. IF xn # 0 THEN atan := NbrRe.Sign( xn ) * NbrRe.Pi / 2
  301. ELSE DataErrors.Error( "Both arguments cannot be zero." ); atan := 0
  302. END
  303. ELSIF xn = 0 THEN atan := (1 - NbrRe.Sign( xd )) * NbrRe.Pi / 2
  304. ELSE atan := NbrRe.ArcTan( xn / xd ) + NbrRe.Sign( xn ) * (1 - NbrRe.Sign( xd )) * NbrRe.Pi / 2
  305. END;
  306. RETURN atan
  307. END ArcTan2;
  308. (** Hyperbolic Functions *)
  309. PROCEDURE Sinh*( x: NbrRe.Real ): NbrRe.Real;
  310. VAR abs, expM1, sinh: NbrRe.Real;
  311. BEGIN
  312. abs := NbrRe.Abs( x );
  313. IF abs < 1 THEN expM1 := Exp( abs ) - 1; sinh := NbrRe.Sign( x ) * (expM1 + expM1 / (1 + expM1)) / 2
  314. ELSIF abs < expNegligible THEN sinh := (Exp( x ) - Exp( -x )) / 2
  315. ELSE sinh := NbrRe.Sign( x ) * Exp( abs ) / 2
  316. END;
  317. RETURN sinh
  318. END Sinh;
  319. PROCEDURE Cosh*( x: NbrRe.Real ): NbrRe.Real;
  320. VAR abs, cosh: NbrRe.Real;
  321. BEGIN
  322. abs := NbrRe.Abs( x );
  323. IF abs < expNegligible THEN cosh := (Exp( x ) + Exp( -x )) / 2 ELSE cosh := Exp( abs ) / 2 END;
  324. RETURN cosh
  325. END Cosh;
  326. PROCEDURE Tanh*( x: NbrRe.Real ): NbrRe.Real;
  327. VAR abs, exp, expM, exp2xM1, tanh: NbrRe.Real;
  328. BEGIN
  329. abs := NbrRe.Abs( x );
  330. IF abs < 1 THEN exp2xM1 := Exp( 2 * abs ) - 1; tanh := NbrRe.Sign( x ) * exp2xM1 / (2 + exp2xM1)
  331. ELSIF abs < expNegligible THEN exp := Exp( x ); expM := Exp( -x ); tanh := (exp - expM) / (exp + expM)
  332. ELSE tanh := NbrRe.Sign( x )
  333. END;
  334. RETURN tanh
  335. END Tanh;
  336. PROCEDURE ArcSinh*( x: NbrRe.Real ): NbrRe.Real;
  337. (* ArcSinh(x) is the arcus hyperbolic sine of 'x'. *)
  338. VAR abs, asinh: NbrRe.Real; a: ArcSinhA; b: ArcSinhB;
  339. BEGIN
  340. abs := NbrRe.Abs( x );
  341. IF abs > sqrtInfinity THEN DataErrors.ReError( x, "Argument is too large." ); asinh := 0
  342. ELSIF x < -delta THEN asinh := -Ln( abs + Sqrt( abs ) * Sqrt( abs + 1 / abs ) )
  343. ELSIF x < delta THEN
  344. IF x = 0 THEN asinh := 0
  345. ELSE NEW( a ); NEW( b ); asinh := x * Sqrt( 1 + x * x ) * MathReSeries.ContinuedFraction( a, b, x )
  346. END
  347. ELSE asinh := Ln( x + Sqrt( x ) * Sqrt( x + 1 / x ) )
  348. END;
  349. RETURN asinh
  350. END ArcSinh;
  351. PROCEDURE ArcCosh*( x: NbrRe.Real ): NbrRe.Real;
  352. (* ArcCosh(x) is the arcus hyperbolic cosine of 'x'.
  353. All arguments greater than or equal to 1 are legal. *)
  354. VAR acosh: NbrRe.Real;
  355. BEGIN
  356. IF x < 1 THEN DataErrors.ReError( x, "Argument is out of range, i.e., x >= 1." ); acosh := 0
  357. ELSIF x = 1 THEN acosh := 0
  358. ELSIF x < sqrtInfinity THEN acosh := Ln( x + Sqrt( x ) * Sqrt( x - 1 / x ) )
  359. ELSE DataErrors.ReError( x, "Argument is too large." ); acosh := 0
  360. END;
  361. RETURN acosh
  362. END ArcCosh;
  363. PROCEDURE ArcTanh*( x: NbrRe.Real ): NbrRe.Real;
  364. (* ArcTanh(x) is the arcus hyperbolic tangent of 'x'. *)
  365. VAR abs, atanh: NbrRe.Real; a: ArcTanhA; b: ArcTanhB;
  366. BEGIN
  367. abs := NbrRe.Abs( x );
  368. IF abs > 1 THEN DataErrors.ReError( x, "Argument is out of range, i.e., -1 <= x <= 1." ); atanh := 0
  369. ELSIF abs = 1 THEN atanh := NbrRe.Sign( x ) * expNegligible
  370. ELSIF abs > delta THEN atanh := Ln( (1 + x) / (1 - x) ) / 2
  371. ELSIF abs > 0 THEN NEW( a ); NEW( b ); atanh := x * MathReSeries.ContinuedFraction( a, b, x )
  372. ELSE atanh := 0
  373. END;
  374. RETURN atanh
  375. END ArcTanh;
  376. BEGIN
  377. IF NbrRe.MaxNbr = MAX( REAL ) THEN MaxFactorial := 34 ELSE MaxFactorial := 171 END;
  378. maxIterations := 1000; expZero := Ln( 1/NbrRe.MaxNbr ); expInfinity := Ln( NbrRe.MaxNbr );
  379. expNegligible := -Ln( NbrRe.Epsilon ) / 2; sqrtInfinity := Sqrt( NbrRe.MaxNbr ) / 2; delta := 0.1;
  380. ln10 := NbrRe.Ln( 10 ); ln10Inv := 1 / ln10; ln2 := NbrRe.Ln( 2 ); ln2Inv := 1 / ln2
  381. END MathRe.