1  /**
     2   * com.sekati.math.MathBase
     3   * @version 1.1.9
     4   * @author jason m horwitz | sekati.com
     5   * Copyright (C) 2007  jason m horwitz, Sekat LLC. All Rights Reserved.
     6   * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
     7   */
     8  
     9  import com.sekati.math.Integer;
    10  
    11  /**
    12   * Static class wrapping various Math utilities.
    13   */
    14  class com.sekati.math.MathBase {			
    15  
    16  	/**
    17  	 * Returns the highest value of all passed arguments
    18  	 * Like Math.max() but supports any number of args passed to it
    19  	 * @return Number
    20  	 */
    21  	public static function max():Number {
    22  		return maxArray( arguments );
    23  	}
    24  
    25  	/**
    26  	 * Returns the lowest value of all passed arguments
    27  	 * Like Math.min() but supports any number of args passed to it
    28  	 * @return Number
    29  	 */
    30  	public static function min():Number {
    31  		return minArray( arguments );
    32  	}
    33  
    34  	/**
    35  	 * Returns the highest value of all items in array
    36  	 * Like Math.max() but supports any number of items
    37  	 * @param a (Array)
    38  	 * @return Number
    39  	 */
    40  	public static function maxArray(a:Array):Number {
    41  		var val:Number = null;
    42  		for (var i in a) {
    43  			if (a[i] > val || val == null) {
    44  				val = Number( a[i] );
    45  			}
    46  		}
    47  		return val;
    48  	}
    49  
    50  	/**
    51  	 * Returns the lowest value of all items in array
    52  	 * Like Math.min() but supports any number of items
    53  	 * @param a (Array)
    54  	 * @return Number
    55  	 */
    56  	public static function minArray(a:Array):Number {
    57  		var val:Number = null;
    58  		for (var i in a) {
    59  			if (a[i] < val || val == null) {
    60  				val = Number( a[i] );
    61  			}
    62  		}
    63  		return val;
    64  	}
    65  
    66  	/**
    67  	 * Same as Math.foor with extra argument to specify number of decimals
    68  	 * @param val (Number)
    69  	 * @param decimal (Number)
    70  	 * @return Number
    71  	 */
    72  	public static function floor(val:Number, decimal:Number):Number {
    73  		var n:Number = Math.pow( 10, decimal );
    74  		return Math.floor( val * n ) / n;
    75  	}	
    76  
    77  	/**
    78  	 * Round to a given amount of decimals
    79  	 * @param val (Number)
    80  	 * @param decimal (Number)
    81  	 * @return Number
    82  	 */
    83  	public static function round(val:Number, decimal:Number):Number {
    84  		return Math.round( val * Math.pow( 10, decimal ) ) / Math.pow( 10, decimal );
    85  	}
    86  
    87  	/**
    88  	 * Round to nearest .5
    89  	 * @param val (Number)
    90  	 * @return Number
    91  	 * {@code Example:
    92  	 * 	trace(MathBase.roundHalf(4.47)); // returns 4.5
    93  	 * }
    94  	 */	
    95  	public static function roundHalf(val:Number):Number {
    96  		var num:String = String( Math.round( val * 10 ) / 10 );
    97  		var tmp:Array = num.split( "." );
    98  		var integer:Object = tmp[0]; 
    99  		// loose type since we swap from String to Number (cheap!)
   100  		var decimal:Number = tmp[1];
   101  		if (decimal >= 3 && decimal <= 7 && decimal != null) {
   102  			decimal = 5;
   103  		} else {
   104  			if (decimal > 7) {
   105  				integer = Number( integer ) + 1;
   106  			}
   107  			decimal = 0;
   108  		}
   109  		return Number( integer + "." + decimal );
   110  	}
   111  
   112  	/**
   113  	 * Will constrain a value to the defined boundaries
   114  	 * @param val (Number)
   115  	 * @param min (Number)
   116  	 * @param max (Number)
   117  	 * @return Number
   118  	 * {@code Examples:
   119  	 * val: 20, 2 to 5    this will give back 5 since 5 is the top boundary
   120  	 * val: 3, 2 to 5     this will give back 3
   121  	 * }
   122  	 */
   123  	public static function constrain(val:Number, min:Number, max:Number):Number {
   124  		if (val < min) {
   125  			val = min;
   126  		} else if (val > max) {
   127  			val = max;
   128  		}
   129  		return val;
   130  	}
   131  
   132  	/**
   133  	 * Return the proportional value of two pairs of numbers.
   134  	 * @param x1 (Number)
   135  	 * @param x2 (Number)
   136  	 * @param y1 (Number)
   137  	 * @param y2 (Number)
   138  	 * @param x (Number) optional
   139  	 * @return Number
   140  	 */
   141  	public static function proportion(x1:Number, x2:Number, y1:Number, y2:Number, x:Number):Number {
   142  		var n:Number = (!x) ? 1 : x;
   143  		var slope:Number = (y2 - y1) / (x2 - x1);
   144  		return (slope * (n - x1) + y1);
   145  	}
   146  
   147  	/**
   148  	 * Check if number is positive (zero is considered positive)
   149  	 * @param n (Number)
   150  	 * @return Boolean
   151  	 */
   152  	public static function isPositive(n:Number):Boolean {
   153  		return (n >= 0);
   154  	}
   155  
   156  	/**
   157  	 * Check if number is negative
   158  	 * @param n (Number)
   159  	 * @return Boolean
   160  	 */
   161  	public static function isNegative(n:Number):Boolean {
   162  		return (n < 0);
   163  	}	
   164  
   165  	/**
   166  	 * Check if number is Odd (convert to Integer if necessary)
   167  	 * @param n (Number)
   168  	 * @return Boolean
   169  	 */
   170  	public static function isOdd(n:Number):Boolean {
   171  		var i:Integer = new Integer( n );
   172  		var e:Integer = new Integer( 2 );
   173  		return Boolean( i % e );	
   174  	}
   175  
   176  	/**
   177  	 * Check if number is Even (convert to Integer if necessary)
   178  	 * @param n (Number)
   179  	 * @return Boolean
   180  	 */
   181  	public static function isEven(n:Number):Boolean {
   182  		var int:Integer = new Integer( n );
   183  		var e:Integer = new Integer( 2 );
   184  		return (int % e == 0);
   185  	}
   186  
   187  	/**
   188  	 * Check if number is Prime (divisible only itself and one)
   189  	 * @param n (Number)
   190  	 * @return Boolean
   191  	 */
   192  	public static function isPrime(n:Number):Boolean {
   193  		if (n > 2 && n % 2 == 0) return false;
   194  		var l:Number = Math.sqrt( n );
   195  		for (var i:Number = 3; i <= l ; i += 2) {
   196  			if (n % i == 0) return false;
   197  		}
   198  	}
   199  
   200  	/**
   201  	 * Calculate the factorial of the integer.
   202  	 * @param n (Number) 
   203  	 * @return Number
   204  	 */
   205  	 
   206  	public static function factorial(n:Number):Number {
   207  		if (n == 0) return 1;
   208  		var d:Number = n.valueOf( );
   209  		var i:Number = d - 1;
   210  		while (i) {
   211  			d = d * i;
   212  			i--;
   213  		}
   214  		return d;
   215  	}
   216  
   217  	/**
   218  	 * Return an array of divisors of the integer.
   219  	 * @param n (Number)
   220  	 * @return Number
   221  	 */
   222  	public static function getDivisors(n:Number):Array {
   223  		var r:Array = new Array( );
   224  		for (var i:Number = 1, e:Number = n / 2; i <= e ; i++) {
   225  			if (n % i == 0) r.push( i );
   226  		}
   227  		if (n != 0) r.push( n.valueOf( ) );
   228  		return r;
   229  	}
   230  
   231  	/**
   232  	 * Check if number is an Integer
   233  	 * @param n (Number)
   234  	 * @return Boolean
   235  	 */
   236  	public static function isInteger(n:Number):Boolean {
   237  		return (n % 1 == 0);
   238  	}
   239  
   240  	/**
   241  	 * Check if number is Natural (positive Integer)
   242  	 * @param n (Number)
   243  	 * @return Boolean
   244  	 */
   245  	public static function isNatural(n:Number):Boolean {
   246  		return (n >= 0 && n % 1 == 0);
   247  	}
   248  
   249  	/**
   250  	 * Returns a random number inside a specific range
   251  	 * @param start (Number)
   252  	 * @param end (Number)
   253  	 * @return Number
   254  	 */	
   255  	public static function rnd(start:Number, end:Number):Number {
   256  		return Math.round( Math.random( ) * (end - start) ) + start;
   257  	}
   258  
   259  	/**
   260  	 * Correct "roundoff errors" in floating point math.
   261  	 * @param n (Number)
   262  	 * @param precision (Number) - optional [default: returns (10000 * number) / 10000]
   263  	 * @return Number
   264  	 * @see {@link http://www.zeuslabs.us/2007/01/30/flash-floating-point-number-errors/} 
   265  	 */
   266  	public static function sanitizeFloat(n:Number, precision:Number):Number {
   267  		var p:Number = (!precision) ? 5 : int( precision );
   268  		var c:Number = Math.pow( 10, p );
   269  		return Math.round( c * n ) / c;
   270  	}
   271  
   272  	/**
   273  	 * Evaluate if two numbers are nearly equal
   274  	 * @param n1 (Number)
   275  	 * @param n2 (Number)
   276  	 * @param precision (Number) - optional [default: 0.00001 <diff> -0.00001]
   277  	 * @return Boolean
   278  	 * @see {@link http://www.zeuslabs.us/2007/01/30/flash-floating-point-number-errors/}
   279  	 */
   280  	public static function fuzzyEval(n1:Number, n2:Number, precision:Number):Boolean {
   281  		var d:Number = n1 - n2;
   282  		var p:Number = (!precision) ? 5 : int( precision );
   283  		var r:Number = Math.pow( 10, -p );
   284  		return d < r && d > -r;
   285  	}	
   286  
   287  	private function MathBase() {
   288  	}
   289  }