GNU Octave, rotunjește un număr la unități de precizie (Programare, Linux, Matrix, Rotunjire, Precizie, Octavă)

Eric Leschinski a intrebat.

În GNU Octave versiunea 3.4.3 vreau să rotunjesc o matrice la o precizie de 2 unități pe conținutul unei matrice, astfel.

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

Aceasta se tipărește:

1.1235   2.1235
3.1235   4.1234

După cum puteți vedea, disp forțează precizia la „5”, eu vreau ca precizia unităților să fie 2. Cum pot face acest lucru?

3 răspunsuri
Eric Leschinski

Cum se rotunjesc elementele dintr-o matrice în Octave:

Există multe moduri diferite de a rotunji o matrice și de a rotunji un număr în Octave.

Opțiunea 1, utilizarea funcției de format sprintf

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

Ieșire, observați simbolul „%5.2f”. „f” înseamnă că se așteaptă un float, iar 5 înseamnă că ocupă 5 spații. 2 înseamnă precizie de 2 unități după virgulă.

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

Opțiunea 2, rotunjire la cifre semnificative utilizând eval și mat2str

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

Ieșirematrice rotunjită la 3 cifre semnificative, observați că 100,123 a fost rotunjit la 100, în timp ce 2,12345 a fost rotunjit la 2,12.

mymatrix2 = 100.0000     2.1200
              3.1200     4.1200

Opțiunea 3, utilizați funcția round

Funcția round nu are un parametru de precizie în Octave. Cu toate acestea, o puteți ocoli prin înmulțirea fiecărui element din matrice cu 100, rotunjirea la cel mai apropiat int, apoi împărțirea fiecărui element la 100:

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

Ieșire, rotunjirea are loc corect:

ans = 100.1200     2.1200
        3.1200     4.1200

Opțiunea 4, specificați un parametru output_precision(num)

Ați observat că opțiunea 3 de mai sus a păstrat zerourile din urmă, ceea ce poate fi nedorit, așa că puteți să le spuneți să dispară prin setarea 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 are un comportament ciudat atunci când încearcă să facă rotunjirea, deoarece octave se străduiește să aplice uniform o rotunjire uniformă tuturor elementelor dintr-o matrice. Deci, dacă aveți mai multe coloane cu valori extrem de diferite, octave vede o valoare mică și spune: „Ar trebui să o convertesc într-o exponențială de genul 1.0e-04, și astfel, același exponențial este aplicat întregii structuri de date din matrice.

Ufos

pentru cei care vor să o facă să funcționeze fără a săpa adânc în discuții de ce lucrurile stau așa (și anume octave round încă nu suportă un al doilea argument care să definească precizia).

SOLUȚIE:

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

Comentarii

  • De ce nu octave nu suportă round cu un al doilea argument?! –  > Por Jonathon Reinhart.
  • @JonathonReinhart, nu reușesc să găsesc problema corespunzătoare pe savannah.gnu.org, dar explicația este următoarea. Comportamentul round(number, precision) provine de la faptul că aveți un matematică simbolică [sym], care înlocuiește pachetul implicit cu un singur argument round al matlab-ului de bază cu versiunea cu două argumente. Deoarece octave își propune să implementeze doar matlab-ul de bază, iar implementarea pachetelor sale este o altă etapă, astfel încât utilizatorii rămân cu stilul anilor ’80 round. –  > Por Ufos.
  • Pe de altă parte, matlab’s round(x, precision) nu va rula pe mașina altcuiva, care nu are pachetul de matematică simbolică, prin urmare, luați în considerare scrierea unei funcții customg, și folosiți-o peste tot. –  > Por Ufos.
  • versiunea octave’s round a fost compatibilă cu Matlab atunci când a fost scrisă pentru prima dată (de exemplu, înainte de 2014). bug-ul 55682 există de ceva timp în legătură cu această problemă. Puteți vedea discuția de acolo pentru un motiv pentru care nu s-a întâmplat încă. savannah.gnu.org/bugs/?55682 –  > Por Nick J.
  • Acest lucru nu va funcționa corect pentru valori negative. a = floor(a) ar trebui să fie înlocuit cu if (a >= 0) a = floor(a); else a = ceil(a); endif; –  > Por Cromax.
