{"id":1376,"date":"2015-08-07T16:26:19","date_gmt":"2015-08-07T20:26:19","guid":{"rendered":"https:\/\/blogs.mathworks.com\/steve\/?p=1376"},"modified":"2019-11-01T11:44:24","modified_gmt":"2019-11-01T15:44:24","slug":"typecast-got-faster-in-r2014b","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/steve\/2015\/08\/07\/typecast-got-faster-in-r2014b\/","title":{"rendered":"Typecast got faster in R2014b"},"content":{"rendered":"<div class=\"content\"><p>Some years ago we added the function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/typecast.html\"><tt>typecast<\/tt><\/a> to MATLAB. I've been wanting to write about this useful little function ever since we significantly speeded it up in the R2014b release.<\/p><p>The function <tt>typecast<\/tt> converts numeric values from one type to another based on the underlying bytes in the numeric representation.<\/p><p>Clear as mud, right? Let me try a simple example to illustrate. Here is a vector of two numbers, each of which is represented using one byte:<\/p><pre class=\"codeinput\">x = uint8([128 6])\r\n<\/pre><pre class=\"codeoutput\">\r\nx =\r\n\r\n  128    6\r\n\r\n<\/pre><p>The call <tt>typecast(x,'uint16')<\/tt> takes those two one-byte numbers and converts them to one 16-bit number by jamming together the original bytes.<\/p><pre class=\"codeinput\">y = typecast(x,<span class=\"string\">'uint16'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\ny =\r\n\r\n   1664\r\n\r\n<\/pre><p>Here's how the number 1664 is related to the original pair of numbers:<\/p><pre class=\"codeinput\">128 + 6*2^8\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n        1664\r\n\r\n<\/pre><p>If you give <tt>typecast<\/tt> four one-byte numbers, it will happily convert them into a pair of two-byte numbers.<\/p><pre class=\"codeinput\">p = uint8([128 6 200 3])\r\n<\/pre><pre class=\"codeoutput\">\r\np =\r\n\r\n  128    6  200    3\r\n\r\n<\/pre><pre class=\"codeinput\">typecast(p,<span class=\"string\">'uint16'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n   1664    968\r\n\r\n<\/pre><p>Or, if you prefer, it will convert them into one four-byte number:<\/p><pre class=\"codeinput\">typecast(p,<span class=\"string\">'uint32'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n    63440512\r\n\r\n<\/pre><p>The function <tt>typecast<\/tt> performs these conversions between all of the integer and floating-point numeric types. These days I tend to use <tt>typecast<\/tt> (together with its cousin <tt>swapbytes<\/tt>) when writing low-level binary file reading code. For files that fit easily into memory, I might just read all the file bytes at once using <tt>fileread<\/tt>, and then I'll use indexing, <tt>swapbytes<\/tt>, and <tt>typecast<\/tt> into meaningful MATLAB data.<\/p><p>Let's examine how long it takes to perform this conversion. First, make a vector containing 256 one-byte values.<\/p><pre class=\"codeinput\">bytes = uint8(0:255);\r\n<\/pre><p>Now use <tt>timeit<\/tt> to estimate how long it takes to convert those values to 128 two-byte values.<\/p><pre class=\"codeinput\">f = @() typecast(bytes,<span class=\"string\">'uint16'<\/span>);\r\nt_microseconds = timeit(f) * 1e6\r\n<\/pre><pre class=\"codeoutput\">\r\nt_microseconds =\r\n\r\n   19.8762\r\n\r\n<\/pre><p>How would you expect the computation time to change as the input vector gets longer?<\/p><p>Here's a plot of computation times that I measured using MATLAB R2014a.<\/p><pre class=\"codeinput\">r2014a = load(<span class=\"string\">'typecast speedup R2014a ah-eddins-maci'<\/span>);\r\nplot(r2014a.n*256,r2014a.times*1e6)\r\nxlabel(<span class=\"string\">'Number of input bytes'<\/span>)\r\nylabel(<span class=\"string\">'Conversion time (microseconds)'<\/span>)\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle(<span class=\"string\">'typecast performance (R2014a)'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/typecast_speedup_01.png\" alt=\"\"> <p>The computation time appears to be proportional to the input vector length, which is not too surprising.<\/p><p>And here are the results measured using the latest MATLAB (R2015a).<\/p><pre class=\"codeinput\">r2015a = load(<span class=\"string\">'typecast speedup R2015a ah-eddins-maci'<\/span>);\r\nplot(r2015a.n*256,r2015a.times*1e6)\r\nxlabel(<span class=\"string\">'Number of input bytes'<\/span>)\r\nylabel(<span class=\"string\">'Conversion time (microseconds)'<\/span>)\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle(<span class=\"string\">'typecast performance (R2015a)'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/typecast_speedup_02.png\" alt=\"\"> <p>To make the comparison easier, show the results on the same plot.<\/p><pre class=\"codeinput\">plot(r2014a.n*256,r2014a.times*1e6)\r\nhold <span class=\"string\">on<\/span>\r\nplot(r2015a.n*256,r2015a.times*1e6)\r\nxlabel(<span class=\"string\">'Number of input bytes'<\/span>)\r\nylabel(<span class=\"string\">'Conversion time (microseconds)'<\/span>)\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle(<span class=\"string\">'typecast performance'<\/span>)\r\nlegend({<span class=\"string\">'R2014a'<\/span>,<span class=\"string\">'R2015a'<\/span>})\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/typecast_speedup_03.png\" alt=\"\"> <p>Now that is a little surprising! Not only is the R2015a computation time lower, it appears to be independent of the input vector length. That's because the implementation has been optimized to avoid making a copy in memory of the input vector's data. (For more about this kind of optimization, see Loren's <a href=\"https:\/\/blogs.mathworks.com\/loren\/2006\/05\/10\/memory-management-for-functions-and-variables\/\">2006 blog post about MATLAB memory use for functions and variables<\/a>.)<\/p><p>Have you had reason to use <tt>typecast<\/tt> in your own work? If so, please leave a comment. I'd be very interested to hear about your application.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_1d8a39c0a0404a6a8f773915d1c6e902() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='1d8a39c0a0404a6a8f773915d1c6e902 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 1d8a39c0a0404a6a8f773915d1c6e902';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2015 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_1d8a39c0a0404a6a8f773915d1c6e902()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2015a<br><\/p><\/div><!--\r\n1d8a39c0a0404a6a8f773915d1c6e902 ##### SOURCE BEGIN #####\r\n%%\r\n% Some years ago we added the function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/typecast.html |typecast|> to MATLAB.\r\n% I've been wanting to write about this useful little function ever since we\r\n% significantly speeded it up in the R2014b release.\r\n%\r\n% The function |typecast| converts numeric values from one type to another based\r\n% on the underlying bytes in the numeric representation.\r\n%\r\n% Clear as mud, right? Let me try a simple example to illustrate. Here is a\r\n% vector of two numbers, each of which is represented using one byte:\r\n\r\nx = uint8([128 6])\r\n\r\n%%\r\n% The call |typecast(x,'uint16')| takes those two one-byte numbers and converts them to one\r\n% 16-bit number by jamming together the original bytes.\r\n\r\ny = typecast(x,'uint16')\r\n\r\n%%\r\n% Here's how the number 1664 is related to the original pair of numbers:\r\n\r\n128 + 6*2^8\r\n\r\n%%\r\n% If you give |typecast| four one-byte numbers, it will happily convert them\r\n% into a pair of two-byte numbers.\r\n\r\np = uint8([128 6 200 3])\r\n\r\n%%\r\n\r\ntypecast(p,'uint16')\r\n\r\n%%\r\n% Or, if you prefer, it will convert them into one four-byte number:\r\n\r\ntypecast(p,'uint32')\r\n\r\n%%\r\n% The function |typecast| performs these conversions between all of the integer\r\n% and floating-point numeric types. These days I tend to use |typecast|\r\n% (together with its cousin |swapbytes|) when writing low-level binary file\r\n% reading code. For files that fit easily into memory, I might just read all the\r\n% file bytes at once using |fileread|, and then I'll use indexing, |swapbytes|,\r\n% and |typecast| into meaningful MATLAB data.\r\n%\r\n% Let's examine how long it takes to perform this conversion. First, make a\r\n% vector containing 256 one-byte values.\r\n\r\nbytes = uint8(0:255);\r\n\r\n%%\r\n% Now use |timeit| to estimate how long it takes to convert those values to 128\r\n% two-byte values.\r\n\r\nf = @() typecast(bytes,'uint16');\r\nt_microseconds = timeit(f) * 1e6\r\n\r\n%%\r\n% How would you expect the computation time to change as the input vector gets\r\n% longer?\r\n%\r\n% Here's a plot of computation times that I measured using MATLAB R2014a.\r\n\r\nr2014a = load('typecast speedup R2014a ah-eddins-maci');\r\nplot(r2014a.n*256,r2014a.times*1e6)\r\nxlabel('Number of input bytes')\r\nylabel('Conversion time (microseconds)')\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle('typecast performance (R2014a)')\r\n\r\n%%\r\n% The computation time appears to be proportional to the input vector length,\r\n% which is not too surprising.\r\n\r\n%%\r\n% And here are the results measured using the latest MATLAB (R2015a).\r\n\r\nr2015a = load('typecast speedup R2015a ah-eddins-maci');\r\nplot(r2015a.n*256,r2015a.times*1e6)\r\nxlabel('Number of input bytes')\r\nylabel('Conversion time (microseconds)')\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle('typecast performance (R2015a)')\r\n\r\n%%\r\n% To make the comparison easier, show the results on the same plot.\r\n\r\nplot(r2014a.n*256,r2014a.times*1e6)\r\nhold on\r\nplot(r2015a.n*256,r2015a.times*1e6)\r\nxlabel('Number of input bytes')\r\nylabel('Conversion time (microseconds)')\r\nax = gca;\r\nax.YLim(1) = 0;\r\ntitle('typecast performance')\r\nlegend({'R2014a','R2015a'})\r\n\r\n%%\r\n% Now that is a little surprising! Not only is the R2015a computation time\r\n% lower, it appears to be independent of the input vector length. That's because\r\n% the implementation has been optimized to avoid making a copy in memory of the\r\n% input vector's data. (For more about this kind of optimization, see Loren's\r\n% <https:\/\/blogs.mathworks.com\/loren\/2006\/05\/10\/memory-management-for-functions-and-variables\/ \r\n% 2006 blog post about MATLAB memory use for functions and variables>.)\r\n%\r\n% Have you had reason to use |typecast| in your own work? If so, please leave a\r\n% comment. I'd be very interested to hear about your application.\r\n##### SOURCE END ##### 1d8a39c0a0404a6a8f773915d1c6e902\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/steve\/files\/typecast_speedup_03.png\" onError=\"this.style.display ='none';\" \/><\/div><p>Some years ago we added the function typecast to MATLAB. I've been wanting to write about this useful little function ever since we significantly speeded it up in the R2014b release.The function... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/steve\/2015\/08\/07\/typecast-got-faster-in-r2014b\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[80,90,92,362,68,474,52,609,555,94,96],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1376"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/comments?post=1376"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1376\/revisions"}],"predecessor-version":[{"id":1380,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/posts\/1376\/revisions\/1380"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/media?parent=1376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/categories?post=1376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/steve\/wp-json\/wp\/v2\/tags?post=1376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}