当天真地在bash中使用mod命令时,残差会在负分子中得到错误的符号(在我看来):
如果我写:
for i in {-5..5}; do echo $(( $i % 3 )) ; done
我得到输出(作为一行)
-2 -1 0 -2 -1 0 1 2 0 1 2
我如何实现“正确”的行为
1 2 0 1 2 0 1 2 0 1 2
我知道这是一个老问题,但不是循环,直到结果为正或启动perl或python考虑以下内容:
for i in {-5..5}; do echo $(( (($i % 3) + 3) % 3)) ; done
这将导致OP的期望输出。
这是因为第一个模将结果带到-3到3的范围,加3,导致结果在0到6的范围内,然后我们可以再次执行模数(加3对此没有影响)。
一般来说:mod = ((a % b) + b) % b
Add 3
然后Mod 3
到第一组结果:
$ for i in {-5..5}; do printf "%d " $(( (($i % 3) + 3) % 3 )) ; done
1 2 0 1 2 0 1 2 0 1 2
如果您知道最大范围,则可以在第一个模运算之前添加一个足够大的3的倍数,以使所有数字为正数。
$ for i in {-5..5}; do printf "%d " $(( ($i + 3000000) % 3 )) ; done
但是,第一种方法更清洁,更普遍。
最后,为了好玩:
positive_mod() {
local dividend=$1
local divisor=$2
printf "%d" $(( (($dividend % $divisor) + $divisor) % $divisor ))
}
for i in {-5..5}; do
printf "%d " $(positive_mod $i 3)
done
根据wikipedia允许的负面迹象。
[
a mod n
的结果]如果余数为非零,这仍然会留下符号模糊:剩余部分有两种可能的选择,一种是负的,另一种是正的,并且出现两种可能的商选择。通常,在数论中,总是选择正余数,但编程语言根据语言和a或n的符号选择。
所以由编程语言来定义它。由于bash显然已经走向了“负剩余”的方式,你可能会逃到例如像这样的perl:
for i in {-5..5}; do perl -le "print $i%3"; done
这是以为每个整数单独启动Perl解释器为代价的。
确实!由于OP似乎关心正确的数学,你可能会考虑切换到像python
这样的东西并进行循环以及其中的所有内容。