Eric Leschinski

Am găsit următoarea funcție GNU Octave extrem de utilă. Aceasta vă permite să specificați o rotunjire personalizată pentru fiecare coloană individuală a unei matrice MxN.

Puneți această funcție într-un fișier numit display_rounded_matrix.m

function display_rounded_matrix(matrix, precision, outputFile)
  %precision can be a single number, applied to all, or a 
  %matrix of values to be applied to the columns. 

  space_between_columns = "";
  format_part = "%10.";

  precision_format = cell(columns(precision), 1);
  for i = 1:columns(precision),
    precision_format{i,1} = strcat(format_part, num2str(precision(1,i)), "f");
  end

  if (nargin == 3 && outputFile != 0)
    if (rows(precision) == 1 && columns(precision) == 1)
      rows = rows(matrix);
      cols = columns(matrix);
      format = strcat(format_part, num2str(precision), "f");
      for i = 1:rows
        for j = 1:cols
          fprintf(outputFile, sprintf(format, matrix(i,j)));
          if (j ~= cols)
            fprintf(outputFile, space_between_columns);
          end
        end
        if i ~= rows
          fprintf(outputFile, "
");
        end
      end
      fprintf(outputFile, "
");
    elseif (rows(precision) == 1 && columns(precision) == columns(matrix))
      %here we have to custom make the rounding
      rows = rows(matrix);
      cols = columns(matrix);
      for i = 1:rows
        for j = 1:cols
          fprintf(outputFile, sprintf(precision_format{j,1}, matrix(i,j)));
          if (j ~= cols)
            fprintf(outputFile, space_between_columns);
          end
        end
        if i ~= rows
          fprintf(outputFile, "
");
        end
      end
      fprintf(outputFile, "
");
    else
      disp("STOP!, you invoked display_rounded_matrix with bad parameters");
    end

  elseif (nargin == 3 && outputFile == 0)
%print to screen instead

if (rows(precision) == 1 && columns(precision) == 1)
      rows = rows(matrix);
      cols = columns(matrix);
      format = strcat(format_part, num2str(precision), "f");
      for i = 1:rows
        for j = 1:cols
          printf(sprintf(format, matrix(i,j)));
          if (j ~= cols)
            printf(space_between_columns);
          end
        end
        if i ~= rows
          printf("
");
        end
      end
      printf("
");
    elseif (rows(precision) == 1 && columns(precision) == columns(matrix))
      %here we have to custom make the rounding
      rows = rows(matrix);
      cols = columns(matrix);
      for i = 1:rows
        for j = 1:cols
          %format = strcat(format_part, num2str(precision(1,j)), "f");
          format = [format_part num2str(precision(1,j)) "f"];
          printf(sprintf(format, matrix(i,j)));
          if (j ~= cols)
            printf(space_between_columns);
          end
        end
        if i ~= rows
          printf("
");
        end
      end
      printf("
");
    else
      disp("STOP!, you invoked display_rounded_matrix with bad parameters");
    end

  elseif (nargin == 2)
    display_rounded_matrix(matrix, precision, 0);
  else
    disp("STOP!, you invoked display_rounded_matrix with wrong number of arguments");
  end
end

Apoi o puteți invoca astfel:

A = [ 53.0 410400  0.0094; 52.56 778300 -0.0069; 53.56 451500 -0.0340 ];
specified_rounding = [2 0 5];
display_rounded_matrix(A, specified_rounding, outputFile=0);

Aceasta va afișa pe ecran următoarele (observați rotunjimile diferite pentru fiecare coloană!

octave:5> display_rounded_matrix(A, specified_rounding, outputFile=0);
  53.00    410400   0.00940
  52.56    778300  -0.00690
  53.56    451500  -0.03400

cel de-al treilea parametru este un mâner de fișier, ați putea redirecționa ieșirea și către un fișier:

outputFile = fopen("output.txt", "w");
A = [ 53.0 410400  0.0094; 52.56 778300 -0.0069; 53.56 451500 -0.0340 ];
specified_rounding = [2 0 5];
display_rounded_matrix(A, specified_rounding, outputFile);

Ceea ce va face același lucru ca mai sus, dar va trimite ieșirea la output.txt