1

Example in Windows calculator when we do "3^8.73" result is "14630,816172800116064202808828951", but when we do in Java "Math.pow(3, 8.73)" result is "14630.816172800123".

How can I do pow in Java with presicion like in Windows calculator (32 numbers after comma)?

I can't use BigDecimal class, because there is only pow(int) - I need pow(double) method.

I can't find any solution on about this problem. There are maybe better classes than BigDecimal for Android, where we can do pow(double)?

Thanks for answers :* .

Oxygenium
  • 71
  • 1
  • 2
  • 7
  • Use long and BigInteger as if it was decimal, then convert. – MLProgrammer-CiM May 19 '15 at 21:46
  • Related question: [Java's BigDecimal.power(BigDecimal exponent): Is there a Java library that does it?](http://stackoverflow.com/q/16441769) – Frxstrem May 19 '15 at 22:01
  • Yup, I saw this topic, but it don't help me. Apfloat library is working only on Java, not on Android. BigDecimalMath isn't good library. Example for "**BigDecimalMath.pow(new BigDecimal("3"), new BigDecimal("8.73"))**" sum is "**6000**". – Oxygenium May 19 '15 at 22:23

1 Answers1

1

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;
    }
}
Community
  • 1
  • 1
Oxygenium
  • 71
  • 1
  • 2
  • 7