我只是为无符号整数做了这个。界限并不完美,但非常严格。对于 100,000 个随机输入,少于 200 个与通过抽样计算的实际间隔相差 0.1% 以上。而且它总是保守的(包含真实的界限)。
关键是使用 FindLeadingOnes 函数作为构建块。这允许表达有效位相互匹配的情况。这一点很重要,因为整数区间的前导位具有匹配上限和下限的属性,也匹配区间中的所有值。因此,考虑前导匹配位允许计算输出区间端点的最高有效位。
此外,对于在一个输入区间内保持不变但在另一个输入区间内变化的中间位,有必要将运算符应用于上限和下限,以获得这些位的区间。这在 iXOr 中可以看到。
最后,AND 的上限是 min(left.upper,right.upper),因为其中一个为 0 的位不能在输出中为 1。与 OR 的下限类似。
(不要注意 ToInt 和 ToFloat 的东西。我实际上是在定点数上这样做的。如果你只是让这些函数成为空操作,它会工作得很好。
interval iAnd(const interval lv, const interval rv)
{
unsigned int ll = ToInt(lv.lower), lu = ToInt(lv.upper), rl = ToInt(rv.lower), ru = ToInt(rv.upper);
unsigned int lvx = FindLeadingOnes(~(ll ^ lu));
unsigned int rvx = FindLeadingOnes(~(rl ^ ru));
unsigned int constmask = (lvx | rvx);
return interval(ToFloat((ll & rl) & constmask), ToFloat(std::min(lu, ru)));
}
和或:
interval iOr(const interval lv, const interval rv)
{
unsigned int ll = ToInt(lv.lower), lu = ToInt(lv.upper), rl = ToInt(rv.lower), ru = ToInt(rv.upper);
unsigned int lvx = FindLeadingOnes(ll & lu) | FindLeadingOnes(~ll & ~lu);
unsigned int rvx = FindLeadingOnes(rl & ru) | FindLeadingOnes(~rl & ~ru);
unsigned int constmask = (lvx | rvx);
return interval(ToFloat(std::max(ll, rl)), ToFloat((lu | ru) | ~constmask));
}
和异或:
interval iXOr(const interval lv, const interval rv)
{
unsigned int ll = ToInt(lv.lower), lu = ToInt(lv.upper), rl = ToInt(rv.lower), ru = ToInt(rv.upper);
unsigned int lvx = FindLeadingOnes(ll & lu) | FindLeadingOnes(~ll & ~lu);
unsigned int rvx = FindLeadingOnes(rl & ru) | FindLeadingOnes(~rl & ~ru);
unsigned int constmask = (lvx | rvx);
interval iout(ToFloat((ll ^ rl) & constmask), ToFloat((lu ^ ru) & constmask)); // Not sure which is larger; interval constructor sorts them.
iout.extend(ToFloat(ToInt(iout.upper) | ~constmask)); // Now that the upper is known, extend it upward for the lsbs.
return iout;
}
这是我的 FindLeadingOnes(用于我的 16 位定点。不过,您可以使用更多位:
unsigned int FindLeadingOnes(unsigned int v)
{
for(unsigned int mask = 0x8000; mask != 0xffff; mask |= mask >> 1u) {
if ((mask & v) != mask)
return (mask << 1u) & 0xffff;
}
return 0xffff;
}