是否可以在 shell 脚本中使用dc来舍入堆栈的顶部?如果是,是否有命令将结果向上和向下舍入?
多谢你们!
dc
手册说:
大多数算术运算都受“精度值”的影响,您可以使用
k
命令对其进行设置。默认精度值为零...
/
弹出两个值,将弹出的第二个值与弹出的第一个值相除,然后推送结果。小数位数由精度值指定。
因此,您可以使用截断(向零舍入)0k1/
,或者仅1/
当您知道精度为 0(默认为 0)时。例如:
$ dc -e '12.9 1/ p'
12
$ dc -e '_12.9 1/ p'
-12
其他类型的舍入更困难。要四舍五入到最接近的整数,您可以使用[_1*]sad.5r0>a+0k1/
,例如:
$ dc -e '12.9 [_1*]sad.5r0>a+0k1/ p'
13
$ dc -e '_12.9 [_1*]sad.5r0>a+0k1/ p'
-13
快速解释:
[_1*]sa
将命令_1*
(乘以 -1)存储在寄存器中a
。d
复制堆栈顶部的值(我们要舍入的值,称为v)。.5r
推入 0.5 然后交换前两个值,因此堆栈现在是v 0.5 v。0>a
a
如果 0 > v(即如果v为负数) ,则执行寄存器中的命令。如果v为正,则堆栈现在为 0.5 v ,如果v为负,则为-0.5 v。+
将前两个值相加,如果 v 为正,则推v + 0.5,如果v为负,推v - 0.5 。0k1/
如上所述截断。如果您知道要四舍五入的数字是非负数,则可以使用.5+0k1/
; 如果您还知道精度为 0,则可以使用.5+1/
.
要四舍五入,请使用[dX[1-]sa0<a]sad0>a0k1/
.
要四舍五入,请使用[dX[1+]sa0<a]sad0<a0k1/
.
所有这些建议都使用 register a
,因此您可能需要在实际程序中对其进行调整。
在 Gareth 的回答的基础上,使用以下方法进行银行家的四舍五入(即四舍五入到最接近的偶数):[_1*]sa[d1r0>a+]sbd0k1/2%0!=b1/
。
请注意,这使用了额外的寄存器b。
这有点密集,所以让我们分解一下:
[_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).