computing t = pow(-11.5, .333)

J

John Smith

In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN.

I worked around the problem by putting the standard function in a
wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

JS
 
P

pete

John said:
In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN.

I worked around the problem by putting the standard function in a
wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

-11.5 has a third root which is negative,
if that's what you're really trying to find.

However, if you consider that
a negative number raised to an even integer power, is positive,
and that
a negative number raised to an odd integer power, is negative,
then it just seems natural that
the sign of a negative number raised to a non integer,
should be undefined.
 
R

Robert Gamble

John said:
In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN.

I worked around the problem by putting the standard function in a
wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

I don't know why the pow function is defined this way and there is
little insight in the rationale. You can obtain the expected result of
pow(-11.5, .333) by using the cube root function from C99 if your
implementation provide it: cbrt(-11.5);.

Robert Gamble
 
R

Robert Gamble

Robert said:
I don't know why the pow function is defined this way and there is
little insight in the rationale.

I obviously didn't give enough thought to that. Any negative number
raised to a fractional power that is not the reciprocal of an odd
number (1/3, 1/5, 1/7, etc) will have a complex result. C99 provides
support for complex numbers and you can perform such calculations with
the cpow family of functions.
You can obtain the expected result of
pow(-11.5, .333) by using the cube root function from C99 if your
implementation provide it: cbrt(-11.5);.

Robert Gamble
 
C

CBFalconer

John said:
In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN.

I worked around the problem by putting the standard function in a
wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

Yes. What you are doing has no meaning. You are actually
returning -(b**x) instead of (-b)**x, where I am using ** to
represent exponentiation. What is the real problem?

Consider: what is the square root of -1/2? There is no answer in
the real plane. You need complex variables for this. Yet this is
just the value of (-0.5)**0.5.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
E

Eric Sosman

John said:
In a C program I need to do exponentiation where the base is negative
and the exponent is a fraction. In standard C this would be something
like t = pow(-11.5, .333), but with this combination of arguments there
is a domain error and the result is a percolating NaN.

I worked around the problem by putting the standard function in a wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the standard
library function? Has anyone else had a problem with this and found a
better solution?

The reason for the limitation is mathematical: The proper
result of pow(-1,1.5) is -i, where i is the square root of -1.
That imaginary value is not in the range of double, so the pow
function cannot return it.

You define xpow(-1,1.5) as -pow(1,1.5), or -1. C allows
you to do so, but notice that you've now violated the usual
laws of exponents:

pow(x,a) * pow(x,b) == pow(x, a+b) /* mathematically */
so
pow(-1,1.5) * pow(-1,1.5)
== pow(-1,3.0)
== -1
but
xpow(-1,1.5) * xpow(-1,1.5)
== -pow(1,1.5) * -pow(1,1.5)
== -1 * -1
== 1

If you're happy with this state of affairs, go ahead and
be happy -- but don't ask the rest of the world to join in
your rejoicing.
 
H

Howard Hinnant

John Smith said:
In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN.

I worked around the problem by putting the standard function in a
wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

You might try something more along the lines of:

double root(double b, int x)
{
if(b < 0 && !(x & 1))
return 0./0.;
if (b < 0)
return -pow(-b, 1./x);
return pow(b, 1./x);
}

This will give you correct results for both:

root(-11.5, 3);
root(-11.5, 2);
root( 11.5, 2);
root( 11.5, 3);

-Howard
 
D

Dik T. Winter

> In a C program I need to do exponentiation where the base is
> negative and the exponent is a fraction. In standard C this would
> be something like t = pow(-11.5, .333), but with this combination
> of arguments there is a domain error and the result is a
> percolating NaN.

Rightly so.
> I worked around the problem by putting the standard function in a
> wrapper:
> double xpow(double b, double x)
> {
> double p;
>
> if(b < 0)
> {
> p = pow(-b, x);
> p *= -1.0;
> }
> else p = pow(b, x);
>
> return p;
> }

What is xpow(-1, 2) with your function? Does it divert from reality?
Or (talking about fractions) what about xpow(-1, 0.5)?
> Is there any particular reason for this limitation in the
> standard library function?

Yes, there is a pretty good reason. When the 'b' argument is negative
there may not even be a solution within the reals when the 'x' argument
is a fraction.
 
J

Jordan Abel

I obviously didn't give enough thought to that. Any negative number
raised to a fractional power that is not the reciprocal of an odd
number (1/3, 1/5, 1/7, etc) will have a complex result.

Or with such reciprocals - I believe that, traditionally, raising
a negative number to the fractional power yields the root with the
lowest [counterclockwise] angle on the complex plane from the positive
real axis - which is going to be less than pi (the angle for negative
numbers), while the nth-root operator yields the negative real root.
 
J

Julian V. Noble

John said:
In a C program I need to do exponentiation where the base is negative
and the exponent is a fraction. In standard C this would be something
like t = pow(-11.5, .333), but with this combination of arguments there
is a domain error and the result is a percolating NaN.

I worked around the problem by putting the standard function in a wrapper:

