arithmetic.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. import { cbrt, expm1, isInteger, log10, log1p, log2, sign, toFixed } from '../../utils/number.js';
  2. var n1 = 'number';
  3. var n2 = 'number, number';
  4. export function absNumber(a) {
  5. return Math.abs(a);
  6. }
  7. absNumber.signature = n1;
  8. export function addNumber(a, b) {
  9. return a + b;
  10. }
  11. addNumber.signature = n2;
  12. export function subtractNumber(a, b) {
  13. return a - b;
  14. }
  15. subtractNumber.signature = n2;
  16. export function multiplyNumber(a, b) {
  17. return a * b;
  18. }
  19. multiplyNumber.signature = n2;
  20. export function divideNumber(a, b) {
  21. return a / b;
  22. }
  23. divideNumber.signature = n2;
  24. export function unaryMinusNumber(x) {
  25. return -x;
  26. }
  27. unaryMinusNumber.signature = n1;
  28. export function unaryPlusNumber(x) {
  29. return x;
  30. }
  31. unaryPlusNumber.signature = n1;
  32. export function cbrtNumber(x) {
  33. return cbrt(x);
  34. }
  35. cbrtNumber.signature = n1;
  36. export function cubeNumber(x) {
  37. return x * x * x;
  38. }
  39. cubeNumber.signature = n1;
  40. export function expNumber(x) {
  41. return Math.exp(x);
  42. }
  43. expNumber.signature = n1;
  44. export function expm1Number(x) {
  45. return expm1(x);
  46. }
  47. expm1Number.signature = n1;
  48. /**
  49. * Calculate gcd for numbers
  50. * @param {number} a
  51. * @param {number} b
  52. * @returns {number} Returns the greatest common denominator of a and b
  53. */
  54. export function gcdNumber(a, b) {
  55. if (!isInteger(a) || !isInteger(b)) {
  56. throw new Error('Parameters in function gcd must be integer numbers');
  57. }
  58. // https://en.wikipedia.org/wiki/Euclidean_algorithm
  59. var r;
  60. while (b !== 0) {
  61. r = a % b;
  62. a = b;
  63. b = r;
  64. }
  65. return a < 0 ? -a : a;
  66. }
  67. gcdNumber.signature = n2;
  68. /**
  69. * Calculate lcm for two numbers
  70. * @param {number} a
  71. * @param {number} b
  72. * @returns {number} Returns the least common multiple of a and b
  73. */
  74. export function lcmNumber(a, b) {
  75. if (!isInteger(a) || !isInteger(b)) {
  76. throw new Error('Parameters in function lcm must be integer numbers');
  77. }
  78. if (a === 0 || b === 0) {
  79. return 0;
  80. }
  81. // https://en.wikipedia.org/wiki/Euclidean_algorithm
  82. // evaluate lcm here inline to reduce overhead
  83. var t;
  84. var prod = a * b;
  85. while (b !== 0) {
  86. t = b;
  87. b = a % t;
  88. a = t;
  89. }
  90. return Math.abs(prod / a);
  91. }
  92. lcmNumber.signature = n2;
  93. /**
  94. * Calculate the logarithm of a value, optionally to a given base.
  95. * @param {number} x
  96. * @param {number | null | undefined} base
  97. * @return {number}
  98. */
  99. export function logNumber(x, y) {
  100. if (y) {
  101. return Math.log(x) / Math.log(y);
  102. }
  103. return Math.log(x);
  104. }
  105. /**
  106. * Calculate the 10-base logarithm of a number
  107. * @param {number} x
  108. * @return {number}
  109. */
  110. export function log10Number(x) {
  111. return log10(x);
  112. }
  113. log10Number.signature = n1;
  114. /**
  115. * Calculate the 2-base logarithm of a number
  116. * @param {number} x
  117. * @return {number}
  118. */
  119. export function log2Number(x) {
  120. return log2(x);
  121. }
  122. log2Number.signature = n1;
  123. /**
  124. * Calculate the natural logarithm of a `number+1`
  125. * @param {number} x
  126. * @returns {number}
  127. */
  128. export function log1pNumber(x) {
  129. return log1p(x);
  130. }
  131. log1pNumber.signature = n1;
  132. /**
  133. * Calculate the modulus of two numbers
  134. * @param {number} x
  135. * @param {number} y
  136. * @returns {number} res
  137. * @private
  138. */
  139. export function modNumber(x, y) {
  140. if (y > 0) {
  141. // We don't use JavaScript's % operator here as this doesn't work
  142. // correctly for x < 0 and x === 0
  143. // see https://en.wikipedia.org/wiki/Modulo_operation
  144. return x - y * Math.floor(x / y);
  145. } else if (y === 0) {
  146. return x;
  147. } else {
  148. // y < 0
  149. // TODO: implement mod for a negative divisor
  150. throw new Error('Cannot calculate mod for a negative divisor');
  151. }
  152. }
  153. modNumber.signature = n2;
  154. /**
  155. * Calculate the nth root of a, solve x^root == a
  156. * http://rosettacode.org/wiki/Nth_root#JavaScript
  157. * @param {number} a
  158. * @param {number} [2] root
  159. * @private
  160. */
  161. export function nthRootNumber(a) {
  162. var root = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
  163. var inv = root < 0;
  164. if (inv) {
  165. root = -root;
  166. }
  167. if (root === 0) {
  168. throw new Error('Root must be non-zero');
  169. }
  170. if (a < 0 && Math.abs(root) % 2 !== 1) {
  171. throw new Error('Root must be odd when a is negative.');
  172. }
  173. // edge cases zero and infinity
  174. if (a === 0) {
  175. return inv ? Infinity : 0;
  176. }
  177. if (!isFinite(a)) {
  178. return inv ? 0 : a;
  179. }
  180. var x = Math.pow(Math.abs(a), 1 / root);
  181. // If a < 0, we require that root is an odd integer,
  182. // so (-1) ^ (1/root) = -1
  183. x = a < 0 ? -x : x;
  184. return inv ? 1 / x : x;
  185. // Very nice algorithm, but fails with nthRoot(-2, 3).
  186. // Newton's method has some well-known problems at times:
  187. // https://en.wikipedia.org/wiki/Newton%27s_method#Failure_analysis
  188. /*
  189. let x = 1 // Initial guess
  190. let xPrev = 1
  191. let i = 0
  192. const iMax = 10000
  193. do {
  194. const delta = (a / Math.pow(x, root - 1) - x) / root
  195. xPrev = x
  196. x = x + delta
  197. i++
  198. }
  199. while (xPrev !== x && i < iMax)
  200. if (xPrev !== x) {
  201. throw new Error('Function nthRoot failed to converge')
  202. }
  203. return inv ? 1 / x : x
  204. */
  205. }
  206. export function signNumber(x) {
  207. return sign(x);
  208. }
  209. signNumber.signature = n1;
  210. export function sqrtNumber(x) {
  211. return Math.sqrt(x);
  212. }
  213. sqrtNumber.signature = n1;
  214. export function squareNumber(x) {
  215. return x * x;
  216. }
  217. squareNumber.signature = n1;
  218. /**
  219. * Calculate xgcd for two numbers
  220. * @param {number} a
  221. * @param {number} b
  222. * @return {number} result
  223. * @private
  224. */
  225. export function xgcdNumber(a, b) {
  226. // source: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
  227. var t; // used to swap two variables
  228. var q; // quotient
  229. var r; // remainder
  230. var x = 0;
  231. var lastx = 1;
  232. var y = 1;
  233. var lasty = 0;
  234. if (!isInteger(a) || !isInteger(b)) {
  235. throw new Error('Parameters in function xgcd must be integer numbers');
  236. }
  237. while (b) {
  238. q = Math.floor(a / b);
  239. r = a - q * b;
  240. t = x;
  241. x = lastx - q * x;
  242. lastx = t;
  243. t = y;
  244. y = lasty - q * y;
  245. lasty = t;
  246. a = b;
  247. b = r;
  248. }
  249. var res;
  250. if (a < 0) {
  251. res = [-a, -lastx, -lasty];
  252. } else {
  253. res = [a, a ? lastx : 0, lasty];
  254. }
  255. return res;
  256. }
  257. xgcdNumber.signature = n2;
  258. /**
  259. * Calculates the power of x to y, x^y, for two numbers.
  260. * @param {number} x
  261. * @param {number} y
  262. * @return {number} res
  263. */
  264. export function powNumber(x, y) {
  265. // x^Infinity === 0 if -1 < x < 1
  266. // A real number 0 is returned instead of complex(0)
  267. if (x * x < 1 && y === Infinity || x * x > 1 && y === -Infinity) {
  268. return 0;
  269. }
  270. return Math.pow(x, y);
  271. }
  272. powNumber.signature = n2;
  273. /**
  274. * round a number to the given number of decimals, or to zero if decimals is
  275. * not provided
  276. * @param {number} value
  277. * @param {number} decimals number of decimals, between 0 and 15 (0 by default)
  278. * @return {number} roundedValue
  279. */
  280. export function roundNumber(value) {
  281. var decimals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  282. if (!isInteger(decimals) || decimals < 0 || decimals > 15) {
  283. throw new Error('Number of decimals in function round must be an integer from 0 to 15 inclusive');
  284. }
  285. return parseFloat(toFixed(value, decimals));
  286. }
  287. /**
  288. * Calculate the norm of a number, the absolute value.
  289. * @param {number} x
  290. * @return {number}
  291. */
  292. export function normNumber(x) {
  293. return Math.abs(x);
  294. }
  295. normNumber.signature = n1;