ARM.MathL.Mod 3.8 KB

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