Code of the Day: Javascript, Fix for isNaN


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: Undefined array key "layout" in /home/bateeqjg/public_html/news/wp-content/plugins/wp-about-author/wp-about-author.php on line 94

Javascript is a dynamically typed langauges. This feature causes for Arrays, Booleans, and other types to be converted to a numeric values depending on usage.
However this feature can cause headarches when trying to detect numbers.

For example, isNaN() detects if a value is a non-number. That’s what NaN stands for, “Not a number”.
So you might think that the opposite result from isNaN() would indicate if a value is a number.

// Works for most cases but not for strict comparisons.
var isNumber = function(val){
	return !isNaN( val );
};

Example:
Note: Click the “result” tab to run the test cases in jsfiddle.net.

Solution:
So here’s a simple fix for isNaN and isNumber.

// isNaN2 returns a boolean for if a value is not a number or +-Infinity
var isNaN2 = (function (global) {
    var _isNaN = global.isNaN;
    return function (val) {
        return _isNaN("" + val) || (typeof val === "object" && !(val || "").hasOwnProperty('push'));
    };
}(this));
// isNumeric returns a boolean for if a value is a number or +-Infinity
var isNumeric = (function (global) {
    var _isNaN = global.isNaN;
    return function (val) {
        return !_isNaN("" + val)&&(typeof val !== "object" || (val || "").hasOwnProperty('push'));
    };
}(this));


isNaN vs isNaN2

Testcases for isNaN2 and isNumeric

*Update*
Well it turns out that jQuery has a better implementation. The only difference is that infinity is not a number, which is correct.

$.isNumeric = function( obj ){
    return !isNaN( parseFloat( obj ) ) && isFinite( obj );
};


api.jquery.com/jQuery.isNumeric

Larry Battle

Larry Battle

I love to program, and discover new tech. Check out my <a href="http://stackoverflow.com/users/527776/larry-battle">stackoverflow</a> and <a href="https://github.com/LarryBattle">github</a> accounts.

More Posts - Website

Follow Me:Add me on XAdd me on LinkedInAdd me on YouTube

Code of the Day: Javascript, Prime Factors of a Number


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: Undefined array key "layout" in /home/bateeqjg/public_html/news/wp-content/plugins/wp-about-author/wp-about-author.php on line 94

Javascript: Prime Factorization

Today’s code is a enhancement of Code Renaissance‘s version of “Finding Prime Numbers in Javascript”.
Main difference are the following.

  1. Faster performance by eliminating recursion and caching Math.sqrt.
  2. Whole numbers bigger than 1 return an empty array, since they’re not prime numbers.
  3. Decimal values are converted to whole numbers.

/**
* @author Larry Battle - http://bateru.com/news/contact-me
* @date May 11, 2012
* @license MIT and GPL v3
* @purpose Return the prime factors of a number.
* @info - http://bateru.com/news/?s=prime+factors
*/
var getPrimeFactors = function(num) {
    num = Math.floor(num);
    var root, factors = [], x, sqrt = Math.sqrt, doLoop = 1 < num;
    while( doLoop ){
        root = sqrt(num);
        x = 2;
        if (num % x) {
            x = 3;
            while ((num % x) && ((x += 2) < root));
        }
        x = (x > root) ? num : x;
        factors.push(x);
        doLoop = ( x != num );
        num /= x;
    }
    return factors;
}

Example:
getPrimeFactors(15120) // returns [2, 2, 2, 3, 3, 3, 7]

Demo:

Larry Battle

Larry Battle

I love to program, and discover new tech. Check out my <a href="http://stackoverflow.com/users/527776/larry-battle">stackoverflow</a> and <a href="https://github.com/LarryBattle">github</a> accounts.

More Posts - Website

Follow Me:Add me on XAdd me on LinkedInAdd me on YouTube

Code of the Day: Javascript, Convert decimal to a simplified fraction


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: Undefined array key "layout" in /home/bateeqjg/public_html/news/wp-content/plugins/wp-about-author/wp-about-author.php on line 94

Inspired from a stackoverflow.com question.
Convert decimal amount to text string fraction in Javascript?

Code

/**
 * @author Larry Battle <http://bateru.com/news/contact-me>
 * @license MIT
 * @version 1.0
 * @date May 08, 2012
 * @purpose To provide a function that converts a decimal to a simplified fraction.
 * @info <http://bateru.com/news/2012/05/code-of-the-day-javascript-convert-decimal-to-a-simplified-fraction/>
 */
