• Post Reply Bookmark Topic Watch Topic
  • New Topic

Is there a mathematician in the house?  RSS feed

 
Tom Clement
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Tom Clement
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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 ]
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Tom Clement
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Tom Clement
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks to both of you, I'll get busy, Tom.
 
Tom Clement
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!