Tom Clement

Greenhorn

Posts: 26

posted 13 years ago

I've still been unable to solve what should be the last logic problem in my program. It has to do with resolving floating point calculations.

power = -5.300000190734863

base = 20

20 to the -5th = 3.125000E-7 using BigDecimal divide().

How do I calculate the .300000190734863

to arrive at correct answer of

1.2721571e-7

I'm using BigDecimal because of the size of some of the calculations.

Oh, and I've tested the program on whole numbers and it works fine when tested against the calculator, it's the handling of the fractional part that's killing me.

Thank you all, very much...... Tom

power = -5.300000190734863

base = 20

20 to the -5th = 3.125000E-7 using BigDecimal divide().

How do I calculate the .300000190734863

to arrive at correct answer of

1.2721571e-7

I'm using BigDecimal because of the size of some of the calculations.

Oh, and I've tested the program on whole numbers and it works fine when tested against the calculator, it's the handling of the fractional part that's killing me.

Thank you all, very much...... Tom

Warren Dew

blacksmith

Ranch Hand

Ranch Hand

Posts: 1332

2

posted 13 years ago

Well, if BigDecimal had a natural log function, you could use the fact that 20^0.3 is equal to exp ( ln(20) * 0.3 ) to derive it from the natural log.

Since it doesn't, it looks to me like you might have to implement the natural log first using a Taylor expansion or something similar.

Are you sure a double isn't big enough for your purposes? I personally have problems trusting a nominally arithmetic class that has an ordering inconsistent with equals.

Since it doesn't, it looks to me like you might have to implement the natural log first using a Taylor expansion or something similar.

Are you sure a double isn't big enough for your purposes? I personally have problems trusting a nominally arithmetic class that has an ordering inconsistent with equals.

Tom Clement

Greenhorn

Posts: 26

posted 13 years ago

Yeah, I've had overflow problems. There must be a way, I'm missing.

But, right now the program is implemented with double.

The new BigDecimal is going to have a pow() method. However, since it's beta

I'm not going to use it.

I'm no math wiz, but I don't see why it doesn't work to convert the fractional

part of the power to a percentage of the base and divide by that?

I'm almost tempted to ask Dr Math, but that's so cheesy.

BTW, I'm going to try the ln( I saw somebody else using it in a similar way. Perhaps that'll work, I'll let you know if I have any success. Thanks.

Tom

[ April 10, 2004: Message edited by: Tom Clement ]

But, right now the program is implemented with double.

The new BigDecimal is going to have a pow() method. However, since it's beta

I'm not going to use it.

I'm no math wiz, but I don't see why it doesn't work to convert the fractional

part of the power to a percentage of the base and divide by that?

I'm almost tempted to ask Dr Math, but that's so cheesy.

BTW, I'm going to try the ln( I saw somebody else using it in a similar way. Perhaps that'll work, I'll let you know if I have any success. Thanks.

Tom

[ April 10, 2004: Message edited by: Tom Clement ]

Jim Yingst

Wanderer

Sheriff

Sheriff

Posts: 18671

posted 13 years ago

Well, it doesn't seem to be necessary for the numbers you've given. Maybe BigDecimal was needed for other parts of this calculation, but not here? If so, just use doubleValue() to convert from BigDecimal to double. Or if you really need BigDecimal, can you provide an example of actual values which require it? Is the base really big? Is the exponent really big? Is it just the result that's too big for double? The answers to these questions will determine what strategies are possible. But I suspect you don't really need BigDecimal, and it will be simples to get rid of it (for this part of the calculation at least).

Also it only works for int exponents.

I'm not sure what you mean. If you have

exp= a + b

then

pow(base, exp) = pow(base, a + b) = pow(base, a) * pow(base, b)

So

pow(20, -5.300000190734863) = pow(20, -5) * pow(20, -.300000190734863)

I'm not sure how useful that is though, since Math.pow() already works fine for the original values.

**I'm using BigDecimal because of the size of some of the calculations.**

