我正在寻找一种算法,给定自然参数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
,其中p2
和p1
可能指向同一个区块时,它必须检查p2
和{{1}指向的区域不要以上述规则禁止的方式重叠。上面的参数“size”对应于p1
和p2
指向的类型的大小。这个尺寸是静态的。已知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对应于重叠不精确的情况。
答案 0 :(得分:3)
看来你正在寻找线性同余系统的解决方案。 Chinese remainder theorem应该适用。它不会应用你的边界检查,但如果它找到了解决方案,你可以自己检查边界。
编辑:忘掉CRT。
假设size <= m1
和size <= m2
,将内存区域的低(包含)和高(独占)边缘建模为线性关系:
addr1low = l1 + k1*m1
addr1high = addr1low + size = l1 + k1*m1 + size
addr2low = l2 + k2*m2
addr2high = addr2low + size = l2 + k2*m2 + size
您想知道k1, k2
或addr1low < 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)
p1和p2的相互排列是周期性的,周期等于1cm(m1,m2)= m1 * m2 / gcd(m1,m2)。在显而易见的解决方案中,假设您将k1从0迭代到n1。由于提到的重复模式,您可以在达到m2 / gcd(m1,m2)时立即停止。我假设你已经减少了(l1,n1)到交叉点。
让我们重新提出一个问题: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)))。