master
Raw Download raw file
  1
  2  'use strict';
  3
  4  /***
  5   * @package Number
  6   * @dependency core
  7   * @description Number formatting, rounding (with precision), and ranges. Aliases to Math methods.
  8   *
  9   ***/
 10
 11
 12  function abbreviateNumber(num, roundTo, str, mid, limit, bytes) {
 13    var fixed        = num.toFixed(20),
 14        decimalPlace = fixed.search(/\./),
 15        numeralPlace = fixed.search(/[1-9]/),
 16        significant  = decimalPlace - numeralPlace,
 17        unit, i, divisor;
 18    if(significant > 0) {
 19      significant -= 1;
 20    }
 21    i = max(min(floor(significant / 3), limit === false ? str.length : limit), -mid);
 22    unit = str.charAt(i + mid - 1);
 23    if(significant < -9) {
 24      i = -3;
 25      roundTo = abs(significant) - 9;
 26      unit = str.slice(0,1);
 27    }
 28    divisor = bytes ? pow(2, 10 * i) : pow(10, i * 3);
 29    return withPrecision(num / divisor, roundTo || 0).format() + unit.trim();
 30  }
 31
 32
 33  extend(number, false, true, {
 34
 35    /***
 36     * @method Number.random([n1], [n2])
 37     * @returns Number
 38     * @short Returns a random integer between [n1] and [n2].
 39     * @extra If only 1 number is passed, the other will be 0. If none are passed, the number will be either 0 or 1.
 40     * @example
 41     *
 42     *   Number.random(50, 100) -> ex. 85
 43     *   Number.random(50)      -> ex. 27
 44     *   Number.random()        -> ex. 0
 45     *
 46     ***/
 47    'random': function(n1, n2) {
 48      var minNum, maxNum;
 49      if(arguments.length == 1) n2 = n1, n1 = 0;
 50      minNum = min(n1 || 0, isUndefined(n2) ? 1 : n2);
 51      maxNum = max(n1 || 0, isUndefined(n2) ? 1 : n2) + 1;
 52      return floor((math.random() * (maxNum - minNum)) + minNum);
 53    }
 54
 55  });
 56
 57  extend(number, true, true, {
 58
 59    /***
 60     * @method log(<base> = Math.E)
 61     * @returns Number
 62     * @short Returns the logarithm of the number with base <base>, or natural logarithm of the number if <base> is undefined.
 63     * @example
 64     *
 65     *   (64).log(2) -> 6
 66     *   (9).log(3)  -> 2
 67     *   (5).log()   -> 1.6094379124341003
 68     *
 69     ***/
 70
 71    'log': function(base) {
 72       return math.log(this) / (base ? math.log(base) : 1);
 73     },
 74
 75    /***
 76     * @method abbr([precision] = 0)
 77     * @returns String
 78     * @short Returns an abbreviated form of the number.
 79     * @extra [precision] will round to the given precision.
 80     * @example
 81     *
 82     *   (1000).abbr()    -> "1k"
 83     *   (1000000).abbr() -> "1m"
 84     *   (1280).abbr(1)   -> "1.3k"
 85     *
 86     ***/
 87    'abbr': function(precision) {
 88      return abbreviateNumber(this, precision, 'kmbt', 0, 4);
 89    },
 90
 91    /***
 92     * @method metric([precision] = 0, [limit] = 1)
 93     * @returns String
 94     * @short Returns the number as a string in metric notation.
 95     * @extra [precision] will round to the given precision. Both very large numbers and very small numbers are supported. [limit] is the upper limit for the units. The default is %1%, which is "kilo". If [limit] is %false%, the upper limit will be "exa". The lower limit is "nano", and cannot be changed.
 96     * @example
 97     *
 98     *   (1000).metric()            -> "1k"
 99     *   (1000000).metric()         -> "1,000k"
100     *   (1000000).metric(0, false) -> "1M"
101     *   (1249).metric(2) + 'g'     -> "1.25kg"
102     *   (0.025).metric() + 'm'     -> "25mm"
103     *
104     ***/
105    'metric': function(precision, limit) {
106      return abbreviateNumber(this, precision, 'nμm kMGTPE', 4, isUndefined(limit) ? 1 : limit);
107    },
108
109    /***
110     * @method bytes([precision] = 0, [limit] = 4)
111     * @returns String
112     * @short Returns an abbreviated form of the number, considered to be "Bytes".
113     * @extra [precision] will round to the given precision. [limit] is the upper limit for the units. The default is %4%, which is "terabytes" (TB). If [limit] is %false%, the upper limit will be "exa".
114     * @example
115     *
116     *   (1000).bytes()                 -> "1kB"
117     *   (1000).bytes(2)                -> "0.98kB"
118     *   ((10).pow(20)).bytes()         -> "90,949,470TB"
119     *   ((10).pow(20)).bytes(0, false) -> "87EB"
120     *
121     ***/
122    'bytes': function(precision, limit) {
123      return abbreviateNumber(this, precision, 'kMGTPE', 0, isUndefined(limit) ? 4 : limit, true) + 'B';
124    },
125
126    /***
127     * @method isInteger()
128     * @returns Boolean
129     * @short Returns true if the number has no trailing decimal.
130     * @example
131     *
132     *   (420).isInteger() -> true
133     *   (4.5).isInteger() -> false
134     *
135     ***/
136    'isInteger': function() {
137      return this % 1 == 0;
138    },
139
140    /***
141     * @method isOdd()
142     * @returns Boolean
143     * @short Returns true if the number is odd.
144     * @example
145     *
146     *   (3).isOdd()  -> true
147     *   (18).isOdd() -> false
148     *
149     ***/
150    'isOdd': function() {
151      return !isNaN(this) && !this.isMultipleOf(2);
152    },
153
154    /***
155     * @method isEven()
156     * @returns Boolean
157     * @short Returns true if the number is even.
158     * @example
159     *
160     *   (6).isEven()  -> true
161     *   (17).isEven() -> false
162     *
163     ***/
164    'isEven': function() {
165      return this.isMultipleOf(2);
166    },
167
168    /***
169     * @method isMultipleOf(<num>)
170     * @returns Boolean
171     * @short Returns true if the number is a multiple of <num>.
172     * @example
173     *
174     *   (6).isMultipleOf(2)  -> true
175     *   (17).isMultipleOf(2) -> false
176     *   (32).isMultipleOf(4) -> true
177     *   (34).isMultipleOf(4) -> false
178     *
179     ***/
180    'isMultipleOf': function(num) {
181      return this % num === 0;
182    },
183
184
185    /***
186     * @method format([place] = 0, [thousands] = ',', [decimal] = '.')
187     * @returns String
188     * @short Formats the number to a readable string.
189     * @extra If [place] is %undefined%, will automatically determine the place. [thousands] is the character used for the thousands separator. [decimal] is the character used for the decimal point.
190     * @example
191     *
192     *   (56782).format()           -> '56,782'
193     *   (56782).format(2)          -> '56,782.00'
194     *   (4388.43).format(2, ' ')      -> '4 388.43'
195     *   (4388.43).format(2, '.', ',') -> '4.388,43'
196     *
197     ***/
198    'format': function(place, thousands, decimal) {
199      var i, str, split, integer, fraction, result = '';
200      if(isUndefined(thousands)) {
201        thousands = ',';
202      }
203      if(isUndefined(decimal)) {
204        decimal = '.';
205      }
206      str      = (isNumber(place) ? withPrecision(this, place || 0).toFixed(max(place, 0)) : this.toString()).replace(/^-/, '');
207      split    = str.split('.');
208      integer  = split[0];
209      fraction = split[1];
210      for(i = integer.length; i > 0; i -= 3) {
211        if(i < integer.length) {
212          result = thousands + result;
213        }
214        result = integer.slice(max(0, i - 3), i) + result;
215      }
216      if(fraction) {
217        result += decimal + repeatString('0', (place || 0) - fraction.length) + fraction;
218      }
219      return (this < 0 ? '-' : '') + result;
220    },
221
222    /***
223     * @method hex([pad] = 1)
224     * @returns String
225     * @short Converts the number to hexidecimal.
226     * @extra [pad] will pad the resulting string to that many places.
227     * @example
228     *
229     *   (255).hex()   -> 'ff';
230     *   (255).hex(4)  -> '00ff';
231     *   (23654).hex() -> '5c66';
232     *
233     ***/
234    'hex': function(pad) {
235      return this.pad(pad || 1, false, 16);
236    },
237
238    /***
239     * @method times(<fn>)
240     * @returns Number
241     * @short Calls <fn> a number of times equivalent to the number.
242     * @example
243     *
244     *   (8).times(function(i) {
245     *     // This function is called 8 times.
246     *   });
247     *
248     ***/
249    'times': function(fn) {
250      if(fn) {
251        for(var i = 0; i < this; i++) {
252          fn.call(this, i);
253        }
254      }
255      return this.toNumber();
256    },
257
258    /***
259     * @method chr()
260     * @returns String
261     * @short Returns a string at the code point of the number.
262     * @example
263     *
264     *   (65).chr() -> "A"
265     *   (75).chr() -> "K"
266     *
267     ***/
268    'chr': function() {
269      return string.fromCharCode(this);
270    },
271
272    /***
273     * @method pad(<place> = 0, [sign] = false, [base] = 10)
274     * @returns String
275     * @short Pads a number with "0" to <place>.
276     * @extra [sign] allows you to force the sign as well (+05, etc). [base] can change the base for numeral conversion.
277     * @example
278     *
279     *   (5).pad(2)        -> '05'
280     *   (-5).pad(4)       -> '-0005'
281     *   (82).pad(3, true) -> '+082'
282     *
283     ***/
284    'pad': function(place, sign, base) {
285      return padNumber(this, place, sign, base);
286    },
287
288    /***
289     * @method ordinalize()
290     * @returns String
291     * @short Returns an ordinalized (English) string, i.e. "1st", "2nd", etc.
292     * @example
293     *
294     *   (1).ordinalize() -> '1st';
295     *   (2).ordinalize() -> '2nd';
296     *   (8).ordinalize() -> '8th';
297     *
298     ***/
299    'ordinalize': function() {
300      var suffix, num = abs(this), last = parseInt(num.toString().slice(-2));
301      return this + getOrdinalizedSuffix(last);
302    },
303
304    /***
305     * @method toNumber()
306     * @returns Number
307     * @short Returns a number. This is mostly for compatibility reasons.
308     * @example
309     *
310     *   (420).toNumber() -> 420
311     *
312     ***/
313    'toNumber': function() {
314      return parseFloat(this, 10);
315    }
316
317  });
318
319  /***
320   * @method round(<precision> = 0)
321   * @returns Number
322   * @short Shortcut for %Math.round% that also allows a <precision>.
323   *
324   * @example
325   *
326   *   (3.241).round()  -> 3
327   *   (-3.841).round() -> -4
328   *   (3.241).round(2) -> 3.24
329   *   (3748).round(-2) -> 3800
330   *
331   ***
332   * @method ceil(<precision> = 0)
333   * @returns Number
334   * @short Shortcut for %Math.ceil% that also allows a <precision>.
335   *
336   * @example
337   *
338   *   (3.241).ceil()  -> 4
339   *   (-3.241).ceil() -> -3
340   *   (3.241).ceil(2) -> 3.25
341   *   (3748).ceil(-2) -> 3800
342   *
343   ***
344   * @method floor(<precision> = 0)
345   * @returns Number
346   * @short Shortcut for %Math.floor% that also allows a <precision>.
347   *
348   * @example
349   *
350   *   (3.241).floor()  -> 3
351   *   (-3.841).floor() -> -4
352   *   (3.241).floor(2) -> 3.24
353   *   (3748).floor(-2) -> 3700
354   *
355   ***
356   * @method [math]()
357   * @returns Number
358   * @short Math related functions are mapped as shortcuts to numbers and are identical. Note that %Number#log% provides some special defaults.
359   *
360   * @set
361   *   abs
362   *   sin
363   *   asin
364   *   cos
365   *   acos
366   *   tan
367   *   atan
368   *   sqrt
369   *   exp
370   *   pow
371   *
372   * @example
373   *
374   *   (3).pow(3) -> 27
375   *   (-3).abs() -> 3
376   *   (1024).sqrt() -> 32
377   *
378   ***/
379
380  function buildNumber() {
381    function createRoundingFunction(fn) {
382      return function (precision) {
383        return precision ? withPrecision(this, precision, fn) : fn(this);
384      }
385    }
386    extend(number, true, true, {
387      'ceil':   createRoundingFunction(ceil),
388      'round':  createRoundingFunction(round),
389      'floor':  createRoundingFunction(floor)
390    });
391    extendSimilar(number, true, true, 'abs,pow,sin,asin,cos,acos,tan,atan,exp,pow,sqrt', function(methods, name) {
392      methods[name] = function(a, b) {
393        return math[name](this, a, b);
394      }
395    });
396  }
397
398  buildNumber();
399