var mixin = {};
mixin.getKeys = function (obj) {
    var props = [];
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            props.push(prop);
        }
    }
    return props;
};
mixin.getFractionObject = (function () {
    var obj = {
        0 : '0',
        1 : '1'
    },
    num = 10,
    den = 11,
    value;
    while (--num) {
        while (--den > 1) {
            value = (num / den).toFixed(3);
            if (value < 1) {
                obj[value] = num + "/" + den;
            }
        }
        den = 11;
    }
    obj.keys = mixin.getKeys(obj);
    return function () {
        return obj;
    };
}
    ());
mixin.getClosestNum = function (arr, val) {
    if (typeof arr !== "object" || !(arr.hasOwnProperty('length')) || isNaN(val)) {
        return false;
    }
    var i = arr.length,
    j = i - 1,
    minDiff = Math.abs(+val - arr[j]),
    diff;
    while (i--) {
        diff = Math.abs(+val - arr[i]);
        if (diff < minDiff) {
            minDiff = diff;
            j = i;
        }
    }
    return arr[j];
};
mixin.getFractionFromDecimal = function (dec) {
    if (isNaN(dec) || !isFinite(dec)) {
        return false;
    }
    if (!/\./.test(dec)) {
        return dec;
    }
    var fracs = mixin.getFractionObject(),
    matches = dec.toString().match(/(\d+)(\.\d+)/),
    fraction = fracs[mixin.getClosestNum(fracs.keys, Math.abs(+matches[2]))],
    sign = ( 0 < dec || (fraction == "0" && Math.abs(dec) < 1) ) ? '' : '-';
    if (1 < Math.abs(dec)) {
        if (isNaN(fraction)) {
            fraction = +matches[1] + " " + fraction;
        } else {
            fraction = +matches[1] + (+fraction);
        }
    }
    return sign + fraction;
};

Testcases and Demo

// Qunit Testcases
$(document).ready(function(){
	var runAllTests = function () {
		test("Test getKeys()", function () {
			var obj = {};
			deepEqual([], getKeys(obj), "Empty objects should have no props.");
			obj.a = 1;
			deepEqual(['a'], getKeys(obj), "a should be returned as a property.");
			obj = {
				1 : 1,
				2 : 1,
				3 : 1
			}
			deepEqual(['1', '2', '3'], getKeys(obj), "1,2,3 should be properties.");
		});
		test("Test getClosestNum()", function () {
			var arr = [0, 1, 2, 3, 10, 99, 1000];
			equal(false, getClosestNum({}, 1), "First argument must be an array.");
			equal(false, getClosestNum(arr), "Second argument must be an defined.");
			equal(false, getClosestNum(arr, {}), "Second argument must be an number.");
			var runThisTest = function (nums, expect) {
				var i = expect.length;
				while (i--) {
					equal(getClosestNum(nums, expect[i][0]), expect[i][1], expect[i][0] + " is the closest to " + expect[i][1]);
				}
			};
			runThisTest(arr, [
					[-10, 0],
					[0.3, 0],
					[0.5, 1],
					[2.1, 2],
					[10.1, 10],
					[100, 99],
					[600, 1000]
				]);
		});
		test("Test getFractionObject()", function () {
			var fracs = getFractionObject();
			var props = getKeys( fracs );
 
			areAllNumbers = true;
			var i = props.length;
			while( i-- ){
				if( isNaN( props[ i ] ) ){
					areAllNumbers = false;
				}
			}
			ok( areAllNumbers, "getFractionObject() returns an object with all properties as a number." );
			equal( fracs[ 0 ], "0", "0.500 should be 0" );
			equal( fracs[ '0.333' ], "1/3", "0.333 should be 1/3" );
			equal( fracs[ '0.500' ], "1/2", "0.500 should be 1/2" );
			equal( fracs[ '0.900' ], "9/10", "0.900 should be 9/10" );
			equal( fracs[ 1 ], "1", "0.500 should be 1" );
		});
		test("Test getFractionFromDecimal() with invalid inputs", function(){
			equal(getFractionFromDecimal( "ten" ), false );
			equal(getFractionFromDecimal( NaN ),  false );
			equal(getFractionFromDecimal( undefined ),  false );
			equal(getFractionFromDecimal( Infinity ),  false );
		});
		test("Test getFractionFromDecimal() with only decimal values <= 1", function(){
			equal(getFractionFromDecimal(0.001), "0" );
			equal(getFractionFromDecimal(0.23), "2/9" );
			equal(getFractionFromDecimal(0.335), "1/3" );
			equal(getFractionFromDecimal(0.756), "3/4" );
			equal(getFractionFromDecimal(0.995), "1" );
		});
		test("Test getFractionFromDecimal() with integers", function(){
			equal(getFractionFromDecimal(12), "12" );
			equal(getFractionFromDecimal(3), "3" );
		});
		test("Test getFractionFromDecimal() with negative values", function(){
			equal(getFractionFromDecimal(-0.001), "0" );
			equal(getFractionFromDecimal(-0.23), "-2/9" );
			equal(getFractionFromDecimal(-0.335), "-1/3" );
			equal(getFractionFromDecimal(-0.756), "-3/4" );
			equal(getFractionFromDecimal(-0.995), "-1" );
		});
		test("Test getFractionFromDecimal() with numbers bigger than 1.", function(){
			equal(getFractionFromDecimal(10.001), "10" );
			equal(getFractionFromDecimal(-10.001), "-10" );
			equal(getFractionFromDecimal(12.23), "12 2/9" );
			equal(getFractionFromDecimal(3.335), "3 1/3" );
			equal(getFractionFromDecimal(99.756), "99 3/4" );
			equal(getFractionFromDecimal(34.995), "35" );
		});
	};
	runAllTests();
});

