mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Add complex square root (#394)
This commit is contained in:
parent
cc0d1ec076
commit
92ebef16ee
3 changed files with 288 additions and 0 deletions
133
libc/tinymath/complex.h
Normal file
133
libc/tinymath/complex.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
#ifndef _COMPLEX_H
|
||||
#define _COMPLEX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define complex _Complex
|
||||
#ifdef __GNUC__
|
||||
#define _Complex_I (__extension__ (0.0f+1.0fi))
|
||||
#else
|
||||
#define _Complex_I (0.0f+1.0fi)
|
||||
#endif
|
||||
#define I _Complex_I
|
||||
|
||||
double complex cacos(double complex);
|
||||
float complex cacosf(float complex);
|
||||
long double complex cacosl(long double complex);
|
||||
|
||||
double complex casin(double complex);
|
||||
float complex casinf(float complex);
|
||||
long double complex casinl(long double complex);
|
||||
|
||||
double complex catan(double complex);
|
||||
float complex catanf(float complex);
|
||||
long double complex catanl(long double complex);
|
||||
|
||||
double complex ccos(double complex);
|
||||
float complex ccosf(float complex);
|
||||
long double complex ccosl(long double complex);
|
||||
|
||||
double complex csin(double complex);
|
||||
float complex csinf(float complex);
|
||||
long double complex csinl(long double complex);
|
||||
|
||||
double complex ctan(double complex);
|
||||
float complex ctanf(float complex);
|
||||
long double complex ctanl(long double complex);
|
||||
|
||||
double complex cacosh(double complex);
|
||||
float complex cacoshf(float complex);
|
||||
long double complex cacoshl(long double complex);
|
||||
|
||||
double complex casinh(double complex);
|
||||
float complex casinhf(float complex);
|
||||
long double complex casinhl(long double complex);
|
||||
|
||||
double complex catanh(double complex);
|
||||
float complex catanhf(float complex);
|
||||
long double complex catanhl(long double complex);
|
||||
|
||||
double complex ccosh(double complex);
|
||||
float complex ccoshf(float complex);
|
||||
long double complex ccoshl(long double complex);
|
||||
|
||||
double complex csinh(double complex);
|
||||
float complex csinhf(float complex);
|
||||
long double complex csinhl(long double complex);
|
||||
|
||||
double complex ctanh(double complex);
|
||||
float complex ctanhf(float complex);
|
||||
long double complex ctanhl(long double complex);
|
||||
|
||||
double complex cexp(double complex);
|
||||
float complex cexpf(float complex);
|
||||
long double complex cexpl(long double complex);
|
||||
|
||||
double complex clog(double complex);
|
||||
float complex clogf(float complex);
|
||||
long double complex clogl(long double complex);
|
||||
|
||||
double cabs(double complex);
|
||||
float cabsf(float complex);
|
||||
long double cabsl(long double complex);
|
||||
|
||||
double complex cpow(double complex, double complex);
|
||||
float complex cpowf(float complex, float complex);
|
||||
long double complex cpowl(long double complex, long double complex);
|
||||
|
||||
double complex csqrt(double complex);
|
||||
float complex csqrtf(float complex);
|
||||
long double complex csqrtl(long double complex);
|
||||
|
||||
double carg(double complex);
|
||||
float cargf(float complex);
|
||||
long double cargl(long double complex);
|
||||
|
||||
double cimag(double complex);
|
||||
float cimagf(float complex);
|
||||
long double cimagl(long double complex);
|
||||
|
||||
double complex conj(double complex);
|
||||
float complex conjf(float complex);
|
||||
long double complex conjl(long double complex);
|
||||
|
||||
double complex cproj(double complex);
|
||||
float complex cprojf(float complex);
|
||||
long double complex cprojl(long double complex);
|
||||
|
||||
double creal(double complex);
|
||||
float crealf(float complex);
|
||||
long double creall(long double complex);
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define __CIMAG(x, t) \
|
||||
(+(union { _Complex t __z; t __xy[2]; }){(_Complex t)(x)}.__xy[1])
|
||||
|
||||
#define creal(x) ((double)(x))
|
||||
#define crealf(x) ((float)(x))
|
||||
#define creall(x) ((long double)(x))
|
||||
|
||||
#define cimag(x) __CIMAG(x, double)
|
||||
#define cimagf(x) __CIMAG(x, float)
|
||||
#define cimagl(x) __CIMAG(x, long double)
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#if defined(_Imaginary_I)
|
||||
#define __CMPLX(x, y, t) ((t)(x) + _Imaginary_I*(t)(y))
|
||||
#elif defined(__clang__)
|
||||
#define __CMPLX(x, y, t) (+(_Complex t){ (t)(x), (t)(y) })
|
||||
#else
|
||||
#define __CMPLX(x, y, t) (__builtin_complex((t)(x), (t)(y)))
|
||||
#endif
|
||||
#define CMPLX(x, y) __CMPLX(x, y, double)
|
||||
#define CMPLXF(x, y) __CMPLX(x, y, float)
|
||||
#define CMPLXL(x, y) __CMPLX(x, y, long double)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
22
libc/tinymath/complex_impl.internal.h
Normal file
22
libc/tinymath/complex_impl.internal.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef _COMPLEX_IMPL_H
|
||||
#define _COMPLEX_IMPL_H
|
||||
|
||||
#include <libc/tinymath/complex.h>
|
||||
#include "libc/math.h"
|
||||
|
||||
#undef __CMPLX
|
||||
#undef CMPLX
|
||||
#undef CMPLXF
|
||||
#undef CMPLXL
|
||||
|
||||
#define __CMPLX(x, y, t) \
|
||||
((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z)
|
||||
|
||||
#define CMPLX(x, y) __CMPLX(x, y, double)
|
||||
#define CMPLXF(x, y) __CMPLX(x, y, float)
|
||||
#define CMPLXL(x, y) __CMPLX(x, y, long double)
|
||||
|
||||
hidden double complex __ldexp_cexp(double complex,int);
|
||||
hidden float complex __ldexp_cexpf(float complex,int);
|
||||
|
||||
#endif
|
133
libc/tinymath/csqrt.c
Normal file
133
libc/tinymath/csqrt.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ │
|
||||
│ Musl Libc │
|
||||
│ Copyright © 2005-2014 Rich Felker, et al. │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files (the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
||||
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
||||
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
||||
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||||
│ │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/tinymath/complex_impl.internal.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Musl libc (MIT License)\\n\
|
||||
Copyright 2005-2014 Rich Felker, et. al.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
/* clang-format off */
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrt.c */
|
||||
/*-
|
||||
* Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
|
||||
* 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* gcc doesn't implement complex multiplication or division correctly,
|
||||
* so we need to handle infinities specially. We turn on this pragma to
|
||||
* notify conforming c99 compilers that the fast-but-incorrect code that
|
||||
* gcc generates is acceptable, since the special cases have already been
|
||||
* handled.
|
||||
*/
|
||||
#pragma STDC CX_LIMITED_RANGE ON
|
||||
|
||||
/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */
|
||||
#define THRESH 0x1.a827999fcef32p+1022
|
||||
|
||||
double complex csqrt(double complex z)
|
||||
{
|
||||
double complex result;
|
||||
double a, b;
|
||||
double t;
|
||||
int scale;
|
||||
|
||||
a = creal(z);
|
||||
b = cimag(z);
|
||||
|
||||
/* Handle special cases. */
|
||||
if (z == 0)
|
||||
return CMPLX(0, b);
|
||||
if (isinf(b))
|
||||
return CMPLX(INFINITY, b);
|
||||
if (isnan(a)) {
|
||||
t = (b - b) / (b - b); /* raise invalid if b is not a NaN */
|
||||
return CMPLX(a, t); /* return NaN + NaN i */
|
||||
}
|
||||
if (isinf(a)) {
|
||||
/*
|
||||
* csqrt(inf + NaN i) = inf + NaN i
|
||||
* csqrt(inf + y i) = inf + 0 i
|
||||
* csqrt(-inf + NaN i) = NaN +- inf i
|
||||
* csqrt(-inf + y i) = 0 + inf i
|
||||
*/
|
||||
if (signbit(a))
|
||||
return CMPLX(fabs(b - b), copysign(a, b));
|
||||
else
|
||||
return CMPLX(a, copysign(b - b, b));
|
||||
}
|
||||
/*
|
||||
* The remaining special case (b is NaN) is handled just fine by
|
||||
* the normal code path below.
|
||||
*/
|
||||
|
||||
/* Scale to avoid overflow. */
|
||||
if (fabs(a) >= THRESH || fabs(b) >= THRESH) {
|
||||
a *= 0.25;
|
||||
b *= 0.25;
|
||||
scale = 1;
|
||||
} else {
|
||||
scale = 0;
|
||||
}
|
||||
|
||||
/* Algorithm 312, CACM vol 10, Oct 1967. */
|
||||
if (a >= 0) {
|
||||
t = sqrt((a + hypot(a, b)) * 0.5);
|
||||
result = CMPLX(t, b / (2 * t));
|
||||
} else {
|
||||
t = sqrt((-a + hypot(a, b)) * 0.5);
|
||||
result = CMPLX(fabs(b) / (2 * t), copysign(t, b));
|
||||
}
|
||||
|
||||
/* Rescale. */
|
||||
if (scale)
|
||||
result *= 2;
|
||||
return result;
|
||||
}
|
Loading…
Add table
Reference in a new issue