Java 中各种输入函数的记忆

Memoization of a function of various inputs in Java

我有一个将各种 double 变量作为输入的昂贵函数:

public double f(double v1, double v2, double v3){
    ...
    return output;
}

所以我尝试使用两种不同的策略来记住它的输出。

嵌套的 HashMaps:

Map<Double,Map<Double,Map<Double,Double>>> map = new HashMap<>();

public double f(double v1, double v2, double v3){
    // This is abbreviated: in my case I made sure to call only once each "get()"
    if(map.containsKey(v1) && map.get(v1).containsKey(v2) && map.get(v1).get(v2).containsKey(v3))
         return map.get(v1).get(v2).get(v3);
    ...
    // calculations
    ...
    // put "output" in the map (and create new intermediate HashMaps when needed)
    ...
    return output;
}

自定义 HashMap 键:

public class DoubleKey {
   public final double[] values;
   public DoubleKey(double[] values){ this.values = values;}

   @Override
   public boolean equals(Object key){
      if(key instanceof DoubleKey)
         return Arrays.equals(values, ((DoubleKey)key).values);
      return false;
   }

   @Override
   public int hashcode(){
      return Arrays.hashcode(values);
   }
}

Map<DoubleKey,Double> map = new HashMap<>();

public double f(double v1, double v2, double v3){
    DoubleKey key = new DoubleKey(new double[]{v1,v2,v3});
    if(map.containsKey(key))
         return map.get(key);
    ...
    // calculations
    ...
    map.put(key, output);
    return output;
}

现在,我希望第二种方法更快,因为它使用单个 Hashmap,并且通常感觉更优雅。但事实证明,与产生巨大速度提升的第一种方法相比,我从第二种方法中获得的收益较少。

你知道为什么第二种方法效率会降低吗?是使用Arrays.equals()and/orArrays.hashcode()的成本吗?

更一般地说,您知道其他更有效的记忆技术吗?

两个解不相等。第一个硬编码仅支持 3 个双参数,而第二个支持任意数量的参数。

如果你只需要支持 3 个参数,我认为保存 3 个实例变量更有效:

编辑: 在评论之后,将使用可变参数 ctor 的原始答案替换为显式的单个参数。可能更有效(不构造数组)。还使实例变量最终化以启用编译器优化

public class DoubleKey
{
    final double arg1, arg2, arg3;
    final int hashCode;

    public DoubleKey(double arg1, double arg2, double arg3)
    {
        this.arg1 = arg1;
        this.arg2 = arg2;
        this.arg3 = arg3;
        hashCode = Objects.hash(arg1, arg2, arg3);
    }

    @Override
    public boolean equals(Object key)
    {
        if (key instanceof DoubleKey) {
            DoubleKey dk = (DoubleKey) key;
            return arg1 == dk.arg1 && arg2 == dk.arg2 && arg3 == dk.arg3;
        }
        return false;
    }

    @Override
    public int hashCode()
    {
        return hashCode;
    }
}

构建 DoubleKey 实例现在更容易

DoubleKey key = new DoubleKey(v1,v2,v3);