我必须存储几个非常低的概率值的产品(例如1E-80).使用原始的
java double将导致零,因为下溢.我不希望该值为零,因为稍后会有一个较大的数字(例如1E100),这将使值在双重可以处理的范围内.
所以,我自己创建了一个不同的类(MyDouble),它用于保存基本部分和指数部分.当进行计算时,例如乘法,我乘以基本部分,并添加指数.
该程序与原始双重类型很快.但是,当我使用我自己的类(MyDouble)时,程序真的很慢.我认为这是因为每次创建简单操作时都需要创建新的对象,而当不再需要对象时,垃圾回收器必须做很多工作.
我的问题是,有没有更好的方式,你认为我可以解决这个问题?如果没有,有没有办法,我可以用我自己的课程(MyDouble)来加速程序?
[注意:采取日志,后来取指数不能解决我的问题]
MyDouble类:
public class MyDouble { public MyDouble(double base,int power){ this.base = base; this.power = power; } public static MyDouble multiply(double... values) { MyDouble returnMyDouble = new MyDouble(0); double prodBase = 1; int prodPower = 0; for( double val : values) { MyDouble ad = new MyDouble(val); prodBase *= ad.base; prodPower += ad.power; } String newBaseString = "" + prodBase; String[] splitted = newBaseString.split("E"); double newBase = 0; int newPower = 0; if(splitted.length == 2) { newBase = Double.parseDouble(splitted[0]); newPower = Integer.parseInt(splitted[1]); } else { newBase = Double.parseDouble(splitted[0]); newPower = 0; } returnMyDouble.base = newBase; returnMyDouble.power = newPower + prodPower; return returnMyDouble; } }
解决方法
缓慢可能是因为在split和string concats中创建的中间字符串对象.
尝试这个:
/** * value = base * 10 ^ power. */ public class MyDouble { // Threshold values to determine whether given double is too small or not. private static final double SMALL_EPSILON = 1e-8; private static final double SMALL_EPSILON_MULTIPLIER = 1e8; private static final int SMALL_EPSILON_POWER = 8; private double myBase; private int myPower; public MyDouble(double base,int power){ myBase = base; myPower = power; } public MyDouble(double base) { myBase = base; myPower = 0; adjustPower(); } /** * If base value is too small,increase the base by multiplying with some number and * decrease the power accordingly. * <p> E.g 0.000 000 000 001 * 10^1 => 0.0001 * 10^8 */ private void adjustPower() { // Increase the base & decrease the power // if given double value is less than threshold. if (myBase < SMALL_EPSILON) { myBase = myBase * SMALL_EPSILON_MULTIPLIER; myPower -= SMALL_EPSILON_POWER; } } /** * This method multiplies given double and updates this object. */ public void multiply(MyDouble d) { myBase *= d.myBase; myPower += d.myPower; adjustPower(); } /** * This method multiplies given primitive double value with this object and update the * base and power. */ public void multiply(double d) { multiply(new MyDouble(d)); } @Override public String toString() { return "Base:" + myBase + ",Power=" + myPower; } /** * This method multiplies given double values and returns MyDouble object. * It make sure that too small double values do not zero out the multiplication result. */ public static MyDouble multiply(double...values) { MyDouble result = new MyDouble(1); for (int i=0; i<values.length; i++) { result.multiply(values[i]); } return result; } public static void main(String[] args) { MyDouble r = MyDouble.multiply(1e-80,1e100); System.out.println(r); }
}
如果您的目的仍然很慢,您可以修改multiply()方法直接对原始double进行操作,而不是创建一个MyDouble对象.