double xpow(double b, double x)
{
double p;

if(b < 0)
{
p = pow(-b, x);
p *= -1.0;
}
else p = pow(b, x);

return p;
}

Is there any particular reason for this limitation in the standard
library function? Has anyone else had a problem with this and found a
better solution?

JS

To understand this you must look under the hood. The power function
with an exponent specified as a decimal fraction almost certainly
will do this:

pow(a,b) = exp(b*ln(a));

since the ordinary (real) logarithm of a negative number is undefined
in many implementations it will return NaN. I myself would make it
abort immediately with an error message such as

"Can't take logarithm of negative number!"

(and I have done just that in floating point libraries I have written)
but de gustibus non est disputandum, and others doubtless had good
reasons for going the NaN route.

Although I have not looked into <math.h> for the details, I would
not be surprised to find that in many C implementations pow can
tell whether the exponent b is a floating point number or a positive
(or negative) integer smaller in magnitude than some value N, for
which a^b = a*...*a (computed via the minimal-multiplication algorithm)
is faster than computing two transcendental functions.

That is, I would expect a properly written pow function to compute

pow(a,2) = a*a;
pow(a,-2) = 1/(a*a);

whereas

pow(a,2.0) = exp(2.0*ln(a));
 
P

pete

Julian V. Noble wrote:
That is, I would expect a properly written pow function to compute

pow(a,2) = a*a;
pow(a,-2) = 1/(a*a);

whereas

pow(a,2.0) = exp(2.0*ln(a));

It would take some kind of compiler trick,
as well as proper function writing, for a called function
to be able to distinguish between two arguments
which compare equal when converted to the type of the parameter,
but which have different types.
 
K

Kenneth Brody

pete said:
John said:
In a C program I need to do exponentiation where the base is
negative and the exponent is a fraction. In standard C this would
be something like t = pow(-11.5, .333), but with this combination
of arguments there is a domain error and the result is a
percolating NaN. [...]
Is there any particular reason for this limitation in the
standard library function? Has anyone else had a problem with
this and found a better solution?

It's not a "limitation in the standard library function", but rather
a "limitation" of math itself. You cannot express the fractional power
of a negative number as a real number in the general case.
-11.5 has a third root which is negative,
if that's what you're really trying to find.

Of course, a power of ".333" is _not_ a third root, as ".333" is only
_close_ to 1/3. (For large enough values of "close".)
However, if you consider that
a negative number raised to an even integer power, is positive,
and that
a negative number raised to an odd integer power, is negative,
then it just seems natural that
the sign of a negative number raised to a non integer,
should be undefined.

Now, his solution of negating the number, and again negating the result,
does "work" for odd integral roots and odd integral powers, but not in
the general case.

[...]

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
J

John Smith

CBFalconer said:
Yes. What you are doing has no meaning.

This is what happens when a non-mathematician attempts
mathematical programming.

You are actually
returning -(b**x) instead of (-b)**x, where I am using ** to
represent exponentiation. What is the real problem?

Consider: what is the square root of -1/2? There is no answer in
the real plane. You need complex variables for this. Yet this is
just the value of (-0.5)**0.5.

My project involves solving cubic and quartic equations which
sometimes have complex roots and I am feeling my way along in the
dark. Occasionally there is a faint glimmer of light in the
distance. thanks to all for your responses. They have been helpful.

JS
 
C

CBFalconer

John said:
CBFalconer wrote:
.... snip ...

My project involves solving cubic and quartic equations which
sometimes have complex roots and I am feeling my way along in the
dark. Occasionally there is a faint glimmer of light in the
distance. thanks to all for your responses. They have been helpful.

If you want real roots (which may not exist for a quartic, but must
exist for a cubic) consider a Newton-Raphson solution. Off to the
books with you. This is now no longer a C question, but
algorithmic, and better suited to comp.programming.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
J

Julian V. Noble

pete said:
It would take some kind of compiler trick,
as well as proper function writing, for a called function
to be able to distinguish between two arguments
which compare equal when converted to the type of the parameter,
but which have different types.

Not really, Fortran did it by looking for the decimal point. That is,
if it could interpret the literal exponent as an integer it would. If
it were forced to interpret it as a real (by the presence of a dp, e.g.)
it would do that. How it dealt with symbolic exponents doubtless had
to do with the type of the exponent name. Remember this is all done
at compile-time, not run-time. I once wrote a system where a variable
contained a token identifying its type so it could be done at run-time.
It really isn't that hard.
 
P

pete

P.J. Plauger said:
Essentially by calling trunc(x) and seeing if the return value
differs from x. (More precisely, we use the _Dint function that
was discussed at length in these pages a few months ago.)

There's no function that can be called from pow,
that will distinguish
pow(a, 2);
from
pow(a, 2.0);
 
P

pete

pete said:
There's no function that can be called from pow,
that will distinguish
pow(a, 2);
from
pow(a, 2.0);

I'm not very familiar with C99, so for a moment
I thought trunc() was one of your own, like _Dint.

Now that I've read the standard description of trunc,
I can say that there's absolutley no way that calling trunc
can help to distinguish
pow(a, 2);
from
pow(a, 2.0);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top