当在 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
根据维基百科,负号是允许的。
[ 的结果
a mod n
] 如果余数非零,这仍然会留下符号歧义:余数有两种可能的选择,一种是负数,另一种是正数,商数有两种可能的选择。通常,在数论中,总是选择正余数,但编程语言根据语言和 a 或 n 的符号进行选择。
所以由编程语言来定义它。由于 bash 显然采用了“负余数”方式,因此您可能会像这样逃到 perl 中:
for i in {-5..5}; do perl -le "print $i%3"; done
这是以为每个整数单独启动 Perl 解释器为代价的。
的确!由于 OP 似乎关心正确的数学,您可能会考虑切换到类似的东西python
并执行循环和其中的所有内容。