Java's Bigdecimal.Power(Bigdecimal Exponent): Is There a Java Library That Does It

Java's BigDecimal.power(BigDecimal exponent): Is there a Java library that does it?

There is a Math.BigDecimal implementation of core mathematical functions with source code available from the Cornell University Library here (also you can download the library as a tar.gz). Here is a sample of the library use:

import org.nevec.rjm.*;
import java.math.BigDecimal;

public class test {
public static void main(String... args) {
BigDecimal a = new BigDecimal("1.21");
BigDecimal b = new BigDecimal("0.5");

System.out.println(BigDecimalMath.pow(a, b).toString());
}
}

Prints out:

1.1

Update

The license information is now clear in the May 2015 update:

The full source code is made available under the LGPL v3.0.

Power doesn't seem to work with BigDecimal (Java)

The first argument to pow is not a BigDecimal, but rather an int.

(On a side note, you're aware that testPow will immediately reach and remain at 1, yes?)

How to do a fractional power on BigDecimal in Java?

The solution for arguments under 1.7976931348623157E308 (Double.MAX_VALUE) but supporting results with MILLIONS of digits:

Since double supports numbers up to MAX_VALUE (for example, 100! in double looks like this: 9.332621544394415E157), there is no problem to use BigDecimal.doubleValue(). But you shouldn't just do Math.pow(double, double) because if the result is bigger than MAX_VALUE you will just get infinity. SO: use the formula X^(A+B)=X^A*X^B to separate the calculation to TWO powers, the big, using BigDecimal.pow, and the small (remainder of the 2nd argument), using Math.pow, then multiply. X will be copied to DOUBLE - make sure it's not bigger than MAX_VALUE, A will be INT (maximum 2147483647 but the BigDecimal.pow doesn't support integers more than a billion anyway), and B will be double, always less than 1. This way you can do the following (ignore my private constants etc):

    int signOf2 = n2.signum();
try {
// Perform X^(A+B)=X^A*X^B (B = remainder)
double dn1 = n1.doubleValue();
// Compare the same row of digits according to context
if (!CalculatorUtils.isEqual(n1, dn1))
throw new Exception(); // Cannot convert n1 to double
n2 = n2.multiply(new BigDecimal(signOf2)); // n2 is now positive
BigDecimal remainderOf2 = n2.remainder(BigDecimal.ONE);
BigDecimal n2IntPart = n2.subtract(remainderOf2);
// Calculate big part of the power using context -
// bigger range and performance but lower accuracy
BigDecimal intPow = n1.pow(n2IntPart.intValueExact(),
CalculatorConstants.DEFAULT_CONTEXT);
BigDecimal doublePow =
new BigDecimal(Math.pow(dn1, remainderOf2.doubleValue()));
result = intPow.multiply(doublePow);
} catch (Exception e) {
if (e instanceof CalculatorException)
throw (CalculatorException) e;
throw new CalculatorException(
CalculatorConstants.Errors.UNSUPPORTED_NUMBER_ +
"power!");
}
// Fix negative power
if (signOf2 == -1)
result = BigDecimal.ONE.divide(result, CalculatorConstants.BIG_SCALE,
RoundingMode.HALF_UP);

Results examples:

50!^10! = 12.50911317862076252364259*10^233996181

50!^0.06 = 7395.788659356498101260513

Getting much higher precision with BigDecimal (or another class) in Java

Here is an explanation why what you are doing is not working.

Math.pow() returns a double. So your code is calculating the value using the precision provided by double, and then creating a BigDecimal from that double. It's too late to set the precision on the big decimal since it only has the double as input.

So you can not use Math.pow() for your purpose. Instead you need to find another library that does arbitrary precision calculations.

Refer to this question for more: Java's BigDecimal.power(BigDecimal exponent): Is there a Java library that does it?

How to raise double to bigInteger in java

Looks like the standard Java library does not provide any way to compute powers with arbitraty precision.

If you don't really need arbitrary precision and double precision is enough, you could use Math.pow(double, double).

If your exponent is actually an integer, you could try BigInteger.pow(int):

BigInteger result = new BigInteger("312413431431431431434314134").pow(5);

And if you actually need arbitraty precision power operation, you'll have to look at some library. For example, there is Apfloat: https://github.com/mtommila/apfloat

You could do something like this:

BigDecimal base = new BigDecimal("12341341341341341341341343414134134");
double exponent = 1.5;
Apfloat apfloatBase = new Apfloat(base);
Apfloat apfloatExponent = new Apfloat(exponent);
Apfloat result = ApfloatMath.pow(apfloatBase, apfloatExponent);

Javadocs: http://www.apfloat.org/apfloat_java/docs/org/apfloat/Apfloat.html
http://www.apfloat.org/apfloat_java/docs/org/apfloat/ApfloatMath.html

Java/Android pow precision/scale like in Windows calculator

omg...

I speend a few days on this. I have tried many algorithms and none of them don't worked... And then I wrote in my function:

pow(new BigDecimal(3), new BigDecimal("8.73")) // <-- this is String in 2 argument (good)

NOT:

pow(new BigDecimal(3), new BigDecimal(8.73)) // <-- this is double in 2 argument (bad)

And now all is working...

So if you wanna too have good function/method pow(BigDecimal x, BigDecimal y) you must download this class: BigFunctions.java (I get this code from this book: Java Number Cruncher: The Java ...) there is good method ln, and exp - we need them to our pow. Next put this class into your Project and at the end you must write this method in your some class (complete version of this method is at the end of this 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;
}

In some cases like here:

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);

We have result:

1.41421356237309504880168872420970

2.00000000000000000000000000000001

So we can modify our method like that:

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;
}

And result is:

1.41421356237309504880168872420970

2







Edit:

I found one problem - when we enhances big value then his precision isn't good, so below you have final version of pow method.

COMPLETE POW METHOD:

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;
}
}


Related Topics



Leave a reply



Submit