17

In GNU Octave version 3.4.3 I want to round a matrix to 2 units precision on the contents of a matrix like this.

mymatrix=[1.1234567, 2.12345; 3.1234567891, 4.1234];
disp(mymatrix);

This prints:

1.1235   2.1235
3.1235   4.1234

As you can see, the disp forces the precision to '5', I want the units precision to be 2. How do I do this?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335

2 Answers2

31

How to round off elements in a matrix in Octave:

There are many different ways to round a matrix and round a number in octave.

Option 1, use of sprintf format feature

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
rows = rows(mymatrix);
cols = columns(mymatrix);
for i = 1:rows
  for j = 1:cols
    sprintf("%5.2f", mymatrix(j,i))
  endfor
endfor

Output, note the "%5.2f" token. The 'f' means expect a float, the 5 means occupy 5 spaces. The 2 means 2 units precision after the decimal point.

ans = 100.12
ans =   3.12
ans =   2.12
ans =   4.12

Option 2, round to significant digits using eval and mat2str

mymatrix2=[100.1234567, 2.12345; 3.1234567891, 4.1234];
j = mat2str(mymatrix2, 3);
mymatrix2=eval(j)

Output, matrix rounded to 3 significant digits, notice 100.123 rounded to 100 while the 2.12345 was rounded to 2.12

mymatrix2 = 100.0000     2.1200
              3.1200     4.1200

Option 3, use the round function

The round function does not have a precision parameter in Octave. However you can hack around it by multiplying each item in the matrix by 100, rounding it to the nearest int, then dividing each item by 100:

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
round(mymatrix .* 100) ./ 100

Output, round occurs correctly:

ans = 100.1200     2.1200
        3.1200     4.1200

Option 4, specify a output_precision(num)

You noticed that option 3 above kept the trailing zeros, which may be undesirable, so you can tell them to go away by setting output_precision:

mymatrix=[100.1234567, 2.12345; 3.1234567891, 4.1234];
disp(mymatrix);
output_precision(3)
disp(mymatrix)

Output:

100.1235     2.1235
  3.1235     4.1234

100.123     2.123
  3.123     4.123

Octave has some odd behavior when trying to do rounding because octave tries hard to uniformly apply a uniform rounding to all items in a matrix. So if you have multiple columns with wildly different values, octave sees a tiny value and says: "I should convert that to an exponential like 1.0e-04, and so the same exponential is applied to the entire data structure in the matrix.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • Why doesn't it just mirror MATLAB's `round` functionality? – Nike May 25 '23 at 04:28
  • In the end I used your third option: `round(mymatrix .* 100000) ./ 100000` to round with 5 decimal digits. The first option gave me a a 1D vector instead of a matrix. The second option doesn't seem to round correctly according to what you say, so I went with the third option. – Nike May 25 '23 at 05:27
6

for those who want to get it working without digging deep into discussion why things are this way (namely octave round still does not support a second argument defining precision).

WORKAROUND:

a = [0.056787654, 0.0554464; 0.056787654, 0.0554464];
a
round_digit = 2;
if exist('OCTAVE_VERSION', 'builtin') ~= 0;
     a = a.*(10^(round_digit));
     if (a >= 0) a = floor(a); else a = ceil(a); endif;
     a = a.*(10^(-round_digit));
else
     a = round(a, round_digit);
end
a
Ufos
  • 3,083
  • 2
  • 32
  • 36
  • 3
    Why *doesn't* octave support `round` with a second argument?! – Jonathon Reinhart Oct 03 '17 at 15:22
  • 2
    @JonathonReinhart, I am unable to find the corresponding issue on `savannah.gnu.org`, but the explanation is following. The behavior `round(number, precision)` comes from you having a **symbolic math** [`sym`] package, which replaces the default one-argument `round` of the bare-bones matlab with the augmented two-arguments version. Since octave aims to only implement the baseline matlab, and implementing its packages is a different milestone, so the users are left with 80's style `round`. – Ufos Oct 04 '17 at 14:37
  • 1
    On the other hand, matlab's `round(x, precision)` won't run on someone else's machine, who doesn't have symbolic math package, therefore consider writing a customg function, and use it everywhere. – Ufos Oct 04 '17 at 14:38
  • Base MATLAB’s `round` has had a second parameter [since 2014](https://www.mathworks.com/help/matlab/ref/round.html#mw_a1bb074e-8701-48bf-88bb-6b402b1b6267). – Cris Luengo Mar 31 '20 at 13:23
  • 1
    octave's version of round was compatible with Matlab when it was first written (e.g., before 2014). bug 55682 has been around for a little while regarding that issue. You can see the discussion there for some reason why it hasn't happened yet. https://savannah.gnu.org/bugs/?55682 – Nick J Apr 22 '20 at 22:55
  • 1
    This will not work correctly for negative values. `a = floor(a)` should be replaced with `if (a >= 0) a = floor(a); else a = ceil(a); endif;` – Cromax Dec 29 '20 at 23:09