Well, it doesn't seem to be necessary for the numbers you've given. Maybe BigDecimal was needed for other parts of this calculation, but not here? If so, just use doubleValue() to convert from BigDecimal to double. Or if you really need BigDecimal, can you provide an example of actual values which require it? Is the base really big? Is the exponent really big? Is it just the result that's too big for double? The answers to these questions will determine what strategies are possible. But I suspect you don't really need BigDecimal, and it will be simples to get rid of it (for this part of the calculation at least).

**The new BigDecimal is going to have a pow() method. However, since it's beta I'm not going to use it.**

Also it only works for int exponents.

**I'm no math wiz, but I don't see why it doesn't work to convert the fractional part of the power to a percentage of the base and divide by that?**

I'm not sure what you mean. If you have

exp= a + b

then

pow(base, exp) = pow(base, a + b) = pow(base, a) * pow(base, b)

So

pow(20, -5.300000190734863) = pow(20, -5) * pow(20, -.300000190734863)

I'm not sure how useful that is though, since Math.pow() already works fine for the original values.

"I'm not back." - Bill Harding, *Twister*

Tom Clement

Greenhorn

Posts: 26

posted 13 years ago

Hi Jim,

As I said, "I'm using BigDecimal because of the size of some of the calculations."

It is open ended, could be 26^10250 or even larger. Numerous values are above double's limit.

Also, the program is currently implemented with double and does overflow occasionally. Although, it's been

addressed so nothing bad happens, it's still annoying and needs to be fixed.

Now, as to your formula :

data = Math.pow(20, -5) * Math.pow(20, -.300000190734863);

System.out.println(data);

, yes it works, it puts out the correct answer. But I can't seem to duplicate the second part.

The first part:

Math.pow(20, -5), No problem)

simple division works

I put it in a for loop and iterate the division of the base by the number of the exp.

Second part, not so simple.

I've tried it directly, and even tried converting the exp to a percentage of 20, e.g.,6.00000381469726

So in summation, let me put it this way:

I've got 3.125000E-7 * ? = 1.2721571e-7

Again, I'm using this as a simple test case. The actual numbers would be much larger. If I can get

BigDecimal to work here, it will also work on larger exps. Thank you very much for your response,

and if I could get you to help me work through this I'd be very appreciative. What formula do I use to convert the second part to the correct number? Thanks again, Tom

As I said, "I'm using BigDecimal because of the size of some of the calculations."

It is open ended, could be 26^10250 or even larger. Numerous values are above double's limit.

Also, the program is currently implemented with double and does overflow occasionally. Although, it's been

addressed so nothing bad happens, it's still annoying and needs to be fixed.

Now, as to your formula :

data = Math.pow(20, -5) * Math.pow(20, -.300000190734863);

System.out.println(data);

, yes it works, it puts out the correct answer. But I can't seem to duplicate the second part.

The first part:

Math.pow(20, -5), No problem)

simple division works

I put it in a for loop and iterate the division of the base by the number of the exp.

Second part, not so simple.

I've tried it directly, and even tried converting the exp to a percentage of 20, e.g.,6.00000381469726

So in summation, let me put it this way:

I've got 3.125000E-7 * ? = 1.2721571e-7

Again, I'm using this as a simple test case. The actual numbers would be much larger. If I can get

BigDecimal to work here, it will also work on larger exps. Thank you very much for your response,

and if I could get you to help me work through this I'd be very appreciative. What formula do I use to convert the second part to the correct number? Thanks again, Tom

Warren Dew

blacksmith

Ranch Hand

Ranch Hand

Posts: 1332

2

posted 13 years ago

Taylor series expansions for exp(x) and ln(x) if you need them:

exp(x) = sum (n=0 to infinity) ( x**n / n! )

ln (x) = sum (n=1 to infinity) ( -1**(n+1) * (x-1)**n / n ) (for 0 < x < 2)

For ln(x) with x > 1, you can divide by e until you get a value less than one, then use the taylor series expansion. ln(x) will then be the number of times you divided by e plus the (negative) value of the expansion above for the fractional value you get when you get to less than one.

With appropriate convergence cutoffs, this should work okay for numbers of arbitrary magnitudes; if it gets slow for really large numbers, there are some optimizations you can make. If in addition to handling arbitrarily large magnitudes, you also need to handle arbitrary precision, that could get more complex - though you could perhaps still handle it by using convergence cutoffs (and precisions of e) that varied based on the precision of the inputs.

