Round, With Tie Breakers, A Prototype

In February and March I published three blog posts about an enhancement request for MATLAB concerning tie breakers with the圆形的function, including the ability to round ties to even.第一回合,第二轮andRound Three。从那时起,由我的同事(和学术曾曾孙子)Heiko Weichelt组织的Mathworks的我们中的一群人一直在考虑这一要求。我们最近进行了虚拟设计评论。这篇文章描述了一个原型,其中包含了该评论中讨论的功能。

Contents

圆形的

Traditionally,帮助圆形的had only one line.

ROUND(X) rounds each element of X to the nearest integer.

一个few years ago, two optional arguments were added.

ROUND(X, N), for positive integers N, rounds to N digits to the right of the decimal point. If N is zero, X is rounded to the nearest integer. If N is less than zero, X is rounded to the left of the decimal point. N must be a scalar integer.
ROUND(X, N, 'significant') rounds each element to its N most significant digits, counting from the most-significant or left side of the number. N must be a positive integer scalar.

floor and ceil

The functionsfloorandceilhave important roles in any discussion of rounding. Every real number,x, that is not an integer, lies between two integers,

floor(x) < x < ceil(x) = floor(x) + 1

Ifxis an integer, then

地板(x)= x = ceil(x)

The functionfloor(x)defines "roundingx对minus infinity" and the functionCEIL(X)is "roundingx对plus infinity".

The functionfix(x),也称为“整数的一部分x", is

fix(x) = floor(x) if x >= 0, = ceil(x) if x < 0.

The "fractional part ofx" is

frac(x)= x- fix(x)。

两个例子

x = 9.64 x = -9.64落地(x)= 9落地(x)= -10 ceil(x)= 10 ceil(x)= -9 fix(x)= 9 fix(x)= -9 frac(x)= 0.64 frac(x)= -0.64

Ties

The traditional code for圆(x)是一行。

圆(x)=符号(x)。*地板(abs(x) + 0.5)

This implies that

圆(x)= floor(x) if frac(x) < 0.5 = ceil(x) if frac(x) > 0.5

This unambiguously defines圆(x)for almost allx。The only ambiguous situations are the圆形的ing ties。They occur when the fractional part ofxis exactly 1/2, or 0.5 in decimal. Ties are relatively rare. Traditionally, MATLAB has rounded ties away from zero.

当未指定缩放率时,纽带是两个连续整数之间的数字,

halfs = -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, ...

The "round ties away from zero" rule produces

圆形的(halfs) = -4, -3, -2, -1, 1, 2, 3, 4, ...

Recently, there has been some interest in alternatives to this behavior. One alternative is "round ties to nearest even". For the halfway numbers, this would be

halfs_even = -4,-2,-2,0,0,2,2,4,...

Nearest decimal

以下是四舍五入到最近的小数值的四个示例。

格式短的格式袖珍的
  • Express intercity mileage distance in whole numbers. The distance from my home office to MathWorks headquarters is 406.3 miles. What is this to the nearest mile?
miles = Round(406.3)
miles = 406
  • The patient's body temperature is 98.64 degrees. Express this in nearest tenths of a degree.
温度=圆形(98.64,1)
temp = 98.6000
  • Express monetary values in hundredths. The computed interest is 13.8327 Euros. Express this in hundredths of a Euro.
cents = Round(13.8327,2)
cents = 13.8300
  • The population of Tallahassee in 2019 was reported to be 194,500. What is this to the nearest one-thousand people?
流行=圆形(194500,-3)
流行= 195000

这些例子中只有一个涉及领带。有了圆形的规则,塔拉哈西人的人口将被列为194,000而不是195,000。

IEEE 754

The圆形的function is not the same as the round-to-even setting for IEEE 754 floating point arithmetic. The圆形的function is done with software by MATLAB; its input is doubles (or singles) and the output is flints (floating point numbers whose values are integers.) The IEEE 754 setting is done in hardware, its input is extended precision or registers with guard bits and its output is doubles that are rarely flints.

Name-value pairs

Several reviewers preferred name-value pairs. Name-value pairs have been part of MATLAB syntax for a long time and a recent enhancement involves the use of an equals sign to specify them. For example

plot(x,y,'ko','markersize',10)

现在可以写

plot(x,y,marker='o',color='black',markersize=10)

The left hand portion of a name-value pair is theparamNameand the list of possible right hand portions isparamValues

一个t first, I was not enthusiastic about using a name-value pair for tie-braking in圆形的。But after working on this prototype and blog post, I am now in favor. TheparamNamecould be

圆形

There would be six possibleparamValues

awayFromZero towardZero toEven toOdd towardPlusInfinity towardMinusInfinity

