确定两个周期性间隔序列是否具有非空交集的算法

时间:2011-09-03 21:03:49

标签: algorithm language-agnostic modulo

我正在寻找一种算法,给定自然参数l1,n1,m1,l2,n2,m2和size, 当且仅当存在自然数k1,k2,r1,r2时才回答“真”:

l1 + k1 * m1 + r1 = l2 + k2 * m2 + r2

具有约束k1< = n1,k2< = n2,r1<尺寸,r2<尺寸和r1<> R2。

明显的解决方案是min(n1,n2)线性。我正在寻找一些更高效的东西。

上下文

我试图在静态分析器中实现对C99规则6.5.16.1:3的检查

  

如果从另一个对象读取存储在对象中的值   以任何方式重叠第一个对象的存储,然后是   否则,重叠应该是准确的,行为是   未定义。

当分析器遇到*p1 = *p2; p1,其中p2p1可能指向同一个区块时,它必须检查p2和{{1}指向的区域不要以上述规则禁止的方式重叠。上面的参数“size”对应于p1p2指向的类型的大小。这个尺寸是静态的。已知p1指向块内的偏移量表示为集合l1 + k1 * m1,其中l1和m1是固定的,已知的自然整数和k1在0和n1之间变化(n1也是固定且已知的) 。类似地,已知偏移p2指向某些已知的l2,m2和n2的形式为l2 + k2 * m2。等式l1 + k1 * m1 + r1 = l2 + k2 * m2 + r2对应于一些重叠偏移的存在。条件r1<>当分析仪必须发出警告时,r2对应于重叠不精确的情况。

2 个答案:

答案 0 :(得分:3)

看来你正在寻找线性同余系统的解决方案。 Chinese remainder theorem应该适用。它不会应用你的边界检查,但如果它找到了解决方案,你可以自己检查边界。

编辑:忘掉CRT。

假设size <= m1size <= m2,将内存区域的低(包含)和高(独占)边缘建模为线性关系:

addr1low = l1 + k1*m1
addr1high = addr1low + size = l1 + k1*m1 + size
addr2low = l2 + k2*m2
addr2high = addr2low + size = l2 + k2*m2 + size

您想知道k1, k2addr1low < addr2low < addr1high范围内是否存在addr1low < addr2high < addr1high。注意排他性不平等;这样我们就可以避免完全重叠范围。

假设m1 = m2 = m。考虑:

addr1low < addr2low
l1 + k1*m < l2 + k2*m
(k1 - k2) * m < l2 - l1
k1 - k2 < (l2 - l1) / m

addr2low < addr1high
l2 + k2*m < l1 + k1*m + size
l2 - l1 < (k1 - k2) * m + size
(l2 - l1 - size) < (k1 - k2) * m
(l2 - l1 - size) / m < k1 - k2

上述进展是可逆的。假设k1, k2可能为0,-n2 <= k1 - k2 <= n1。如果(l2 - l1 - size) / m(l2 - l1) / m之间存在一个整数,则系统保持并且存在重叠。也就是说,如果是ceil(max((l2 - l1 - size) / m, -n2)) <= floor(min((l2 - l1) / m, n1))。另一种情况(addr1low < addr2high < addr1high)也是如此:

addr1low < addr2high
l1 + k1*m < l2 + k2*m + size
// ..
(l1 - l2 - size) / m < k2 - k1

addr2high < addr1high
addr2low + size < addr1low + size
addr2low < addr1low
// ..
k2 - k1 < (l1 - l2) / m

现在测试变为ceil(max((l1 - l2 - size) / m, -n1)) <= floor(min((l1 - l2) / m, n2))

现在考虑m1 <> m1,不失一般性,请m1 < m2

将变量视为连续,解决交叉点:

addr1low < addr2low
l1 + k*m1 < l2 + k*m2
(l1 - l2) < k * (m2 - m1)
(l1 - l2) / (m2 - m1) < k

addr2low < addr1high
l2 + k*m2 < l1 + k*m1 + size
l2 - l1 - size < k * (m1 - m2)
(l2 - l1 - size) / (m1 - m2) > k  // m1 - m2 < 0

同样,这些步骤是可逆的,因此任何满足边界的整数k < min(n1, n2)都会使系统保持不变。也就是说,如果ceil(max((l1 - l2) / (m2 - m1), 0)) <= floor(min((l2 - l1 - size) / (m1 - m2), n1, n2)),则成立。另一种情况:

addr1low < addr2high
l1 + k*m1 < l2 + k*m2 + size
l1 - l2 - size < k * (m2 - m1)
(l1 - l2 - size) / (m2 - m1) < k

addr2high < addr1high
addr2low + size < addr1low + size
addr2low < addr1low
l2 + k*m2 < l1 + k*m1
l2 - l1 < k * (m1 - m2)
(l2 - l1) / (m1 - m2) > k   // m1 - m2 < 0

此处测试成为ceil(max((l1 - l2 - size) / (m2 - m1), 0)) <= floor(min((l2 - l1) / (m1 - m2), n1, n2))

最终的伪代码可能如下所示:

intersectos?(l1, n1, m1, l2, n2, m2, size) {
  if (m1 == m2) {
    return ceil(max((l2 - l1 - size) / m, -n2)) <= floor(min((l2 - l1) / m, n1)) ||
           ceil(max((l1 - l2 - size) / m, -n1)) <= floor(min((l1 - l2) / m, n2));
  }

  if (m1 > m2) {
    swap the arguments
  }

  return ceil(max((l1 - l2) / (m2 - m1), 0)) <= floor(min((l2 - l1 - size) / (m1 - m2), n1, n2)) ||
         ceil(max((l1 - l2 - size) / (m2 - m1), 0)) <= floor(min((l2 - l1) / (m1 - m2), n1, n2));
}

答案 1 :(得分:2)

1。对明显算法的一个小改进

p1和p2的相互排列是周期性的,周期等于1cm(m1,m2)= m1 * m2 / gcd(m1,m2)。在显而易见的解决方案中,假设您将k1从0迭代到n1。由于提到的重复模式,您可以在达到m2 / gcd(m1,m2)时立即停止。我假设你已经减少了(l1,n1)到交叉点。

2。一个更棘手的方法

让我们重新提出一个问题:p1和p2之间的最小非零距离是否小于大小?

首先,让我们考虑p1-p2。然后我们将p2-p1添加到混合物中。

所以我们想找到

的最小非零值

p1 - p2 =(l1 + k1 * m1) - (l2 + k2 * m2)=(l1-l2)+(k1 * m1 - k2 * m2)。

设d = gcd(m1,m2)。如果我们允许k1和k2取任意整数值,则k1 * m1 - k2 * m2的所有可能值的集合与任意整数k的k * d的所有可能值的集合完全相同。

因此,(l1-l2)+(k1 * m1-k2 * m2)的最小非零值是(l1-l2)mod d,如果它不为零或者否则为d。这里,即使(l1-l2)为负,mod也会给出正结果。

让我们找到最小的k1和k2。扩展的欧几里德算法给出了a1和a2(可能是负的),使得d = a1 * m1-a2 * m2。该解决方案是唯一的,直到添加0 =(m2 / d)* m1 - (m1 / d)* m2。然后

(l1-l2)mod d =(l1-l2)+ k * d

(l1-l2)mod d =(l1-l2)+ k *(a1 * m1 - a2 * m2)

(l1-l2)mod d =(l1-l2)+(k * a1)* m1 - (k * a2)* m2

加上或减去0 =(m2 / d)* m1 - (m1 / d)* m2足够的次数,使得m1和m2的系数均为正且最小。这为你提供了p2在距离(l1-l2)mod d第一次到达p1的位置。

如果刚发现k1和k2处于界限且(l1-l2)mod d非零,那么这肯定地回答了问题。否则对(l1-l2)mod d + d重复相同的操作。并不断重复,直到你达到规模。

然后重复p2-p1而不是p1-p2。

如果没有一个步骤给出肯定答案,那么答案是否定的。

该算法的复杂性为O(size / gcd(m1,m2))。

在每种特定情况下,首选哪种算法取决于特定数字。计算gcd也不是免费的(O(log(min(m1,m2)))。

相关问题