complex.h math functions
Steve Kargl
sgk at troutmask.apl.washington.edu
Sun Oct 2 12:19:03 PDT 2005
On Sat, Oct 01, 2005 at 09:38:44PM +1000, Bruce Evans wrote:
> >A slightly better implementation than
> >the above would be
> >
> > if (y == 0.) return (cos(x));
> > if (x == 0.) return (cosh(y));
> > return (cosh(y) * (cos(x) - I * sin(x) * tanh(y)));
>
> I'm not sure if this is better. The special cases may be so rare that
> checking for them slows down the average case. I think special handling
> is unnecessary since cos(0) is exactly 1.0, etc, so the checks are just
> an optimization of the special args. OTOH, the type-generic version
> should have special checks using something like
> "if (__builtin_const_p(y) && y == 0.)" to classify the pure real case,
> etc. Inline function args are never constant, so the type-generic
> version must be implemented as a macro.
Type-generic stuff is way above my C competency level. I'll
leave that to bde, das, of stefanf. :-)
>
> >...
> >OK, I'll use the implementation details of ccosh to infer the
> >handling of exceptional values.
> >
At the risk of embarassing myself once again on freebsd-standards,
here's an implementation of ccosh. If this is acceptable, I'll
proceed with implementations for csinh, ctanh, ccos, csin, and
ctan.
One question: Can we use a #define for complex float or do we
need an trivial C program? That is, in math.h can we do
#define ccoshf(z) ccosh((float complex)(z))
--
Steve
/*-
* Copyright (c) 2005, Steven G. Kargl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Hyperbolic cosine of a complex argument z = x + i y such that i = sqrt(-1).
*
* cosh(z) = cosh(x+iy)
* = cosh(x) if y == 0.
* = cos(y) if x == 0.
* = cosh(x) [cos(y) + i tanh(x) sin(y)] otherwise.
*
* Exception values are noted in the comments within the source code.
* These values and the return result were taken from n869.pdf.
*/
#include <complex.h>
#include <math.h>
#include "math_private.h"
double complex
ccosh(double complex z)
{
int con = 1;
double x, y;
int32_t hx, hy, ix, iy, lx, ly;
x = creal(z);
y = cimag(z);
if (x < 0.) {
/* Even function: ccosh(-z) = ccosh(z). */
x = -x;
y = -y;
/* Required identity: ccosh(conj(z)) = conj(ccosh(z)). */
if (y < 0.) {
con = -1;
y = -y;
}
}
EXTRACT_WORDS(hx, lx, x);
EXTRACT_WORDS(hy, ly, y);
ix = 0x7fffffff&hx; /* if ix >= 0x7ff00000, then inf or NaN */
iy = 0x7fffffff&hy; /* if iy >= 0x7ff00000, then inf or NaN */
/* Filter out the non-exceptional cases. x and y are finite. */
if (ix < 0x7ff00000 && iy < 0x7ff00000) {
/* cosh(+0 + I 0) = 1. */
if ((ix|lx) == 0 && (iy|ly) == 0)
return 1.;
return (cosh(x) * (cos(y) + I * con * tanh(x) * sin(y)));
}
/*
* cosh(+0 + I Inf) = NaN +- I 0, sign of 0 is unspecified,
* invalid exception.
* cosh(+0 + I NaN) = NaN +- I 0, sign of 0 is unspecified.
*/
if ((ix|lx) == 0 && iy >= 0x7ff00000)
return (y - y) / (y - y);
/*
* cosh(x + I Inf) = NaN + I NaN, finite x != 0, invalid exception.
* cosh(x + I NaN) = NaN + I NaN, finite x != 0, opt. inval. except.
*/
if (ix < 0x7ff00000 && iy >= 0x7ff00000)
return (x - x) / (x - x) + I * (x - x) / (x - x);
/*
* cosh(+Inf + I 0) = +Inf + I 0
* cosh(+Inf + I Inf) = +Inf + I NaN, invalid exception.
* cosh(+Inf + I y) = +Inf [cos(y) + I sin(y)], y != 0 and finite.
* cosh(+Inf + I NaN) = +Inf + I NaN.
*/
if (ix >= 0x7ff00000 && ((hx&0xfffff)|lx) == 0) {
if ((iy|ly) == 0)
return (x * x);
else if (iy >= 0x7ff00000)
return (x * x) + I * (y - y) / (y - y);
return (x * x) * (cos(y) + I * con * sin(y));
}
/*
* cosh(NaN + I 0) = NaN +- I 0, sign of 0 unspecified.
* cosh(NaN + I y) = NaN + I NaN, nonzero y, opt. inval. except.
* cosh(NaN + I NaN) = NaN + I NaN.
*/
if (ix >= 0x7ff00000 && ((hx&0xfffff)|lx) != 0) {
if ((iy|ly) == 0)
return x * x;
return x * x + I * x * x;
}
}
More information about the freebsd-standards
mailing list