simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

arithmetic.js (7257B)


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