Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
传递函数作为Java中快速数值的静态类_Java_Function_Static_Numerics - Fatal编程技术网

传递函数作为Java中快速数值的静态类

传递函数作为Java中快速数值的静态类,java,function,static,numerics,Java,Function,Static,Numerics,我想用java进行一些数值计算,为了使运算真正模块化,我想把传递函数作为其他函数的参数。我在搜索,通常是在java中使用类来扭曲函数。我真的不需要实例化这些类,因为里面没有数据,我想让它尽可能快地在某个地方编写,最终的静态方法由JIT编译器内联。所以我做了这样的东西 public static class Function2 { public static float eval(float a, float b){ return Float.NaN; } } public static

我想用java进行一些数值计算,为了使运算真正模块化,我想把传递函数作为其他函数的参数。我在搜索,通常是在java中使用类来扭曲函数。我真的不需要实例化这些类,因为里面没有数据,我想让它尽可能快地在某个地方编写,最终的静态方法由JIT编译器内联。所以我做了这样的东西

public static class Function2 {
  public static float eval(float a, float b){ return Float.NaN; }  
}

public static class FAdd extends Function2 {
  public static float eval(float a, float b){ return a+b; }  
}

public static class Fmult extends Function2 {
  public static float eval(float a, float b){ return a*b; }  
}

void arrayOp( float [] a, float [] b, float [] out, Function2 func ){
  for (int i=0; i<a.length; i++){     out[i] = func.eval( a[i], b[i] );   }
}

float [] a,b, out;

void setup(){
  println( FAdd.eval(10,20) );
  arrayOp( a,b, out, FAdd );
}
但是它打印错误:当我试图将它传递给arrayOp时,找不到类似FAdd的内容,即使println FAdd.eval10,20工作正常。所以,出于某种原因,似乎不可能通过静态类作为prameter

你有什么建议来解决这样的任务?实际上,我希望FAdd是类似于宏的东西,nad arrayOp是polymorf,其行为取决于我传入的宏。但理想情况是在编译时而不是在运行时解决,以提高数值速度。编译后的结果应该与我编写的相同

void arrayAdd( float [] a, float [] b, float [] out ){
  for (int i=0; i<a.length; i++){     out[i] = a[i]  + b[i];    }
}
void arrayMult( float [] a, float [] b, float [] out ){
  for (int i=0; i<a.length; i++){     out[i] = a[i] * b[i];   }
} 

你考虑过使用枚举吗

private void test() {
  test(3.0f, 4.0f, F.Add);
  test(3.0f, 4.0f, F.Sub);
  test(3.0f, 4.0f, F.Mul);
  test(3.0f, 4.0f, F.Div);
  float[] a = {1f, 2f, 3f, 4f, 5f};
  float[] b = {4f, 9f, 16f, 25f, 36f};
  test(a, b, F.Add);
  test(a, b, F.Sub);
  test(a, b, F.Mul);
  test(a, b, F.Div);
}

private void test(float[] a, float[] b, F f) {
  System.out.println(Arrays.toString(a) + " " + f + " " + Arrays.toString(b) + " = " + Arrays.toString(f.f(a, b, f)));
}

private void test(float a, float b, F f) {
  System.out.println(a + " " + f + " " + b + " = " + f.f(a, b));
}

public enum F {
  Add {
    @Override
    public float f(float x, float y) {
      return x + y;
    }

    @Override
    public String toString() {
      return "+";
    }
  },
  Sub {
    @Override
    public float f(float x, float y) {
      return x - y;
    }

    @Override
    public String toString() {
      return "-";
    }
  },
  Mul {
    @Override
    public float f(float x, float y) {
      return x * y;
    }

    @Override
    public String toString() {
      return "*";
    }
  },
  Div {
    @Override
    public float f(float x, float y) {
      return x / y;
    }

    @Override
    public String toString() {
      return "/";
    }
  };

  // Evaluate to a new array.
  static float[] f(float[] x, float[] y, F f) {
    float[] c = new float[x.length];
    for (int i = 0; i < x.length; i++) {
      c[i] = f.f(x[i], y[i]);
    }
    return c;
  }

  // All must have an f(x,y) method.
  public abstract float f(float x, float y);

  // Also offer a toString - defaults to the enum name.  
  @Override
  public String toString() {
    return this.name();
  }
}

您想要实现的实际上是或lambda表达式的功能,它位于Java编程语言的JSR335 lambda表达式中,将在Java8中提供。目前,只有匿名内部类接近于此。stackoverflow中的这个问题可能会对您有所帮助。

您实际上在实现中混淆了实例和类。当您有这样声明的方法时:

void arrayOp( float [] a, float [] b, float [] out, Function2 func ){
   for (int i=0; i<a.length; i++){     out[i] = func.eval( a[i], b[i] );   }
}
假设您想将类本身发送给一个方法,那么您的arrayOp声明将如下所示:

