Editor's Note: This file was selected as MATLAB Central Pick of the Week
This little function rounds a number (or the elements of a vector ot matrix) towards the nearest number with N significant digits.
Examples:
roundsd(0.012345,3) returns 0.0123
roundsd(12345,2) returns 12000
roundsd(12.345,4,'ceil') returns 12.35
This is a useful complement to Matlab's ROUND, ROUND10 and ROUNDN (Mapping toolbox), especially when dealing with data with a large variety of order of magnitudes.
I was about to upload this file when I found "sd_round.m" by Edward Zechmann (see aknowledgment), which has similar feature (and more). But, because my script is very different in coding (much much shorter), I decided to share it anyway.
François Beauducel (2021). Round with significant digits (https://www.mathworks.com/matlabcentral/fileexchange/26212-round-with-significant-digits), MATLAB Central File Exchange. Retrieved .
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!Create scripts with code, output, and formatted text in a single executable document.
Thanks for the excellent little utility. I like the different rounding methods that are supported.
The error Colin Morris identified is in line 74:
if ~ischar(method) || ~ismember(opt,method)
The problem comes from the "ismember(opt, method)" requirement. From the R2011b
documentation, "ismember" returns a logical array the same size as the first argument.
Replacing the line with this:
if ~ischar(method) || ~ismember(method, opt)
fixes the problem.
How is this function different from the Matlab built-in funciton chop?
I noticed chop doesn't have a doc page, so it's impossible to find with docsearch.
Running on 2011a. I believe if found an error between lines 73-76. When explicitly stating the method ( i.e. 'fix',or 'ceil'), I receive the runtime error :
??? Operands to the || and && operators must be convertible to logical scalar values.
Error in ==> roundsd at 74
if ~ischar(method) || ~ismember(opt,method)
commenting the else statement between lines 73-76 solves the issue for me.
-C
Great function. I should find it earlier.
Will, it's a precision problem of floating point arithmetic. Try:
3.55/0.1-35.5
ans =
-7.105427357601e-15
This little number trigger the balance. I think it's hard to overcome.
Does not work in all cases. Try rounding 3.55 to 1 decimal place and you get 3.5 instead of 3.6
veru good
a very useful extension to the usual round functions.
one small speed improvement can be achieved. Using find is very slow. one can use logical indexing just like this:
y(x==0) = 0;
it does the same job while much faster with lager arrays.
Thanks,
Tobi
Very nice simple and compact code.
Should be build into next Matlab versions.
Much appreciated -- thanks.
So useful that it should be built in to the Matlab round function, as it is in other languages
I think your submission deserves a much better overall rating.
Thanks Oleg.
Yes, I will complete the "see also" function list in future updates.
1) you effectively need the "find" in Matlab versions < 7... and also single pipe for the OR test.
2) like you I have hesitated between "switch" and "feval". But the feval code is much shorter...
François.
I would mention in the see also line the other rounding functions you use.
I never used matlab < 7 so I don't know if this applies:
1) no need to use find: y(find(x==0)) = 0;
2) I would use switch case instead of feval.
Oleg
Thanks Daniel for your time. I submitted an updated version that corrects the zero-value behaviour, and I added some options for the rounding method.
About the mlint messages, I kept my original syntax which is voluntarily backward compatible (with Matlab versions < 7).
I also noticed some mlint-messages that I fixed. The core of the code now looks like this:
if ~isnumeric(n) || numel(n) ~= 1 || n < 0 || mod(n,1) ~= 0
error('N argument must be a scalar positive integer.')
end
valuesZero = (x==0);
og = 10.^(floor(log10(abs(x)) - n + 1));
y = round(x./og).*og;
y(valuesZero) = 0;
I just wrote one of these and was anout to upload it. But since you had allready done it, there is no point. This file would get a very high mark by me for several reasons:
1) Simple function, no bloated features
2) Error checking.
3) Well formated documentation.
Unfortunately, your script doesn't handle 0. That pulls down the mark significantly.