{"id":6792,"date":"2021-03-08T16:53:34","date_gmt":"2021-03-08T21:53:34","guid":{"rendered":"https:\/\/blogs.mathworks.com\/cleve\/?p=6792"},"modified":"2021-03-08T16:53:34","modified_gmt":"2021-03-08T21:53:34","slug":"round-with-tie-breakers-round-three","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/cleve\/2021\/03\/08\/round-with-tie-breakers-round-three\/","title":{"rendered":"Round, With Tie Breakers, Round Three"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p>I recently published <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2021\/02\/25\/round-with-ties-to-even\/\">Round, With Ties to Even<\/a> and followed that with <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2021\/03\/02\/round-with-tie-breakers-round-two\/\">Round Two<\/a>.  Then, in an email, Andy Bartlett pointed out that my new <tt>round<\/tt> function fails for some large values of <tt>x<\/tt> between <tt>flintmax\/2<\/tt> and <tt>flintmax<\/tt>.<\/p><!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#a671370a-6f40-4104-b479-e697499dbc7b\"><tt>flintmax\/2<\/tt><\/a><\/li><li><a href=\"#48e9c6a5-0d15-4441-b6d8-f828215f1bb8\">Rounding<\/a><\/li><li><a href=\"#a7268701-3d97-438d-b0b6-deb553b62de6\"><tt>round<\/tt><\/a><\/li><li><a href=\"#98e070ea-b963-422b-93c9-4c67d4abb62e\">test<\/a><\/li><\/ul><\/div><h4><tt>flintmax\/2<\/tt><a name=\"a671370a-6f40-4104-b479-e697499dbc7b\"><\/a><\/h4><p>The quantity <tt>f = flintmax\/2<\/tt> is equal to <tt>2^52<\/tt>, which is <tt>1\/eps<\/tt>. The <tt>help<\/tt> entry for <tt>format bank<\/tt> says it is a fixed format for dollars and cents.  That's true, but I also like to use it for displaying large flints.<\/p><pre class=\"codeinput\">   format <span class=\"string\">bank<\/span>\r\n   f = flintmax\/2\r\n<\/pre><pre class=\"codeoutput\">f =\r\n 4503599627370496.00\r\n<\/pre><p>The numbers in the interval <tt>[f flintmax]<\/tt> are the <i>largest<\/i> flints.  They are all integers. The spacing between them is one.<\/p><pre class=\"codeinput\">   eps(f)\r\n<\/pre><pre class=\"codeoutput\">ans =\r\n          1.00\r\n<\/pre><p>All floating point numbers larger than <tt>flintmax<\/tt> are integers, but the spacing between is larger than one, so they cannot be used for integer arithmetic.<\/p><h4>Rounding<a name=\"48e9c6a5-0d15-4441-b6d8-f828215f1bb8\"><\/a><\/h4><p>The idea behind all versions of <tt>round<\/tt> is the following. Suppose <tt>abs(x)<\/tt> is between two integers, <tt>y-1<\/tt> and <tt>y<\/tt>.  Then<\/p><pre class=\"codeinput\">   a = abs(x) + 0.5;\r\n<\/pre><p>is between <tt>y-0.5<\/tt> and <tt>y+0.5<\/tt>.  And<\/p><pre class=\"codeinput\">   r = floor(a);\r\n<\/pre><p>is equal to either <tt>y-1<\/tt> or <tt>y<\/tt>, whichever is closer to <tt>abs(x)<\/tt>.<\/p><p>That idea works for almost all <tt>x<\/tt>.  However, if <tt>x<\/tt> is between <tt>f<\/tt> and <tt>flintmax<\/tt>, the quantity <tt>x + 0.5<\/tt> is not a floating point number and must itself be rounded to the nearest even by the addition hardware. If <tt>y<\/tt> is odd, the resulting <tt>a<\/tt> will be <tt>y+1<\/tt>, which is too large.<\/p><p>So, I must compute <tt>a<\/tt> by<\/p><pre class=\"codeinput\">   a = abs(x) + (0.5 - eps\/4);\r\n<\/pre><p>The quantity <tt>(0.5 - eps\/4)<\/tt> is the next smaller floating point number less that <tt>0.5<\/tt>.<\/p><h4><tt>round<\/tt><a name=\"a7268701-3d97-438d-b0b6-deb553b62de6\"><\/a><\/h4><p>This is the resulting proposal for the enhancement request on <tt>round<\/tt>. It is available <a href=\"https:\/\/blogs.mathworks.com\/cleve\/files\/Round3.m\">here<\/a>.  Only the line computing <tt>a<\/tt> has changed from Round Two.<\/p><pre class=\"codeinput\">   type <span class=\"string\">Round.m<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\nfunction r = round(varargin)\r\n% r = round(x) scales and rounds the elements of x to the nearest integers.\r\n% Default: ties, elements halfway between integers, are rounded away from zero.\r\n%\r\n% r = round(x,'even') ties round to even integers.\r\n% r = round(x,'odd') ties round to odd integers.\r\n% r = round(x,'up') ties round away from zero (same as default).\r\n% r = round(x,'down') ties round towards zero.\r\n% r = round(x,'plus') ties round to the right on the number line.\r\n% r = round(x,'minus') ties round to the left on the number line.\r\n%\r\n% r = round(x,n), n &gt;= 0, round(10^n*x)\/10^n, round(12.3456,2) = 12.3500        \r\n% r = round(x,-n), n &gt; 0, 10^n*round(x\/10^n), round(1234.56,-2) = 1200.\r\n% r = round(x,n,'significant'), round(.001234,2,'significant') = .0012\r\n% r = round(x,n,'decimals) same as round(x,n).\r\n%\r\n% r = round(x,...), ties, n, 'significant' and 'decimals' can be in any order.\r\n%\r\n% Use Round(...) with capital R to distinguish from built-in round(...).\r\n\r\n    [x,n,ties] = parse_input(varargin{:});\r\n    x = prescale(x,n);\r\n    \r\n    a = abs(x) + (0.5-eps\/4);\r\n    r = floor(a);\r\n        \r\n    switch ties\r\n       case 'even'\r\n           m = (r == a) &amp; (mod(r,2) == 1); \r\n       case 'odd'\r\n           m = (r == a) &amp; (mod(r,2) == 0);\r\n       case 'down'\r\n           m = (r == a);\r\n       case 'up'\r\n           m = [];\r\n       case 'plus'\r\n           m = (x &lt; 0) &amp; (r == a);\r\n       case 'minus'\r\n           m = (x &gt; 0) &amp; (r == a);\r\n       otherwise\r\n           error(['''' ties ''' not recognized.'])\r\n    end\r\n    r(m) = r(m) - 1;\r\n    r = sign(x).*r;\r\n\r\n    r = postscale(r,n);\r\n   \r\n    % ----------------------------------------------\r\n   \r\n    function [x,n,ties] = parse_input(varargin)\r\n        x = varargin{1};\r\n        n = zeros(size(x));\r\n        ties = 'up';\r\n        for k = 2:nargin\r\n            if isnumeric(varargin{k})\r\n                n(:) = varargin{k};\r\n            elseif strcmp(varargin{k},'significant')\r\n                n(:) = n(:) - ceil(log10(abs(x(:))));\r\n            elseif strcmp(varargin{k},'decimals')\r\n                % ignore\r\n            else\r\n                ties = varargin{k};\r\n            end\r\n        end\r\n    end\r\n   \r\n    function x = prescale(x,n)\r\n        if any(n ~= 0)\r\n            k = n &gt; 0;\r\n            x(k) = 10.^n(k).*x(k);\r\n            k = n &lt; 0;\r\n            x(k) = x(k).\/10.^(-n(k));\r\n        end\r\n    end\r\n \r\n    function r = postscale(r,n)\r\n        if any(n ~= 0)\r\n            k = n &gt; 0;\r\n            r(k) = r(k).\/10.^n(k);\r\n            k = n &lt; 0;\r\n            r(k) = 10.^(-n(k)).*r(k);\r\n        end\r\n    end\r\nend\r\n<\/pre><h4>test<a name=\"98e070ea-b963-422b-93c9-4c67d4abb62e\"><\/a><\/h4><p>The vector <tt>x = f:flintmax<\/tt> would have <tt>2^52+1<\/tt> elements. That's too many.  The first four and the last four is enough.<\/p><pre class=\"codeinput\">    format <span class=\"string\">hex<\/span>\r\n    x = [f+(0:3); 2*f-(3:-1:0)]\r\n    r = Round(x)\r\n    up = Round(x,<span class=\"string\">'up'<\/span>)\r\n    down = Round(x,<span class=\"string\">'down'<\/span>)\r\n    even = Round(x,<span class=\"string\">'even'<\/span>)\r\n    odd = Round(x,<span class=\"string\">'odd'<\/span>)\r\n    plus = Round(x,<span class=\"string\">'plus'<\/span>)\r\n    minus = Round(x,<span class=\"string\">'minus'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">x =\r\n   4330000000000000   4330000000000001   4330000000000002   4330000000000003\r\n   433ffffffffffffd   433ffffffffffffe   433fffffffffffff   4340000000000000\r\nr =\r\n   4330000000000000   4330000000000001   4330000000000002   4330000000000003\r\n   433ffffffffffffd   433ffffffffffffe   433fffffffffffff   4340000000000000\r\nup =\r\n   4330000000000000   4330000000000001   4330000000000002   4330000000000003\r\n   433ffffffffffffd   433ffffffffffffe   433fffffffffffff   4340000000000000\r\ndown =\r\n   432ffffffffffffe   4330000000000000   4330000000000001   4330000000000002\r\n   433ffffffffffffc   433ffffffffffffd   433ffffffffffffe   433fffffffffffff\r\neven =\r\n   4330000000000000   4330000000000000   4330000000000002   4330000000000002\r\n   433ffffffffffffc   433ffffffffffffe   433ffffffffffffe   4340000000000000\r\nodd =\r\n   432ffffffffffffe   4330000000000001   4330000000000001   4330000000000003\r\n   433ffffffffffffd   433ffffffffffffd   433fffffffffffff   433fffffffffffff\r\nplus =\r\n   4330000000000000   4330000000000001   4330000000000002   4330000000000003\r\n   433ffffffffffffd   433ffffffffffffe   433fffffffffffff   4340000000000000\r\nminus =\r\n   432ffffffffffffe   4330000000000000   4330000000000001   4330000000000002\r\n   433ffffffffffffc   433ffffffffffffd   433ffffffffffffe   433fffffffffffff\r\n<\/pre><script language=\"JavaScript\"> <!-- \r\n    function grabCode_cb1cad3432704c689dd5206b6210d8b8() {\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='cb1cad3432704c689dd5206b6210d8b8 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' cb1cad3432704c689dd5206b6210d8b8';\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 2021 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_cb1cad3432704c689dd5206b6210d8b8()\"><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; R2021a<br><\/p><\/div><!--\r\ncb1cad3432704c689dd5206b6210d8b8 ##### SOURCE BEGIN #####\r\n%% Round, With Tie Breakers, Round Three\r\n% I recently published\r\n% <https:\/\/blogs.mathworks.com\/cleve\/2021\/02\/25\/round-with-ties-to-even\/\r\n% Round, With Ties to Even> and followed that with\r\n% <https:\/\/blogs.mathworks.com\/cleve\/2021\/03\/02\/round-with-tie-breakers-round-two\/\r\n% Round Two>.  Then, in an email, Andy Bartlett pointed out\r\n% that my new |round| function fails for some large\r\n% values of |x| between |flintmax\/2| and |flintmax|.\r\n\r\n%% |flintmax\/2|\r\n% The quantity |f = flintmax\/2| is equal to |2^52|, which is |1\/eps|.\r\n% The |help| entry for |format bank| says it is a fixed format for\r\n% dollars and cents.  That's true, but I also like to use it for\r\n% displaying large flints.\r\n\r\n   format bank\r\n   f = flintmax\/2\r\n   \r\n%%\r\n% The numbers in the interval\r\n% |[f flintmax]| are the _largest_ flints.  They are all integers.  \r\n% The spacing between them is one.\r\n\r\n   eps(f)\r\n   \r\n%%\r\n% All floating point numbers larger than |flintmax| are integers,\r\n% but the spacing between is larger than one, so they cannot be used for \r\n% integer arithmetic.\r\n\r\n%% Rounding\r\n% The idea behind all versions of |round| is the following.\r\n% Suppose |abs(x)| is between two integers, |y-1| and |y|.  Then\r\n%\r\n   a = abs(x) + 0.5;\r\n  \r\n%%\r\n% is between |y-0.5| and |y+0.5|.  And\r\n%\r\n   r = floor(a);\r\n \r\n%%\r\n% is equal to either |y-1| or |y|, whichever is closer to |abs(x)|.\r\n%\r\n% That idea works for almost all |x|.  However, if |x| is between |f| and\r\n% |flintmax|, the quantity |x + 0.5| is not a floating point number and\r\n% must itself be rounded to the nearest even by the addition hardware.\r\n% If |y| is odd, the resulting |a| will be |y+1|, which is too large.\r\n%\r\n% So, I must compute |a| by\r\n\r\n   a = abs(x) + (0.5 - eps\/4);\r\n\r\n%%\r\n% The quantity |(0.5 - eps\/4)| is the next smaller floating point number\r\n% less that |0.5|.\r\n\r\n%% |round|\r\n% This is the resulting proposal for the enhancement request on |round|.\r\n% It is available <https:\/\/blogs.mathworks.com\/cleve\/files\/Round3.m\r\n% here>.  Only the line computing |a| has changed from Round Two.\r\n\r\n   type Round.m\r\n\r\n%% test\r\n% The vector |x = f:flintmax| would have |2^52+1| elements.\r\n% That's too many.  The first four and the last four is enough.\r\n\r\n    format hex\r\n    x = [f+(0:3); 2*f-(3:-1:0)]\r\n    r = Round(x)\r\n    up = Round(x,'up')\r\n    down = Round(x,'down')\r\n    even = Round(x,'even')\r\n    odd = Round(x,'odd')\r\n    plus = Round(x,'plus')\r\n    minus = Round(x,'minus')\r\n\r\n   \r\n\r\n    \r\n\r\n##### SOURCE END ##### cb1cad3432704c689dd5206b6210d8b8\r\n-->","protected":false},"excerpt":{"rendered":"<!--introduction--><p>I recently published <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2021\/02\/25\/round-with-ties-to-even\/\">Round, With Ties to Even<\/a> and followed that with <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2021\/03\/02\/round-with-tie-breakers-round-two\/\">Round Two<\/a>.  Then, in an email, Andy Bartlett pointed out that my new <tt>round<\/tt> function fails for some large values of <tt>x<\/tt> between <tt>flintmax\/2<\/tt> and <tt>flintmax<\/tt>.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/cleve\/2021\/03\/08\/round-with-tie-breakers-round-three\/\">read more >><\/a><\/p>","protected":false},"author":78,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16,7,37],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/6792"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/users\/78"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/comments?post=6792"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/6792\/revisions"}],"predecessor-version":[{"id":6796,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/6792\/revisions\/6796"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/media?parent=6792"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/categories?post=6792"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/tags?post=6792"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}