È possibile arrotondare la parte superiore della pila utilizzando dc in uno script di shell? Se sì ci sono comandi per arrotondare il risultato su e giù?Arrotondare il risultato utilizzando dc (calcolatrice da tavolo)
Grazie ragazzi!
È possibile arrotondare la parte superiore della pila utilizzando dc in uno script di shell? Se sì ci sono comandi per arrotondare il risultato su e giù?Arrotondare il risultato utilizzando dc (calcolatrice da tavolo)
Grazie ragazzi!
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*]sa
memorizza il comando _1*
(moltiplicare per -1) nel registro a
.d
duplica il valore in cima allo stack (il valore che vogliamo arrotondare, chiamiamolo v)..5r
spinge 0,5 e scambia i primi due valori, quindi la pila è ora v 0,5 v.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.+
aggiunge i due valori e spinge v + 0,5 se v è positivo, o v - 0,5 se v è negativo.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.
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).