exp(x) = sum (n=0 to infinity) ( x**n / n! )

ln (x) = sum (n=1 to infinity) ( -1**(n+1) * (x-1)**n / n ) (for 0 < x < 2)

For ln(x) with x > 1, you can divide by e until you get a value less than one, then use the taylor series expansion. ln(x) will then be the number of times you divided by e plus the (negative) value of the expansion above for the fractional value you get when you get to less than one.

With appropriate convergence cutoffs, this should work okay for numbers of arbitrary magnitudes; if it gets slow for really large numbers, there are some optimizations you can make. If in addition to handling arbitrarily large magnitudes, you also need to handle arbitrary precision, that could get more complex - though you could perhaps still handle it by using convergence cutoffs (and precisions of e) that varied based on the precision of the inputs.

Jim Yingst

Wanderer

Sheriff

Sheriff

Posts: 18671

posted 13 years ago

And as I said, "Or if you really need BigDecimal, can you provide an example of actual values which require it? Is the base really big? Is the exponent really big? Is it just the result that's too big for double? The answers to these questions will determine what strategies are possible."

You've now provided one additional example, 26^10250. Based on that, it looks like your

Now as long as the operands are doubles, that simplifies the problem. Let's take an example like

26^10250.0852783

You can use the previously discussed technique to write this as

26^10250 * 26^.0852783

Now for 26^10250 the result can't be stored in a double, so you need BigDecimal for that. But for 26^.0852783, the result

I think this approach would be somewhat easier than using Taylor series as Warren suggests. However one advantage of the Taylor series approach is that you can andle arbitrary presicision with it. As Warren notes, this can get more complex to determine how many terms are necessary to achieve the desired precision. But it's

**As I said, "I'm using BigDecimal because of the size of some of the calculations."**

And as I said, "Or if you really need BigDecimal, can you provide an example of actual values which require it? Is the base really big? Is the exponent really big? Is it just the result that's too big for double? The answers to these questions will determine what strategies are possible."

You've now provided one additional example, 26^10250. Based on that, it looks like your

*operands*can still both be represented by doubles, while the

*result*needs to be represented as BigDecimal. This is useful to know, as there are a number of other complications if the operands are so large (or small) that they can't be represented using doubles. Often it would mean that the result will be so huge (or tiny) that it can't even be represented by a BigDecimal. E.g. try calculating (1e-2000000000)^2 using BigDecimal - you'll get an ArithmeticException for underflow.

Now as long as the operands are doubles, that simplifies the problem. Let's take an example like

26^10250.0852783

You can use the previously discussed technique to write this as

26^10250 * 26^.0852783

Now for 26^10250 the result can't be stored in a double, so you need BigDecimal for that. But for 26^.0852783, the result

*can*be stored in a double. Since the exponent is between 0 and 1, the result will be between 1 and 26. Great. So you can still use Math.pow() here to save yourself some time and headaches. It won't overflow. Then later you can combine this with the BigDecimal result of 26^10250, and the overall result will have to also be BigDecimal. But that's no problem at this stage, as you've just got to do a simple multiplication to finish this off.

I think this approach would be somewhat easier than using Taylor series as Warren suggests. However one advantage of the Taylor series approach is that you can andle arbitrary presicision with it. As Warren notes, this can get more complex to determine how many terms are necessary to achieve the desired precision. But it's

*possible*at least. Conversely by using Math.pow() for part of the calculation, you're limited to the precision available to double. Typically this is something like 16 significant digits, which is pretty good really, and probably more than you need. However if you do require more, Math.pow() can't help you, and you will have to use Taylor series, or some other advanced numeric technique.

"I'm not back." - Bill Harding, *Twister*

Tom Clement

Greenhorn

Posts: 26

posted 13 years ago

Ok, Jim, I've implemented your method and it works!

I've already tested it many times through comparison with two different

types of calculators and it works great. I can now sleep at night, thank you all, this thread has been well worth it. Tom

I've already tested it many times through comparison with two different

types of calculators and it works great. I can now sleep at night, thank you all, this thread has been well worth it. Tom