Question about Math.pow() in Java

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Hey all,
I was writing an expression evaluator for my Java class...but I've run into a problem. Java's power function seems to be like, inaccurate. Also, if it matters, I use Eclipse as my compiler. For example, if I do:
double x = Math.pow(512, (double) 1/3);

x comes out as 7.999...9 (15 decimal places). It should come out to 8...512^(1/3)--cubed root of 512. The inaccuracy is tiny, but still...I find this to be kind of strange. Also, if i do:

double y = Math.pow(x,3);

I should ostensibly get 512 back...but I don't. I get a number that's close, but not exactly 512. Repeating this process will cause y to diverge from 512 very very very gradually. Anyway, I was wondering if there are any ways to get around this problem? I realize that it's not hard to round up...but you couldn't do that for something like, pow(5,(double)3/7) because...lord knows what the "real" value of that is.

I realize that it's not a huge deal, but still, it just kind of bothers me. I mean, I have worked briefly with cpp, and the pow() function in math.h returns 8 for pow(512,(double)1/3).

I also tried to use a combination of natural log and e^x to calculate a power...which was even worse than using pow() (in Java).

Are there any other methods I can use?

Also...Java & cpp's pow() functions do not allow you to do like, pow(-8,(double)1/3)...should be -2, but both cpp & Java give you NaN. Generally...for a^b, if a is <=0, then b has to be a whole number. Is there anyway to fix this except to use like an if statement to evaluate the expression as if it were positive and put the negative back in the end (given that the power is an odd one)?

Thanks all,
-Eric
 

MrChad

Lifer
Aug 22, 2001
13,507
3
81
Any time you deal with floats/doubles in programming, you are dealing with approximations of those numbers. This is simply the result of conversions from base10 to binary back to base10. AFAIK there's no way around it.
 

dighn

Lifer
Aug 12, 2001
22,820
4
81
rounding shouldn't cause too much trouble, just round to many decimal places so that it's accurate enough for your purposes but enough to give you a good result for these really small errors
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: MrChad
Any time you deal with floats/doubles in programming, you are dealing with approximations of those numbers. This is simply the result of conversions from base10 to binary back to base10. AFAIK there's no way around it.

Yeah...but my question is, how come I don't have this problem working in CPP? Also, what about the thing with negative exponents? Does anyone provide a function that can handle those or do I have to write a 'special case'?

edit: For example in cpp, this code:
double x=pow(8,(double)1/2);
cout<<x<<endl;
double y = pow(x,2);
cout<<y;

That outputs:
2.8284
8

In java, the same code
2.8284271247461903
8.000000000000002

Is it just that the cpp pow() function has like, some built-in roundoff and Java retains the entire value? Or am I just stupid or what...lol. '


OR should i just stop worrying about it and deal with my 0.00000000000001 error...hehe
 

rjain

Golden Member
May 1, 2003
1,475
0
0
It just has to do with the format you use to display the number.

The negative exponent goes back to the fact that you can't precisely represent 1/3 in binary. So it doesn't know if you want 2^(-1/3) or 2^(-0.3333333333278). This is all standard IEEE floating point behavior. FP is really for numerical simulations, not for mathematical computations. It's designed so that you can quickly compute values to within a speicified precision as long as you follow certain rules when writing the code, since FP math isn't associative, for example.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: rjain
It just has to do with the format you use to display the number.

The negative exponent goes back to the fact that you can't precisely represent 1/3 in binary. So it doesn't know if you want 2^(-1/3) or 2^(-0.3333333333278). This is all standard IEEE floating point behavior. FP is really for numerical simulations, not for mathematical computations. It's designed so that you can quickly compute values to within a speicified precision as long as you follow certain rules when writing the code, since FP math isn't associative, for example.

Ah, I see what you mean. So if I want to be able to handle -2^(1/3), I need to like, evaluate it as a 2^1/3 and just put the negative back at the end?

And...I tried a bunch of other #s with Java & Cpp...and it does seem like cpp's pow() function just rounds off...it rounds off pretty early too...like 8 sig figs or something, while Java outputs the whole deal...so they both have error, but cpp makes it 'disappear'

Cool...thanks all :) If anything I've said is wrong...please let me know. Otherwise, good deal...thanks again everyone.

-Eric
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Originally posted by: notfred
Don't teachers teach what a floating point number is anymore?

Well...my problem is that I never took intro level CS courses...I jumped straight into the highest course offered. So there's some stuff like this that I wasn't aware of.
 

Xyphic

Junior Member
Jun 8, 2002
14
0
0
If I understand your question about powers of negative numbers, then what you want to do is a bit more complex (pun intended) than you expect.

If you want to take a power of a negative number and want a real number answer, you have to use an integer power (as you stated). If it isn't an integer, you'll most likely end up with an imaginary part to go with your real part.

Take the simplest example: -1^0.5 (minus one to the power of one half). This is *not* the same as -(1^0.5). A square root is such that if sqrt(a) = b then b^2 = a. So we need to find a number b such that b^2 = -1. In order to preserve the little sanity that remains to them, mathematicians dub this value i (for imaginary). So i^2 = -1 and hence -1^0.5 = i.

So, what you want to do with non-integer powers of negative numbers won't work with Java and CPP's standard pow functions. That's why you get NaN when you try it.

Apologies if I misunderstood your query, but I have to use this flipping education somewhere.
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Well, I know that I should get NaN for even roots of negative numbers. However, -8^(1/3) is -2. And I was wondering if there was any way to make Java (or any other pow function) understand that I wanted the cubed (or 5th, or 9th, or 3/7, or whatever) root. Which...since pow is usually like pow(double a, double b), it doesnt seem like that is at all possible without some kind of a Complex Number class.

Or at least...that's what I've gotten from the responses to my query :)
 

Xyphic

Junior Member
Jun 8, 2002
14
0
0
I get you now. You're looking to find the Real root if one exists. You sound pretty up with what you're doing, so you're probably aware than an n'th power polynomial of the form ax^n+b=0 has exactly n roots. This means there are exactly n solutions to the equation x=b^(1/n). In your case, -8^(1/3), there are three solutions. One of them happens to be -2, another happens to be (1.0 + i1.732050807568877) or thereabouts. I couldn't tell you what the third is without working it out.

The pow() function is expensive enough as it is without working out all the solutions to your input and then checking whether any of them are Real number answers. I got the second solution above from a complex number class I wrote a while back - using the method I chose for calculating powers of complex numbers, it happened to give me that root rather than the 'obvious' -2.

Hope this explains exactly why you get back NaN when you try it. There's probably something in the code that says something similar to:

if ((number < 0) && (power < 1))
{
return NaN;
}
 

eLiu

Diamond Member
Jun 4, 2001
6,407
1
0
Ah...that makes a lot of sense :) I had completely forgotten about that law of roots (fundamental theorem of algebra...or something like that).

Thanks a ton Xyphic! :)