Example
mixin.getFractionFromDecimal(-99.756); // returns “-99 3/4”

Larry Battle

Larry Battle

I love to program, and discover new tech. Check out my <a href="http://stackoverflow.com/users/527776/larry-battle">stackoverflow</a> and <a href="https://github.com/LarryBattle">github</a> accounts.

More Posts - Website

Follow Me:Add me on XAdd me on LinkedInAdd me on YouTube

Code of the day: Converts Bytes to Simplify Units


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/bateeqjg/public_html/news/wp-content/plugins/wp-syntax/wp-syntax.php on line 380

Warning: Undefined array key "layout" in /home/bateeqjg/public_html/news/wp-content/plugins/wp-about-author/wp-about-author.php on line 94

A few days ago I noticed that my “code of the day” article was wrong. So I spent some time fixing it and provided test cases to check my work.
The main difference about this script is that it allows you to support both the SI and IEC standard and fixes a few rounding errors.

// function: getBytesWithUnit
// input: bytes (number)
// input: useSI (boolean), if true then uses SI standard (1KB = 1000bytes), otherwise uses IEC (1KiB = 1024 bytes)
// input: precision (number), sets the maximum length of decimal places.
// input: useSISuffix (boolean), if true forces the suffix to be in SI standard. Useful if you want 1KB = 1024 bytes
// returns (string), represents bytes is the most simplified form.
var getBytesWithUnit = function (bytes, useSI, precision, useSISuffix) {
	"use strict";
	if (!(!isNaN(bytes) && +bytes > -1 && isFinite(bytes))) {
		return false;
	}
	var units, obj,	amountOfUnits, unitSelected, suffix;
	units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	obj = {
		base : useSI ? 10 : 2,
		unitDegreeDiff : useSI ? 3 : 10
	};
	amountOfUnits = Math.max(0, Math.floor(Math.round(Math.log(+bytes) / Math.log(obj.base) * 1e6) / 1e6));
	unitSelected = Math.floor(amountOfUnits / obj.unitDegreeDiff);
	unitSelected = units.length > unitSelected ? unitSelected : units.length - 1;
	suffix = (useSI || useSISuffix) ? units[unitSelected] : units[unitSelected].replace('B', 'iB');
	bytes = +bytes / Math.pow(obj.base, obj.unitDegreeDiff * unitSelected);
	precision = precision || 3;
	if (bytes.toString().length > bytes.toFixed(precision).toString().length) {
		bytes = bytes.toFixed(precision);
	}
	return bytes + " " + suffix;
};



Demo: Test Script here

Want to learn more about Javascript?
Check out this “Professional JavaScript for Web Developers”.

Larry Battle

Larry Battle

I love to program, and discover new tech. Check out my <a href="http://stackoverflow.com/users/527776/larry-battle">stackoverflow</a> and <a href="https://github.com/LarryBattle">github</a> accounts.

More Posts - Website

Follow Me:Add me on XAdd me on LinkedInAdd me on YouTube