parseInt alternative - javascript

Firstly - my description ;)
I've got a XmlHttpRequests JSON response from the server.
MySQL driver outputs all data as string and PHP returns it as it is, so any integer is returned as string, therefore:
Is there any fast alternative (hack) for parseInt() function in JS which can parse pure numeric string, e.g.
var foo = {"bar": "123"};
...
foo.bar = parseInt(foo.bar); // (int) 123

To convert to an integer simply use the unary + operator, it should be the fastest way:
var int = +string;
Conversions to other types can be done in a similar manner:
var string = otherType + "";
var bool = !!anything;
More info.

Type casting in JavaScript is done via the constructor functions of the built-in types without new, ie
foo.bar = Number(foo.bar);
This differs from parseInt() in several ways:
leading zeros won't trigger octal mode
floating point values will be parsed as well
the whole string is parsed, i.e. if it contains additional non-numeric characters, the return value will be NaN

First off, have you actually documented that it's slow and is causing problems? Otherwise, I wouldn't bother looking for a solution, because there really isn't a problem.
Secondly, I would guess that since parseInt is a native JS-method, it would be implemented in a way that is very fast, and probably in the native language of the VM (probably C, depending on the browser/VM). I think you could have some trouble making a faster method out of pure JS. =)
Of course, I'm not a JS guru, so I don't know for sure, but this is what my intuition tells me, and tends to be the standard answer to "how would I make a faster alternative for libraryFunction()?" questions.

Cast it to an int in PHP before you json_encode() it:
$foo->bar = (int)$foo->bar;
print('var foo = ' . json_encode($foo));
Incidentally, when using parseInt it's good practice to always specify the second parameter unless you really want string starting with 0 to be interpreted as octal and so on:
parseInt('010', 10); // 10

Fast shortcut to parseInt is
("78.5" | 0) //bitwise or forces the string to parse as int
This is what ASM uses to represent ints in js.

You aren't going to get better than parseInt, but the real bug is that the PHP is providing what is supposed to be a number as a string.
And ditto to what Daniel said - don't go looking for micro-optimisations like this until you have benchmarked your code and discovered that it's worth doing.

The Number constructor also exists, but it should be the same as parseInt in term of speed (as already said you should correct the PHP part instead of the javascript one anyway) :
var i = "123";
i = new Number(i); // Number numeric wrapper
var j = "123";
j = Number(j); // Number primitive
BTW if someone is interested i searched by curiosity for the V8 (Google chrome) implementation of parseInt and it's here on google code.

How slow can it be? How many times per second is this process being called? How many different numeric return values are there? I whipped together a script and tested 100,000 numbers. Parsing them from strings took 687ms. Searching them in an array took 541ms. That's a very small improvement. I agree with other posters. You may not get better than the native parseInt() method.

Casting is a wee bit faster than parsing but slower than searching.
Also, in Firefox the fastest method turns out to be parseInt() followed by searching. Firefox also turned out to be 6 times faster on average than IE. Interesting.
Cool idea using the unary operator. In Firefox that turned out to be comparable to parseInt(). In IE it turned out to be the fastest method.

if the objects are larger you could try JSON, it is a typed format so you do not need to convert the values.

This solution is faster than parseInt() if you parse strings of decimal integer that is 20 or less in length. For some browser, you may still be faster than parseInt() up to 33 digits in length. Also, you still be faster than auto-cast.
It is because, the parseInt() for the browser does take some time to warm up, so if you only using a simple method to parse, you beat it for a while until it catches up. Don't use this for nodeJS though. When run parseInt() from nodeJS, it is startup time is a lot less than when running from a browser.
45 is the '-' sign in ASCII, 43 is the '+' sign in ASCII. 48 is '0'. Only 48 to 57 xor 48 become 0 - 9(in their order). No other numbers xor 48 yields 0-9.
This will return undefined if the string is not a valid decimal integer string or if the string is empty. It throws a string with value "Not a string" if the input is not of type string.
var toNumber = function (input) {
if ( typeof input !== "string" ) throw "Not a string";
var length = input.length;
if ( length === 0 ) return;
var c1 = input.charCodeAt(0);
if ( c1 === 45 || c1 === 43 ){
if ( length === 1 ) return;
var start = 1;
} else {
var start = 0;
}
var out = 0, c;
while( start < length && input.charCodeAt(start) === 48 ) start++;
for ( ; start < length; start++){
c = input.charCodeAt(start) ^ 48;
if ( c > 9 ) return;
out = (out * 10) + c;
}
if ( c1 === 45 ) return out * -1;
return out;
}

