Total Complexity | 243 |
Complexity/F | 2.89 |
Lines of Code | 1020 |
Function Count | 84 |
Duplicated Lines | 11 |
Ratio | 1.08 % |
Changes | 8 | ||
Bugs | 3 | Features | 2 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like src/ub.numbers.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | /** global: UB */ |
||
3 | UB.intMaxValue = 2147483647; |
||
4 | UB.intMinValue = -2147483648; |
||
5 | UB.floatMaxValue = 3.40282e+038; /// 038 or 056? .. it was originally 038F |
||
6 | UB.floatMinValue = -3.40282e+038; |
||
7 | UB.doubleMaxValue = 9223372036854775807; |
||
8 | UB.doubleMinValue = -9223372036854775808; |
||
9 | |||
10 | UB.roman1s = ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"]; |
||
11 | UB.roman10s = ["", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"]; |
||
12 | UB.roman100s = ["", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"]; |
||
13 | UB.roman1000s = ["", "m", "mm", "mmm", "mmmm", "", "", "", "", ""]; |
||
14 | UB.roman = [UB.roman1s, UB.roman10s, UB.roman100s, UB.roman1000s]; |
||
15 | |||
16 | UB.letterLegal = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "BB", "CC", "DD", "EE", "FF", "GG", "HH", "II", "JJ", "KK", "LL", "MM", "NN", "OO", "PP", "QQ", "RR", "SS", "TT", "UU", "VV", "WW", "XX", "YY", "ZZ", "AAA", "BBB", "CCC", "DDD", "EEE", "FFF", "GGG", "HHH", "III", "JJJ", "KKK", "LLL", "MMM", "NNN", "OOO", "PPP", "QQQ", "RRR", "SSS", "TTT", "UUU", "VVV", "WWW", "XXX", "YYY", "ZZZ", "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLL", "MMMM", "NNNN", "OOOO", "PPPP", "QQQQ", "RRRR", "SSSS", "TTTT", "UUUU", "VVVV", "WWWW", "XXXX", "YYYY", "ZZZZ", "AAAAA", "BBBBB", "CCCCC", "DDDDD", "EEEEE", "FFFFF", "GGGGG", "HHHHH", "IIIII", "JJJJJ", "KKKKK", "LLLLL", "MMMMM", "NNNNN", "OOOOO", "PPPPP", "QQQQQ", "RRRRR", "SSSSS", "TTTTT", "UUUUU", "VVVVV", "WWWWW", "XXXXX", "YYYYY", "ZZZZZ"]; |
||
17 | UB.letterExcel = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL", "BM", "BN", "BO", "BP", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BX", "BY", "BZ", "CA", "CB", "CC", "CD", "CE", "CF", "CG", "CH", "CI", "CJ", "CK", "CL", "CM", "CN", "CO", "CP", "CQ", "CR", "CS", "CT", "CU", "CV", "CW", "CX", "CY", "CZ", "DA", "DB", "DC", "DD", "DE", "DF", "DG", "DH", "DI", "DJ", "DK", "DL", "DM", "DN", "DO", "DP", "DQ", "DR", "DS", "DT", "DU", "DV", "DW", "DX", "DY", "DZ"]; |
||
18 | |||
19 | UB.decZeros = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; |
||
20 | UB.hexChars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; |
||
21 | UB.toDegrees = (180 / Math.PI); |
||
22 | UB.toRadians = (Math.PI / 180); |
||
23 | |||
24 | UB.minOf3 = function(num1, num2, num3){ |
||
25 | if (num1 < num2) { |
||
26 | if (num1 < num3) { |
||
27 | return num1; |
||
28 | } |
||
29 | return num3; |
||
30 | } |
||
31 | if (num2 < num3) { |
||
32 | return num2; |
||
33 | } |
||
34 | return num3; |
||
35 | }; |
||
36 | UB.maxOf3 = function(num1, num2, num3){ |
||
37 | if (num1 > num2) { |
||
38 | if (num1 > num3) { |
||
39 | return num1; |
||
40 | } |
||
41 | return num3; |
||
42 | } |
||
43 | if (num2 > num3) { |
||
44 | return num2; |
||
45 | } |
||
46 | return num3; |
||
47 | }; |
||
48 | |||
49 | UB.minOf4 = function(num1, num2, num3, num4){ |
||
50 | if (num1 < num2) { |
||
51 | |||
52 | // 1, 3, 4 |
||
53 | if (num1 < num3) { |
||
54 | |||
55 | // 1, 4 |
||
56 | if (num1 < num4) { |
||
57 | return num1; |
||
58 | } |
||
59 | return num4; |
||
60 | } |
||
61 | |||
62 | // 3, 4 |
||
63 | if (num3 < num4) { |
||
64 | return num3; |
||
65 | } |
||
66 | return num4; |
||
67 | |||
68 | } |
||
69 | |||
70 | // 2, 3, 4 |
||
71 | if (num2 < num3) { |
||
72 | |||
73 | // 2, 4 |
||
74 | if (num2 < num4) { |
||
75 | return num2; |
||
76 | } |
||
77 | return num4; |
||
78 | } |
||
79 | |||
80 | // 3, 4 |
||
81 | if (num3 < num4) { |
||
82 | return num3; |
||
83 | } |
||
84 | return num4; |
||
85 | }; |
||
86 | UB.maxOf4 = function(num1, num2, num3, num4){ |
||
87 | if (num1 > num2) { |
||
88 | |||
89 | // 1, 3, 4 |
||
90 | if (num1 > num3) { |
||
91 | |||
92 | // 1, 4 |
||
93 | if (num1 > num4) { |
||
94 | return num1; |
||
95 | } |
||
96 | return num4; |
||
97 | } |
||
98 | |||
99 | // 3, 4 |
||
100 | if (num3 > num4) { |
||
101 | return num3; |
||
102 | } |
||
103 | return num4; |
||
104 | |||
105 | } |
||
106 | |||
107 | // 2, 3, 4 |
||
108 | if (num2 > num3) { |
||
109 | |||
110 | // 2, 4 |
||
111 | if (num2 > num4) { |
||
112 | return num2; |
||
113 | } |
||
114 | return num4; |
||
115 | |||
116 | } |
||
117 | |||
118 | // 3, 4 |
||
119 | if (num3 > num4) { |
||
120 | return num3; |
||
121 | } |
||
122 | return num4; |
||
123 | }; |
||
124 | |||
125 | /** calc overlap of 2 numeric ranges */ |
||
126 | UB.overlap = function(value1Start, value1End, value2Start, value2End){ |
||
127 | |||
128 | // swap if reversed |
||
129 | if (value1Start > value1End) { |
||
130 | var temp = value1Start; |
||
131 | value1Start = value1End; |
||
132 | value1End = temp; |
||
133 | } |
||
134 | if (value2Start > value2End) { |
||
135 | temp = value2Start; |
||
136 | value2Start = value2End; |
||
137 | value2End = temp; |
||
138 | } |
||
139 | |||
140 | // exit if no overlap |
||
141 | if (value1End < value2Start || value2End < value1Start) { |
||
142 | return 0; |
||
143 | } |
||
144 | |||
145 | // return overlap of 2 ranges |
||
146 | if (value1Start >= value2Start && value1End <= value2End) { |
||
147 | return (value1End - value1Start); |
||
148 | } else if (value2Start >= value1Start && value2End <= value1End) { |
||
149 | return (value2End - value2Start); |
||
150 | } else if (value1Start < value2Start && value1End <= value2End) { |
||
151 | return (value1End - value2Start); |
||
152 | } else if (value2Start < value1Start && value2End <= value1End) { |
||
153 | return (value2End - value1Start); |
||
154 | } |
||
155 | return 0; |
||
156 | }; |
||
157 | |||
158 | // distance between 2 lat/lon coords |
||
159 | UB.latLonDistance = function(latitude1, longitude1, latitude2, longitude2){ |
||
160 | |||
161 | // all lat/lons are floating point numbers in degrees |
||
162 | |||
163 | var theta = longitude1 - longitude2; |
||
164 | var miles = (Math.sin(latitude1*UB.toRadians)*Math.sin(latitude2*UB.toRadians)) + (Math.cos(latitude1*UB.toRadians)*Math.cos(latitude2*UB.toRadians)*Math.cos(theta*UB.toRadians)); |
||
165 | miles = Math.acos(miles); |
||
166 | miles = (miles * UB.toDegrees); |
||
167 | |||
168 | miles = miles * 60 * 1.1515; |
||
169 | var feet = miles*5280; |
||
170 | var yards = feet / 3; |
||
171 | var kilometers = miles*1.609344; |
||
172 | var meters = kilometers*1000; |
||
173 | return [miles, feet, yards, kilometers, meters]; |
||
174 | }; |
||
175 | |||
176 | |||
177 | var stringFuncs = { |
||
178 | |||
179 | /** CONVERT LEGAL LETTER TO NUMBER .. A = 1, B = 2, C = 3 */ |
||
180 | legalNumeralToNumber: function(zeroBased){ |
||
181 | var s = this.toString(); |
||
182 | return UB.letterLegal.indexOf(s.toUpperCase()) + (zeroBased ? 0 : 1); |
||
183 | }, |
||
184 | /** CONVERT EXCEL COLUMN ID TO NUMBER .. A = 1, B = 2, C = 3 */ |
||
185 | excelColumnToNumber: function(zeroBased = false){ |
||
186 | var s = this.toString(); |
||
187 | return UB.letterExcel.indexOf(s.toUpperCase()) + (zeroBased ? 0 : 1); |
||
188 | }, |
||
189 | |||
190 | hexToDecimal: function(onlyDigits = 0){ |
||
191 | var hex = this.toString(); |
||
192 | hex = hex.toUpperCase(); |
||
193 | |||
194 | // remove prefix |
||
195 | if (hex.indexOf("0X") === 0){ |
||
196 | hex = hex.substr(2); |
||
197 | }else if (hex.charAt(0) == "#"){ |
||
198 | hex = hex.substr(1); |
||
199 | } |
||
200 | |||
201 | if (onlyDigits) { |
||
202 | hex = hex.substr(0, onlyDigits); |
||
203 | } |
||
204 | return int("0x" + hex); |
||
205 | }, |
||
206 | |||
207 | binaryToDecimal: function(){ |
||
208 | var bin = this.toString(); |
||
209 | bin = bin.toUpperCase(); |
||
210 | |||
211 | // remove prefix |
||
212 | if (bin.indexOf("0B") === 0){ |
||
213 | bin = bin.substr(2); |
||
214 | } |
||
215 | |||
216 | var byte = 0; |
||
217 | for (var i = 0, il = bin.length, il2 = bin.length - 1;i<il;i++){ |
||
218 | byte += uint(bin.charAt(il2 - i)) * Math.pow(2,i); |
||
219 | } |
||
220 | return byte; |
||
221 | }, |
||
222 | |||
223 | none:null |
||
224 | }; |
||
225 | |||
226 | // register funcs |
||
227 | UB.registerFuncs(String.prototype, stringFuncs); |
||
228 | |||
229 | |||
230 | |||
231 | var numberFuncs = { |
||
232 | |||
233 | View Code Duplication | distance: function(v2, type){ |
|
|
|||
234 | var v1 = this; |
||
235 | // type .. 0=any, 1=pos, 2=neg |
||
236 | var v = v2 - v1; |
||
237 | if (type == 1) { |
||
238 | return v > 0 ? v : -v; |
||
239 | }else if (type == 2) { |
||
240 | return v > 0 ? -v : v; |
||
241 | } |
||
242 | return v; |
||
243 | }, |
||
244 | round: function(){ |
||
245 | return Math.round(this); |
||
246 | }, |
||
247 | ceil: function(){ |
||
248 | return Math.ceil(this); |
||
249 | }, |
||
250 | floor: function(){ |
||
251 | return Math.floor(this); |
||
252 | }, |
||
253 | abs: function(negative = false){ |
||
254 | var v = this; |
||
255 | if (negative){ |
||
256 | return v > 0 ? -v : v; |
||
257 | } |
||
258 | return v > 0 ? v : -v; |
||
259 | }, |
||
260 | acos: function(degrees = false){ |
||
261 | var v = this; |
||
262 | if (degrees) { |
||
263 | return Math.acos(v) * UB.toDegrees; |
||
264 | } |
||
265 | return Math.acos(v); |
||
266 | }, |
||
267 | asin: function(degrees = false){ |
||
268 | var v = this; |
||
269 | if (degrees) { |
||
270 | return Math.asin(v) * UB.toDegrees; |
||
271 | } |
||
272 | return Math.asin(v); |
||
273 | }, |
||
274 | atan: function(degrees = false){ |
||
275 | var v = this; |
||
276 | if (degrees) { |
||
277 | return Math.atan(v) * UB.toDegrees; |
||
278 | } |
||
279 | return Math.atan(v); |
||
280 | }, |
||
281 | atan2: function(x, degrees = false){ |
||
282 | var y = this; |
||
283 | if (degrees) { |
||
284 | return Math.atan2(y, x) * UB.toDegrees; |
||
285 | } |
||
286 | return Math.atan2(y, x); |
||
287 | }, |
||
288 | exp: function(){ |
||
289 | var v = this; |
||
290 | return Math.exp(v); |
||
291 | }, |
||
292 | log: function(){ |
||
293 | var v = this; |
||
294 | return Math.log(v); |
||
295 | }, |
||
296 | pow: function(power){ |
||
297 | var base = this; |
||
298 | return Math.pow(base, power) |
||
299 | }, |
||
300 | sin: function(degrees = false){ |
||
301 | var angle = this; |
||
302 | if (degrees) { |
||
303 | return Math.sin(angle * UB.toRadians); |
||
304 | } |
||
305 | return Math.sin(angle); |
||
306 | }, |
||
307 | cos: function(degrees = false){ |
||
308 | var angle = this; |
||
309 | if (degrees) { |
||
310 | return Math.cos(angle * UB.toRadians); |
||
311 | } |
||
312 | return Math.cos(angle); |
||
313 | }, |
||
314 | tan: function(degrees = false){ |
||
315 | var angle = this; |
||
316 | if (degrees) { |
||
317 | return Math.tan(angle * UB.toRadians); |
||
318 | } |
||
319 | return Math.tan(angle); |
||
320 | }, |
||
321 | sqrt: function(){ |
||
322 | var v = this; |
||
323 | return Math.sqrt(v); |
||
324 | }, |
||
325 | compare: function(v2){ |
||
326 | var v1 = this; |
||
327 | if (v1 < v2) { |
||
328 | return -1; |
||
329 | } |
||
330 | if (v1 > v2) { |
||
331 | return 1; |
||
332 | } |
||
333 | return 0; |
||
334 | }, |
||
335 | positive: function(){ |
||
336 | var val = this; |
||
337 | return val > 0 ? val : -val; |
||
338 | }, |
||
339 | negative: function(){ |
||
340 | var val = this; |
||
341 | return val > 0 ? -val : val; |
||
342 | }, |
||
343 | |||
344 | exists: function(zeroOK = false){ |
||
345 | var v = this; |
||
346 | if (zeroOK) { |
||
347 | return (v == v); |
||
348 | } |
||
349 | return v == v && v != 0; |
||
350 | }, |
||
351 | |||
352 | |||
353 | min: function(num2){ |
||
354 | var num1 = this; |
||
355 | if (num1 < num2) { |
||
356 | return num1; |
||
357 | } |
||
358 | return num2; |
||
359 | }, |
||
360 | max: function(num2){ |
||
361 | var num1 = this; |
||
362 | if (num1 > num2) { |
||
363 | return num1; |
||
364 | } |
||
365 | return num2; |
||
366 | }, |
||
367 | atMost: function(limit){ |
||
368 | var num = this; |
||
369 | return num > limit ? limit : num; |
||
370 | }, |
||
371 | atLeast: function(limit){ |
||
372 | var num = this; |
||
373 | return num < limit ? limit : num; |
||
374 | }, |
||
375 | |||
376 | |||
377 | |||
378 | /** Render a percentage (25%) using 2 values */ |
||
379 | percentageToString: function(current, decimals = 0){ |
||
380 | var total = this; |
||
381 | return ((current / total) * 100).roundTo(decimals) + "%"; |
||
382 | }, |
||
383 | |||
384 | |||
385 | // CONVERT TO ABBREVIATION .. 1.5K |
||
386 | toAbbreviation: function(decimals = 1){ |
||
387 | var num = this; |
||
388 | if (num < 0) { |
||
389 | return "-" + (-num).toAbbreviation; // -5.2K, -5.2M .. |
||
390 | } |
||
391 | if (num < 1000) { |
||
392 | return String(num); // 520 |
||
393 | } |
||
394 | if (num < 1000000) { |
||
395 | return (num / 1000).roundToDigits(decimals) + 'K'; // 5.2K |
||
396 | } |
||
397 | if (num < 1000000000) { |
||
398 | return (num / 1000000).roundToDigits(decimals) + 'M'; // 5.2M |
||
399 | } |
||
400 | return (num / 1000000000).roundToDigits(decimals) + 'G'; // 5.2B |
||
401 | }, |
||
402 | |||
403 | |||
404 | // CONVERT TO ROMAN |
||
405 | toRomanNumeral: function(){ |
||
406 | var n = this; |
||
407 | if (n < 1) { |
||
408 | n = 1; |
||
409 | } |
||
410 | |||
411 | // exit quickly if single digit |
||
412 | if (n <= 9) { |
||
413 | return UB.roman1s[n]; |
||
414 | } |
||
415 | |||
416 | // create roman number if longer |
||
417 | var str = n.toString(); |
||
418 | var output = []; |
||
419 | for (var n = 0, nl = str.length;n<nl;n++){ |
||
420 | var series = ((nl - 1) - n); |
||
421 | var charIndex = int(str.charAt(n)); |
||
422 | output.push(UB.roman[series][charIndex]); |
||
423 | } |
||
424 | return output.join(""); |
||
425 | }, |
||
426 | |||
427 | /** CONVERT TO LEGAL LETTER .. 1 = A, 2 = B, 3 = C .. AA, BB, CC */ |
||
428 | toLegalNumeral: function(){ |
||
429 | var n = this; |
||
430 | if (n < 1) { |
||
431 | n = 1; |
||
432 | } |
||
433 | return UB.letterLegal[n]; |
||
434 | }, |
||
435 | // CONVERT TO NORMAL LETTER .. A, B, C .. AB, AB, AC .. BA, BB, BC |
||
436 | toLetterNumeral: function(){ |
||
437 | var n = this; |
||
438 | if (n <= 26) { |
||
439 | return UB.letterLegal[n]; |
||
440 | } |
||
441 | return "?"; |
||
442 | }, |
||
443 | /** CONVERT TO EXCEL COLUMN ID .. 1 = A, 2 = B, 3 = C .. AA, AB, AC */ |
||
444 | toExcelColumn: function(zeroBased = false){ |
||
445 | var n = this; |
||
446 | var min = zeroBased?0:1; |
||
447 | if (n < min) { |
||
448 | n = min; |
||
449 | } |
||
450 | return UB.letterExcel[zeroBased ? n : n-1]; |
||
451 | }, |
||
452 | |||
453 | // CONVERT TO ORDINAL FORMAT .. 1st, 2nd, 3rd |
||
454 | toOrdinal: function(){ |
||
455 | var i = this; |
||
456 | var j = i % 10; |
||
457 | var k = i % 100; |
||
458 | if (j == 1 && k != 11) { |
||
459 | return i + "st"; |
||
460 | } |
||
461 | if (j == 2 && k != 12) { |
||
462 | return i + "nd"; |
||
463 | } |
||
464 | if (j == 3 && k != 13) { |
||
465 | return i + "rd"; |
||
466 | } |
||
467 | return i + "th"; |
||
468 | }, |
||
469 | |||
470 | |||
471 | // OR |
||
472 | or: function(returnVal, ifNull = 0){ |
||
473 | var n = this; |
||
474 | if (n == ifNull) { |
||
475 | return returnVal; |
||
476 | } |
||
477 | return n; |
||
478 | }, |
||
479 | |||
480 | |||
481 | /** Calc padding for a given length */ |
||
482 | padding: function(multipleOf){ |
||
483 | var length = this; |
||
484 | return (multipleOf - (length % multipleOf)); |
||
485 | }, |
||
486 | |||
487 | multipleOf: function(multipleOf){ |
||
488 | var value = this; |
||
489 | return value + (multipleOf - (value % multipleOf)); |
||
490 | }, |
||
491 | |||
492 | /** Calc x % of the given value */ |
||
493 | percentage: function(percentWanted){ |
||
494 | var val100Percent = this; |
||
495 | if (percentWanted == 100) { |
||
496 | return val100Percent; |
||
497 | } |
||
498 | return val100Percent * (percentWanted / 100.0); |
||
499 | }, |
||
500 | |||
501 | /** Calc the % of otherVal in relation to val100Percent */ |
||
502 | percentOf: function(otherVal){ |
||
503 | var val100Percent = this; |
||
504 | return (otherVal / val100Percent) * 100.0; |
||
505 | }, |
||
506 | |||
507 | /** Calc the difference between 2 numbers in % |
||
508 | // ... 100, 50 shows -50% difference |
||
509 | // ... 100, 150 shows 50% difference */ |
||
510 | percentDifference: function(otherVal){ |
||
511 | var val100Percent = this; |
||
512 | return ((otherVal - val100Percent) / val100Percent) * 100.0; |
||
513 | }, |
||
514 | |||
515 | /** Returns the number halfway between the 2 given numbers |
||
516 | Value1 can be greater than Value2. */ |
||
517 | between: function(value2){ |
||
518 | return this.middle(value2); |
||
519 | }, |
||
520 | |||
521 | /** Returns the number halfway between the 2 given numbers |
||
522 | Value1 can be greater than Value2. */ |
||
523 | middle: function(value2){ |
||
524 | var value1 = this; |
||
525 | if (value1 > value2) { |
||
526 | return value2 + ((value1 - value2) / 2); |
||
527 | } |
||
528 | return value1 + ((value2 - value1) / 2); |
||
529 | }, |
||
530 | |||
531 | calcScale: function(targetValue){ |
||
532 | var value = this; |
||
533 | if (targetValue === 0 && value === 0) { |
||
534 | return 0; |
||
535 | } |
||
536 | return (value / targetValue); |
||
537 | }, |
||
538 | |||
539 | ensure: function(defaultVal){ |
||
540 | var value = this; |
||
541 | if (value === 0) { |
||
542 | return defaultVal; |
||
543 | } |
||
544 | return value; |
||
545 | }, |
||
546 | |||
547 | snapToHigher: function(snapBy){ |
||
548 | var val = this; |
||
549 | return Math.ceil(val / snapBy) * snapBy; |
||
550 | }, |
||
551 | snapToLower: function(snapBy){ |
||
552 | var val = this; |
||
553 | return Math.floor(val / snapBy) * snapBy; |
||
554 | }, |
||
555 | snapTo: function(snapBy){ |
||
556 | var val = this; |
||
557 | return Math.round(val / snapBy) * snapBy; |
||
558 | }, |
||
559 | |||
560 | toInt: function(round){ |
||
561 | var num = this; |
||
562 | if (!round || round == "truncate") { |
||
563 | return parseInt(num); |
||
564 | } |
||
565 | if (round == "round") { |
||
566 | return Math.round(num); |
||
567 | } |
||
568 | if (round == "floor") { |
||
569 | return Math.floor(num); |
||
570 | } |
||
571 | if (round == "ceiling") { |
||
572 | return Math.ceil(num); |
||
573 | } |
||
574 | return 0; |
||
575 | }, |
||
576 | |||
577 | /** |
||
578 | * Formats a Number adding commas and the specified decimal digits. |
||
579 | * Supports the million/billion and lakh/crore system. |
||
580 | * |
||
581 | * @param system "million" or "lakh" |
||
582 | * @param decimals -1 = keep exact decimals as number, 0 = no decimals, 1+ = specific decimals |
||
583 | * @param alwaysShowDecimal add decimal even if decimal part is 0 |
||
584 | */ |
||
585 | formatNumber: function(system, decimals = -1, alwaysShowDecimal = false){ |
||
586 | var num = this; |
||
587 | |||
588 | var commas = system == "lakh" ? 2 : 3; |
||
589 | |||
590 | // test if number is negative |
||
591 | var neg = false; |
||
592 | if (num < 0) { |
||
593 | neg = true; |
||
594 | num = -num; |
||
595 | } |
||
596 | // get the left number |
||
597 | var numStr = String(num); |
||
598 | var hasDot = numStr.indexOf(".")>-1; |
||
599 | if (hasDot) { |
||
600 | var parts = numStr.split("."); |
||
601 | var whole = parts[0]; |
||
602 | var decimal = parts[1]; |
||
603 | }else{ |
||
604 | whole = numStr; |
||
605 | decimal = null; |
||
606 | } |
||
607 | |||
608 | // if at least 4 digits |
||
609 | if (whole.length > 3) { |
||
610 | |||
611 | // extract 3 digits first |
||
612 | var wholeRight3 = whole.substr(whole.length - 3, 3); |
||
613 | whole = whole.substr(0, whole.length - 3); |
||
614 | |||
615 | // add million / crore seperators |
||
616 | if (whole.length < commas) { |
||
617 | whole = whole + "," + wholeRight3; |
||
618 | }else { |
||
619 | var thou = ""; |
||
620 | var rem = whole.substr(0, int(whole.length % commas)); |
||
621 | var l = ((int(whole.length / commas)*commas) - commas) + (whole.length % commas); |
||
622 | for (var c = 0;l >= 0;l -= commas, c++){ |
||
623 | thou = whole.substr(l, commas) + (c === 0 ? "" : ",") + thou; |
||
624 | } |
||
625 | whole = (rem == "" ? "" : rem + ",") + thou + "," + wholeRight3; |
||
626 | } |
||
627 | } |
||
628 | |||
629 | // return with or without dot |
||
630 | var result = whole; |
||
631 | if (hasDot) { |
||
632 | if (decimals > 0) { |
||
633 | // 4.200 |
||
634 | result = whole + "." + decimal.substr(0, decimals).padRight("0", decimals); |
||
635 | }else if (decimals === 0) { |
||
636 | // 4 |
||
637 | //result = whole; |
||
638 | }else if (decimals === -1) { |
||
639 | // 4.2 |
||
640 | result = whole + "." + decimal; |
||
641 | } |
||
642 | |||
643 | }else if (alwaysShowDecimal && decimals > 0) { |
||
644 | |||
645 | // 4.0000 |
||
646 | result = whole + "." + decimals.repeat("0"); |
||
647 | }else { |
||
648 | |||
649 | // 4 |
||
650 | //result = whole; |
||
651 | } |
||
652 | return (neg ? "-" + result : result); |
||
653 | }, |
||
654 | |||
655 | ensureNotNaN: function(instead = 0){ |
||
656 | var val = this; |
||
657 | if (val != val) { /// fast isNaN check |
||
658 | return instead; |
||
659 | } |
||
660 | return val; |
||
661 | }, |
||
662 | |||
663 | scale: function(inputMin, inputMax, outputMin, outputMax, outputLimit = true, outputFlip = false){ |
||
664 | var input = this; |
||
665 | |||
666 | // ensure input within limits |
||
667 | if (input < inputMin) { |
||
668 | input = inputMin; |
||
669 | } |
||
670 | if (input > inputMax) { |
||
671 | input = inputMax; |
||
672 | } |
||
673 | |||
674 | // convert input to % |
||
675 | var percent = ((1*(input - inputMin)) / (inputMax - inputMin)); |
||
676 | |||
677 | // convert % to output |
||
678 | var output = (percent*(outputMax - outputMin)) + outputMin; |
||
679 | |||
680 | // ensure output within limits |
||
681 | if (outputLimit){ |
||
682 | if (output < outputMin) { |
||
683 | output = outputMin; |
||
684 | } |
||
685 | if (output > outputMax) { |
||
686 | output = outputMax; |
||
687 | } |
||
688 | } |
||
689 | |||
690 | // flip output |
||
691 | if (outputFlip) { |
||
692 | output = ((outputMax - outputMin) - (output - outputMin)) + outputMin; |
||
693 | } |
||
694 | |||
695 | // return scaled, limit-checked output |
||
696 | return output; |
||
697 | }, |
||
698 | smartScale: function(inputMin, inputMax, outputMin, outputMax){ |
||
699 | var input = this; |
||
700 | if (inputMin > inputMax) { |
||
701 | if (outputMin > outputMax) { |
||
702 | return input.flipWithin(inputMin, inputMax).scale(inputMax, inputMin, outputMax, outputMin, true, true); |
||
703 | } |
||
704 | return input.flipWithin(inputMin, inputMax).scale(inputMax, inputMin, outputMin, outputMax); |
||
705 | } |
||
706 | if (outputMin > outputMax) { |
||
707 | return input.scale(inputMin, inputMax, outputMax, outputMin, true, true); |
||
708 | } |
||
709 | return input.scale(inputMin, inputMax, outputMin, outputMax); |
||
710 | }, |
||
711 | |||
712 | flipWithin: function(min, max){ |
||
713 | var input = this; |
||
714 | if (max < min) { |
||
715 | return ((min - max) - (input - max)) + min; |
||
716 | } |
||
717 | return ((max - min) - (input - min)) + min; |
||
718 | }, |
||
719 | |||
720 | limitToDigits: function(digits){ |
||
721 | var input = this; |
||
722 | return parseFloat(input.toString().substr(0, digits)); |
||
723 | }, |
||
724 | limit: function(min, max){ |
||
725 | var input = this; |
||
726 | |||
727 | // ensure ok |
||
728 | if (input != input) { /// fast isNaN check |
||
729 | return min; |
||
730 | } |
||
731 | |||
732 | // flip limits if in reverse order |
||
733 | if (min > max) { |
||
734 | var temp = max; |
||
735 | max = min; |
||
736 | min = temp; |
||
737 | } |
||
738 | |||
739 | // ensure within limits |
||
740 | if (input < min) { |
||
741 | return min; |
||
742 | }else if (input > max) { |
||
743 | return max; |
||
744 | } |
||
745 | return input; |
||
746 | }, |
||
747 | limitToArray: function(array, extraMax = 0, extraMin = 0){ |
||
748 | var pointer = this; |
||
749 | if (pointer <= -extraMin) { |
||
750 | return -extraMin; |
||
751 | } |
||
752 | var last = (array.length + extraMax) - 1; |
||
753 | if (last === -1) { |
||
754 | return -extraMin; |
||
755 | }else if (pointer > last) { |
||
756 | return last; |
||
757 | } |
||
758 | return pointer; |
||
759 | }, |
||
760 | |||
761 | wrap: function(min, max){ |
||
762 | var input = this; |
||
763 | |||
764 | // flip limits if in reverse order |
||
765 | if (min > max) { |
||
766 | var temp = max; |
||
767 | max = min; |
||
768 | min = temp; |
||
769 | } |
||
770 | |||
771 | // ensure wrapped to limits |
||
772 | var diff = (max - min) + 1; |
||
773 | while (input < min) { |
||
774 | input += diff; |
||
775 | } |
||
776 | while (input > max) { |
||
777 | input -= diff; |
||
778 | } |
||
779 | return input; |
||
780 | }, |
||
781 | wrapToMax: function(max){ |
||
782 | var value = this; |
||
783 | var diff = max + 1; |
||
784 | while (value < 0) { |
||
785 | value += diff; |
||
786 | } |
||
787 | return value % diff; |
||
788 | }, |
||
789 | |||
790 | /** Identical to modulo operator, except negative values are also supported, and brought into positive range. |
||
791 | Value will never reach limit, just like the modulo operator. |
||
792 | Simpler than `wrap` which takes `min` and `max`. */ |
||
793 | modulo: function(limit){ |
||
794 | var input = this; |
||
795 | |||
796 | // ensure wrapped to limits |
||
797 | while (input < 0) { |
||
798 | input += limit; |
||
799 | } |
||
800 | while (input >= limit) { |
||
801 | input -= limit; |
||
802 | } |
||
803 | return input; |
||
804 | }, |
||
805 | |||
806 | roundToDigits: function(decimals = 4){ |
||
807 | var input = this; |
||
808 | |||
809 | if (decimals <= 0) { |
||
810 | return Math.round(input); |
||
811 | } |
||
812 | |||
813 | // Returns a number rounded to specified number of decimals |
||
814 | var multiplier = Math.pow(10, decimals); |
||
815 | return Math.round(input*multiplier)/multiplier; |
||
816 | }, |
||
817 | roundTo: function(decimals){ |
||
818 | var input = this; |
||
819 | |||
820 | // Returns a number rounded to specified number of decimals |
||
821 | // Add zeros to always return those many decimals |
||
822 | var num = input.roundToDigits(decimals).toString(); |
||
823 | if (decimals <= 0) { |
||
824 | return num; |
||
825 | } |
||
826 | var add0 = 0; |
||
827 | if (num.lastIndexOf(".") === -1){ |
||
828 | num = num+"."; |
||
829 | add0 = decimals; |
||
830 | }else{ |
||
831 | add0 = decimals - ((num.length - num.lastIndexOf(".")) - 1); |
||
832 | } |
||
833 | while(add0 > 0){ |
||
834 | num = num+"0"; |
||
835 | add0 --; |
||
836 | } |
||
837 | return num; |
||
838 | }, |
||
839 | |||
840 | |||
841 | |||
842 | // HEX |
||
843 | toHex: function(digits = 6, withHash = true){ |
||
844 | var num = this; |
||
845 | var zeros = ("0000000000000000000000000000000000").substr(0, digits - 1); |
||
846 | return ((withHash ? "#" : "") + (zeros + num.toString(16).toUpperCase()).substr( -digits)); |
||
847 | }, |
||
848 | |||
849 | incrementWithin: function(min, max){ |
||
850 | var num = this; |
||
851 | num++; |
||
852 | if (num > max) { |
||
853 | return min; |
||
854 | } |
||
855 | return num; |
||
856 | }, |
||
857 | decrementWithin: function(min, max){ |
||
858 | var num = this; |
||
859 | num--; |
||
860 | if (num < min) { |
||
861 | return max; |
||
862 | } |
||
863 | return num; |
||
864 | }, |
||
865 | |||
866 | |||
867 | decimalToBinary: function(digits = 8, alt = false){ |
||
868 | if (alt){ |
||
869 | var byte = this; |
||
870 | var bin = ''; |
||
871 | for (var i = 0;i<digits;i++){ |
||
872 | bin += String((byte & (0x80 >> i)) >> (7 - i)); |
||
873 | } |
||
874 | return bin; |
||
875 | } |
||
876 | var num = this; |
||
877 | var zeros = UB.decZeros.substr(0, digits - 1); |
||
878 | return (zeros + num.toString(2)).substr( -digits); |
||
879 | }, |
||
880 | |||
881 | |||
882 | |||
883 | // MISC MATH |
||
884 | pad: function(length, addToEnd = false, padChar = '0'){ |
||
885 | var number = this; |
||
886 | |||
887 | // num to text |
||
888 | var result = String(number); |
||
889 | |||
890 | // exit quickly if already reached target len |
||
891 | if (result.length >= length) { |
||
892 | return result; |
||
893 | } |
||
894 | |||
895 | |||
896 | // pad |
||
897 | if (addToEnd) { |
||
898 | while (result.length < length){ |
||
899 | result = result + padChar; |
||
900 | } |
||
901 | }else { |
||
902 | while (result.length < length){ |
||
903 | result = padChar + result; |
||
904 | } |
||
905 | } |
||
906 | |||
907 | |||
908 | return result; |
||
909 | }, |
||
910 | interpolate: function(min, max){ |
||
911 | var progress = this; |
||
912 | // progress = (0 to 1) |
||
913 | return min + ((max - min) * progress); |
||
914 | }, |
||
915 | hypot: function(b){ |
||
916 | var a = this; |
||
917 | // sqrt(a^2 + b^2) without under/overflow. |
||
918 | |||
919 | var r; |
||
920 | var aAbs = (a > 0 ? a : -a); |
||
921 | var bAbs = (b > 0 ? b : -b); |
||
922 | if (aAbs > bAbs) { |
||
923 | r = b/a; |
||
924 | r = aAbs*Math.sqrt(1+r*r); |
||
925 | } else if (b != 0) { |
||
926 | r = a/b; |
||
927 | r = bAbs*Math.sqrt(1+r*r); |
||
928 | } else { |
||
929 | r = 0.0; |
||
930 | } |
||
931 | return r; |
||
932 | }, |
||
933 | apow: function(value){ |
||
934 | var pow = this; |
||
935 | // input: 1,2,4,8,16,32,64 |
||
936 | // output: 1,2,3,4,5,6,7 |
||
937 | if (value == 1 || value === -1) return value; |
||
938 | var count = 0; |
||
939 | while (value != 0) { |
||
940 | //remainder = value % pow; |
||
941 | value = value / pow; |
||
942 | count++; |
||
943 | } |
||
944 | return count; |
||
945 | }, |
||
946 | invert: function(){ |
||
947 | var value = this; |
||
948 | // input: 0.1 0.5 1 2 8 |
||
949 | // output: 10 2 1 0.5 0.2 |
||
950 | return 1 / value; |
||
951 | }, |
||
952 | powAbs: function(exponent){ |
||
953 | var x = this; |
||
954 | // This function always returns a positive value that conforms to the expected Exponent curve. |
||
955 | // Math.pow: If x is negative, and exponent is not an integer, returns NaN. |
||
956 | if( x >= 0 ) { |
||
957 | return Math.pow( x, exponent ); |
||
958 | } |
||
959 | return Math.pow(-x, 1/exponent); |
||
960 | }, |
||
961 | |||
962 | // count digits in number |
||
963 | getWhole: function(){ |
||
964 | var val = this; |
||
965 | |||
966 | // -10.235 has 2 whole digits |
||
967 | return int(val); |
||
968 | }, |
||
969 | setWhole: function(newval){ |
||
970 | var val = this; |
||
971 | return newval + GetFractional(val); |
||
972 | }, |
||
973 | getFractional: function(){ |
||
974 | var val = this; |
||
975 | |||
976 | // -10.235 has 3 fractional digits |
||
977 | var s = (val < 0 ? -val : val).toString(); |
||
978 | var i = s.indexOf("."); |
||
979 | return (i === -1) ? int(val) : int(s.substr(i + 1)); |
||
980 | }, |
||
981 | setFractional: function(fraction){ |
||
982 | var val = this; |
||
983 | return Number((parseInt(val).toString()) + "." + fraction.toString()); |
||
984 | }, |
||
985 | |||
986 | |||
987 | |||
988 | // SLOT INDEX |
||
989 | minIndex: function(index2){ |
||
990 | var index1 = this; |
||
991 | if (index1 <= -1) { |
||
992 | return index2; |
||
993 | } |
||
994 | if (index2 <= -1) { |
||
995 | return index1; |
||
996 | } |
||
997 | if (index1 < index2) { |
||
998 | return index1; |
||
999 | } |
||
1000 | return index2; |
||
1001 | }, |
||
1002 | maxIndex: function(index2){ |
||
1003 | var index1 = this; |
||
1004 | if (index1 <= -1) { |
||
1005 | return index2; |
||
1006 | } |
||
1007 | if (index2 <= -1) { |
||
1008 | return index1; |
||
1009 | } |
||
1010 | if (index1 > index2) { |
||
1011 | return index1; |
||
1012 | } |
||
1013 | return index2; |
||
1014 | }, |
||
1015 | |||
1016 | |||
1017 | |||
1018 | none:null |
||
1019 | }; |
||
1020 | |||
1021 | // register funcs |
||
1022 | UB.registerFuncs(Number.prototype, numberFuncs); |
||
1023 | |||
1024 |