Java - 接受标量和矢量参数的函数/方法?

时间:2016-12-27 06:03:03

标签: java arrays matrix methods arguments

说我有一个等式:

out = Math.exp(x);

其中xdouble

说我做了10,000次,所以我把它扔进了一个函数:

public double doMath(double x) {
    return Math.exp(x);
}

够容易。我可以传递任何标量:

double in = 1.1234;

out = doMath(in);

// Outputs something like: 1.1313368652

但是尝试将矢量传递给它(1D数组,2D数组等等......)会导致各种问题:

double[] in = {0.1234, 5.6789};

out = doMath(in);

// Outputs something like: IT DOESN'T OUTPUT! CRASH CRASH CRASH!

我想要的是能够传递任何双(标量,1D,2D,3D等)并返回与输入相同的大小,在通过等式后,将算法应用于每个元素

测试用例

double in = 0.1234;

/*
1.1313368652
*/

double[] in = {0.1234, 5.6789};

/*
[ 1.1313368652, 292.6273627191 ]
*/

double[][] in = {{0.1234, 5.6789}, 
                 {0.9876, 5.4321}};

/*
[ [ 1.1313368652, 292.6273627191 ]
  [ 2.6847832542, 228.6288622608 ] ]
*/

double[][][] in = {{{0.1234, 5.6789}, {0.9876}}, 
                   {{5.4321}}, 
                   {{0}, {1}}};

/*
[ [ [ 1.1313368652 292.6273627191 ] [ 2.6847832542 ] ]
  [ [ 228.6288622608 ] ]
  [ [ 1 ] [ 2.7182818285 ] ] ]
*/

我现在唯一的方法是使用overloading

public double doMath(double x)

public double[] doMath(double[] x)

public double[][] doMath(double[][] x)

public double[][][] doMath(double[][][] x)

但这很乏味。可以编写单个函数来接受任何参数维度,并返回类似于我提供的示例吗?

也许有一个名字,我只是不知道?这些都只是数组,但我正在对它们进行处理(并对它们进行其他操作),就像它们是不同维度的矩阵一样。

编辑#1 - 另外......

我尝试过类似的事情:

public double doMath(int... x)

它适用于标量和1D,但没有更高的尺寸。

编辑#2

是否可以编写一个自定义类,自动为多个函数处理它?<​​/ p>

例如,假设我有三种不同的功能:

public mysteryClass firstFunct(mysteryClass x) {
    return Math.pow(x, 2);
}

public mysteryClass secondFunct(mysteryClass x) {
    return Math.exp(x);
}

public mysteryClass thirdFunct(mysteryClass x) {
    return (1 + x) / 2;
}

每个函数都可以使用 - - 任意数量的维度?然后mysteryClass会自动递归地运行每个元素通过函数,而不必修改函数或手动循环遍历每个元素?不确定对象是否可以知道如何使用它,并相应地进行调整。

提前致谢。

2 个答案:

答案 0 :(得分:2)

我不知道有这样做的内置方式,但我得到了一些像这样的工作:

public static Object applyAll(Object x) {
    if (x instanceof Double) {
        return doFunc((Double) x);
    }
    else if (x instanceof Object[]) {
        List<Object> result = new ArrayList<>();
        for (Object element : (Object[])x) {
            result.add(applyAll(element));
        }
        return result.toArray(new Object[0]);
    }
    else {
        throw new RuntimeException("Unexpected class: " + x.getClass());
    }
}

applyAll适用于Double或数组,如果它是一个数组,它会在元素上递归调用并构建结果数组。最终结果是最终结果的数组结构与最外层参数的结构相匹配。但是,如果任何元素不是Double或数组,则会抛出异常。 doFunc是一种接受doubleDouble参数的方法,并返回doubleDouble。您可以轻松地将函数作为参数传递(使用Java 8功能接口),而不是要求doFunc定义。在您的示例中,doFunc会在其参数上返回Math.exp

这可能不是最好的代码,但它有效。您不需要构建列表然后转换为数组,因为数组的大小已经知道了。但是,我没有尝试过改进它。您可以根据需要自由改进或修改它。

答案 1 :(得分:2)

class IncompatibleMultiDoubleException extends RuntimeException {
}

class MultiDouble {
  private double[] data;
  private int[] dims;

  public MultiDouble(int...dimensions) {
    dims = dimensions;
    int tot = 1;
    for (int d : dimensions) {
      tot *= d;
    }
    data = new double[tot];
  }

  // multiply matrix by value
  void cMul(double c) {
    for (int i=0; i<data.length; i++) {
      data[i] *= c;
    }
  }

  // add two matrices together
  void add(MultiDouble other) {
    for(int i=0; i<other.dims.length; i++) {
      if (dims[i] != other.dims[i]) {
        throw new IncompatibleMultiDoubleException();
      }
    }
  }
  // return the index in the data array corrisponding to the
  // given multidim coordinates
  private int index(int...coords) {
    int res = 0;
    for(int i=0; i<coords.length; i++) {
      int tmp = coords[i];
      for(int j=i+1; j<coords.length; j++) {
        tmp *= dims[j];
      }
      res += tmp;
    }
    return res;
  }

  public void set(double value, int...coords) {
    data[index(coords)] = value;
  }

  public double get(int...coords) {
    return data[index(coords)];
  }