ARM.MathL.Mod 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. MODULE MathL;
  2. IMPORT SYSTEM, Reals;
  3. CONST
  4. e* = 2.7182818284590452354E0;
  5. pi* = 3.14159265358979323846E0;
  6. ln2* = 0.693147180559945309417232121458; (** ln(2), from https://en.wikipedia.org/wiki/Natural_logarithm_of_2 *)
  7. eps = 1.2E-7;
  8. NEON = FALSE;
  9. (** Returns the mantissa *)
  10. PROCEDURE Mantissa (x: LONGREAL): HUGEINT;
  11. TYPE
  12. Flt = ARRAY 2 OF LONGINT;
  13. VAR
  14. y: Flt;
  15. BEGIN
  16. y := SYSTEM.VAL(Flt, x);
  17. RETURN y[0] + LSH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, y[1]) * {0 .. 19}), 32)
  18. END Mantissa;
  19. PROCEDURE Equal (x, y: LONGREAL): BOOLEAN;
  20. BEGIN
  21. IF x > y THEN
  22. x := x - y
  23. ELSE
  24. x := y - x
  25. END;
  26. RETURN x < eps
  27. END Equal;
  28. PROCEDURE Sin(x: LONGREAL):LONGREAL;
  29. END Sin;
  30. PROCEDURE Cos(x: LONGREAL):LONGREAL;
  31. END Cos;
  32. PROCEDURE Arctan(x: LONGREAL):LONGREAL;
  33. END Arctan;
  34. PROCEDURE Sqrt(x: LONGREAL):LONGREAL;
  35. END Sqrt;
  36. PROCEDURE Ln(x: LONGREAL):LONGREAL;
  37. END Ln;
  38. PROCEDURE Exp(x: LONGREAL):LONGREAL;
  39. END Exp;
  40. PROCEDURE sin*(x: LONGREAL): LONGREAL;
  41. VAR
  42. xk, prev, res: LONGREAL;
  43. k: LONGINT;
  44. BEGIN
  45. IF NEON THEN
  46. IF x < 0.0 THEN RETURN -Sin(-x) ELSE RETURN Sin(x) END
  47. ELSE
  48. WHILE x >= 2 * pi DO x := x - pi END;
  49. WHILE x < 0 DO x := x + pi END;
  50. res := x;
  51. xk := x;
  52. k := 1;
  53. REPEAT
  54. prev := res;
  55. xk := -xk * x * x / (2 * k) / (2 * k + 1);
  56. res := res + xk;
  57. INC(k)
  58. UNTIL Equal(prev, res) OR (k = 5000);
  59. RETURN res
  60. END
  61. END sin;
  62. PROCEDURE cos*(x: LONGREAL): LONGREAL;
  63. VAR
  64. k, kf: LONGINT;
  65. prev, res, xk: LONGREAL;
  66. BEGIN
  67. IF NEON THEN
  68. IF x < 0.0 THEN RETURN Cos(-x) ELSE RETURN Cos(x) END
  69. ELSE
  70. WHILE x >= 2 * pi DO x := x - pi END;
  71. WHILE x < 0 DO x := x + pi END;
  72. res := 1.0;
  73. xk := 1.0;
  74. kf := 1;
  75. k := 1;
  76. REPEAT
  77. prev := res;
  78. xk := -xk * x * x / (2 * k - 1) / (2 * k);
  79. res := res + xk;
  80. INC(k, 1)
  81. UNTIL Equal(xk, 0.0) OR Equal(prev, res) OR (k = 5000);
  82. RETURN res
  83. END
  84. END cos;
  85. PROCEDURE arctan*(x: LONGREAL): LONGREAL;
  86. VAR
  87. k: LONGINT;
  88. prev, res, term, xk: LONGREAL;
  89. BEGIN
  90. IF NEON THEN
  91. RETURN Arctan(x)
  92. ELSIF (x = 1) OR (x = -1) THEN
  93. RETURN x * pi / 4
  94. ELSIF (x > 1) OR (x < -1) THEN
  95. RETURN pi / 2 - arctan(1 / x)
  96. ELSE
  97. (* atan(x) = sum_k (-1)^(k) x^{2 k + 1} / (2 k + 1), |x| < 1 *)
  98. prev := pi / 2;
  99. res := 0.0;
  100. xk := x;
  101. k := 0;
  102. REPEAT
  103. prev := res;
  104. term := 1 / (2 * k + 1) * xk;
  105. IF ODD(k) THEN
  106. res := res - term
  107. ELSE
  108. res := res + term
  109. END;
  110. xk := xk * x * x;
  111. INC(k)
  112. UNTIL Equal(prev, res) OR (k = 50000);
  113. RETURN res
  114. END
  115. END arctan;
  116. PROCEDURE sqrt*(x: LONGREAL): LONGREAL;
  117. BEGIN
  118. IF x <= 0 THEN
  119. IF x = 0 THEN RETURN 0 ELSE HALT(80) END
  120. ELSIF NEON THEN
  121. RETURN Sqrt(x)
  122. ELSE
  123. RETURN exp(0.5 * ln(x))
  124. END
  125. END sqrt;
  126. PROCEDURE ln*(x: LONGREAL): LONGREAL;
  127. VAR
  128. res, y, yk: LONGREAL;
  129. k: LONGINT;
  130. BEGIN
  131. IF x <= 0 THEN HALT(80)
  132. ELSIF NEON THEN
  133. RETURN Ln(x)
  134. ELSIF x < 1.0 THEN
  135. RETURN -ln(1.0 / x)
  136. ELSIF x >= 2.0 THEN
  137. (*
  138. algorithm idea from http://stackoverflow.com/questions/10732034/how-are-logarithms-programmed
  139. and https://en.wikipedia.org/wiki/Natural_logarithm (Newton's method)
  140. ln(m * 2^e) = e ln(2) + ln(m)
  141. *)
  142. RETURN (Reals.ExpoL(x) - 1023) * ln2 + ln(SYSTEM.VAL(LONGREAL, Mantissa(x) + 3FF0000000000000H))
  143. ELSE
  144. (* ln(x) = 2 * sum_k 1/(2 k + 1) y^k, where y = (x - 1) / (x + 1), x real *)
  145. y := (x - 1) / (x + 1);
  146. yk := y;
  147. res := y;
  148. k := 1;
  149. REPEAT
  150. yk := yk * y * y;
  151. res := res + yk / (2 * k + 1);
  152. INC(k)
  153. UNTIL Equal(yk, 0.0) OR (k = 5000);
  154. RETURN 2.0 * res;
  155. END
  156. END ln;
  157. PROCEDURE exp*(x: LONGREAL): LONGREAL;
  158. VAR
  159. k: LONGINT;
  160. prev, res, xk, kf: LONGREAL;
  161. BEGIN
  162. IF NEON THEN
  163. RETURN Exp(x)
  164. ELSIF x < 0.0 THEN
  165. RETURN 1.0 / exp(-x)
  166. ELSE
  167. (* exp(x) = sum_k x^(k) / k! *)
  168. prev := 0.0;
  169. res := 1.0;
  170. k := 1;
  171. xk := 1;
  172. kf := 1.0;
  173. REPEAT
  174. prev := res;
  175. xk := xk / k * x;
  176. res := res + xk;
  177. INC(k, 1)
  178. UNTIL Equal(xk, 0.0) OR (k = 5000);
  179. RETURN res
  180. END
  181. END exp;
  182. END MathL.