Related

Fastest way to add decimal place(s) after parseFloat(), similar to Python's float()

As far as I know JavaScript's parseFloat() does not add decimal place (i.e. .0) to the number, while Python's float() does. I want parseFloat() to have similar behaviour as float() and want it to run as quick as possible.
I've come up with two rough solutions to achieve this, but I am quite sure they are not the quickest:
Method 1:
function handle_prec(number)
{
if (Number.isInteger(number))
{
let log = Math.log(number) / Math.log(10);
let precision = Math.ceil(log) + 1;
return (parseFloat(number).toPrecision(precision));
}
else
return number;
}
Method 2 (a bit dumb but more straight-forward):
Add ".0" to the end of the number if it's an integer then parse it back to float.
What is the best or fastest way to achieve this? Thanks!
Python distinguishes between integers and floats. JavaScript does not, except in very limited circumstances. Thus, parsing back to float will return it to the original state (where 1 and 1.0 are the same thing). The only way to distinguish 1 and 1.0 in JavaScript is in string form.
Your code is basically it, except the whole if true block can be replaced by number.toFixed(1). Replacing that, and condensing the function a bit:
const handlePrec = number => Number.isInteger(number) ? number.toFixed(1) : number;
with caveat that this will return a string for integers, and original type for everything else. If you want it to return a string always:
const handlePrec = number => Number.isInteger(number)
? number.toFixed(1) : String(number);

What does Math.random() do in this JavaScript snippet?

