Total Complexity | 271 |
Complexity/F | 2.74 |
Lines of Code | 1165 |
Function Count | 99 |
Duplicated Lines | 55 |
Ratio | 4.72 % |
Changes | 2 | ||
Bugs | 1 | Features | 1 |
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 | 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"]; |
||
16 | 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"]; |
||
17 | UB.decZeros = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; |
||
18 | UB.hexChars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; |
||
19 | UB.toDegrees = (180 / Math.PI); |
||
20 | UB.toRadians = (Math.PI / 180); |
||
21 | |||
22 | UB.minOf3 = function(num1, num2, num3){ |
||
23 | if (num1 < num2) { |
||
24 | if (num1 < num3) { |
||
25 | return num1; |
||
26 | }else { |
||
|
|||
27 | return num3; |
||
28 | } |
||
29 | }else { |
||
30 | if (num2 < num3) { |
||
31 | return num2; |
||
32 | }else { |
||
33 | return num3; |
||
34 | } |
||
35 | } |
||
36 | }; |
||
37 | UB.maxOf3 = function(num1, num2, num3){ |
||
38 | if (num1 > num2) { |
||
39 | if (num1 > num3) { |
||
40 | return num1; |
||
41 | }else { |
||
42 | return num3; |
||
43 | } |
||
44 | }else { |
||
45 | if (num2 > num3) { |
||
46 | return num2; |
||
47 | }else { |
||
48 | return num3; |
||
49 | } |
||
50 | } |
||
51 | }; |
||
52 | |||
53 | UB.minOf4 = function(num1, num2, num3, num4){ |
||
54 | if (num1 < num2) { |
||
55 | |||
56 | // 1, 3, 4 |
||
57 | if (num1 < num3) { |
||
58 | |||
59 | // 1, 4 |
||
60 | if (num1 < num4) { |
||
61 | return num1; |
||
62 | }else { |
||
63 | return num4; |
||
64 | } |
||
65 | }else { |
||
66 | |||
67 | // 3, 4 |
||
68 | if (num3 < num4) { |
||
69 | return num3; |
||
70 | }else { |
||
71 | return num4; |
||
72 | } |
||
73 | } |
||
74 | |||
75 | }else { |
||
76 | |||
77 | // 2, 3, 4 |
||
78 | if (num2 < num3) { |
||
79 | |||
80 | // 2, 4 |
||
81 | if (num2 < num4) { |
||
82 | return num2; |
||
83 | }else { |
||
84 | return num4; |
||
85 | } |
||
86 | }else { |
||
87 | |||
88 | // 3, 4 |
||
89 | if (num3 < num4) { |
||
90 | return num3; |
||
91 | }else { |
||
92 | return num4; |
||
93 | } |
||
94 | } |
||
95 | } |
||
96 | }; |
||
97 | UB.maxOf4 = function(num1, num2, num3, num4){ |
||
98 | if (num1 > num2) { |
||
99 | |||
100 | // 1, 3, 4 |
||
101 | if (num1 > num3) { |
||
102 | |||
103 | // 1, 4 |
||
104 | if (num1 > num4) { |
||
105 | return num1; |
||
106 | }else { |
||
107 | return num4; |
||
108 | } |
||
109 | }else { |
||
110 | |||
111 | // 3, 4 |
||
112 | if (num3 > num4) { |
||
113 | return num3; |
||
114 | }else { |
||
115 | return num4; |
||
116 | } |
||
117 | } |
||
118 | |||
119 | }else { |
||
120 | |||
121 | // 2, 3, 4 |
||
122 | if (num2 > num3) { |
||
123 | |||
124 | // 2, 4 |
||
125 | if (num2 > num4) { |
||
126 | return num2; |
||
127 | }else { |
||
128 | return num4; |
||
129 | } |
||
130 | }else { |
||
131 | |||
132 | // 3, 4 |
||
133 | if (num3 > num4) { |
||
134 | return num3; |
||
135 | }else { |
||
136 | return num4; |
||
137 | } |
||
138 | } |
||
139 | } |
||
140 | }; |
||
141 | |||
142 | /** calc overlap of 2 numeric ranges */ |
||
143 | UB.overlap = function(value1Start, value1End, value2Start, value2End){ |
||
144 | |||
145 | // swap if reversed |
||
146 | if (value1Start > value1End) { |
||
147 | var temp = value1Start; |
||
148 | value1Start = value1End; |
||
149 | value1End = temp; |
||
150 | } |
||
151 | if (value2Start > value2End) { |
||
152 | temp = value2Start; |
||
153 | value2Start = value2End; |
||
154 | value2End = temp; |
||
155 | } |
||
156 | |||
157 | // exit if no overlap |
||
158 | if (value1End < value2Start || value2End < value1Start) { |
||
159 | return 0; |
||
160 | } |
||
161 | |||
162 | // return overlap of 2 ranges |
||
163 | if (value1Start >= value2Start && value1End <= value2End) { |
||
164 | return (value1End - value1Start); |
||
165 | } else if (value2Start >= value1Start && value2End <= value1End) { |
||
166 | return (value2End - value2Start); |
||
167 | } else if (value1Start < value2Start && value1End <= value2End) { |
||
168 | return (value1End - value2Start); |
||
169 | } else if (value2Start < value1Start && value2End <= value1End) { |
||
170 | return (value2End - value1Start); |
||
171 | } |
||
172 | return 0; |
||
173 | }; |
||
174 | |||
175 | // distance between 2 lat/lon coords |
||
176 | UB.latLonDistance = function(latitude1, longitude1, latitude2, longitude2){ |
||
177 | |||
178 | // all lat/lons are floating point numbers in degrees |
||
179 | |||
180 | var theta = longitude1 - longitude2; |
||
181 | 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)); |
||
182 | miles = Math.acos(miles); |
||
183 | miles = (miles * UB.toDegrees); |
||
184 | |||
185 | miles = miles * 60 * 1.1515; |
||
186 | var feet = miles*5280; |
||
187 | var yards = feet / 3; |
||
188 | var kilometers = miles*1.609344; |
||
189 | var meters = kilometers*1000; |
||
190 | return [miles, feet, yards, kilometers, meters]; |
||
191 | }; |
||
192 | |||
193 | |||
194 | var stringFuncs = { |
||
195 | |||
196 | /** CONVERT LEGAL LETTER TO NUMBER .. A = 1, B = 2, C = 3 */ |
||
197 | legalNumeralToNumber: function(zeroBased){ |
||
198 | var s = this.toString(); |
||
199 | return UB.letterLegal.indexOf(s.toUpperCase()) + (zeroBased ? 0 : 1); |
||
200 | }, |
||
201 | /** CONVERT EXCEL COLUMN ID TO NUMBER .. A = 1, B = 2, C = 3 */ |
||
202 | excelColumnToNumber: function(zeroBased = false){ |
||
203 | var s = this.toString(); |
||
204 | return UB.letterExcel.indexOf(s.toUpperCase()) + (zeroBased ? 0 : 1); |
||
205 | }, |
||
206 | |||
207 | hexToDecimal: function(onlyDigits = 0){ |
||
208 | var hex = this.toString(); |
||
209 | hex = hex.toUpperCase(); |
||
210 | |||
211 | // remove prefix |
||
212 | if (hex.indexOf("0X") == 0){ |
||
1 ignored issue
–
show
|
|||
213 | hex = hex.substr(2); |
||
214 | }else if (hex.charAt(0) == "#"){ |
||
215 | hex = hex.substr(1); |
||
216 | } |
||
217 | |||
218 | if (onlyDigits) { |
||
219 | hex = hex.substr(0, onlyDigits); |
||
220 | } |
||
221 | return int("0x" + hex); |
||
222 | }, |
||
223 | |||
224 | binaryToDecimal: function(){ |
||
225 | var num = bin.toString(); |
||
226 | bin = bin.toUpperCase(); |
||
227 | |||
228 | // remove prefix |
||
229 | if (bin.indexOf("0B") == 0){ |
||
1 ignored issue
–
show
|
|||
230 | bin = bin.substr(2); |
||
231 | } |
||
232 | |||
233 | var byte = 0; |
||
234 | for (var i = 0, il = bin.length, il2 = bin.length - 1;i<il;i++){ |
||
235 | byte += uint(bin.charAt(il2 - i)) * Math.pow(2,i); |
||
236 | } |
||
237 | return byte; |
||
238 | }, |
||
239 | |||
240 | none:null |
||
241 | }; |
||
242 | |||
243 | // register funcs |
||
244 | UB.registerFuncs(String.prototype, stringFuncs); |
||
245 | |||
246 | |||
247 | |||
248 | var numberFuncs = { |
||
249 | |||
250 | isOdd: function(){ |
||
251 | var val = this; |
||
252 | return (val % 2) != 0; |
||
1 ignored issue
–
show
|
|||
253 | }, |
||
254 | isEven: function(){ |
||
255 | var val = this; |
||
256 | return (val % 2) == 0; |
||
1 ignored issue
–
show
|
|||
257 | }, |
||
258 | isPositive: function(){ |
||
259 | var val = this; |
||
260 | return (val > 0); |
||
261 | }, |
||
262 | isNegative: function(){ |
||
263 | var val = this; |
||
264 | return (val < 0); |
||
265 | }, |
||
266 | View Code Duplication | relativeTo: function(v2, type){ |
|
267 | var v1 = this; |
||
268 | // type .. 0=any, 1=pos, 2=neg |
||
269 | var v = v2 - v1; |
||
270 | if (type == 1) { |
||
1 ignored issue
–
show
|
|||
271 | return v > 0 ? v : -v; |
||
272 | }else if (type == 2) { |
||
273 | return v > 0 ? -v : v; |
||
274 | } |
||
275 | return v; |
||
276 | }, |
||
277 | abs: function(negative = false){ |
||
278 | var v = this; |
||
279 | if (negative){ |
||
280 | return v > 0 ? -v : v; |
||
281 | } |
||
282 | return v > 0 ? v : -v; |
||
283 | }, |
||
284 | acos: function(degrees = false){ |
||
285 | var v = this; |
||
286 | if (degrees) { |
||
287 | return Math.acos(v) * UB.toDegrees; |
||
288 | } |
||
289 | return Math.acos(v); |
||
290 | }, |
||
291 | asin: function(degrees = false){ |
||
292 | var v = this; |
||
293 | if (degrees) { |
||
294 | return Math.asin(v) * UB.toDegrees; |
||
295 | } |
||
296 | return Math.asin(v); |
||
297 | }, |
||
298 | atan: function(degrees = false){ |
||
299 | var v = this; |
||
300 | if (degrees) { |
||
301 | return Math.atan(v) * UB.toDegrees; |
||
302 | } |
||
303 | return Math.atan(v); |
||
304 | }, |
||
305 | atan2: function(x, degrees = false){ |
||
306 | var y = this; |
||
307 | if (degrees) { |
||
308 | return Math.atan2(y, x) * UB.toDegrees; |
||
309 | } |
||
310 | return Math.atan2(y, x); |
||
311 | }, |
||
312 | exp: function(){ |
||
313 | var v = this; |
||
314 | return Math.exp(v); |
||
315 | }, |
||
316 | log: function(){ |
||
317 | var v = this; |
||
318 | return Math.log(v); |
||
319 | }, |
||
320 | pow: function(power){ |
||
321 | var base = this; |
||
322 | return Math.pow(base, power) |
||
323 | }, |
||
324 | sin: function(degrees = false){ |
||
325 | var angle = this; |
||
326 | if (degrees) { |
||
327 | return Math.sin(angle * UB.toRadians); |
||
328 | } |
||
329 | return Math.sin(angle); |
||
330 | }, |
||
331 | cos: function(degrees = false){ |
||
332 | var angle = this; |
||
333 | if (degrees) { |
||
334 | return Math.cos(angle * UB.toRadians); |
||
335 | } |
||
336 | return Math.cos(angle); |
||
337 | }, |
||
338 | tan: function(degrees = false){ |
||
339 | var angle = this; |
||
340 | if (degrees) { |
||
341 | return Math.tan(angle * UB.toRadians); |
||
342 | } |
||
343 | return Math.tan(angle); |
||
344 | }, |
||
345 | sqrt: function(){ |
||
346 | var v = this; |
||
347 | return Math.sqrt(v); |
||
348 | }, |
||
349 | compare: function(v2){ |
||
350 | var v1 = this; |
||
351 | if (v1 < v2) { |
||
352 | return -1; |
||
353 | } |
||
354 | if (v1 > v2) { |
||
355 | return 1; |
||
356 | } |
||
357 | return 0; |
||
358 | }, |
||
359 | positive: function(){ |
||
360 | var val = this; |
||
361 | return val > 0 ? val : -val; |
||
362 | }, |
||
363 | negative: function(){ |
||
364 | var val = this; |
||
365 | return val > 0 ? -val : val; |
||
366 | }, |
||
367 | |||
368 | exists: function(zeroOK = false){ |
||
369 | var v = this; |
||
370 | if (zeroOK) { |
||
371 | return (v != null && v == v); |
||
1 ignored issue
–
show
|
|||
372 | } |
||
373 | return v != null && v == v && v != 0; |
||
374 | }, |
||
375 | |||
376 | |||
377 | min: function(num2){ |
||
378 | var num1 = this; |
||
379 | if (num1 < num2) { |
||
380 | return num1; |
||
381 | }else { |
||
382 | return num2; |
||
383 | } |
||
384 | }, |
||
385 | max: function(num2){ |
||
386 | var num1 = this; |
||
387 | if (num1 > num2) { |
||
388 | return num1; |
||
389 | }else { |
||
390 | return num2; |
||
391 | } |
||
392 | }, |
||
393 | atMost: function(limit){ |
||
394 | var num = this; |
||
395 | return num > limit ? limit : num; |
||
396 | }, |
||
397 | atLeast: function(limit){ |
||
398 | var num = this; |
||
399 | return num < limit ? limit : num; |
||
400 | }, |
||
401 | |||
402 | |||
403 | isNear: function(target, near = 1){ |
||
404 | var val = this; |
||
405 | return val >= (target - near) && val <= (target + near); |
||
406 | }, |
||
407 | |||
408 | |||
409 | /** Render a percentage (25%) using 2 values */ |
||
410 | percentageToString: function(current, decimals = 0){ |
||
411 | var total = this; |
||
412 | return ((current / total) * 100).roundToString(decimals) + "%"; |
||
413 | }, |
||
414 | |||
415 | |||
416 | // CONVERT TO ABBREVIATION .. 1.5K |
||
417 | toAbbreviation: function(decimals = 1){ |
||
418 | var num = this; |
||
419 | if (num < 0) { |
||
420 | return "-" + (-num).toAbbreviation; // -5.2K, -5.2M .. |
||
421 | } |
||
422 | if (num < 1000) { |
||
423 | return String(num); // 520 |
||
424 | } |
||
425 | if (num < 1000000) { |
||
426 | return (num / 1000).roundToDigits(decimals) + 'K'; // 5.2K |
||
427 | } |
||
428 | if (num < 1000000000) { |
||
429 | return (num / 1000000).roundToDigits(decimals) + 'M'; // 5.2M |
||
430 | } |
||
431 | return (num / 1000000000).roundToDigits(decimals) + 'G'; // 5.2B |
||
432 | }, |
||
433 | |||
434 | |||
435 | // CONVERT TO ROMAN |
||
436 | toRomanNumeral: function(){ |
||
437 | var n = this; |
||
438 | if (n < 1) { |
||
439 | n = 1; |
||
440 | } |
||
441 | |||
442 | // exit quickly if single digit |
||
443 | if (n <= 9) { |
||
444 | return UB.roman1s[n]; |
||
445 | } |
||
446 | |||
447 | // create roman number if longer |
||
448 | var str = n.toString(); |
||
449 | var output = []; |
||
450 | for (var n = 0, nl = str.length;n<nl;n++){ |
||
451 | var series = ((nl - 1) - n); |
||
452 | var charIndex = int(str.charAt(n)); |
||
453 | output.push(UB.roman[series][charIndex]); |
||
454 | } |
||
455 | return output.join(""); |
||
456 | }, |
||
457 | |||
458 | /** CONVERT TO LEGAL LETTER .. 1 = A, 2 = B, 3 = C .. AA, BB, CC */ |
||
459 | toLegalNumeral: function(){ |
||
460 | var n = this; |
||
461 | if (n < 1) { |
||
462 | n = 1; |
||
463 | } |
||
464 | return UB.letterLegal[n]; |
||
465 | }, |
||
466 | // CONVERT TO NORMAL LETTER .. A, B, C .. AB, AB, AC .. BA, BB, BC |
||
467 | toLetterNumeral: function(){ |
||
468 | var n = this; |
||
469 | if (n <= 26) { |
||
470 | return UB.letterLegal[n]; |
||
471 | } |
||
472 | return "?"; |
||
473 | }, |
||
474 | /** CONVERT TO EXCEL COLUMN ID .. 1 = A, 2 = B, 3 = C .. AA, AB, AC */ |
||
475 | toExcelColumn: function(zeroBased = false){ |
||
476 | var n = this; |
||
477 | var min = zeroBased?0:1; |
||
478 | if (n < min) { |
||
479 | n = min; |
||
480 | } |
||
481 | return UB.letterExcel[zeroBased ? n : n-1]; |
||
482 | }, |
||
483 | |||
484 | // CONVERT TO ORDINAL FORMAT .. 1st, 2nd, 3rd |
||
485 | toOrdinal: function(){ |
||
486 | var i = this; |
||
487 | var j = i % 10; |
||
488 | var k = i % 100; |
||
489 | if (j == 1 && k != 11) { |
||
1 ignored issue
–
show
|
|||
490 | return i + "st"; |
||
491 | } |
||
492 | if (j == 2 && k != 12) { |
||
493 | return i + "nd"; |
||
494 | } |
||
495 | if (j == 3 && k != 13) { |
||
496 | return i + "rd"; |
||
497 | } |
||
498 | return i + "th"; |
||
499 | }, |
||
500 | |||
501 | |||
502 | // OR |
||
503 | or: function(returnVal, ifNull = 0){ |
||
504 | var n = this; |
||
505 | if (n == ifNull) { |
||
506 | return returnVal; |
||
507 | } |
||
508 | return n; |
||
509 | }, |
||
510 | |||
511 | |||
512 | /** Calc padding for a given length */ |
||
513 | padding: function(multipleOf){ |
||
514 | var length = this; |
||
515 | return (multipleOf - (length % multipleOf)); |
||
516 | }, |
||
517 | |||
518 | multipleOf: function(multipleOf){ |
||
519 | var value = this; |
||
520 | return value + (multipleOf - (value % multipleOf)); |
||
521 | }, |
||
522 | |||
523 | |||
524 | // FROM C# |
||
525 | |||
526 | distance: function(n2){ |
||
527 | var n1 = this; |
||
528 | return Math.abs(n1 - n2); |
||
529 | }, |
||
530 | |||
531 | /** Calc x % of the given value */ |
||
532 | percentage: function(percentWanted){ |
||
533 | var val100Percent = this; |
||
534 | if (percentWanted == 100) { |
||
535 | return val100Percent; |
||
536 | } |
||
537 | return val100Percent * (percentWanted / 100.0); |
||
538 | }, |
||
539 | |||
540 | /** Calc the % of otherVal in relation to val100Percent */ |
||
541 | percentOf: function(otherVal){ |
||
542 | var val100Percent = this; |
||
543 | return (otherVal / val100Percent) * 100.0; |
||
544 | }, |
||
545 | |||
546 | /** Calc the difference between 2 numbers in % |
||
547 | // ... 100, 50 shows -50% difference |
||
548 | // ... 100, 150 shows 50% difference */ |
||
549 | percentDifference: function(otherVal){ |
||
550 | var val100Percent = this; |
||
551 | return ((otherVal - val100Percent) / val100Percent) * 100.0; |
||
552 | }, |
||
553 | |||
554 | isConsequetive: function(value, value2){ |
||
555 | return value2 == (value - 1) || value2 == (value + 1); |
||
556 | }, |
||
557 | |||
558 | /** Returns the number halfway between the 2 given numbers |
||
559 | Value1 can be greater than Value2. */ |
||
560 | between: function(value2){ |
||
561 | var value1 = this; |
||
562 | if (value1 > value2) { |
||
563 | return value2 + ((value1 - value2) / 2); |
||
564 | } |
||
565 | return value1 + ((value2 - value1) / 2); |
||
566 | }, |
||
567 | |||
568 | /** Returns the number halfway between the 2 given numbers |
||
569 | Value1 can be greater than Value2. */ |
||
570 | middle: function(value2){ |
||
571 | var value1 = this; |
||
572 | if (value1 > value2) { |
||
573 | return value2 + ((value1 - value2) / 2); |
||
574 | } |
||
575 | return value1 + ((value2 - value1) / 2); |
||
576 | }, |
||
577 | |||
578 | calcScale: function(targetValue){ |
||
579 | var value = this; |
||
580 | if (targetValue == 0 && value == 0) { |
||
2 ignored issues
–
show
|
|||
581 | return 0; |
||
582 | } |
||
583 | return (value / targetValue); |
||
584 | }, |
||
585 | |||
586 | ensure: function(defaultVal){ |
||
587 | var value = this; |
||
588 | if (value == 0) { |
||
1 ignored issue
–
show
|
|||
589 | return defaultVal; |
||
590 | } |
||
591 | return value; |
||
592 | }, |
||
593 | |||
594 | snapToHigher: function(snapBy){ |
||
595 | var val = this; |
||
596 | return Math.ceil(val / snapBy) * snapBy; |
||
597 | }, |
||
598 | snapToLower: function(snapBy){ |
||
599 | var val = this; |
||
600 | return Math.floor(val / snapBy) * snapBy; |
||
601 | }, |
||
602 | snapToNearest: function(snapBy){ |
||
603 | var val = this; |
||
604 | return Math.round(val / snapBy) * snapBy; |
||
605 | }, |
||
606 | |||
607 | toInt: function(round){ |
||
608 | var num = this; |
||
609 | if (!round || round == "truncate") { |
||
610 | return parseInt(num); |
||
611 | } |
||
612 | if (round == "round") { |
||
613 | return Math.round(num); |
||
614 | } |
||
615 | if (round == "floor") { |
||
616 | return Math.floor(num); |
||
617 | } |
||
618 | if (round == "ceiling") { |
||
619 | return Math.ceil(num); |
||
620 | } |
||
621 | return 0; |
||
622 | }, |
||
623 | |||
624 | /** |
||
625 | * Formats a Number adding commas and the specified decimal digits. |
||
626 | * Supports the million/billion and lakh/crore system. |
||
627 | * |
||
628 | * @param system "million" or "lakh" |
||
629 | * @param decimals -1 = keep exact decimals as number, 0 = no decimals, 1+ = specific decimals |
||
630 | * @param alwaysShowDecimal add decimal even if decimal part is 0 |
||
631 | */ |
||
632 | formatNumber: function(system, decimals = -1, alwaysShowDecimal = false){ |
||
633 | var num = this; |
||
634 | |||
635 | var commas = system == "lakh" ? 2 : 3; |
||
636 | |||
637 | // test if number is negative |
||
638 | var neg = false; |
||
639 | if (num < 0) { |
||
640 | neg = true; |
||
641 | num = -num; |
||
642 | } |
||
643 | // get the left number |
||
644 | var numStr = String(num); |
||
645 | var hasDot = numStr.indexOf(".")>-1; |
||
646 | if (hasDot) { |
||
647 | var parts = numStr.split("."); |
||
648 | var whole = parts[0]; |
||
649 | var decimal = parts[1]; |
||
650 | }else{ |
||
651 | whole = numStr; |
||
652 | decimal = null; |
||
653 | } |
||
654 | |||
655 | // if at least 4 digits |
||
656 | if (whole.length > 3) { |
||
657 | |||
658 | // extract 3 digits first |
||
659 | var wholeRight3 = whole.substr(whole.length - 3, 3); |
||
660 | whole = whole.substr(0, whole.length - 3); |
||
661 | |||
662 | // add million / crore seperators |
||
663 | if (whole.length < commas) { |
||
664 | whole = whole + "," + wholeRight3; |
||
665 | }else { |
||
666 | var thou = ""; |
||
667 | var rem = whole.substr(0, int(whole.length % commas)); |
||
668 | var l = ((int(whole.length / commas)*commas) - commas) + (whole.length % commas); |
||
669 | for (var c = 0;l >= 0;l -= commas, c++){ |
||
670 | thou = whole.substr(l, commas) + (c == 0 ? "" : ",") + thou; |
||
1 ignored issue
–
show
|
|||
671 | } |
||
672 | whole = (rem == "" ? "" : rem + ",") + thou + "," + wholeRight3; |
||
673 | } |
||
674 | } |
||
675 | |||
676 | // return with or without dot |
||
677 | var result = whole; |
||
678 | if (hasDot) { |
||
679 | if (decimals > 0) { |
||
680 | // 4.200 |
||
681 | result = whole + "." + decimal.substr(0, decimals).padRight("0", decimals); |
||
682 | }else if (decimals == 0) { |
||
1 ignored issue
–
show
|
|||
683 | // 4 |
||
684 | result = whole; |
||
685 | }else if (decimals == -1) { |
||
686 | // 4.2 |
||
687 | result = whole + "." + decimal; |
||
688 | } |
||
689 | |||
690 | }else if (alwaysShowDecimal && decimals > 0) { |
||
691 | |||
692 | // 4.0000 |
||
693 | result = whole + "." + decimals.repeat("0"); |
||
694 | }else { |
||
695 | |||
696 | // 4 |
||
697 | result = whole; |
||
698 | } |
||
699 | return (neg ? "-" + result : result); |
||
700 | }, |
||
701 | |||
702 | ensureNotNaN: function(instead = 0){ |
||
703 | var val = this; |
||
704 | if (val != val) { /// fast isNaN check |
||
705 | return instead; |
||
706 | }else { |
||
707 | return val; |
||
708 | } |
||
709 | }, |
||
710 | |||
711 | isNaN: function(){ |
||
712 | var val = this; |
||
713 | return val != val || isNaN(val); |
||
714 | }, |
||
715 | |||
716 | isAny: function(haystacks, asInt = false, fractionalDigits = -1){ |
||
717 | var needle = this; |
||
718 | |||
719 | // return true if any haystack equals the needle |
||
720 | for (var s = 0, sl = haystacks.length;s<sl;s++){ |
||
721 | var num = haystacks[s]; |
||
722 | |||
723 | // simplify value for comparison |
||
724 | if (asInt) { |
||
725 | num = int(num); |
||
726 | }else if(fractionalDigits != -1) { |
||
727 | num = num.roundToDigits(fractionalDigits); |
||
728 | } |
||
729 | |||
730 | if (needle == num) { |
||
731 | return true; |
||
732 | } |
||
733 | } |
||
734 | return false; |
||
735 | }, |
||
736 | |||
737 | scale: function(inputMin, inputMax, outputMin, outputMax, outputLimit = true, outputFlip = false){ |
||
738 | var input = this; |
||
739 | |||
740 | // ensure input within limits |
||
741 | if (input < inputMin) { |
||
742 | input = inputMin; |
||
743 | } |
||
744 | if (input > inputMax) { |
||
745 | input = inputMax; |
||
746 | } |
||
747 | |||
748 | // convert input to % |
||
749 | var percent = ((1*(input - inputMin)) / (inputMax - inputMin)); |
||
750 | |||
751 | // convert % to output |
||
752 | var output = (percent*(outputMax - outputMin)) + outputMin; |
||
753 | |||
754 | // ensure output within limits |
||
755 | if (outputLimit){ |
||
756 | if (output < outputMin) { |
||
757 | output = outputMin; |
||
758 | } |
||
759 | if (output > outputMax) { |
||
760 | output = outputMax; |
||
761 | } |
||
762 | } |
||
763 | |||
764 | // flip output |
||
765 | if (outputFlip) { |
||
766 | output = ((outputMax - outputMin) - (output - outputMin)) + outputMin; |
||
767 | } |
||
768 | |||
769 | // return scaled, limit-checked output |
||
770 | return output; |
||
771 | }, |
||
772 | smartScale: function(inputMin, inputMax, outputMin, outputMax){ |
||
773 | var input = this; |
||
774 | if (inputMin > inputMax) { |
||
775 | if (outputMin > outputMax) { |
||
776 | return input.flipWithin(inputMin, inputMax).scale(inputMax, inputMin, outputMax, outputMin, true, true); |
||
777 | } else { |
||
778 | return input.flipWithin(inputMin, inputMax).scale(inputMax, inputMin, outputMin, outputMax); |
||
779 | } |
||
780 | } else { |
||
781 | if (outputMin > outputMax) { |
||
782 | return input.scale(inputMin, inputMax, outputMax, outputMin, true, true); |
||
783 | } else { |
||
784 | return input.scale(inputMin, inputMax, outputMin, outputMax); |
||
785 | } |
||
786 | } |
||
787 | }, |
||
788 | |||
789 | flipWithin: function(min, max){ |
||
790 | var input = this; |
||
791 | if (max < min) { |
||
792 | return ((min - max) - (input - max)) + min; |
||
793 | } |
||
794 | return ((max - min) - (input - min)) + min; |
||
795 | }, |
||
796 | |||
797 | limitToDigits: function(digits){ |
||
798 | var input = this; |
||
799 | return parseFloat(input.toString().substr(0, digits)); |
||
800 | }, |
||
801 | View Code Duplication | limit: function(min, max){ |
|
802 | var input = this; |
||
803 | |||
804 | // ensure ok |
||
805 | if (input != input) { /// fast isNaN check |
||
806 | return min; |
||
807 | } |
||
808 | |||
809 | // flip limits if in reverse order |
||
810 | if (min > max) { |
||
811 | var temp = max; |
||
812 | max = min; |
||
813 | min = temp; |
||
814 | } |
||
815 | |||
816 | // ensure within limits |
||
817 | if (input < min) { |
||
818 | return min; |
||
819 | } |
||
820 | if (input > max) { |
||
821 | return max; |
||
822 | } |
||
823 | return input; |
||
824 | }, |
||
825 | limitToArray: function(array, extraMax = 0, extraMin = 0){ |
||
826 | var pointer = this; |
||
827 | if (pointer <= -extraMin) { |
||
828 | return -extraMin; |
||
829 | } |
||
830 | var last = (array.length + extraMax) - 1; |
||
831 | if (last == -1) { |
||
832 | return -extraMin; |
||
833 | } |
||
834 | if (pointer > last) { |
||
835 | return last; |
||
836 | } |
||
837 | return pointer |
||
838 | }, |
||
839 | |||
840 | wrap: function(min, max){ |
||
841 | var value = this; |
||
842 | value -= min; |
||
843 | var diff = (max - min) + 1; |
||
844 | while (value < 0) { |
||
845 | value += diff; |
||
846 | } |
||
847 | return min + (value % diff); |
||
848 | }, |
||
849 | View Code Duplication | wrap2: function(min, max){ |
|
850 | var input = this; |
||
851 | |||
852 | // flip limits if in reverse order |
||
853 | if (min > max) { |
||
854 | var temp = max; |
||
855 | max = min; |
||
856 | min = temp; |
||
857 | } |
||
858 | |||
859 | // ensure wrapped to limits |
||
860 | var diff = (max - min) + 1; |
||
861 | while (input < min) { |
||
862 | input += diff; |
||
863 | } |
||
864 | while (input > max) { |
||
865 | input -= diff; |
||
866 | } |
||
867 | return input; |
||
868 | }, |
||
869 | wrapToMax: function(max){ |
||
870 | var value = this; |
||
871 | var diff = max + 1; |
||
872 | while (value < 0) { |
||
873 | value += diff; |
||
874 | } |
||
875 | return value % diff; |
||
876 | }, |
||
877 | |||
878 | /** Identical to modulo operator, except negative values are also supported, and brought into positive range. |
||
879 | Value will never reach limit, just like the modulo operator. |
||
880 | Simpler than `wrap` which takes `min` and `max`. */ |
||
881 | modulo: function(limit){ |
||
882 | var input = this; |
||
883 | |||
884 | // ensure wrapped to limits |
||
885 | while (input < 0) { |
||
886 | input += limit; |
||
887 | } |
||
888 | while (input >= limit) { |
||
889 | input -= limit; |
||
890 | } |
||
891 | return input; |
||
892 | }, |
||
893 | |||
894 | roundToDigits: function(decimals = 4){ |
||
895 | var input = this; |
||
896 | |||
897 | if (decimals <= 0) { |
||
898 | return Math.round(input); |
||
899 | } |
||
900 | |||
901 | // Returns a number rounded to specified number of decimals |
||
902 | var multiplier = Math.pow(10, decimals); |
||
903 | return Math.round(input*multiplier)/multiplier; |
||
904 | }, |
||
905 | roundToString: function(decimals){ |
||
906 | var input = this; |
||
907 | |||
908 | // Returns a number rounded to specified number of decimals |
||
909 | // Add zeros to always return those many decimals |
||
910 | var num = RoundTo(input, decimals).toString(); |
||
911 | if (decimals <= 0) { |
||
912 | return num; |
||
913 | } |
||
914 | var add0 = 0; |
||
915 | if (num.lastIndexOf(".") == -1){ |
||
916 | num = num+"."; |
||
917 | add0 = decimals; |
||
918 | }else{ |
||
919 | add0 = decimals - ((num.length - num.lastIndexOf(".")) - 1); |
||
920 | } |
||
921 | while(add0 > 0){ |
||
922 | num = num+"0"; |
||
923 | add0 --; |
||
924 | } |
||
925 | return num; |
||
926 | }, |
||
927 | |||
928 | |||
929 | // CHECKS |
||
930 | /** Checks if the value is within min and max (supporting inclusive/exclusive modes) */ |
||
931 | isWithin: function(min, max, inclusive = true){ |
||
932 | var num = this; |
||
933 | if (inclusive) { |
||
934 | if (min > max) { |
||
935 | return (num >= max && num <= min); |
||
936 | } |
||
937 | return (num >= min && num <= max); |
||
938 | } else { |
||
939 | if (min > max) { |
||
940 | return (num > max && num < min); |
||
941 | } |
||
942 | return (num > min && num < max); |
||
943 | } |
||
944 | }, |
||
945 | isWithinArray: function(arr){ |
||
946 | var slot = this; |
||
947 | |||
948 | // no, if array empty / index negative / index more than last slot |
||
949 | var len = arr.length; |
||
950 | if (len == 0 || slot < 0 || slot >= len) { |
||
1 ignored issue
–
show
|
|||
951 | return false; |
||
952 | } |
||
953 | |||
954 | // else yes |
||
955 | return true; |
||
956 | }, |
||
957 | /** Checks if the value is > min and < max */ |
||
958 | isBetween: function(min, max){ |
||
959 | var num = this; |
||
960 | return (num > min && num < max); |
||
961 | }, |
||
962 | isOutside: function(min, max, inclusive = true){ |
||
963 | var num = this; |
||
964 | if (inclusive) { |
||
965 | return num <= min || num >= max; |
||
966 | } |
||
967 | return num < min || num > max; |
||
968 | }, |
||
969 | isFractional: function(){ |
||
970 | var num = this; |
||
971 | return int(num) != num; |
||
972 | }, |
||
973 | isInteger: function(){ |
||
974 | var num = this; |
||
975 | return int(num) == num; |
||
976 | }, |
||
977 | |||
978 | |||
979 | // HEX |
||
980 | /** DO NOT USE THIS FOR `uint`s! */ |
||
981 | toHex: function(digits = 6, withHash = true){ |
||
982 | var num = this; |
||
983 | var zeros = ("0000000000000000000000000000000000").substr(0, digits - 1); |
||
984 | return ((withHash ? "#" : "") + (zeros + num.toString(16).toUpperCase()).substr( -digits)); |
||
985 | }, |
||
986 | /** USE THIS FOR `uint`s! */ |
||
987 | toHexUInt: function(digits = 8, withHash = true){ |
||
988 | var num = this; |
||
989 | var zeros = ("0000000000000000000000000000000000").substr(0, digits - 1); |
||
990 | return ((withHash ? "#" : "") + (zeros + num.toString(16).toUpperCase()).substr( -digits)); |
||
991 | }, |
||
992 | |||
993 | incrementWithin: function(min, max){ |
||
994 | var num = this; |
||
995 | num++; |
||
996 | if (num > max) { |
||
997 | return min; |
||
998 | } |
||
999 | return num; |
||
1000 | }, |
||
1001 | decrementWithin: function(min, max){ |
||
1002 | var num = this; |
||
1003 | num--; |
||
1004 | if (num < min) { |
||
1005 | return max; |
||
1006 | } |
||
1007 | return num; |
||
1008 | }, |
||
1009 | |||
1010 | |||
1011 | decimalToBinary: function(num, digits = 8){ |
||
1012 | var zeros = UB.decZeros.substr(0, digits - 1); |
||
1013 | return (zeros + num.toString(2)).substr( -digits); |
||
1014 | }, |
||
1015 | decimalToBinary2: function(byte, digits = 8){ |
||
1016 | var bin = ''; |
||
1017 | for (var i = 0;i<digits;i++){ |
||
1018 | bin += String((byte & (0x80 >> i)) >> (7 - i)); |
||
1019 | } |
||
1020 | return bin; |
||
1021 | }, |
||
1022 | |||
1023 | |||
1024 | |||
1025 | // MISC MATH |
||
1026 | pad: function(number, length, addToEnd = false, padChar = '0'){ |
||
1027 | |||
1028 | // num to text |
||
1029 | var result = String(number); |
||
1030 | |||
1031 | // exit quickly if already reached target len |
||
1032 | if (result.length >= length) { |
||
1033 | return result; |
||
1034 | } |
||
1035 | |||
1036 | |||
1037 | // pad |
||
1038 | if (addToEnd) { |
||
1039 | while (result.length < length){ |
||
1040 | result = result + padChar; |
||
1041 | } |
||
1042 | }else { |
||
1043 | while (result.length < length){ |
||
1044 | result = padChar + result; |
||
1045 | } |
||
1046 | } |
||
1047 | |||
1048 | |||
1049 | return result; |
||
1050 | }, |
||
1051 | interpolate: function(min, max){ |
||
1052 | var progress = this; |
||
1053 | // progress = (0 to 1) |
||
1054 | /*return( (1 - progress) * min + progress * max ); <---- WHAT IS THIS??? */ |
||
1055 | return min + ((max - min) * progress); |
||
1056 | }, |
||
1057 | hypot: function(b){ |
||
1058 | var a = this; |
||
1059 | // sqrt(a^2 + b^2) without under/overflow. |
||
1060 | |||
1061 | var r; |
||
1062 | var aAbs = (a > 0 ? a : -a); |
||
1063 | var bAbs = (b > 0 ? b : -b); |
||
1064 | if (aAbs > bAbs) { |
||
1065 | r = b/a; |
||
1066 | r = aAbs*Math.sqrt(1+r*r); |
||
1067 | } else if (b != 0) { |
||
1 ignored issue
–
show
|
|||
1068 | r = a/b; |
||
1069 | r = bAbs*Math.sqrt(1+r*r); |
||
1070 | } else { |
||
1071 | r = 0.0; |
||
1072 | } |
||
1073 | return r; |
||
1074 | }, |
||
1075 | apow: function(value){ |
||
1076 | var pow = this; |
||
1077 | // input: 1,2,4,8,16,32,64 |
||
1078 | // output: 1,2,3,4,5,6,7 |
||
1079 | if (value == 1 || value == -1) return value; |
||
1 ignored issue
–
show
|
|||
1080 | var count = 0; |
||
1081 | while (value != 0) { |
||
1082 | //remainder = value % pow; |
||
1083 | value = value / pow; |
||
1084 | count++; |
||
1085 | } |
||
1086 | return count; |
||
1087 | }, |
||
1088 | invert: function(){ |
||
1089 | var value = this; |
||
1090 | // input: 0.1 0.5 1 2 8 |
||
1091 | // output: 10 2 1 0.5 0.2 |
||
1092 | return 1 / value; |
||
1093 | }, |
||
1094 | powAbs: function(exponent){ |
||
1095 | var x = this; |
||
1096 | // This function always returns a positive value that conforms to the expected Exponent curve. |
||
1097 | // Math.pow: If x is negative, and exponent is not an integer, returns NaN. |
||
1098 | if( x >= 0 ) { |
||
1099 | return Math.pow( x, exponent ); |
||
1100 | } else { |
||
1101 | return Math.pow(-x, 1/exponent); |
||
1102 | } |
||
1103 | }, |
||
1104 | |||
1105 | // count digits in number |
||
1106 | getWhole: function(){ |
||
1107 | var val = this; |
||
1108 | |||
1109 | // -10.235 has 2 whole digits |
||
1110 | return int(val); |
||
1111 | }, |
||
1112 | setWhole: function(newval){ |
||
1113 | var val = this; |
||
1114 | return newval + GetFractional(val); |
||
1115 | }, |
||
1116 | getFractional: function(){ |
||
1117 | var val = this; |
||
1118 | |||
1119 | // -10.235 has 3 fractional digits |
||
1120 | var s = (val < 0 ? -val : val).toString(); |
||
1121 | var i = s.indexOf("."); |
||
1122 | return (i == -1) ? int(val) : int(s.substr(i + 1)); |
||
1123 | }, |
||
1124 | setFractional: function(fraction){ |
||
1125 | var val = this; |
||
1126 | return Number((parseInt(val).toString()) + "." + fraction.toString()); |
||
1127 | }, |
||
1128 | |||
1129 | |||
1130 | |||
1131 | // SLOT INDEX |
||
1132 | minIndex: function(index2){ |
||
1133 | var index1 = this; |
||
1134 | if (index1 <= -1) { |
||
1135 | return index2; |
||
1136 | } |
||
1137 | if (index2 <= -1) { |
||
1138 | return index1; |
||
1139 | } |
||
1140 | if (index1 < index2) { |
||
1141 | return index1; |
||
1142 | } else { |
||
1143 | return index2; |
||
1144 | } |
||
1145 | }, |
||
1146 | maxIndex: function(index2){ |
||
1147 | var index1 = this; |
||
1148 | if (index1 <= -1) { |
||
1149 | return index2; |
||
1150 | } |
||
1151 | if (index2 <= -1) { |
||
1152 | return index1; |
||
1153 | } |
||
1154 | if (index1 > index2) { |
||
1155 | return index1; |
||
1156 | } else { |
||
1157 | return index2; |
||
1158 | } |
||
1159 | }, |
||
1160 | |||
1161 | |||
1162 | |||
1163 | none:null |
||
1164 | }; |
||
1165 | |||
1166 | // register funcs |
||
1167 | UB.registerFuncs(Number.prototype, numberFuncs); |
||
1168 | |||
1169 |