用对数解决浮点错误?

时间:2013-12-30 05:40:01

标签: logarithm floating-point-exceptions

我正在尝试为正整数写入基本数字计数器(输入整数并输出该整数的位数)。这是我的通用公式:

dig(x) := Math.floor(Math.log(x,10))

我尝试在Ruby中实现等效的dig(x),并发现当我计算dig(1000)时,我得到2而不是3,因为Math.log返回2.9999999999999996然后会被截断到2.处理这个问题的正确方法是什么? (我假设无论用于实现此方法的语言如何都可能发生此问题,但如果情况并非如此,请在答案中解释一下。)

3 个答案:

答案 0 :(得分:1)

要获得整数中位数的精确计数,你可以做通常的事情:(在C / C ++中,假设n是非负数)

int digits = 0;
while (n > 0) {
  n = n / 10; // integer division, just drops the ones digit and shifts right
  digits = digits + 1;
}

我不确定,但我怀疑运行内置对数函数不会比这更快,这将给你一个确切的答案。

我想了一会儿,无法想出一种方法,使基于对数的方法能够得到任何保证,并且几乎让我自己相信,由于浮点,它可能首先是注定的追求舍入错误等。

答案 1 :(得分:0)

计算机编程艺术第2卷开始,我们将在应用发言权函数之前消除一位错误,将这一位加回来。

x成为log的结果,然后对x += x / 0x10000000执行单精度浮点数(C float)。然后将值传递给floor

这保证是最快的(假设你有数字形式的答案)因为它只使用了一些浮点指令。

答案 2 :(得分:0)

浮点总是受到舍入误差的影响;这是您在使用它时需要注意并积极管理的危险之一。如果你必须使用浮点数,处理它的正确方法是弄清楚预期的累积误差量是多少,并在比较和打印输出中允许这样做 - 适当地进行舍入,比较差异是否在该范围内而不是比较为了平等,等等。

例如,没有像1/10这样的简单事物的精确二进制浮点表示。

(正如其他人所说,你可以重写问题以避免完全使用基于浮点的解决方案,但是因为你特意询问了工作日志()我想解决这个问题;如果我不在目标,道歉一些其他答案提供了关于如何完成结果的具体建议。这将“解决”这个特殊情况,但随着你的浮动操作变得更加复杂,你将不得不继续允许在每一步累积累积,要么在每一步处理错误,要么处理累积错误 - 后者是更复杂但更准确的解决方案。)

如果这对于应用程序来说是一个严重的问题,那么人们有时会使用缩放的固定点(例如,以便士而不是美元来运行财务计算)。或者他们使用一个“大数”包,它以十进制而不是二进制计算;那些有自己的四舍五入问题,但它们更像人类期望的方式。