Java/Android pow precision/scale 就像在 Windows 计算器中一样
Java/Android pow precision/scale like in Windows calculator
Windows 计算器中的示例,当我们执行“3^8.73”时,结果是“14630,816172800116064202808828951”,但是当我们在 Java "Math.pow(3, 8.73)" 中执行时,结果是 "14630.816172800123".
我怎样才能像 Windows 计算器(逗号后的 32 个数字)那样用 presicion 在 Java 中做 pow?
我不能使用 BigDecimal class,因为只有 pow(int) - 我需要 pow(double) 方法。
我找不到关于这个问题的任何解决方案。
对于 Android,可能有比 BigDecimal 更好的 classes,我们可以在哪里做 pow(double)?
感谢您的回答:* .
我的天啊……
我在这上面花了几天时间。我尝试了很多算法,但其中 none 没有用...然后我在我的函数中写道:
pow(new BigDecimal(3), new BigDecimal("8.73")) // <-- this is String in 2 argument (good)
不是:
pow(new BigDecimal(3), new BigDecimal(8.73)) // <-- this is double in 2 argument (bad)
现在一切正常...
所以如果你也想拥有好的 function/method pow(BigDecimal x, BigDecimal y) 你必须下载这个 class: BigFunctions.java (I get this code from this book: Java Number Cruncher: The Java ... ) 有很好的方法 ln,和 exp - 我们需要它们到我们的 pow。接下来将这个 class 放入你的项目中,最后你必须在你的一些 class 中编写这个方法(这个方法的完整版本在这个 post ):
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(y);
BigDecimal result = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP);
return result;
}
在某些情况下,例如此处:
BigDecimal x = pow(new BigDecimal(2), new BigDecimal("0.5")); // sqrt(2)
BigDecimal z = pow(x, new BigDecimal(2)); // x^2;
System.out.println(x);
System.out.println(z);
我们有结果:
1.41421356237309504880168872420970
2.00000000000000000000000000000001
所以我们可以这样修改我们的方法:
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(y);
BigDecimal result = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP);
String regExp = "0{30}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString.substring(commaIndex));
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
return new BigDecimal(resultString.substring(0, commaIndex));
}
return result;
}
结果是:
1.41421356237309504880168872420970
2
编辑:
我发现了一个问题 - 当我们增强大值时,他的精度不好,所以下面是 pow 方法的最终版本。
完整的 POW 方法:
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
String yString = y.toPlainString();
if(y.compareTo(BigDecimal.valueOf(999999999)) == 1) // In smaller ^values (like 1000000) in each algorithm we must waiting infinitely long so this is only 'protection' from exceptions.
{
System.out.println("Too big value for exponentiation");
return new BigDecimal("0");
}
else if(x.compareTo(BigDecimal.valueOf(0)) == 0)
{
return new BigDecimal("0");
}
int yStringCommaIndex = yString.indexOf(".");
if(yStringCommaIndex == -1)
{
String xString = x.toPlainString(), xString2;
int precision = xString.indexOf(".")+1;
if(precision == 0)
{
if(xString.length() > 53)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
precision = xString.length()+1;
}
else if(precision > 54)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
BigDecimal result = x.pow(Integer.parseInt(yString)).setScale(32, RoundingMode.HALF_UP);
xString2 = result.toPlainString();
precision = xString2.indexOf(".");
if(precision > 32)
{
precision = 32;
}
else if(precision == -1 || precision == 1 && xString2.charAt(0) == '0')
{
precision = 0;
}
result = result.setScale(32-precision, RoundingMode.HALF_UP);
String regExp = "9{16}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
String result2 = resultString.substring(0, commaIndex);
resultString = resultString.substring(commaIndex+1);
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString);
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += "."+resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
return new BigDecimal(result2).add(BigDecimal.valueOf(1));
}
result2 += "9";
return new BigDecimal(result2).setScale((result2.length()-1)-(commaIndex+1), RoundingMode.HALF_UP);
}
regExp = "0{16}|0+$";
resultString = result.toPlainString();
commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
result2 = resultString.substring(0, commaIndex+1);
resultString = resultString.substring(commaIndex+1);
pattern = Pattern.compile(regExp);
matcher = pattern.matcher(resultString);
hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
}
return new BigDecimal(result2);
}
return result;
}
else
{
if(x.compareTo(BigDecimal.valueOf(0)) == -1)
{
System.out.println("Wrong input values");
return new BigDecimal("0");
}
BigDecimal x1 = x.pow(Integer.parseInt(yString.substring(0, yStringCommaIndex))); // Integer value
String xString = x.toPlainString(), xString2;
int precision = xString.indexOf(".")+1;
if(precision == 0)
{
if(xString.length() > 53)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
precision = xString.length()+1;
}
else if(precision > 54)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(new BigDecimal("0"+yString.substring(yStringCommaIndex)));
BigDecimal x2 = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP); // Decimal value
BigDecimal result = x1.multiply(x2).setScale(32, RoundingMode.HALF_UP);
xString2 = result.toPlainString();
precision = xString2.indexOf(".");
if(precision > 32)
{
precision = 32;
}
else if(precision == -1 || precision == 1 && xString2.charAt(0) == '0')
{
precision = 0;
}
result = result.setScale(32-precision, RoundingMode.HALF_UP);
String regExp = "9{16}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
String result2 = resultString.substring(0, commaIndex);
resultString = resultString.substring(commaIndex+1);
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString);
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += "."+resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
return new BigDecimal(result2).add(BigDecimal.valueOf(1));
}
result2 += "9";
return new BigDecimal(result2).setScale((result2.length()-1)-(commaIndex+1), RoundingMode.HALF_UP);
}
regExp = "0{16}|0+$";
resultString = result.toPlainString();
commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
result2 = resultString.substring(0, commaIndex+1);
resultString = resultString.substring(commaIndex+1);
pattern = Pattern.compile(regExp);
matcher = pattern.matcher(resultString);
hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
}
return new BigDecimal(result2);
}
return result;
}
}
Windows 计算器中的示例,当我们执行“3^8.73”时,结果是“14630,816172800116064202808828951”,但是当我们在 Java "Math.pow(3, 8.73)" 中执行时,结果是 "14630.816172800123".
我怎样才能像 Windows 计算器(逗号后的 32 个数字)那样用 presicion 在 Java 中做 pow?
我不能使用 BigDecimal class,因为只有 pow(int) - 我需要 pow(double) 方法。
我找不到关于这个问题的任何解决方案。 对于 Android,可能有比 BigDecimal 更好的 classes,我们可以在哪里做 pow(double)?
感谢您的回答:* .
我的天啊……
我在这上面花了几天时间。我尝试了很多算法,但其中 none 没有用...然后我在我的函数中写道:
pow(new BigDecimal(3), new BigDecimal("8.73")) // <-- this is String in 2 argument (good)
不是:
pow(new BigDecimal(3), new BigDecimal(8.73)) // <-- this is double in 2 argument (bad)
现在一切正常...
所以如果你也想拥有好的 function/method pow(BigDecimal x, BigDecimal y) 你必须下载这个 class: BigFunctions.java (I get this code from this book: Java Number Cruncher: The Java ... ) 有很好的方法 ln,和 exp - 我们需要它们到我们的 pow。接下来将这个 class 放入你的项目中,最后你必须在你的一些 class 中编写这个方法(这个方法的完整版本在这个 post ):
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(y);
BigDecimal result = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP);
return result;
}
在某些情况下,例如此处:
BigDecimal x = pow(new BigDecimal(2), new BigDecimal("0.5")); // sqrt(2)
BigDecimal z = pow(x, new BigDecimal(2)); // x^2;
System.out.println(x);
System.out.println(z);
我们有结果:
1.41421356237309504880168872420970
2.00000000000000000000000000000001
所以我们可以这样修改我们的方法:
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(y);
BigDecimal result = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP);
String regExp = "0{30}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString.substring(commaIndex));
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
return new BigDecimal(resultString.substring(0, commaIndex));
}
return result;
}
结果是:
1.41421356237309504880168872420970
2
编辑:
我发现了一个问题 - 当我们增强大值时,他的精度不好,所以下面是 pow 方法的最终版本。
完整的 POW 方法:
public static BigDecimal pow(BigDecimal x, BigDecimal y)
{
String yString = y.toPlainString();
if(y.compareTo(BigDecimal.valueOf(999999999)) == 1) // In smaller ^values (like 1000000) in each algorithm we must waiting infinitely long so this is only 'protection' from exceptions.
{
System.out.println("Too big value for exponentiation");
return new BigDecimal("0");
}
else if(x.compareTo(BigDecimal.valueOf(0)) == 0)
{
return new BigDecimal("0");
}
int yStringCommaIndex = yString.indexOf(".");
if(yStringCommaIndex == -1)
{
String xString = x.toPlainString(), xString2;
int precision = xString.indexOf(".")+1;
if(precision == 0)
{
if(xString.length() > 53)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
precision = xString.length()+1;
}
else if(precision > 54)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
BigDecimal result = x.pow(Integer.parseInt(yString)).setScale(32, RoundingMode.HALF_UP);
xString2 = result.toPlainString();
precision = xString2.indexOf(".");
if(precision > 32)
{
precision = 32;
}
else if(precision == -1 || precision == 1 && xString2.charAt(0) == '0')
{
precision = 0;
}
result = result.setScale(32-precision, RoundingMode.HALF_UP);
String regExp = "9{16}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
String result2 = resultString.substring(0, commaIndex);
resultString = resultString.substring(commaIndex+1);
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString);
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += "."+resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
return new BigDecimal(result2).add(BigDecimal.valueOf(1));
}
result2 += "9";
return new BigDecimal(result2).setScale((result2.length()-1)-(commaIndex+1), RoundingMode.HALF_UP);
}
regExp = "0{16}|0+$";
resultString = result.toPlainString();
commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
result2 = resultString.substring(0, commaIndex+1);
resultString = resultString.substring(commaIndex+1);
pattern = Pattern.compile(regExp);
matcher = pattern.matcher(resultString);
hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
}
return new BigDecimal(result2);
}
return result;
}
else
{
if(x.compareTo(BigDecimal.valueOf(0)) == -1)
{
System.out.println("Wrong input values");
return new BigDecimal("0");
}
BigDecimal x1 = x.pow(Integer.parseInt(yString.substring(0, yStringCommaIndex))); // Integer value
String xString = x.toPlainString(), xString2;
int precision = xString.indexOf(".")+1;
if(precision == 0)
{
if(xString.length() > 53)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
precision = xString.length()+1;
}
else if(precision > 54)
{
System.out.println("Too long value of integer number. Max is 53.");
return new BigDecimal("0");
}
BigDecimal val = BigFunctions.ln(x, 33).setScale(32, RoundingMode.HALF_UP).multiply(new BigDecimal("0"+yString.substring(yStringCommaIndex)));
BigDecimal x2 = BigFunctions.exp(val, 33).setScale(32, RoundingMode.HALF_UP); // Decimal value
BigDecimal result = x1.multiply(x2).setScale(32, RoundingMode.HALF_UP);
xString2 = result.toPlainString();
precision = xString2.indexOf(".");
if(precision > 32)
{
precision = 32;
}
else if(precision == -1 || precision == 1 && xString2.charAt(0) == '0')
{
precision = 0;
}
result = result.setScale(32-precision, RoundingMode.HALF_UP);
String regExp = "9{16}", resultString = result.toPlainString();
int commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
String result2 = resultString.substring(0, commaIndex);
resultString = resultString.substring(commaIndex+1);
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(resultString);
boolean hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += "."+resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
return new BigDecimal(result2).add(BigDecimal.valueOf(1));
}
result2 += "9";
return new BigDecimal(result2).setScale((result2.length()-1)-(commaIndex+1), RoundingMode.HALF_UP);
}
regExp = "0{16}|0+$";
resultString = result.toPlainString();
commaIndex = resultString.indexOf(".");
if(commaIndex == -1)
{
return result;
}
result2 = resultString.substring(0, commaIndex+1);
resultString = resultString.substring(commaIndex+1);
pattern = Pattern.compile(regExp);
matcher = pattern.matcher(resultString);
hasMatch = matcher.find();
if(hasMatch == true)
{
result2 += resultString.substring(0, matcher.start());
if(result2.endsWith("."))
{
result2 = result2.substring(0, commaIndex);
}
return new BigDecimal(result2);
}
return result;
}
}