Issues (81)

src/ub.numbers.js (1 issue)

1
/** global: UB */
2
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){
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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