Java Math.abs与Math.pow的区别

4

这里有一个奇怪的问题。我正在解决一个kNN问题,需要找到最近的邻居。我在研究距离,但我只关心哪一个最接近,而不关心实际距离。但是,由于距离不能为负数,我需要将距离平方或取绝对值。

因此,有两种方法可以实现这一点:

//note: it's been abstracted for multiple dimensions (not just x and y)
for(int i = 0; i < (numAttributes - 1); i++)
{
    distance += Math.pow((a.value(i) - b.value(i)), 2);
}

并且

//note: it's been abstracted for multiple dimensions (not just x and y)
for(int i = 0; i < (numAttributes - 1); i++)
{
    distance += Math.abs(a.value(i) - b.value(i));
}

我的问题是哪个更快。由于这是一个数据挖掘应用程序,我希望它能尽可能快地处理信息。虽然我知道,在底层实现中,二的幂可以通过移位来实现,但我不确定在像Java这样的高级语言中是否也是如此,因为它要被转换成JVM。是否有一种方法比另一种更好?


2
哪一个更快?你可以计时分别测试一下,也可以将这两行代码编译起来,看看哪一个生成了更多的指令。 - Tdorno
1
使用L1范数和L2范数是否具有统计学意义上的差异? - Transcendence
3
什么?Math.pow(..., 2)和位移没有任何关系,也不能计算二的幂次方(应该使用Math.pow(2, ...)来计算)。 - user253751
2
请注意,使用这两种方法将得到不同的结果。如果您正在实现需要平方的算法,则仅使用 abs 不仅更快,而且是错误的(尽管根据许多因素,它可能是足够好的近似值)。 - user253751
3
  1. 单个移位操作无法计算平方,但可以使用移位来计算一个整数的2次幂,但这在这里没有用处。
  2. 我预期 Math.abs(d)Math.pow(d, 2) 快得多。为什么?因为 abs 应该映射到单个按位与操作以清除符号位,而 pow(, 2) 最好情况下映射到乘法,最坏情况下映射到对 pow 的实际函数调用。
  3. immibis是正确的:L1和L2范数具有非常不同的特性;特别是L2在任何地方都可微分,而L1不可微(0处有尖峰),这在某些应用中会导致许多问题。
- Iwillnotexist Idonotexist
显示剩余3条评论
1个回答

5
首先,考虑向量A=[0,0,0]B=[1,1,1]C=[0,0,2]。哪一个更靠近A?是B还是C?在kNN中,关注距离度量绝对至关重要。我们仅讨论曼哈顿和欧几里得距离。例如,您也可以使用余弦相似度,并且应该仔细选择距离度量,考虑您对数据的了解。
其次,考虑一些更智能的方法,而不是这样低级别的优化。比如当检测到距离太大时,立即退出循环for(int i = 0; i < (numAttributes - 1); i++)
第三,使用Math.pow(a,2)来计算a*a绝对非常低效。
第四,i < (numAttributes - 1)?难道你的意思不是i < numAttributes吗?

最后一个属性是非数字的,包含了正确答案(我猜你可以这么说),所以如果我计算它,就会得到一个NAN异常。但是,看着它,我应该把它从循环中剔除,并在其中加入一个break语句来缩短代码。谢谢! - Mackenzie Bodily
使用 Math.pow(a,2) 来计算 a*a 明显非常低效。这并不是真的。请看这里:https://dev59.com/Ul4b5IYBdhLWcg3wbRIf - apangin
@apangin 哦,非常有趣,没想到编译器会做这个工作 :) - Tregoreg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接