【发布时间】:2015-04-11 19:15:52
【问题描述】:
假设我有等间距的双精度数(64 位浮点数)x0,x1,...,xn。等间距意味着对于所有i,x(i+1) - xi 是恒定的;称它为w 的宽度。
给定y 在[x0,xn] 范围内的一个数字,我想找到最大的i 使得xi <= y。
一种天真的方法会依次访问每个i (O(n))。稍微好一点的是使用二分搜索 (O(log n))。
恒定时间查找是计算(y-x0)/w 并将其转换为整数。但是,由于浮点不准确,这有时会给出错误的结果。例如。假设从 0 开始有 100 个宽度为 0.01 的区间。
(int)(0.29/0.01) = 28 //want 29 here
我能否保留恒定时间查找但确保结果始终与二分查找相同?用小数执行计算,而不是双倍的 'w' 和 'x0' 似乎在这里工作,但它总是工作吗?我总是可以通过直接查找来与任一侧的xs 进行比较,但这看起来很丑陋且效率低下。
澄清一下 - 我被赋予了 xi 和值 y 作为双打 - 我无法改变这一点。但是在返回整数索引之前执行的任何中间计算都可以使用我喜欢的任何数据类型。此外,我可以执行一次性的“准备”工作,以加快运行时计算。
编辑:道歉 - 事实证明我没有正确检查“等距” - 当使用浮点算术计算它们的差异时,这些数字通常不是“等距”。
【问题讨论】:
-
(int)(0.29/0.01 + 0.5) = 28如果你想对它进行舍入而不是截断。 (0.289999/0.01 = 28.999999,截断时为 28) -
1) 舍入而不是截断会降低需要调整的可能性。
(int)Math.Round(0.29/0.01)2) 我会使用索引计算,然后使用一个循环来调整它,通过向上/向下步进来调整它,直到你处于正确的位置。对于足够病态的病例,一步调整可能还不够。 3) C# 的浮点规范非常邪恶,除非您在正确的位置从双精度转换为双精度(强制将精度降低为双精度),否则上述算法可能仍然无法始终工作。 -
@iKiWiXz 最好明确并使用 Math.Round、Math.Floor、Math.Ceiling,而不是试图强迫演员这样做
-
@PanagiotisKanavos 你是对的,但我并不想给出答案,我只是想解释一下原因。
-
如果你有 N 个被 W 等间隔的双精度,你确定你需要存储实际的双精度,而不仅仅是每个的索引,这样
xi = index * W?那么解决方案将变得微不足道,不是吗?
标签: c# algorithm floating-point floating-accuracy