approx.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. *
  6. * mostly adapted from https://gist.github.com/imbcmdth/6338194
  7. * which is ported from https://code.google.com/archive/p/fastapprox/ (BSD licensed)
  8. */
  9. const _a_fastPow2 = new ArrayBuffer(4);
  10. const _i_fastPow2 = new Int32Array(_a_fastPow2);
  11. const _f_fastPow2 = new Float32Array(_a_fastPow2);
  12. export function fastPow2(v: number) {
  13. const offset = (v < 0) ? 1 : 0;
  14. const clipNumber = (v < -126) ? -126 : v;
  15. const w = clipNumber | 0;
  16. const z = clipNumber - w + offset;
  17. _i_fastPow2[0] = ((1 << 23) * (clipNumber + 121.2740575 + 27.7280233 / (4.84252568 - z) - 1.49012907 * z));
  18. return _f_fastPow2[0];
  19. }
  20. const _a_fasterPow2 = new ArrayBuffer(4);
  21. const _i_fasterPow2 = new Int32Array(_a_fasterPow2);
  22. const _f_fasterPow2 = new Float32Array(_a_fasterPow2);
  23. export function fasterPow2(v: number) {
  24. const clipNumber = (v < -126) ? -126 : v;
  25. _i_fasterPow2[0] = ((1 << 23) * (clipNumber + 126.94269504));
  26. return _f_fasterPow2[0];
  27. }
  28. export function fastExp(v: number) {
  29. return fastPow2(1.442695040 * v);
  30. }
  31. export function fasterExp(v: number) {
  32. return fasterPow2(1.442695040 * v);
  33. }
  34. const _a_fastLog2 = new ArrayBuffer(8);
  35. const _i_fastLog2 = new Int32Array(_a_fastLog2);
  36. const _f_fastLog2 = new Float32Array(_a_fastLog2);
  37. export function fastLog2(v: number) {
  38. _f_fastLog2[0] = v;
  39. _i_fastLog2[1] = (_i_fastLog2[0] & 0x007FFFFF) | 0x3f000000;
  40. const t = _i_fastLog2[0] * 1.1920928955078125e-7;
  41. return t - 124.22551499 - 1.498030302 * _f_fastLog2[1] - 1.72587999 / (0.3520887068 + _f_fastLog2[1]);
  42. };
  43. const _a_fasterLog2 = new ArrayBuffer(4);
  44. const _i_fasterLog2 = new Int32Array(_a_fasterLog2);
  45. const _f_fasterLog2 = new Float32Array(_a_fasterLog2);
  46. export function fasterLog2(v: number) {
  47. _f_fasterLog2[0] = v;
  48. const t = _i_fasterLog2[0] * 1.1920928955078125e-7;
  49. return t - 126.94269504;
  50. }
  51. export function fastLog(v: number) {
  52. return 0.6931471805599453 * fastLog2(v);
  53. }
  54. export function fasterLog(v: number) {
  55. return 0.6931471805599453 * fasterLog2(v);
  56. }
  57. export function fastLog10(v: number) {
  58. return 0.30102999566398114 * fastLog2(v);
  59. }
  60. export function fasterLog10(v: number) {
  61. return 0.30102999566398114 * fasterLog2(v);
  62. }
  63. export function fastSinh(v: number) {
  64. return 0.5 * (fastExp(v) - fastExp(-v));
  65. }
  66. export function fasterSinh(v: number) {
  67. return 0.5 * (fasterExp(v) - fasterExp(-v));
  68. }
  69. export function fastCosh(v: number) {
  70. return 0.5 * (fastExp(v) + fastExp(-v));
  71. }
  72. export function fasterCosh(v: number) {
  73. return 0.5 * (fasterExp(v) + fasterExp(-v));
  74. }
  75. export function fastTanh(v: number) {
  76. return -1.0 + 2.0 / (1.0 + fastExp(-2.0 * v));
  77. }
  78. export function fasterTanh(v: number) {
  79. return -1.0 + 2.0 / (1.0 + fasterExp(-2.0 * v));
  80. }
  81. const halfPi = Math.PI / 2;
  82. const twoPi = 2 * Math.PI;
  83. const invTwoPi = 1 / (2 * Math.PI);
  84. const twoOverPi = 2 / Math.PI;
  85. const fourOverPi = 4 / Math.PI;
  86. const fourOverPiSq = 4 / (Math.PI * Math.PI);
  87. const halfPiMinusTwoPi = Math.PI / 2 - 2 * Math.PI;
  88. const _q_fastHalfSin = 0.78444488374548933;
  89. const _a_fastHalfSin = new ArrayBuffer(16);
  90. const _i_fastHalfSin = new Int32Array(_a_fastHalfSin);
  91. const _f_fastHalfSin = new Float32Array(_a_fastHalfSin);
  92. function fastHalfSin(v: number) {
  93. _f_fastHalfSin[0] = 0.20363937680730309;
  94. _f_fastHalfSin[1] = 0.015124940802184233;
  95. _f_fastHalfSin[2] = -0.0032225901625579573;
  96. _f_fastHalfSin[3] = v;
  97. const sign = _i_fastHalfSin[3] & 0x80000000;
  98. _i_fastHalfSin[3] = _i_fastHalfSin[3] & 0x7FFFFFFF;
  99. const qpprox = fourOverPi * v - fourOverPiSq * v * _f_fastHalfSin[3];
  100. const qpproxsq = qpprox * qpprox;
  101. _i_fastHalfSin[0] |= sign;
  102. _i_fastHalfSin[1] |= sign;
  103. _i_fastHalfSin[2] ^= sign;
  104. return _q_fastHalfSin * qpprox + qpproxsq * (_f_fastHalfSin[0] + qpproxsq * (_f_fastHalfSin[1] + qpproxsq * _f_fastHalfSin[2]));
  105. }
  106. const _q_fasterHalfSin = 0.78444488374548933;
  107. const _a_fasterHalfSin = new ArrayBuffer(8);
  108. const _i_fasterHalfSin = new Int32Array(_a_fasterHalfSin);
  109. const _f_fasterHalfSin = new Float32Array(_a_fasterHalfSin);
  110. function fasterHalfSin(v: number) {
  111. _f_fasterHalfSin[0] = 0.22308510060189463;
  112. _f_fasterHalfSin[1] = v;
  113. const sign = _i_fasterHalfSin[1] & 0x80000000;
  114. _i_fasterHalfSin[1] &= 0x7FFFFFFF;
  115. const qpprox = fourOverPi * v - fourOverPiSq * v * _f_fasterHalfSin[1];
  116. _i_fasterHalfSin[0] |= sign;
  117. return qpprox * (_q_fasterHalfSin + _f_fasterHalfSin[0] * qpprox);
  118. }
  119. export function fastSin(v: number) {
  120. const k = (v * invTwoPi) | 0;
  121. const half = (v < 0) ? -0.5 : 0.5;
  122. return fastHalfSin((half + k) * twoPi - v);
  123. }
  124. export function fasterSin(v: number) {
  125. const k = (v * invTwoPi) | 0;
  126. const half = (v < 0) ? -0.5 : 0.5;
  127. return fasterHalfSin((half + k) * twoPi - v);
  128. }
  129. export function fastCos(v: number) {
  130. return fastSin(v + halfPi);
  131. }
  132. export function fasterCos(v: number) {
  133. return fasterSin(v + halfPi);
  134. }
  135. function fastHalfCos(v: number) {
  136. const offset = (v > halfPi) ? halfPiMinusTwoPi : halfPi;
  137. return fastHalfSin(v + offset);
  138. }
  139. const _p_fasterHalfCos = 0.54641335845679634;
  140. const _a_fasterHalfCos = new ArrayBuffer(4);
  141. const _i_fasterHalfCos = new Int32Array(_a_fasterHalfCos);
  142. const _f_fasterHalfCos = new Float32Array(_a_fasterHalfCos);
  143. function fasterHalfCos(v: number) {
  144. _f_fasterHalfCos[0] = v;
  145. _i_fasterHalfCos[0] &= 0x7FFFFFFF;
  146. const qpprox = 1.0 - twoOverPi * _f_fasterHalfCos[0];
  147. return qpprox + _p_fasterHalfCos * qpprox * (1.0 - qpprox * qpprox);
  148. }
  149. export function fastTan(v: number) {
  150. const k = (v * invTwoPi) | 0;
  151. const half = (v < 0) ? -0.5 : 0.5;
  152. const x = v - (half + k) * twoPi;
  153. return fastHalfSin(x) / fastHalfCos(x);
  154. }
  155. export function fasterTan(v: number) {
  156. const k = (v * invTwoPi) | 0;
  157. const half = (v < 0) ? -0.5 : 0.5;
  158. const x = v - (half + k) * twoPi;
  159. return fasterHalfSin(x) / fasterHalfCos(x);
  160. }
  161. const piOverFour = Math.PI / 4;
  162. /**
  163. * Adapted from:
  164. * "Efficient approximations for the arctangent function"
  165. * Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006
  166. */
  167. export function fastAtan(v: number) {
  168. return piOverFour * v - v * (Math.abs(v) - 1) * (0.2447 + 0.0663 * Math.abs(v));
  169. }
  170. export function fastAtan2(y: number, x: number) {
  171. // reduce range to [-1, 1] by flipping y/x so the larger is up
  172. let t = Math.abs(x); // used to undo flipping
  173. let opposite = Math.abs(y);
  174. const adjacent = Math.max(t, opposite);
  175. opposite = Math.min(t, opposite);
  176. t = fastAtan(opposite / adjacent);
  177. // undo flipping
  178. t = Math.abs(y) > Math.abs(x) ? halfPi - t : t;
  179. t = x < 0.0 ? Math.PI - t : t;
  180. t = y < 0.0 ? -t : t;
  181. return t;
  182. }