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

Qunit Template


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

QUnit JSFiddle.net Template
http://jsfiddle.net/tWyHg/1/

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