2

长话短说,我有一段代码,已经有十多年的历史了,我们和外部客户都在使用它。我们有一个“班次”数字,通过它我们可以移动一个班次窗口。它被设计为一个整数,因为,我们要遍历数据中的不同位置,所以没有分数移动的概念。现在,他们希望能够有一个非整数班次号码。不是插值,而是简单地让程序进行整数移位,但是当我们通过那个边界时让它移动一点。

一个例子可能更有意义。假设我们有 10 个班次。位置将如下所示:0、10、20、30、40 等

现在,相反,我们希望能够设置 10.4 的移位。因此,我们希望转换按如下方式工作:0、10、20、31、41

10.5 的移位将改为 0、10、21、31、42 等。

基本上,我们将那个小数位相加,当它越过小数点时,我们只需再移动一位。当然,正如浮点运算经常发生的那样,我们会遇到潜在的准确性问题,但我们也希望保持速度。一种幼稚的方法是在开始时将小数位分开并继续对其求和,检查其值并在达到 1.0 时将其递减。这具有遵循我对操作的看法的优势,但它涉及每次迭代的条件检查,并且通常存在累积错误的可能性。

我还可以看到预先计算我们可以添加多少次小数位,然后我们必须检查它是否超过 1.0(所以如果我们的小数位是 0.5,我们知道我们只需要每隔一次检查一次。或者如果它是 0.3,我们知道我们只需要每四个左右检查一次)。

处理重复求和的常用方法当然是用乘法代替它,但在这里,我们并不关心实际的总和,而是预测我们需要“再移一个”来制作哪些帧事情在最后匹配。

我们的典型任务涉及这个类在相对较小的因素组合上运行,例如以 96.46875 的移位迭代少于 3000 次。但是,不能保证此约束将保持有效,因此我被告知要考虑有人将窗口移动一千万次的可能性,我们仍然想知道移动多远。

有什么建议吗?

4

2 回答 2

1

考虑将其设置shift为最接近所需值的两倍,并通过以下方式稍微增加(仅一次):

shift = nexttoward(shift, INFINITY); // Ensure shift is above the threshold.

然后,要计算当前位置,请使用:

result = floor(step * shift);

当 的乘积step与误差shift接近 1 时,这可能会产生一个过大的值。(乘法本身也可能存在轻微的舍入误差。)但是,许多步骤都不会发生这种情况,如下所示。

中的错误shift最多为 1.5 ULP(从十进制的初始转换为 0.5 ULP,从 1 为 1 nexttoward)。如果shift小于 1024,则 ULP 小于 2 10–52。如果step最多为 10,000,000,则误差小于 10,000,000 • 1.5 • 2 10–52,约为 3.41•10 –6。因此,距离产生错误结果所需的幅度还有很长的路要走。

如果您通过shift每次相加而不是通过新的乘法来累积计算结果,则可能会出现额外的错误。这些可能仍然太小而不会导致错误,但应该对其进行评估。

如果您达到上述限制,则有一些方法可以进一步减轻错误。

于 2013-04-19T14:58:37.043 回答
0

为什么不使用地板功能。没有看到你有什么代码,这里猜测什么会起作用

    for (int i=0; i < 3000; i++)
    {
        cout << static_cast<int>(floor(i*shift)) << '\n';
    }

有人可能会反对这种方法的效率,但如果你说的迭代次数少于 3000 次,那就没问题了。

于 2013-04-19T14:32:54.633 回答