{"id":557,"date":"2018-05-22T18:23:37","date_gmt":"2018-05-22T18:23:37","guid":{"rendered":"http:\/\/www.onux.com\/jspp\/blog\/?p=557"},"modified":"2021-10-12T19:38:27","modified_gmt":"2021-10-12T19:38:27","slug":"standard-library-performance-iseven-and-isodd","status":"publish","type":"post","link":"https:\/\/www.onux.com\/jspp\/blog\/standard-library-performance-iseven-and-isodd\/","title":{"rendered":"Standard Library Performance: isEven() and isOdd()"},"content":{"rendered":"<p>Remember what I always advise: always use the JS++ Standard Library if you can. The methods aren&#8217;t just well-tested for validity, but we also test for performance.<\/p>\n<p>Checking if a number is even or odd is the classic fizzbuzz test. Most professional developers can use the modulus operator. However, that&#8217;s not always the fastest implementation.<\/p>\n<pre>\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i &#038; 1) == 0; console.log(x); new Date - t;\r\nfalse\r\n87\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i &#038; 1) == 0; console.log(x); new Date - t;\r\nfalse\r\n90\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i &#038; 1) == 0; console.log(x); new Date - t;\r\nfalse\r\n86\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i &#038; 1) == 0; console.log(x); new Date - t;\r\nfalse\r\n86\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i &#038; 1) == 0; console.log(x); new Date - t;\r\nfalse\r\n86\r\n\r\n= 87ms\r\n\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;\r\nfalse\r\n105\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;\r\nfalse\r\n100\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;\r\nfalse\r\n100\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;\r\nfalse\r\n104\r\n> var t = new Date(); var x; for (var i = 0; i < 50000000; ++i) x = (i % 2) == 0; console.log(x); new Date - t;\r\nfalse\r\n101\r\n\r\n= 102ms\r\n\r\nNode.js v8.11.1 Linux x64\r\nCore i7-4790k, 32gb RAM\r\n<\/pre>\n<pre>\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i &#038; 1) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n1948 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i &#038; 1) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2072 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i &#038; 1) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2086 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i &#038; 1) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2092 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i &#038; 1) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2102\r\n\r\n= 2060ms\r\n\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2058 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2082 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2114 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2102 debugger eval code:1:96\r\nvar t = new Date(); var x; for (var i = 0; i < 5000000; ++i) x = (i % 2) == 0; console.log(x); console.log(new Date - t);\r\nfalse debugger eval code:1:80\r\n2104 debugger eval code:1:96\r\n\r\n= 2092ms\r\n\r\nFirefox 59.0.2, Linux x64\r\nCore i7-4790k, 32gb RAM\r\n<\/pre>\n<p>While the results are not statistically significant in Firefox (because it's very possible SpiderMonkey is manually optimizing this case via a pattern-matched optimization), you can get a 17% performance gain in Node.js via <a href=\"https:\/\/docs.onux.com\/en-US\/Developers\/JavaScript-PP\/Language\/Reference\/Expressions\/bitwise-operators\/and\" rel=\"noopener\" target=\"_blank\">bitwise AND<\/a>.<\/p>\n<p>Due to all the layers of abstraction in JavaScript, it's not entirely evident how much faster a bitwise AND for isEven\/isOdd can really be. In our benchmarks, we were able to achieve a 17% performance improvement in Node.js. As our lead engineer pointed out via email, according to <a href=\"http:\/\/www.agner.org\/optimize\/instruction_tables.pdf\" rel=\"noopener\" target=\"_blank\">this table<\/a>, \"for Intel Skylake-X `div` has a latency of 26 (for 32-bit integers), whereas `and` has latency 1 (\"reciprocal throughput\" has similar difference) so it is an order of magnitude slower, not 20% as in your tests.\"<\/p>\n<p>Look for <code>isEven()<\/code> and <code>isOdd()<\/code> to appear in a future version of the JS++ Standard Library.<\/p>\n<p>You may also be interested in reading <a href=\"https:\/\/www.onux.com\/jspp\/blog\/bitwise-operators-and-specification-compliant-integer-overflow-optimizations\/\">Part II of this post which describes how we leveraged overflow behavior<\/a> to improve performance while preserving correctness for UInteger32.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Remember what I always advise: always use the JS++ Standard Library if you can. The methods aren&#8217;t just well-tested for validity, but we also test for performance. Checking if a number is even or odd is the classic fizzbuzz test. Most professional developers can use the modulus operator. However, that&#8217;s not always the fastest implementation. &hellip; <a href=\"https:\/\/www.onux.com\/jspp\/blog\/standard-library-performance-iseven-and-isodd\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Standard Library Performance: isEven() and isOdd()&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[2,15],"tags":[],"_links":{"self":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/557"}],"collection":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/comments?post=557"}],"version-history":[{"count":9,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/557\/revisions"}],"predecessor-version":[{"id":1256,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/posts\/557\/revisions\/1256"}],"wp:attachment":[{"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/media?parent=557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/categories?post=557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.onux.com\/jspp\/blog\/wp-json\/wp\/v2\/tags?post=557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}