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