【发布时间】:2020-09-03 00:01:29
【问题描述】:
我正在寻找一种快速算法,它可以找到满足以下不等式的最小整数 N,其中 s、q、u 和 p 是 float 数字(使用 IEEE-754 binary32 格式):
s > q + u * p / (N - 1)
其中 N 可以是由带符号的 32 位整数表示的任何正整数。在(N - 1) 转换为float 之后,所有算术都在float 中进行计算。
其他约束是:
- 0p
- -1 ≤
q≤ 1。 -
qs. - 0 u.
我无法弄清楚如何以稳健的方式执行此操作,以正确处理浮点舍入错误和比较。这是我对一个不快且甚至不可靠的解决方案的糟糕尝试,因为我无法确定最小值SOME_AMOUNT:
int n = std::max(1.0f, floorf((u * p / (s - q)) - 1.0f));
// Floating point math might require to round up by some amount...
for (int i = 0; i < SOME_AMOUNT; ++i)
if (!(q + (u * p / (n + 1)) < second))
++n;
您可以在上面看到我使用基本代数计算n 的公式。 for 循环是我试图解释浮点舍入错误的粗略方法。我正在用这样的蛮力检查它:
int nExact = 0;
bool found = false;
for (; nExact < SOME_BIG_NUMBER; ++nExact) {
if (q + (u * p / (nExact + 1)) < second) {
found = true;
break;
}
}
assert(found);
assert(n == nExact);
任何浮点专家在 C++ 中都有相当快的答案?
坦率地说,如果有人能给出一个理论上合理的证明,证明上面“SOME_AMOUNT”的上限,我会相当高兴...
【问题讨论】:
-
在释放手指编写代码之前,在纸上做一些基本的代数操作,将
s > q + u * p / (N - 1)变成不等式,一方面是N,另一方面是其他所有内容。您必须考虑一些情况(例如,如果代数运算涉及除以某物,请注意某物为零的情况),但您最终会得到一些简单的封闭式公式来计算N给定p、q、u和s的值。最多几个if()和else,绝对不用循环。 -
您想要使用浮点算术计算时
s > q + u * p / (N - 1)为真的解决方案,还是使用计算时s > q + u * p / (N - 1) 为真的解决方案实数算术? N 的域是以浮点格式表示的整数集还是整数集? p 和 q 有相同的符号吗?是 s > q 吗?你对 s、q、u 和 p 了解多少?你知道他们的价值观有什么界限吗?他们的域名有什么限制吗?他们来自哪里? -
只是为了切掉部分问题,给定
s > q,如果u和q有不同的符号,那么解决方案是2,假设1由于被零除而被排除, 因为u * q / (2-1)是负数或零,并且s > q + u * q / (2-1)是真的。所以我们可以将问题简化为u和p具有相同的符号。并且u * q可以替换为x,因为它们不参与表达式。所以我们有s > q + x / (N-1),其中 x 是正数。 -
基本算术运算在浮点数中是弱单调的,对应的实数运算是单调或弱单调的。这可能有助于为检查
N的候选人建立界限。 (显然,在实数算术中可以很容易地找到 N,但鉴于我们被要求在浮点算术中找到解决方案,舍入问题可能会导致N的浮动解决方案与 N 的实际解决方案不同。建立界限可以给我们一个有效的经验解决方案。) -
要考虑的一点是,由于 N 是一个 32 位整数,并且使用
float计算表达式,因此必须将 N 转换为float,这会引入舍入误差。考虑 q 至少为 ½s 的情况。那么在float中计算的s-q是精确的(没有舍入误差),满足s > q + x/n的最小float n是(s-q)/x或高或低1 ULP,具体取决于除法中的舍入。例如,我们可能会发现n是 2147483392。在这种情况下,N将是 2147483266,因为N-1是 2147483265,这是四舍五入到 2147483392 的最小整数。
标签: c++ floating-point floating-accuracy floating-point-conversion inequality