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
- Category:
- 历史,
- Numerical Analysis,
- Precision
Comments
To leave a comment, please click这里to sign in to your MathWorks Account or create a new one.