事实证明,这是一个有趣的问题。我所做的假设是,对于 整数 间隔,模是相对于 截断除法 定义的(向 0 舍入)。
因此,mod(-a,m) == -mod(a,m) 代表所有 a、m。此外,sign(mod(a,m)) == sign(a).
定义,在我们开始之前
a 到 b 的闭区间: [a,b]
空区间: [] := [+Inf,-Inf]
否定: @987654325 @
联合: [a,b] u [c,d] := [min(a,c),max(b,d)]
绝对值: |m| := max(m,-m)
更简单的情况:固定模数m
从固定的m 开始更容易。稍后我们将把它推广到两个区间的模。定义递归地构建。用你最喜欢的编程语言实现它应该没有问题。伪代码:
def mod1([a,b], m):
// (1): empty interval
if a > b || m == 0:
return []
// (2): compute modulo with positive interval and negate
else if b < 0:
return -mod1([-b,-a], m)
// (3): split into negative and non-negative interval, compute and join
else if a < 0:
return mod1([a,-1], m) u mod1([0,b], m)
// (4): there is no k > 0 such that a < k*m <= b
else if b-a < |m| && a % m <= b % m:
return [a % m, b % m]
// (5): we can't do better than that
else
return [0,|m|-1]
到目前为止,我们没有比这更好的了。 (5) 中的结果间隔可能过于近似,但它是我们能得到的最好的。如果允许我们返回一组区间,我们可以更精确。
一般情况
同样的想法也适用于我们的模数本身就是一个区间的情况。我们开始:
def mod2([a,b], [m,n]):
// (1): empty interval
if a > b || m > n:
return []
// (2): compute modulo with positive interval and negate
else if b < 0:
return -mod2([-b,-a], [m,n])
// (3): split into negative and non-negative interval, compute, and join
else if a < 0:
return mod2([a,-1], [m,n]) u mod2([0,b], [m,n])
// (4): use the simpler function from before
else if m == n:
return mod1([a,b], m)
// (5): use only non-negative m and n
else if n <= 0:
return mod2([a,b], [-n,-m])
// (6): similar to (5), make modulus non-negative
else if m <= 0:
return mod2([a,b], [1, max(-m,n)])
// (7): compare to (4) in mod1, check b-a < |modulus|
else if b-a >= n:
return [0,n-1]
// (8): similar to (7), split interval, compute, and join
else if b-a >= m:
return [0, b-a-1] u mod2([a,b], [b-a+1,n])
// (9): modulo has no effect
else if m > b:
return [a,b]
// (10): there is some overlapping of [a,b] and [n,m]
else if n > b:
return [0,b]
// (11): either compute all possibilities and join, or be imprecise
else:
return [0,n-1] // imprecise
玩得开心! :)