0

I'm working on a calculator in order to better learn Java. I've written my own code to calculate powers with BigDecimal parameters. As of now, the code cannot handle fractional powers, such as 2^2.2. In order to tackle this problem, I want to implement the exponent identity X^(A+B)=X^A*X^B into my code.

How can I determine whether my BigDecimal parameter op2 has digits to the right of the decimal point, and then determine what the value is? For example, the code will recognize that op2 = 2.2 = 2.0 + 0.2.

I am aware of the scale() function of BigDecimal, but I'm unsure of how it works. For instance,

BigDecimal bd = new BigDecimal(2.1);
System.out.println(bd.scale());
> 51
BigDecimal bd = new BigDecimal(2.2);
System.out.println(bd.scale());
> 50

Here is the current code to calculate powers:

public static BigDecimal power(BigDecimal op1, BigDecimal op2)
{  
    boolean isOp1Zero;
    if (op1.compareTo(new BigDecimal(0)) == 0)
        isOp1Zero = true;
    else
        isOp1Zero = false;

    int distFromZero = op2.compareTo(new BigDecimal(0));

    //x^0 = 1
    if (distFromZero == 0)
        return new BigDecimal(1);

    //0^positive = 0
    else if (isOp1Zero && distFromZero == 1)
        return new BigDecimal(0);

    //non-zero^positive
    else if (!isOp1Zero && distFromZero == 1)
    {
        BigDecimal power = op1;
        for (int i = 1; i < op2.intValueExact(); i++)
        {
            power = power.multiply(op1);
        }

        return power;
    }

    //0^negative undefined
    else if (isOp1Zero && distFromZero == -1)
        throw new IllegalArgumentException("Error - zero to negative power");

    //non-zero^negative
    else if (!isOp1Zero && distFromZero == -1)
    {
        BigDecimal power = op1;
        BigDecimal op2NoSign = op2.multiply(new BigDecimal(-1));
        for (int i = 1; i < op2NoSign.intValueExact(); i++)
        {
            power = power.multiply(op1);
        }

        return new BigDecimal(1).divide(power);
    }
    return null;
}

Any advice appreciated! Thank you.

pez
  • 3,859
  • 12
  • 40
  • 72
  • 1
    Have a look at `BigDecimal.ZERO`, `BigDecimal.ONE`, and [`new BigDecimal(String val)`](http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#BigDecimal(java.lang.String)). – Keppil Aug 05 '14 at 19:19
  • 1
    The way I *always* check for a decimal point is to take the number, modulo `1`. For example `double remainder = 4.7 % 1;`. `remainder` will contain `0.7`. – christopher Aug 05 '14 at 19:21
  • @christopher Thanks! That actually occurred to me earlier and I forgot until now. Oops! But how do I handle something like this: `BigDecimal bd = new BigDecimal(2.1);` `BigDecimal remainder = bd.remainder(new BigDecimal (1));` `System.out.println(remainder);` `>0.100000000000000088817841970012523233890533447265625` Perhaps just cut the remainder off after a certain number of decimal points? – pez Aug 05 '14 at 19:26
  • It's irrelevant isn't it? `BigDecimal` has arbitrary precision for a reason. Attempt to perform the exponentiation with the giant decimal. You never know, it might go beautifully! – christopher Aug 05 '14 at 19:30

2 Answers2

1

You can check use bd.remainder(BigDecimal.ONE):

BigDecimal fraction = bd.remainder(BigDecimal.ONE)
BigDecimal whole = bd.subtract(fraction)

This will work for positive big decimals.

incidentally, I don't see how this is going to help you. How do you compute X^0.4? (That is, without resorting to logarithms)

Keppil
  • 45,603
  • 8
  • 97
  • 119
zmbq
  • 38,013
  • 14
  • 101
  • 171
1

You should use BigDecimal.valueOf() for a start.

BigDecimal bd = BigDecimal.valueOf(2.1);
b.scale() === 1

Next you should work out what precision you are aiming for. Unless you need more than 15 digits of accuracy, using double will be much simpler. However, if you need more accuracy, you should use a library to use BigDecimal for the calculation. e.g. if You use Math.pow() you have wasted your time.

To calculate power, a^b = exp(log(a)*b) Have a look at this as an example Logarithm of a BigDecimal

Community
  • 1
  • 1
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130