I'm watching this Google I/O presentation from 2011 https://www.youtube.com/watch?v=M3uWx-fhjUc
At minute 39:31, Michael shows the output of the closure compiler, which looks like the code included below.
My question is what exactly is this code doing (how and why)
// Question #1 - floor & random? 2147483648?
Math.floor(Math.random() * 2147483648).toString(36);
var b = /&/g,
c = /</g,d=/>/g,
e = /\"/g,
f = /[&<>\"]/;
// Question #2 - sanitizing input, I get it...
// but f.test(a) && ([replaces]) ?
function g(a) {
a = String(a);
f.test(a) && (
a.indexOf("&") != -1 && (a = a.replace(b, "&")),
a.indexOf("<") != -1 && (a = a.replace(c, "<")),
a.indexOf(">") != -1 && (a = a.replace(d, ">")),
a.indexOf('"') != -1 && (a = a.replace(e, """))
);
return a;
};
// Question #3 - void 0 ???
var h = document.getElementById("submit-button"),
i,
j = {
label: void 0,
a: void 0
};
i = '<button title="' + g(j.a) + '"><span>' + g(j.label) + "</span></button>";
h.innerHTML = i;
Edit
Thanks for the insightful answers. I'm still really curious about the reason why the compiler threw in that random string generation at the top of the script. Surely there must be a good reason for it. Anyone???
1) This code is pulled from Closure Library. This code in is simply creating random string. In later version it has been replaced by to simply create a large random integer that is then concatenated to a string:
'closure_uid_' + ((Math.random() * 1e9) >>> 0)
This simplified version is easier for the Closure Compiler to remove so you won't see it leftover like it was previously. Specifically, the Compiler assumes "toString" with no arguments does not cause visible state changes. It doesn't make the same assumption about toString calls with parameters, however. You can read more about the compiler assumptions here:
https://code.google.com/p/closure-compiler/wiki/CompilerAssumptions
2) At some point, someone determined it was faster to test for the characters that might need to be replaced before making the "replace" calls on the assumption most strings don't need to be escaped.
3) As others have stated the void operator always returns undefined, and "void 0" is simply a reasonable way to write "undefined". It is pretty useless in normal usage.
1) I have no idea what the point of number 1 is.
2) Looks to make sure that any symbols are properly converted into their corresponding HTML entities , so yes basically sanitizing the input to make sure it is HTML safe
3) void 0 is essentially a REALLY safe way to make sure it returns undefined . Since the actual undefined keyword in javascript is mutable (i.e. can be set to something else), it's not always safe to assume undefined is actually equal to an undefined value you expect.
When in doubt, check other bases.
2147483648 (base 10) = 0x80000000 (base 16). So it's just making a random number which is within the range of a 32-bit signed int. floor is converting it to an actual int, then toString(36) is converting it to a 36-character alphabet, which is 0-9 (10 characters) plus a-z (26 characters).
The end-result of that first line is a string of random numbers and letters. There will be 6 of them (36^6 = 2176782336), but the first one won't be quite as random as the others (won't be late in the alphabet). Edit: Adrian has worked this out properly in his answer; the first letter can be any of the 36 characters, but is slightly less likely to be Z. The other letters have a small bias towards lower values.
For question 2, if you mean this a = String(a); then yes, it is ensuring that a is a string. This is also a hint to the compiler so that it can make better optimisations if it's able to convert it to machine code (I don't know if they can for strings though).
Edit: OK you clarified the question. f.test(a) && (...) is a common trick which uses short-circuit evaluation. It's effectively saying if(f.test(a)){...}. Don't use it like that in real code because it makes it less readable (although in some cases it is more readable). If you're wondering about test, it's to do with regular expressions.
For question 3, it's new to me too! But see here: What does `void 0` mean? (quick google search. Turns out it's interesting, but weird)
There's a number of different questions rolled into one, but considering the question title I'll just focus on the first here:
Math.floor(Math.random() * 2147483648).toString(36);
In actual fact, this doesn't do anything - as the value is discarded rather than assigned. However, the idea of this is to generate a number between 0 and 2 ^ 31 - 1 and return it in base 36.
Math.random() returns a number from 0 (inclusive) to 1 (exclusive). It is then multipled by 2^31 to produce the range mentioned. The .toString(36) then converts it to base 36, represented by 0 to 9 followed by A to Z.
The end result ranges from 0 to (I believe) ZIK0ZI.
As to why it's there in the first place ... well, examine the slide. This line appears right at the top. Although this is pure conjecture, I actually suspect that the code was cropped down to what's visible, and there was something immediately above it that this was assigned to.

Javascript Checking for NaN - Results not as expected

I have an application that reads in a number via ajax, the number is hexadecimal and I parse it and convert to decimal.
The numbers come in through a wireless serial link and are not 100% reliable so I need to check them before I start processing the data. The numbers take the form ****025781610403e5**** for example. The **** is just a way of checking the start and end of the number that I have used in the past with non web based projects and could be changed.
Anyway to my question at last: As part of error checking I thought I would check for NaN as I do get NaN errors when I have been testing but while *1234 gives a positive NaN 12**34 does not, why is that? and what else can I do to test?
Here is some of the code I have used, please note I am fairly new to javascript.
function readSliceConvert()
{
functionReadForm()
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML=testVal;
testNum1 = h2d(testVal)
document.getElementById("battDb5").innerHTML=testNum1.toString();
testNum2 = parseInt(testVal);
document.getElementById("battDb6").innerHTML=testNum2.toString();
if (isNaN(testNum2))
{
errorCount++;
document.getElementById("battDb3").innerHTML=errorCount.toString();
document.getElementById("battDb4").innerHTML=testVal;
return;
}
}
That's because you are using parseInt, it will silently ignore characters at the end of the string when there are some digit in the beginning of the string that it can parse.
I don't know what your h2d function is doing, but it seems that you are converting the hexadecimal string to a number, then to a string in decimal form, then back to a number. I don't see any reason why the output of parsing the hexadecimal string couldn't be a number.
For example like this, returning null if the parsing fails:
function h2i(str) {
var num = 0;
var digits = "0123456789abcdef";
str = str.toLowerCase();
for (var i = 0; i < str.length; i++) {
var n = digits.indexOf(str.substr(i, 1));
if (n == -1) return null;
num = num * 16 + n;
}
return num;
}
Demo: http://jsfiddle.net/Guffa/6yAaP/
Usage:
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML = testVal;
testNum = h2i(testVal)
document.getElementById("battDb5").innerHTML = testNum.toString();
if (testNum == null)
{
errorCount++;
document.getElementById("battDb3").innerHTML = errorCount.toString();
document.getElementById("battDb4").innerHTML = testVal;
return;
}
Do you know what parseInt() does?
From MDN
parseInt is a top-level function and is not associated with any
object.
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN. If not NaN, the returned value will
be the decimal integer representation of the first argument taken as a
number in the specified radix (base). For example, a radix of 10
indicates to convert from a decimal number, 8 octal, 16 hexadecimal,
and so on. For radices above 10, the letters of the alphabet indicate
numerals greater than 9. For example, for hexadecimal numbers (base
16), A through F are used.
If parseInt encounters a character that is not a numeral in the
specified radix, it ignores it and all succeeding characters and
returns the integer value parsed up to that point. parseInt truncates
numbers to integer values. Leading and trailing spaces are allowed.
Run the code in the console
console.log( parseInt("12**34",10) );
So you are running isNaN against a number since parseInt returns 12.
When you have the * as the first character, there are no leading numbers to return.
console.log( parseInt("*1234",10) );
You're seeing weird behaviour because isNan is broken (see the mozilla docs for details).
A better way to test your data is correctly formatted would be a quick regular expression, like serial.test(/^\d+$/), which will succeed if the entire serial is entirely numeric, or serial.test(/^\*{4}\d+\*{4}$/) which will succeed if the serial is four asterisks, followed by one or more number, followed by another four asterisks.
Update: #Guffa's answer is correct, and should be accepted, but I'll leave this here as I think there's a valid argument in the bigger picture that you could better accomplish what you're trying to do with a regular expression.
Running test on the string executes the supplied regular expression, and returns true if it matches the string.
Regular expressions are just patterns describing text, which can be incredibly complex or as simple as the example I've given (\d+ means match a number (\d) one or more times (+), with anchors for the beginning (^) and end ($) of the string to indicate that we want to match the whole string, not just part of it. They're ridiculously useful, so it's almost certainly worth taking the time to learn the basics of how they work, and expand you knowledge over time. There's a great tutorial on regular-expressions.info that'll get you started in no time.

Is there a limit to the base to which numbers can be associated to?

This may be very convoluted and twisted idea. Got it while learning some JavaScript. It piqued my mind. Hoping there may be someone else who would have thought about it before or might enlighten me :-)
var n = 17;
binary_string = n.toString(2); // Evaluates to "10001"
octal_string = "0" + n.toString(8); // Evaluates to "021"
hex_string = "0x" + n.toString(16); // Evaluates to "0x11"
This made me probe more into bases. I remembered my Digital Engineering course and understood that for every number from 10 for a base greater than 10 will be started naming from 'a', 'b' onwards.
for eg:
var n = 10;
var y = 11;
string = n.toString(12); // Evaluates to 'a'
string = y.toString(12); // Evaluates to 'b'
Then I understood this could go uptil 'z'
Thus
var n = 35;
string = n.toString(36); // Evaluates to "z"
But that seems to be the end. if we do
var n = 35;
string = n.toString(37); // Gives error Error: illegal radix 37 { message="illegal radix 37", more...}
Thus I believe we can only count up to the bases of 36. since for a base 37 counting system, we wont be able to count 36 since we exhausted English characters. Is there anyway we can do it? Maybe we can add other characters.
I know it is very useless thing, and never in life will we ever need it.
But have anyone thought about it already?
see my question here. What symbols are used after base 36
Yes, of course it can be done, just not with JavaScript's toString function.
You just need to decide on which characters to use for your digits. This is largely arbitrary, although there are some established standards. See, for example, Base64, Ascii85 etc.
You can certainly do it, number bases are complete arbitrary (using the English alphabet after 9 is just a common convention). Number#toString is specifically designed to handle base 2 through 36:
The optional radix should be an integer value in the inclusive range 2 to 36.
From the spec, section 15.7.4.2.

Understanding bitwise operations in javascript

I am currently storing data inside an XML doc as binary, 20 digits long, each representing a boolean value.
<matrix>
<resource type="single">
<map>10001010100011110000</map>
<name>Resource Title</name>
<url>http://www.yoursite.com</url>
</resource>
</matrix>
I am parsing this with jQuery and am currently using a for loop and charAt() to determine whether to do stuff if the value is == "1".
for (var i = 0; i < _mapLength; i++) {
if (map.charAt(i) == "1") {
//perform something here
}
}
This takes place a few times as part of a HUGE loop that has run sort of slow. Someone told me that I should use bitwise operators to process this and it would run faster.
My question is either:
Can someone offer me an example of how I could do this? I've tried to read tutorials online and they seem to be flying right over my head. (FYI: I am planning on creating a Ruby script that will convert my binary 0 & 1's into bits in my XML.)
Or does anyone know of a good, simple (maybe even dumbed down version) tutorial or something that could help me grasp these bitwise operator concepts?
Assuming you have no more than 32 bits, you can use JavaScript's built-in parseInt() function to convert your string of 1s and 0s into an integer, and then test the flags using the & (and) operator:
var flags = parseInt("10001010100011110000", 2); // base 2
if ( flags & 0x1 )
{
// do something
}
...
See also: How to check my byte flag?
(question is on the use in C, but applies to the same operators in JS as well)
Single ampersand (&, as opposed to &&) does bit-wise comparison. But first you need to convert your strings to numbers using parseInt().
var map = parseInt("10010", 2); // the 2 tells it to treat the string as binary
var maskForOperation1 = parseInt("10000", 2);
var maskForOperation2 = parseInt("01000", 2);
// ...
if (map & maskForOperation1) { Operation1(); }
if (map & maskForOperation2) { Operation2(); }
// ...
Be extremely wary. Javascript does not have integers -- numbers are stored as 64 bit floating-point. You should get accurate conversion out to 52 bits. If you get more flags than that, bad things will happen as your "number" gets rounded to the nearest representable floating-point number. (ouch!)
Also, bitwise manipulation will not help performance, because the floating point number will be converted to an integer, tested, and then converted back.
If you have several places that you want to check the flags, I'd set the flags on an object, preferably with names, like so:
var flags = {};
flags.use_apples = map.charAt(4);
flags.use_bananas = map.charAt(10);
etc...
Then you can test those flags inside your loop:
if(flags.use_apples) {
do_apple_thing();
}
An object slot test will be faster than a bitwise check, since Javascript is not optimized for bitwise operators. However, if your loop is slow, I fear that decoding these flags is probably not the source of the slowness.
Bitwise operators will certainly be faster but only linearly and not by much. You'll probably save a few milliseconds (unless you're processing HUGE amounts of data in Javascript, which is most likely a bad idea anyway).
You should think about profiling other code in your loop to see what's slowing it down the most. What other algorithms, data structures and allocations do you have in there that could use refactoring?

Categories