1 /* 2 * MathUtils.js - Misc math utility routines 3 * 4 * Copyright © 2013-2015, 2018 JEDLSoft 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 var MathUtils = {}; 21 22 /** 23 * Return the sign of the given number. If the sign is negative, this function 24 * returns -1. If the sign is positive or zero, this function returns 1. 25 * @static 26 * @param {number} num the number to test 27 * @return {number} -1 if the number is negative, and 1 otherwise 28 */ 29 MathUtils.signum = function (num) { 30 var n = num; 31 if (typeof(num) === 'string') { 32 n = parseInt(num, 10); 33 } else if (typeof(num) !== 'number') { 34 return 1; 35 } 36 return (n < 0) ? -1 : 1; 37 }; 38 39 /** 40 * @static 41 * @protected 42 * @param {number} num number to round 43 * @return {number} rounded number 44 */ 45 MathUtils.floor = function (num) { 46 return Math.floor(num); 47 }; 48 49 /** 50 * @static 51 * @protected 52 * @param {number} num number to round 53 * @return {number} rounded number 54 */ 55 MathUtils.ceiling = function (num) { 56 return Math.ceil(num); 57 }; 58 59 /** 60 * @static 61 * @protected 62 * @param {number} num number to round 63 * @return {number} rounded number 64 */ 65 MathUtils.down = function (num) { 66 return (num < 0) ? Math.ceil(num) : Math.floor(num); 67 }; 68 69 /** 70 * @static 71 * @protected 72 * @param {number} num number to round 73 * @return {number} rounded number 74 */ 75 MathUtils.up = function (num) { 76 return (num < 0) ? Math.floor(num) : Math.ceil(num); 77 }; 78 79 /** 80 * @static 81 * @protected 82 * @param {number} num number to round 83 * @return {number} rounded number 84 */ 85 MathUtils.halfup = function (num) { 86 return (num < 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5); 87 }; 88 89 /** 90 * @static 91 * @protected 92 * @param {number} num number to round 93 * @return {number} rounded number 94 */ 95 MathUtils.halfdown = function (num) { 96 return (num < 0) ? Math.floor(num + 0.5) : Math.ceil(num - 0.5); 97 }; 98 99 /** 100 * @static 101 * @protected 102 * @param {number} num number to round 103 * @return {number} rounded number 104 */ 105 MathUtils.halfeven = function (num) { 106 return (Math.floor(num) % 2 === 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5); 107 }; 108 109 /** 110 * @static 111 * @protected 112 * @param {number} num number to round 113 * @return {number} rounded number 114 */ 115 MathUtils.halfodd = function (num) { 116 return (Math.floor(num) % 2 !== 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5); 117 }; 118 119 /** 120 * Do a proper modulo function. The Javascript % operator will give the truncated 121 * division algorithm, but for calendrical calculations, we need the Euclidean 122 * division algorithm where the remainder of any division, whether the dividend 123 * is negative or not, is always a positive number in the range [0, modulus).<p> 124 * 125 * 126 * @static 127 * @param {number} dividend the number being divided 128 * @param {number} modulus the number dividing the dividend. This should always be a positive number. 129 * @return the remainder of dividing the dividend by the modulus. 130 */ 131 MathUtils.mod = function (dividend, modulus) { 132 if (modulus == 0) { 133 return 0; 134 } 135 var x = dividend % modulus; 136 return (x < 0) ? x + modulus : x; 137 }; 138 139 /** 140 * Do a proper adjusted modulo function. The Javascript % operator will give the truncated 141 * division algorithm, but for calendrical calculations, we need the Euclidean 142 * division algorithm where the remainder of any division, whether the dividend 143 * is negative or not, is always a positive number in the range (0, modulus]. The adjusted 144 * modulo function differs from the regular modulo function in that when the remainder is 145 * zero, the modulus should be returned instead.<p> 146 * 147 * 148 * @static 149 * @param {number} dividend the number being divided 150 * @param {number} modulus the number dividing the dividend. This should always be a positive number. 151 * @return the remainder of dividing the dividend by the modulus. 152 */ 153 MathUtils.amod = function (dividend, modulus) { 154 if (modulus == 0) { 155 return 0; 156 } 157 var x = dividend % modulus; 158 return (x <= 0) ? x + modulus : x; 159 }; 160 161 /** 162 * Return the number with the decimal shifted by the given precision. 163 * Positive precisions shift the decimal to the right giving larger 164 * numbers, and negative ones shift the decimal to the left giving 165 * smaller numbers. 166 * 167 * @static 168 * @param {number} number the number to shift 169 * @param {number} precision the number of places to move the decimal point 170 * @returns {number} the number with the decimal point shifted by the 171 * given number of decimals 172 */ 173 MathUtils.shiftDecimal = function shift(number, precision) { 174 var numArray = ("" + number).split("e"); 175 return +(numArray[0] + "e" + (numArray[1] ? (+numArray[1] + precision) : precision)); 176 }; 177 178 /** 179 * Returns the base 10 logarithm of a number. For platforms that support 180 * Math.log10() it is used directly. For plaforms that do not, such as Qt/QML, 181 * it will be calculated using the natural logarithm. 182 * 183 * @param {number} num the number to take the logarithm of 184 * @returns {number} the base-10 logarithm of the given number 185 */ 186 MathUtils.log10 = function(num) { 187 if (typeof(Math.log10) === "function") { 188 return Math.log10(num); 189 } 190 191 return Math.log(num) / Math.LN10; 192 }; 193 194 /** 195 * Return the given number with only the given number of significant digits. 196 * The number of significant digits can start with the digits greater than 197 * 1 and straddle the decimal point, or it may start after the decimal point. 198 * If the number of digits requested is less than 1, the original number 199 * will be returned unchanged. 200 * 201 * @static 202 * @param {number} number the number to return with only significant digits 203 * @param {number} digits the number of significant digits to include in the 204 * returned number 205 * @param {function(number): number=} round a rounding function to use 206 * @returns {number} the given number with only the requested number of 207 * significant digits 208 */ 209 MathUtils.significant = function(number, digits, round) { 210 if (digits < 1 || number === 0) return number; 211 var rnd = round || Math.round; 212 var factor = -Math.floor(MathUtils.log10(Math.abs(number))) + digits - 1; 213 return MathUtils.shiftDecimal(rnd(MathUtils.shiftDecimal(number, factor)), -factor); 214 }; 215 216 module.exports = MathUtils; 217