Math.ob07 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. (*
  2. BSD 2-Clause License
  3. Copyright (c) 2019-2022, Anton Krotov
  4. All rights reserved.
  5. *)
  6. MODULE Math;
  7. IMPORT SYSTEM;
  8. CONST
  9. pi* = 3.1415926535897932384626433832795028841972E0;
  10. e* = 2.7182818284590452353602874713526624977572E0;
  11. ZERO = 0.0E0;
  12. ONE = 1.0E0;
  13. HALF = 0.5E0;
  14. TWO = 2.0E0;
  15. sqrtHalf = 0.70710678118654752440E0;
  16. eps = 5.5511151E-17;
  17. ln2Inv = 1.44269504088896340735992468100189213E0;
  18. piInv = ONE / pi;
  19. Limit = 1.0536712E-8;
  20. piByTwo = pi / TWO;
  21. expoMax = 1023;
  22. expoMin = 1 - expoMax;
  23. VAR
  24. LnInfinity, LnSmall, large, miny: REAL;
  25. PROCEDURE [oberon] sqrt* (x: REAL): REAL;
  26. BEGIN
  27. ASSERT(x >= ZERO);
  28. $IF (CPU_X8664)
  29. SYSTEM.CODE(
  30. 0F2H, 0FH, 51H, 45H, 10H, (* sqrtsd xmm0, qword[rbp + 10h] *)
  31. 05DH, (* pop rbp *)
  32. 0C2H, 08H, 00H (* ret 8 *)
  33. )
  34. $ELSIF (CPU_X86)
  35. SYSTEM.CODE(
  36. 0DDH, 045H, 008H, (* fld qword [ebp + 08h] *)
  37. 0D9H, 0FAH, (* fsqrt *)
  38. 05DH, (* pop ebp *)
  39. 0C2H, 008H, 000H (* ret 8 *)
  40. )
  41. $END
  42. RETURN 0.0
  43. END sqrt;
  44. PROCEDURE sqri* (x: INTEGER): INTEGER;
  45. RETURN x * x
  46. END sqri;
  47. PROCEDURE sqrr* (x: REAL): REAL;
  48. RETURN x * x
  49. END sqrr;
  50. PROCEDURE exp* (x: REAL): REAL;
  51. CONST
  52. c1 = 0.693359375E0;
  53. c2 = -2.1219444005469058277E-4;
  54. P0 = 0.249999999999999993E+0;
  55. P1 = 0.694360001511792852E-2;
  56. P2 = 0.165203300268279130E-4;
  57. Q1 = 0.555538666969001188E-1;
  58. Q2 = 0.495862884905441294E-3;
  59. VAR
  60. xn, g, p, q, z: REAL;
  61. n: INTEGER;
  62. BEGIN
  63. IF x > LnInfinity THEN
  64. x := SYSTEM.INF()
  65. ELSIF x < LnSmall THEN
  66. x := ZERO
  67. ELSIF ABS(x) < eps THEN
  68. x := ONE
  69. ELSE
  70. IF x >= ZERO THEN
  71. n := FLOOR(ln2Inv * x + HALF)
  72. ELSE
  73. n := FLOOR(ln2Inv * x - HALF)
  74. END;
  75. xn := FLT(n);
  76. g := (x - xn * c1) - xn * c2;
  77. z := g * g;
  78. p := ((P2 * z + P1) * z + P0) * g;
  79. q := (Q2 * z + Q1) * z + HALF;
  80. x := HALF + p / (q - p);
  81. PACK(x, n + 1)
  82. END
  83. RETURN x
  84. END exp;
  85. PROCEDURE ln* (x: REAL): REAL;
  86. CONST
  87. c1 = 355.0E0 / 512.0E0;
  88. c2 = -2.121944400546905827679E-4;
  89. P0 = -0.64124943423745581147E+2;
  90. P1 = 0.16383943563021534222E+2;
  91. P2 = -0.78956112887491257267E+0;
  92. Q0 = -0.76949932108494879777E+3;
  93. Q1 = 0.31203222091924532844E+3;
  94. Q2 = -0.35667977739034646171E+2;
  95. VAR
  96. zn, zd, r, z, w, p, q, xn: REAL;
  97. n: INTEGER;
  98. BEGIN
  99. ASSERT(x > ZERO);
  100. UNPK(x, n);
  101. x := x * HALF;
  102. IF x > sqrtHalf THEN
  103. zn := x - ONE;
  104. zd := x * HALF + HALF;
  105. INC(n)
  106. ELSE
  107. zn := x - HALF;
  108. zd := zn * HALF + HALF
  109. END;
  110. z := zn / zd;
  111. w := z * z;
  112. q := ((w + Q2) * w + Q1) * w + Q0;
  113. p := w * ((P2 * w + P1) * w + P0);
  114. r := z + z * (p / q);
  115. xn := FLT(n)
  116. RETURN (xn * c2 + r) + xn * c1
  117. END ln;
  118. PROCEDURE power* (base, exponent: REAL): REAL;
  119. BEGIN
  120. ASSERT(base > ZERO)
  121. RETURN exp(exponent * ln(base))
  122. END power;
  123. PROCEDURE ipower* (base: REAL; exponent: INTEGER): REAL;
  124. VAR
  125. i: INTEGER;
  126. a: REAL;
  127. BEGIN
  128. a := 1.0;
  129. IF base # 0.0 THEN
  130. IF exponent # 0 THEN
  131. IF exponent < 0 THEN
  132. base := 1.0 / base
  133. END;
  134. i := ABS(exponent);
  135. WHILE i > 0 DO
  136. WHILE ~ODD(i) DO
  137. i := LSR(i, 1);
  138. base := sqrr(base)
  139. END;
  140. DEC(i);
  141. a := a * base
  142. END
  143. ELSE
  144. a := 1.0
  145. END
  146. ELSE
  147. ASSERT(exponent > 0);
  148. a := 0.0
  149. END
  150. RETURN a
  151. END ipower;
  152. PROCEDURE log* (base, x: REAL): REAL;
  153. BEGIN
  154. ASSERT(base > ZERO);
  155. ASSERT(x > ZERO)
  156. RETURN ln(x) / ln(base)
  157. END log;
  158. PROCEDURE SinCos (x, y, sign: REAL): REAL;
  159. CONST
  160. ymax = 210828714;
  161. c1 = 3.1416015625E0;
  162. c2 = -8.908910206761537356617E-6;
  163. r1 = -0.16666666666666665052E+0;
  164. r2 = 0.83333333333331650314E-2;
  165. r3 = -0.19841269841201840457E-3;
  166. r4 = 0.27557319210152756119E-5;
  167. r5 = -0.25052106798274584544E-7;
  168. r6 = 0.16058936490371589114E-9;
  169. r7 = -0.76429178068910467734E-12;
  170. r8 = 0.27204790957888846175E-14;
  171. VAR
  172. n: INTEGER;
  173. xn, f, x1, g: REAL;
  174. BEGIN
  175. ASSERT(y < FLT(ymax));
  176. n := FLOOR(y * piInv + HALF);
  177. xn := FLT(n);
  178. IF ODD(n) THEN
  179. sign := -sign
  180. END;
  181. x := ABS(x);
  182. IF x # y THEN
  183. xn := xn - HALF
  184. END;
  185. x1 := FLT(FLOOR(x));
  186. f := ((x1 - xn * c1) + (x - x1)) - xn * c2;
  187. IF ABS(f) < Limit THEN
  188. x := sign * f
  189. ELSE
  190. g := f * f;
  191. g := (((((((r8 * g + r7) * g + r6) * g + r5) * g + r4) * g + r3) * g + r2) * g + r1) * g;
  192. g := f + f * g;
  193. x := sign * g
  194. END
  195. RETURN x
  196. END SinCos;
  197. PROCEDURE sin* (x: REAL): REAL;
  198. BEGIN
  199. IF x < ZERO THEN
  200. x := SinCos(x, -x, -ONE)
  201. ELSE
  202. x := SinCos(x, x, ONE)
  203. END
  204. RETURN x
  205. END sin;
  206. PROCEDURE cos* (x: REAL): REAL;
  207. RETURN SinCos(x, ABS(x) + piByTwo, ONE)
  208. END cos;
  209. PROCEDURE tan* (x: REAL): REAL;
  210. VAR
  211. s, c: REAL;
  212. BEGIN
  213. s := sin(x);
  214. c := sqrt(ONE - s * s);
  215. x := ABS(x) / (TWO * pi);
  216. x := x - FLT(FLOOR(x));
  217. IF (0.25 < x) & (x < 0.75) THEN
  218. c := -c
  219. END
  220. RETURN s / c
  221. END tan;
  222. PROCEDURE arctan2* (y, x: REAL): REAL;
  223. CONST
  224. P0 = 0.216062307897242551884E+3; P1 = 0.3226620700132512059245E+3;
  225. P2 = 0.13270239816397674701E+3; P3 = 0.1288838303415727934E+2;
  226. Q0 = 0.2160623078972426128957E+3; Q1 = 0.3946828393122829592162E+3;
  227. Q2 = 0.221050883028417680623E+3; Q3 = 0.3850148650835119501E+2;
  228. Sqrt3 = 1.7320508075688772935E0;
  229. VAR
  230. atan, z, z2, p, q: REAL;
  231. yExp, xExp, Quadrant: INTEGER;
  232. BEGIN
  233. IF ABS(x) < miny THEN
  234. ASSERT(ABS(y) >= miny);
  235. atan := piByTwo
  236. ELSE
  237. z := y;
  238. UNPK(z, yExp);
  239. z := x;
  240. UNPK(z, xExp);
  241. IF yExp - xExp >= expoMax - 3 THEN
  242. atan := piByTwo
  243. ELSIF yExp - xExp < expoMin + 3 THEN
  244. atan := ZERO
  245. ELSE
  246. IF ABS(y) > ABS(x) THEN
  247. z := ABS(x / y);
  248. Quadrant := 2
  249. ELSE
  250. z := ABS(y / x);
  251. Quadrant := 0
  252. END;
  253. IF z > TWO - Sqrt3 THEN
  254. z := (z * Sqrt3 - ONE) / (Sqrt3 + z);
  255. INC(Quadrant)
  256. END;
  257. IF ABS(z) < Limit THEN
  258. atan := z
  259. ELSE
  260. z2 := z * z;
  261. p := (((P3 * z2 + P2) * z2 + P1) * z2 + P0) * z;
  262. q := (((z2 + Q3) * z2 + Q2) * z2 + Q1) * z2 + Q0;
  263. atan := p / q
  264. END;
  265. CASE Quadrant OF
  266. |0:
  267. |1: atan := atan + pi / 6.0
  268. |2: atan := piByTwo - atan
  269. |3: atan := pi / 3.0 - atan
  270. END
  271. END;
  272. IF x < ZERO THEN
  273. atan := pi - atan
  274. END
  275. END;
  276. IF y < ZERO THEN
  277. atan := -atan
  278. END
  279. RETURN atan
  280. END arctan2;
  281. PROCEDURE arcsin* (x: REAL): REAL;
  282. BEGIN
  283. ASSERT(ABS(x) <= ONE)
  284. RETURN arctan2(x, sqrt(ONE - x * x))
  285. END arcsin;
  286. PROCEDURE arccos* (x: REAL): REAL;
  287. BEGIN
  288. ASSERT(ABS(x) <= ONE)
  289. RETURN arctan2(sqrt(ONE - x * x), x)
  290. END arccos;
  291. PROCEDURE arctan* (x: REAL): REAL;
  292. RETURN arctan2(x, ONE)
  293. END arctan;
  294. PROCEDURE sinh* (x: REAL): REAL;
  295. BEGIN
  296. x := exp(x)
  297. RETURN (x - ONE / x) * HALF
  298. END sinh;
  299. PROCEDURE cosh* (x: REAL): REAL;
  300. BEGIN
  301. x := exp(x)
  302. RETURN (x + ONE / x) * HALF
  303. END cosh;
  304. PROCEDURE tanh* (x: REAL): REAL;
  305. BEGIN
  306. IF x > 15.0 THEN
  307. x := ONE
  308. ELSIF x < -15.0 THEN
  309. x := -ONE
  310. ELSE
  311. x := ONE - TWO / (exp(TWO * x) + ONE)
  312. END
  313. RETURN x
  314. END tanh;
  315. PROCEDURE arsinh* (x: REAL): REAL;
  316. RETURN ln(x + sqrt(x * x + ONE))
  317. END arsinh;
  318. PROCEDURE arcosh* (x: REAL): REAL;
  319. BEGIN
  320. ASSERT(x >= ONE)
  321. RETURN ln(x + sqrt(x * x - ONE))
  322. END arcosh;
  323. PROCEDURE artanh* (x: REAL): REAL;
  324. BEGIN
  325. ASSERT(ABS(x) < ONE)
  326. RETURN HALF * ln((ONE + x) / (ONE - x))
  327. END artanh;
  328. PROCEDURE sgn* (x: REAL): INTEGER;
  329. VAR
  330. res: INTEGER;
  331. BEGIN
  332. IF x > ZERO THEN
  333. res := 1
  334. ELSIF x < ZERO THEN
  335. res := -1
  336. ELSE
  337. res := 0
  338. END
  339. RETURN res
  340. END sgn;
  341. PROCEDURE fact* (n: INTEGER): REAL;
  342. VAR
  343. res: REAL;
  344. BEGIN
  345. res := ONE;
  346. WHILE n > 1 DO
  347. res := res * FLT(n);
  348. DEC(n)
  349. END
  350. RETURN res
  351. END fact;
  352. PROCEDURE DegToRad* (x: REAL): REAL;
  353. RETURN x * (pi / 180.0)
  354. END DegToRad;
  355. PROCEDURE RadToDeg* (x: REAL): REAL;
  356. RETURN x * (180.0 / pi)
  357. END RadToDeg;
  358. (* Return hypotenuse of triangle *)
  359. PROCEDURE hypot* (x, y: REAL): REAL;
  360. VAR
  361. a: REAL;
  362. BEGIN
  363. x := ABS(x);
  364. y := ABS(y);
  365. IF x > y THEN
  366. a := x * sqrt(1.0 + sqrr(y / x))
  367. ELSE
  368. IF x > 0.0 THEN
  369. a := y * sqrt(1.0 + sqrr(x / y))
  370. ELSE
  371. a := y
  372. END
  373. END
  374. RETURN a
  375. END hypot;
  376. BEGIN
  377. large := 1.9;
  378. PACK(large, expoMax);
  379. miny := ONE / large;
  380. LnInfinity := ln(large);
  381. LnSmall := ln(miny);
  382. END Math.