2013-10-11 11 views

risposta

6

Il dc manual dice:

operazioni aritmetiche La maggior parte sono influenzati dal "valore di precisione", che si può impostare con il comando k. Il valore di precisione predefinito è zero ...

/ Inserisce due valori, divide il secondo prelevato dal primo e stampa il risultato. Il numero di cifre della frazione è specificato dal valore di precisione.

Così si può troncare (rotonda verso lo zero) utilizzando 0k1/, o semplicemente 1/ se si sa che la precisione è 0, che è di default. Ad esempio:

$ dc -e '12.9 1/ p' 
12 
$ dc -e '_12.9 1/ p' 
-12 

Altri tipi di arrotondamento sono più difficili. Per intorno all'intero più vicino, è possibile utilizzare [_1*]sad.5r0>a+0k1/, ad esempio:

$ dc -e '12.9 [_1*]sad.5r0>a+0k1/ p' 
13 
$ dc -e '_12.9 [_1*]sad.5r0>a+0k1/ p' 
-13 

Una spiegazione pratica:

  1. [_1*]sa memorizza il comando _1* (moltiplicare per -1) nel registro a.
  2. d duplica il valore in cima allo stack (il valore che vogliamo arrotondare, chiamiamolo v).
  3. .5r spinge 0,5 e scambia i primi due valori, quindi la pila è ora v 0,5 v.
  4. 0>a esegue il comando nel registro a se 0>v (cioè, se v è negativo). Lo stack è ora 0,5 v se v è positivo, o -0.5 v se v è negativo.
  5. + aggiunge i due valori e spinge v + 0,5 se v è positivo, o v - 0,5 se v è negativo.
  6. 0k1/ tronca come descritto sopra.

Se si sa che il numero che si sta arrotondando è non negativo, è sufficiente utilizzare .5+0k1/; e se sai anche che la precisione è 0, puoi usare .5+1/.

A round down, utilizzare [dX[1-]sa0<a]sad0>a0k1/.

A arrotondare, utilizzare [dX[1+]sa0<a]sad0<a0k1/.

Tutti questi suggerimenti utilizzano il registro a, quindi potrebbe essere necessario regolarli nel programma attuale.

1

Sulla risposta di Gareth, utilizzare la seguente per arrotondamento (cioè tutto l'approssimazione anche intero) bancario: [_1*]sa[d1r0>a+]sbd0k1/2%0!=b1/.

Nota utilizza un registro aggiuntivo, b.

Questo è un po 'denso, quindi cerchiamo di scomposizione:

[_1*]sa   #1- Assign a macro "$input *= -1" to register 'a' 
[d1r0>a+]sb  #2- Assign a macro "if($input<0){$input -= 1} else{$input += 1}" 
       #  to register 'b' 
d    #3- Duplicate the input value; the duplicate will be used 
       #  to decide if the input is odd or even. 
0k    #4- Set precision to 0; this makes the 1/ operation truncate 
       #  all digits to the right of the decimal point. 
1/    #5- Truncate those decimal places on our duplicate input. 
2%    #6- Modulo 2; if we get 0, it was even, otherwise it's odd. 
       #  Note this consumes the duplicate from line #3. 
0!=b   #7- If it was odd, run the macro in register 'b'. This adds +/-1 
       #  to the input, respectively if it's positive or negative. 
1/    #8- Truncate decimal places; if the input was odd we're now 
       #  at floor($input+1) for positive or floor($input-1) 
       #  for negative; if it was even we're at floor($input). 
Problemi correlati