例如

x = (0.1:0.2:0.9)' r_from = Round(x,roundTies='awayFromZero') r_even = Round(x,roundTies='toeven')
x = 0.1000 0.3000 0.5000 0.7000 0.9000 r_from = 0 0 1 1 1 1 r_even = 0 0 0 0 1 1 1

Not-a-Number

This occurred to me while writing this post. How about a seventh choice for handling ties?

r_nan = Round(x,roundTies='toNaN')
r_nan = 0 0 nan 1 1

帮助

The next five sections are the code for a prototype. The file name isRound.mwith a capitalR因此我们也可以访问圆形的function from the current release. The code is available here:Round.m

code = split(string(fileread(“Round.m”),'%_');

The help text is concise.

disp(code(1))
函数x =圆形(varargin)%圆形朝着最近的十进制或整数。%圆(x)X圆的每个元素到最近的整数。%圆(x,n)到第n个小数点。%round(x,n,数字=“显着”)到n个显着数字。%round(x,n,Digits =“ Decimals”)与圆形(x,n)相同。%%round(x,...,roundties =“ overfromzero”)%round(x,...,roundties =“ tozero”)%round(x,...,roundties =“ toodd”)%round(x,...,roundties =“ toeeven”)%round(x,...,roundties =“ toplusinfinity”)%round(x,...,roundties =“ tominusinfinity”)%cisties是罕见的。圆(x,n)仅当两个连续整数之间的点的圆形误差在百分比的圆误差之内。

例子

The help text continues with a few examples.

disp(代码(2))
% Examples % % x = 123456.789 % % round(x) 123457 % round(x,-3) 123000 % round(x,2) 123456.79 % % x = 1.125 % % round(x) 1.000 % round(x,1) 1.100 % round(x,2) 1.130 % round(x,2,roundTies="toEven") 1.120 % round(x,2,roundTies="toOdd") 1.130 % round(x,3) 1.125 % round(x,3,"significant") 1.130 % % x = 1.115 % xlo = 1115/1000 - eps/25 % xhi = 1115/1000 + 24*eps/25 % % round(x,2) 1.120 % round(xlo,2,roundTies="toOdd") 1.110 % round(xhi,2,roundTies="toEven") 1.120

main

Here is the body ofRound。The numerically sensitive portions are the definition of精确的和选择<or<=in the determination oft, the ties.

disp(代码(3))
% main program [x,n,sig,tie] = parse(varargin{:}); x0 = x; s = sign(x); x = abs(x); if sig n = n - ceil(log10(x)); else n = n - zeros(size(x)); end x = scale(x,n); z = x; f = z - floor(z); m = (f < 0.5); x(m) = floor(z(m)); m = (f >= 0.5); x(m) = ceil(z(m)); exact = (x0 == single(x0)); if exact t = (f == 0.5); % ties else t = abs(f - 0.5) <= eps(z); % ties end x(t) = ceil(z(t)); switch tie case 'even' m = (mod(x(t),2) == 1); case 'odd' m = (mod(x(t),2) == 0); case 'plus' m = (s(t) < 0); case 'minus' m = (s(t) > 0); case 'zero' m = 1; case 'nan' m = NaN; otherwise m = 0; end x(t) = x(t) - m; x = s.*scale(x,-n);

parse

该解析器以非常简单的方式处理名称值对。一个more serious parserwould be more discriminating.

disp(代码(4))
function [x,n,sig,tie] = parse(varargin) x = varargin{1}; n = 0; sig = false; tie = 'from'; for k = 2:nargin vk = varargin{k}; if isnumeric(vk) n = vk; elseif vk == "significant" sig = true; elseif vk == "decimals" || ... vk == "roundTies" || ... vk == "digits" % ignore else tie = char(vk); caps = find(double(tie) < double('a')); if length(caps) > 1 && caps(2) > caps(1)+2 tie = lower(tie(caps(1):caps(2)-1)); elseif length(caps) > 0 && length(tie(caps:end)) <= 5 tie = lower(tie(caps(1):end)); else error(vk + " not recognized.") end end end end

规模

This scaling function always multiplies or divides by positive integer powers of 10, which are exact forn < = 16

disp(代码(5))
function x = scale(x,n) k = (n > 0); x(k) = x(k).*10.^n(k); k = (n < 0); x(k) = x(k)./10.^(-n(k)); end

graphic

Here is the graphic from previous posts, now labeled by theparamValues

graphic

软件

The prototype code is available here:Round.m




Published with MATLAB® R2021b

|

Comments

To leave a comment, please click这里to sign in to your MathWorks Account or create a new one.