user4159038
user4159038

Reputation:

Power function handling negative base with non integer exponents

Math.pow(), pow(), whatever it's called, a lot of languages (and calculators) have some built in function to calculate x=a^b for floats (or doubles). There's the special case of a being negative and b not being an integer. Some will return NaN, others give a complex result (ahem Python). But some are actually capable of giving real results, and so what I'm wondering is how. To explain my confusion:

Suppose b is rational: b=c/d. Now we look at the parity of c and d:

Floats are stored in a particular format that means if it were interpreted literally it would always be an even d (power of 2 actually). There's no way to know the real parity of c and d since that information is lost in computation. It would just have to guess.

So my guess as to what it's doing - it tries to find a rational c/d close to b, with odd d and both c and d less than some threshold t. Smaller t means it can be more sure it's correct but it'll work on less numbers. If that succeeds, it uses the parity of c. Otherwise it pretends d is even. After all, a float can be anything and the math library doesn't want to give a possibly wrong result by assuming it's rational when it might not be.

That's only my guess though. If anyone has actually seen the code in one of these power functions (or a specification, that's just as good) and could provide insight, that'd be great.

Upvotes: 4

Views: 2429

Answers (2)

aka.nice
aka.nice

Reputation: 9382

If you are ready to cheat, here is how you can raise a negative to any power:

x^(b/c)=x^(2b/2c)=(x^2b)^(1/2c)

x^2b is positive, so no problem for taking the 2c-th root

Upvotes: 0

Spektre
Spektre

Reputation: 51845

first see: Power by squaring for negative exponents

Now let assume case x^y where x<0 and y is not integer. If you use

x^y = exp2(y*log2(x))

then you;re limited by the log2 definition range hence the NaN or |x|^y. If you want something better instead you can try to disect y to this form:

y = a/b

where a,b are integers. If possible (or if rounding applied) then you change the problem to this:

x^y = (x^a)^(1/b)

so now you can handle more cases (exactly as you suggested):

  1. if a is even sub-result is no longer negative

    as x^a>=0 so (x^a)^(1/b)>=0

  2. if both a,b are odd result is negative

  3. else result is NaN or use |x|^y instead

Now back to your float question the number is always in this form:

y = mantissa*exp2(exponent)

so yes b is even (unless exponent!=0 which means number is integer). As mantissa is stored as an integer you can obtain its parity by inspecting its LSB. Do not forget that in floats the MSB is missing and always should be 1 unless a special case like de-normalized or Nan/Inf numbers are present

Upvotes: 1

Related Questions