void arrayOp( float [] a, float [] b, float [] out, Class func ){
调用此方法时,将以以下方式传入参数:

arrayOp( a,b, out, FAdd.class );

但是静态方法不能通过继承被重写。你需要一个完全不同的实现来实现你的目标。也就是说,@OldCurmudgeon为您的问题提供了一个非常好的解决方案。考虑使用它。

你正在做一些大规模的假设,最快的代码只有在它最终的静态方法。您很可能是错的,应该把重点放在正确地构建它和测试性能上

如上所述,一种方法是使用敌人的武器。我想说,你应该做的是有一个与eval函数的接口。然后可以传入接口的实现


Java虚拟机将实现对代码的适当优化。

静态方法不能被重写,但您可以使用匿名类执行此操作:

public static class Function2 {
    public float eval(float a, float b){ return Float.NaN; }  
}

arrayOp(a, b, out, new Function2() {
    public float eval(float a, float b){
        return FAdd.eval(a, b);
    }});

请注意,Function2中eval的方法声明不是静态的。

我做了一些测试,似乎真的没有必要在现代机器上对其进行优化

机器1-我的旧家用电脑32位WinXP,英特尔奔腾3,我不确定java版本 对于float.mult和float.add这两种操作,静态版本的速度要快2倍以上

static  100000000 [ops]  406.0 [s]  4.06 [ns/op] 
dynamic 100000000 [ops]  1188.0 [s]  11.88 [ns/op] 
但是对于float Sqrt,差异已经非常小了

static  100000000 [ops]  922.0 [s]  9.22 [ns/op] 
dynamic 100000000 [ops]  1172.0 [s]  11.719999 [ns/op] 
机器2-我的工作电脑-64位ubuntu 12.04LTS、Intel Core5、java版本1.6.0_12-ea、JavaTM SE运行时环境构建1.6.0_12-ea-b02、java HotSpotTM 64位服务器VM构建11.2-b01、混合模式 对于float,结果要好得多。添加:

static  1000000000 [ops]  1747.0 [s]  1.7470001 [ns/op] 
dynamic 1000000000 [ops]  1750.0 [s]  1.75 [ns/op] 
所以-我认为处理器或JIT已经足够聪明了,不需要优化这个函数

注: -没有传递函数的静态平均解我只是内联的 手动将操作输入到循环中, -当我使用传递函数作为动态对象实例而不是静态类时,动态平均解。JIT似乎理解类中没有动态数据,因此无论如何它都会在编译时解析它

因此,我的动态解决方案非常简单:


函数在Java中不是一流的对象,因此这在Java中是不可能的。结果是一样的,但它不会在任何需要的地方快速运行。如果性能非常关键,您应该像最后一样提供单独的方法。@Makoto方法将是Java 8中的第一类对象,但尚未发布;这是一种非常好的技术,对于解决方案来说是+1。但是,请认识到,这与为每个操作定义单独的类和实例没有什么不同。它只是简单地减少了类型。@parsifal-不仅减少了类型,而且它还遵守了各种编码原则,例如等等。此外,每个类只实例化一次。@OldCurmudgeon-注意,我并没有说这是一种不好的做法。然而,根据我的经验,Enum有任何行为的想法让很多人感到惊讶。创建枚举的匿名子类可能会让人更加惊讶。哇,有趣的是,枚举有一些不平凡的功能。然而,我更喜欢类而不是枚举,因为类可以在内部进行扩展,如果用户希望为arrayOp定义自己的函数核心,则稍后可以重写该类。另外,我主要是在处理方面工作,似乎枚举仍然不在那里工作。我不喜欢这里的新内容,这可能会 分配新对象。我不确定它是否在JIT中进行了优化,是否可以在编译时内联没有数据的新对象?
static  100000000 [ops]  922.0 [s]  9.22 [ns/op] 
dynamic 100000000 [ops]  1172.0 [s]  11.719999 [ns/op] 
static  1000000000 [ops]  1747.0 [s]  1.7470001 [ns/op] 
dynamic 1000000000 [ops]  1750.0 [s]  1.75 [ns/op] 
public class Function2 {
  public float eval(float a, float b){ return Float.NaN; }  
}

public class FAdd extends Function2 {
  public float eval(float a, float b){ return a+b; }
}

public class FMult extends Function2 {
  public float eval(float a, float b){ return a*b; }  
}

public void arrayOp( float [] a, float [] b, float [] out, Function2 func ){
  for (int i=0; i<a.length; i++){     out[i] = func.eval( a[i], b[i] );   }
}

final int m = 100;
final int n = 10000000;
float t1,t2;
float [] a,b, out;
a = new float[n];   b = new float[n];   out = new float[n];
t1 = millis();
Function2 func = new FMult(); 
for (int i=0;i<m;i++) arrayOp( a,b, out, func );
t2 = millis();
println( " dynamic " +(n*m)+" [ops]  "+(t2-t1)+" [s]  "+ 1000000*((t2-t1)/(n*m))+" [ns/op] " );