【问题标题】:Java performance problem for math.absmath.abs 的 Java 性能问题
【发布时间】:2011-02-27 05:39:05
【问题描述】:

我正在使用Jama matrix 执行 SVD 操作。我有几个关于性能的问题。

我并不担心这么多的准确性,我认为 double 比 Float 更准确,对吗?如果我使用 float 而不是 double,它会在多大程度上提高性能并降低准确性?

在 Jama 矩阵中,它使用一个经常调用的函数,它使用 double 和 Math.abs 函数,这需要大量的堆和 CPU。如果我将其更改为 double 并删除 Math.abs,它将在准确性方面对性能和结果产生多大影响?

这是 Jama 数学函数:

   public static double hypot(double a, double b) {
      double r;
      if (Math.abs(a) > Math.abs(b)) {
         r = b/a;
         r = Math.abs(a)*Math.sqrt(1+r*r);
      } else if (b != 0) {
         r = a/b;
         r = Math.abs(b)*Math.sqrt(1+r*r);
      } else {
         r = 0.0;
      }
      return r;
   }

这是我想用这个函数做的事情

   public static float hypot(float a, float b) {
      float r;
      if (a > b) {
         r = b/a;
         r = (float) (a*Math.sqrt(1+r*r));
      } else if (b != 0) {
         r = a/b;
         r = (float) (b*Math.sqrt(1+r*r));
      } else {
         r = 0;
      }
      return r;
   }

我不知道这是否是一个好方法。 谢谢

【问题讨论】:

  • 我根本看不到单个 Math.abs 方法如何使用任何堆?
  • Jama 如此频繁地调用 Math.abs,如果你有很大的 Matrix,那么它会杀死你的系统 :( 然后会有数百万次调用 Math.abs ...
  • 所以你确信这个方法永远不会被负操作数调用?无论如何,如果您的尝试能大大提高速度,尤其是在 64 位 VM 上,我会感到惊讶。但是试试吧,暂时不用担心精度,看看它实际上会产生多大的不同。只有你自己知道;我们不知道您的代码是否会产生积极影响。
  • @user289333 - 调用函数数百万次使用相同的小堆栈空间数百万次,根本没有堆空间。 (关于所有这些调用的 CPU 时间开销,您是对的。这样编码矩阵数学库似乎有些荒谬。)
  • sqrt) 函数是迄今为止最昂贵的操作。比 abs() 更多。

标签: java performance math data-structures matrix


【解决方案1】:

我希望一个好的 JIT 将 Math.abs 调用内联到一条指令。如果您的代码在 FPU 上运行(很可能),使用 float 不会为您带来任何速度,因为几乎所有 FPU 都是 64 位或更高版本。

但是,该算法如此不寻常的原因是它在其操作数的大小为 10^150 的数量级时防止溢出。如果您正在考虑使用float,您的操作数不得大于大约 10^38,这意味着最快的算法将是:

public static double hypot(double a, double b) {
    return Math.sqrt(a * a + b * b);
}

【讨论】:

  • 如果您查看 Math 的源代码,您会发现 abs(float) 不会作为单个指令内联。它调用Float.floatToIntBits,将符号位清零,然后调用Float.intBitsToFloat。反过来,这两个Float 方法是本机方法(可能只是返回传递的值)。假设一切都是内联的,这将变成三个没有分支的指令。 (实际上有点圆滑。)
  • Ted:JIT 编译器可能对许多库函数有特殊情况,就像 C 编译器对 fabsstrcpy 之类的东西有特殊情况一样。成单个指令(或附近)。
【解决方案2】:

您的方法不适用于否定论点。只需添加:

if (a < 0) a = -a;
if (b < 0) b = -b;

在您的功能开始时,一切都应该很好。 (“不工作”是指它不会总是以最小化舍入误差和溢出风险的方式进行计算。)

【讨论】:

  • 实际上使用a = Math.abs(a) 可能比使用if 更快,因为abs 可以优化为单个指令,而if 需要一个难以预测的分支.
  • @Gabe - 真的吗?那会是什么单一的指令?在Java bytecodes 中,没有什么能比得上fabs
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多