4

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:

  • d is even: no real x -> NaN or error

  • d is odd, c is even: positive x

  • d is odd, c is odd: negative x

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.

  • 1
    It would help greatly if you gave examples of the languages and calculators that "are actually capable of giving real results." The only one I know is the TI Nspire CX handheld graphing calculator, and I believe that Texas Instruments is notorious for keeping its source code for the calculators non-open (though they open some software using the calculator). – Rory Daulton Aug 26 '17 at 13:15
  • For non-integer exponents you would get *complex roots*; for irrational exponents you get *infinitely many* of them. You can use mathematical identities to work around the limitations of `Math.pow` - see *Euler's identity* and *De Moivre's theorem* – meowgoesthedog Aug 26 '17 at 16:28
  • 2
    Can you give specific examples? I find the question confusing. As noted, all numeric binary floating-point numbers *are* rational numbers (that is, fractions), with d even (namely a power of two). If "parity" refers to the property of an integer being either odd or even, we therefore know that d is even, and the bit pattern of the floating-point number tells us whether c is odd or even. So I don't understand the claim "There's no way to know the real parity of c and d since that information is lost". – njuffa Aug 26 '17 at 16:31
  • 1
    If you replace a float by the reduced fraction it exactly represents, either it is an integer, or the denominator is necessarily even and the numerator necessarily odd (think reduced). So in no way you could have a real result returned... – aka.nice Aug 27 '17 at 07:39
  • check this out [real domain pow based on complex domain math](https://stackoverflow.com/a/67089172/2521214) – Spektre Apr 14 '21 at 10:11

2 Answers2

1

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

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
0

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

aka.nice
  • 9,100
  • 1
  • 28
  • 40
  • Your code does not find the proper power of x for real x, it finds that power for *the absolute value of x*. That is not the same thing. For example, your code claims that `(-1)^(1/3)` is `1`, but it should give `-1` (as the OP wants) or `1/2 + sqrt(3)/2*j` (as Python approximately returns). – Rory Daulton Aug 27 '17 at 16:53
  • Of course, that's why it's named cheating ;) What inspired this silly answer is the dissertation about float significand parity: it makes no sense, once the fraction reduced, the numerator will be odd (unless the float representation is an integer). Also, the definition of raising to a Fraction is somehow arbitrary. – aka.nice Aug 28 '17 at 05:52