事实证明,这是一个有趣的问题。我做的假设是,对于整数区间,模运算是相对于截断除法(朝0取整)定义的。
因此,所有a、m都有mod(-a,m) == -mod(a,m)
。此外,sign(mod(a,m)) == sign(a)
。
开始前的定义
从a到b的闭区间: [a,b]
空区间: [] := [+Inf,-Inf]
否定: -[a,b] := [-b,-a]
联合: [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
玩得开心!:)