ARM.Math.Mod 3.6 KB

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