Import openlibm_0.6.0+dfsg.orig.tar.gz
authorMo Zhou <cdluminate@gmail.com>
Thu, 21 Jun 2018 09:01:29 +0000 (10:01 +0100)
committerMo Zhou <cdluminate@gmail.com>
Thu, 21 Jun 2018 09:01:29 +0000 (10:01 +0100)
[dgit import orig openlibm_0.6.0+dfsg.orig.tar.gz]

439 files changed:
.gitignore [new file with mode: 0644]
.mailmap [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
LICENSE.md [new file with mode: 0644]
Make.inc [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
aarch64/Make.files [new file with mode: 0644]
aarch64/fenv.c [new file with mode: 0644]
amd64/Make.files [new file with mode: 0644]
amd64/bsd_asm.h [new file with mode: 0644]
amd64/bsd_fpu.h [new file with mode: 0644]
amd64/bsd_ieeefp.h [new file with mode: 0644]
amd64/e_remainder.S [new file with mode: 0644]
amd64/e_remainderf.S [new file with mode: 0644]
amd64/e_remainderl.S [new file with mode: 0644]
amd64/e_sqrt.S [new file with mode: 0644]
amd64/e_sqrtf.S [new file with mode: 0644]
amd64/e_sqrtl.S [new file with mode: 0644]
amd64/fenv.c [new file with mode: 0644]
amd64/s_llrint.S [new file with mode: 0644]
amd64/s_llrintf.S [new file with mode: 0644]
amd64/s_llrintl.S [new file with mode: 0644]
amd64/s_logbl.S [new file with mode: 0644]
amd64/s_lrint.S [new file with mode: 0644]
amd64/s_lrintf.S [new file with mode: 0644]
amd64/s_lrintl.S [new file with mode: 0644]
amd64/s_remquo.S [new file with mode: 0644]
amd64/s_remquof.S [new file with mode: 0644]
amd64/s_remquol.S [new file with mode: 0644]
amd64/s_rintl.S [new file with mode: 0644]
amd64/s_scalbn.S [new file with mode: 0644]
amd64/s_scalbnf.S [new file with mode: 0644]
amd64/s_scalbnl.S [new file with mode: 0644]
appveyor.yml [new file with mode: 0644]
arm/Make.files [new file with mode: 0644]
arm/fenv.c [new file with mode: 0644]
bsdsrc/Make.files [new file with mode: 0644]
bsdsrc/b_exp.c [new file with mode: 0644]
bsdsrc/b_log.c [new file with mode: 0644]
bsdsrc/b_tgamma.c [new file with mode: 0644]
bsdsrc/mathimpl.h [new file with mode: 0644]
i387/Make.files [new file with mode: 0644]
i387/bsd_asm.h [new file with mode: 0644]
i387/bsd_ieeefp.h [new file with mode: 0644]
i387/bsd_npx.h [new file with mode: 0644]
i387/e_exp.S [new file with mode: 0644]
i387/e_fmod.S [new file with mode: 0644]
i387/e_log.S [new file with mode: 0644]
i387/e_log10.S [new file with mode: 0644]
i387/e_log10f.S [new file with mode: 0644]
i387/e_logf.S [new file with mode: 0644]
i387/e_remainder.S [new file with mode: 0644]
i387/e_remainderf.S [new file with mode: 0644]
i387/e_remainderl.S [new file with mode: 0644]
i387/e_sqrt.S [new file with mode: 0644]
i387/e_sqrtf.S [new file with mode: 0644]
i387/e_sqrtl.S [new file with mode: 0644]
i387/fenv.c [new file with mode: 0644]
i387/invtrig.c [new file with mode: 0644]
i387/s_ceil.S [new file with mode: 0644]
i387/s_ceilf.S [new file with mode: 0644]
i387/s_ceill.S [new file with mode: 0644]
i387/s_copysign.S [new file with mode: 0644]
i387/s_copysignf.S [new file with mode: 0644]
i387/s_copysignl.S [new file with mode: 0644]
i387/s_cos.S [new file with mode: 0644]
i387/s_floor.S [new file with mode: 0644]
i387/s_floorf.S [new file with mode: 0644]
i387/s_floorl.S [new file with mode: 0644]
i387/s_llrint.S [new file with mode: 0644]
i387/s_llrintf.S [new file with mode: 0644]
i387/s_llrintl.S [new file with mode: 0644]
i387/s_logb.S [new file with mode: 0644]
i387/s_logbf.S [new file with mode: 0644]
i387/s_logbl.S [new file with mode: 0644]
i387/s_lrint.S [new file with mode: 0644]
i387/s_lrintf.S [new file with mode: 0644]
i387/s_lrintl.S [new file with mode: 0644]
i387/s_remquo.S [new file with mode: 0644]
i387/s_remquof.S [new file with mode: 0644]
i387/s_remquol.S [new file with mode: 0644]
i387/s_rint.S [new file with mode: 0644]
i387/s_rintf.S [new file with mode: 0644]
i387/s_rintl.S [new file with mode: 0644]
i387/s_scalbn.S [new file with mode: 0644]
i387/s_scalbnf.S [new file with mode: 0644]
i387/s_scalbnl.S [new file with mode: 0644]
i387/s_sin.S [new file with mode: 0644]
i387/s_tan.S [new file with mode: 0644]
i387/s_trunc.S [new file with mode: 0644]
i387/s_truncf.S [new file with mode: 0644]
i387/s_truncl.S [new file with mode: 0644]
include/openlibm.h [new file with mode: 0644]
include/openlibm_complex.h [new file with mode: 0644]
include/openlibm_fenv.h [new file with mode: 0644]
include/openlibm_fenv_amd64.h [new file with mode: 0644]
include/openlibm_fenv_arm.h [new file with mode: 0644]
include/openlibm_fenv_i387.h [new file with mode: 0644]
include/openlibm_fenv_mips.h [new file with mode: 0644]
include/openlibm_fenv_powerpc.h [new file with mode: 0644]
include/openlibm_math.h [new file with mode: 0644]
ld128/Make.files [new file with mode: 0644]
ld128/e_acoshl.c [new file with mode: 0644]
ld128/e_atanhl.c [new file with mode: 0644]
ld128/e_coshl.c [new file with mode: 0644]
ld128/e_expl.c [new file with mode: 0644]
ld128/e_fmodl.c [new file with mode: 0644]
ld128/e_hypotl.c [new file with mode: 0644]
ld128/e_lgammal_r.c [new file with mode: 0644]
ld128/e_log10l.c [new file with mode: 0644]
ld128/e_log2l.c [new file with mode: 0644]
ld128/e_logl.c [new file with mode: 0644]
ld128/e_powl.c [new file with mode: 0644]
ld128/e_rem_pio2l.h [new file with mode: 0644]
ld128/e_sinhl.c [new file with mode: 0644]
ld128/e_tgammal.c [new file with mode: 0644]
ld128/invtrig.c [new file with mode: 0644]
ld128/invtrig.h [new file with mode: 0644]
ld128/k_cosl.c [new file with mode: 0644]
ld128/k_sinl.c [new file with mode: 0644]
ld128/k_tanl.c [new file with mode: 0644]
ld128/s_asinhl.c [new file with mode: 0644]
ld128/s_ceill.c [new file with mode: 0644]
ld128/s_erfl.c [new file with mode: 0644]
ld128/s_exp2l.c [new file with mode: 0644]
ld128/s_expm1l.c [new file with mode: 0644]
ld128/s_floorl.c [new file with mode: 0644]
ld128/s_log1pl.c [new file with mode: 0644]
ld128/s_modfl.c [new file with mode: 0644]
ld128/s_nanl.c [new file with mode: 0644]
ld128/s_nextafterl.c [new file with mode: 0644]
ld128/s_nexttoward.c [new file with mode: 0644]
ld128/s_nexttowardf.c [new file with mode: 0644]
ld128/s_remquol.c [new file with mode: 0644]
ld128/s_tanhl.c [new file with mode: 0644]
ld128/s_truncl.c [new file with mode: 0644]
ld80/Make.files [new file with mode: 0644]
ld80/e_acoshl.c [new file with mode: 0644]
ld80/e_atanhl.c [new file with mode: 0644]
ld80/e_coshl.c [new file with mode: 0644]
ld80/e_expl.c [new file with mode: 0644]
ld80/e_fmodl.c [new file with mode: 0644]
ld80/e_hypotl.c [new file with mode: 0644]
ld80/e_lgammal_r.c [new file with mode: 0644]
ld80/e_log10l.c [new file with mode: 0644]
ld80/e_log2l.c [new file with mode: 0644]
ld80/e_logl.c [new file with mode: 0644]
ld80/e_powl.c [new file with mode: 0644]
ld80/e_rem_pio2l.h [new file with mode: 0644]
ld80/e_sinhl.c [new file with mode: 0644]
ld80/e_tgammal.c [new file with mode: 0644]
ld80/invtrig.c [new file with mode: 0644]
ld80/invtrig.h [new file with mode: 0644]
ld80/k_cosl.c [new file with mode: 0644]
ld80/k_sinl.c [new file with mode: 0644]
ld80/k_tanl.c [new file with mode: 0644]
ld80/s_asinhl.c [new file with mode: 0644]
ld80/s_ceill.c [new file with mode: 0644]
ld80/s_erfl.c [new file with mode: 0644]
ld80/s_exp2l.c [new file with mode: 0644]
ld80/s_expm1l.c [new file with mode: 0644]
ld80/s_floorl.c [new file with mode: 0644]
ld80/s_log1pl.c [new file with mode: 0644]
ld80/s_modfl.c [new file with mode: 0644]
ld80/s_nanl.c [new file with mode: 0644]
ld80/s_nextafterl.c [new file with mode: 0644]
ld80/s_nexttoward.c [new file with mode: 0644]
ld80/s_nexttowardf.c [new file with mode: 0644]
ld80/s_remquol.c [new file with mode: 0644]
ld80/s_tanhl.c [new file with mode: 0644]
ld80/s_truncl.c [new file with mode: 0644]
mips/Make.files [new file with mode: 0644]
mips/fenv-softfloat.h [new file with mode: 0644]
mips/fenv.c [new file with mode: 0644]
openlibm.pc.in [new file with mode: 0644]
powerpc/Make.files [new file with mode: 0644]
powerpc/fenv.c [new file with mode: 0644]
src/Make.files [new file with mode: 0644]
src/aarch64_fpmath.h [new file with mode: 0644]
src/amd64_fpmath.h [new file with mode: 0644]
src/bsd_cdefs.h [new file with mode: 0644]
src/cdefs-compat.h [new file with mode: 0644]
src/common.c [new file with mode: 0644]
src/e_acos.c [new file with mode: 0644]
src/e_acosf.c [new file with mode: 0644]
src/e_acosh.c [new file with mode: 0644]
src/e_acoshf.c [new file with mode: 0644]
src/e_acosl.c [new file with mode: 0644]
src/e_asin.c [new file with mode: 0644]
src/e_asinf.c [new file with mode: 0644]
src/e_asinl.c [new file with mode: 0644]
src/e_atan2.c [new file with mode: 0644]
src/e_atan2f.c [new file with mode: 0644]
src/e_atan2l.c [new file with mode: 0644]
src/e_atanh.c [new file with mode: 0644]
src/e_atanhf.c [new file with mode: 0644]
src/e_cosh.c [new file with mode: 0644]
src/e_coshf.c [new file with mode: 0644]
src/e_exp.c [new file with mode: 0644]
src/e_expf.c [new file with mode: 0644]
src/e_fmod.c [new file with mode: 0644]
src/e_fmodf.c [new file with mode: 0644]
src/e_fmodl.c [new file with mode: 0644]
src/e_hypot.c [new file with mode: 0644]
src/e_hypotf.c [new file with mode: 0644]
src/e_hypotl.c [new file with mode: 0644]
src/e_j0.c [new file with mode: 0644]
src/e_j0f.c [new file with mode: 0644]
src/e_j1.c [new file with mode: 0644]
src/e_j1f.c [new file with mode: 0644]
src/e_jn.c [new file with mode: 0644]
src/e_jnf.c [new file with mode: 0644]
src/e_lgamma.c [new file with mode: 0644]
src/e_lgamma_r.c [new file with mode: 0644]
src/e_lgammaf.c [new file with mode: 0644]
src/e_lgammaf_r.c [new file with mode: 0644]
src/e_lgammal.c [new file with mode: 0644]
src/e_log.c [new file with mode: 0644]
src/e_log10.c [new file with mode: 0644]
src/e_log10f.c [new file with mode: 0644]
src/e_log2.c [new file with mode: 0644]
src/e_log2f.c [new file with mode: 0644]
src/e_logf.c [new file with mode: 0644]
src/e_pow.c [new file with mode: 0644]
src/e_powf.c [new file with mode: 0644]
src/e_rem_pio2.c [new file with mode: 0644]
src/e_rem_pio2f.c [new file with mode: 0644]
src/e_remainder.c [new file with mode: 0644]
src/e_remainderf.c [new file with mode: 0644]
src/e_remainderl.c [new file with mode: 0644]
src/e_sinh.c [new file with mode: 0644]
src/e_sinhf.c [new file with mode: 0644]
src/e_sqrt.c [new file with mode: 0644]
src/e_sqrtf.c [new file with mode: 0644]
src/e_sqrtl.c [new file with mode: 0644]
src/fpmath.h [new file with mode: 0644]
src/i386_fpmath.h [new file with mode: 0644]
src/k_cos.c [new file with mode: 0644]
src/k_cosf.c [new file with mode: 0644]
src/k_exp.c [new file with mode: 0644]
src/k_expf.c [new file with mode: 0644]
src/k_log.h [new file with mode: 0644]
src/k_logf.h [new file with mode: 0644]
src/k_rem_pio2.c [new file with mode: 0644]
src/k_sin.c [new file with mode: 0644]
src/k_sinf.c [new file with mode: 0644]
src/k_tan.c [new file with mode: 0644]
src/k_tanf.c [new file with mode: 0644]
src/math_private.h [new file with mode: 0644]
src/math_private_openbsd.h [new file with mode: 0644]
src/mips_fpmath.h [new file with mode: 0644]
src/polevll.c [new file with mode: 0644]
src/powerpc_fpmath.h [new file with mode: 0644]
src/s_asinh.c [new file with mode: 0644]
src/s_asinhf.c [new file with mode: 0644]
src/s_atan.c [new file with mode: 0644]
src/s_atanf.c [new file with mode: 0644]
src/s_atanl.c [new file with mode: 0644]
src/s_cabs.c [new file with mode: 0644]
src/s_cabsf.c [new file with mode: 0644]
src/s_cabsl.c [new file with mode: 0644]
src/s_cacos.c [new file with mode: 0644]
src/s_cacosf.c [new file with mode: 0644]
src/s_cacosh.c [new file with mode: 0644]
src/s_cacoshf.c [new file with mode: 0644]
src/s_cacoshl.c [new file with mode: 0644]
src/s_cacosl.c [new file with mode: 0644]
src/s_carg.c [new file with mode: 0644]
src/s_cargf.c [new file with mode: 0644]
src/s_cargl.c [new file with mode: 0644]
src/s_casin.c [new file with mode: 0644]
src/s_casinf.c [new file with mode: 0644]
src/s_casinh.c [new file with mode: 0644]
src/s_casinhf.c [new file with mode: 0644]
src/s_casinhl.c [new file with mode: 0644]
src/s_casinl.c [new file with mode: 0644]
src/s_catan.c [new file with mode: 0644]
src/s_catanf.c [new file with mode: 0644]
src/s_catanh.c [new file with mode: 0644]
src/s_catanhf.c [new file with mode: 0644]
src/s_catanhl.c [new file with mode: 0644]
src/s_catanl.c [new file with mode: 0644]
src/s_cbrt.c [new file with mode: 0644]
src/s_cbrtf.c [new file with mode: 0644]
src/s_cbrtl.c [new file with mode: 0644]
src/s_ccos.c [new file with mode: 0644]
src/s_ccosf.c [new file with mode: 0644]
src/s_ccosh.c [new file with mode: 0644]
src/s_ccoshf.c [new file with mode: 0644]
src/s_ccoshl.c [new file with mode: 0644]
src/s_ccosl.c [new file with mode: 0644]
src/s_ceil.c [new file with mode: 0644]
src/s_ceilf.c [new file with mode: 0644]
src/s_ceill.c [new file with mode: 0644]
src/s_cexp.c [new file with mode: 0644]
src/s_cexpf.c [new file with mode: 0644]
src/s_cexpl.c [new file with mode: 0644]
src/s_cimag.c [new file with mode: 0644]
src/s_cimagf.c [new file with mode: 0644]
src/s_cimagl.c [new file with mode: 0644]
src/s_clog.c [new file with mode: 0644]
src/s_clogf.c [new file with mode: 0644]
src/s_clogl.c [new file with mode: 0644]
src/s_conj.c [new file with mode: 0644]
src/s_conjf.c [new file with mode: 0644]
src/s_conjl.c [new file with mode: 0644]
src/s_copysign.c [new file with mode: 0644]
src/s_copysignf.c [new file with mode: 0644]
src/s_copysignl.c [new file with mode: 0644]
src/s_cos.c [new file with mode: 0644]
src/s_cosf.c [new file with mode: 0644]
src/s_cosl.c [new file with mode: 0644]
src/s_cpow.c [new file with mode: 0644]
src/s_cpowf.c [new file with mode: 0644]
src/s_cpowl.c [new file with mode: 0644]
src/s_cproj.c [new file with mode: 0644]
src/s_cprojf.c [new file with mode: 0644]
src/s_cprojl.c [new file with mode: 0644]
src/s_creal.c [new file with mode: 0644]
src/s_crealf.c [new file with mode: 0644]
src/s_creall.c [new file with mode: 0644]
src/s_csin.c [new file with mode: 0644]
src/s_csinf.c [new file with mode: 0644]
src/s_csinh.c [new file with mode: 0644]
src/s_csinhf.c [new file with mode: 0644]
src/s_csinhl.c [new file with mode: 0644]
src/s_csinl.c [new file with mode: 0644]
src/s_csqrt.c [new file with mode: 0644]
src/s_csqrtf.c [new file with mode: 0644]
src/s_csqrtl.c [new file with mode: 0644]
src/s_ctan.c [new file with mode: 0644]
src/s_ctanf.c [new file with mode: 0644]
src/s_ctanh.c [new file with mode: 0644]
src/s_ctanhf.c [new file with mode: 0644]
src/s_ctanhl.c [new file with mode: 0644]
src/s_ctanl.c [new file with mode: 0644]
src/s_erf.c [new file with mode: 0644]
src/s_erff.c [new file with mode: 0644]
src/s_exp2.c [new file with mode: 0644]
src/s_exp2f.c [new file with mode: 0644]
src/s_expm1.c [new file with mode: 0644]
src/s_expm1f.c [new file with mode: 0644]
src/s_fabs.c [new file with mode: 0644]
src/s_fabsf.c [new file with mode: 0644]
src/s_fabsl.c [new file with mode: 0644]
src/s_fdim.c [new file with mode: 0644]
src/s_floor.c [new file with mode: 0644]
src/s_floorf.c [new file with mode: 0644]
src/s_floorl.c [new file with mode: 0644]
src/s_fma.c [new file with mode: 0644]
src/s_fmaf.c [new file with mode: 0644]
src/s_fmal.c [new file with mode: 0644]
src/s_fmax.c [new file with mode: 0644]
src/s_fmaxf.c [new file with mode: 0644]
src/s_fmaxl.c [new file with mode: 0644]
src/s_fmin.c [new file with mode: 0644]
src/s_fminf.c [new file with mode: 0644]
src/s_fminl.c [new file with mode: 0644]
src/s_fpclassify.c [new file with mode: 0644]
src/s_frexp.c [new file with mode: 0644]
src/s_frexpf.c [new file with mode: 0644]
src/s_frexpl.c [new file with mode: 0644]
src/s_ilogb.c [new file with mode: 0644]
src/s_ilogbf.c [new file with mode: 0644]
src/s_ilogbl.c [new file with mode: 0644]
src/s_isfinite.c [new file with mode: 0644]
src/s_isinf.c [new file with mode: 0644]
src/s_isnan.c [new file with mode: 0644]
src/s_isnormal.c [new file with mode: 0644]
src/s_llrint.c [new file with mode: 0644]
src/s_llrintf.c [new file with mode: 0644]
src/s_llrintl.c [new file with mode: 0644]
src/s_llround.c [new file with mode: 0644]
src/s_llroundf.c [new file with mode: 0644]
src/s_llroundl.c [new file with mode: 0644]
src/s_log1p.c [new file with mode: 0644]
src/s_log1pf.c [new file with mode: 0644]
src/s_logb.c [new file with mode: 0644]
src/s_logbf.c [new file with mode: 0644]
src/s_logbl.c [new file with mode: 0644]
src/s_lrint.c [new file with mode: 0644]
src/s_lrintf.c [new file with mode: 0644]
src/s_lrintl.c [new file with mode: 0644]
src/s_lround.c [new file with mode: 0644]
src/s_lroundf.c [new file with mode: 0644]
src/s_lroundl.c [new file with mode: 0644]
src/s_modf.c [new file with mode: 0644]
src/s_modff.c [new file with mode: 0644]
src/s_modfl.c [new file with mode: 0644]
src/s_nan.c [new file with mode: 0644]
src/s_nearbyint.c [new file with mode: 0644]
src/s_nextafter.c [new file with mode: 0644]
src/s_nextafterf.c [new file with mode: 0644]
src/s_nextafterl.c [new file with mode: 0644]
src/s_nexttoward.c [new file with mode: 0644]
src/s_nexttowardf.c [new file with mode: 0644]
src/s_remquo.c [new file with mode: 0644]
src/s_remquof.c [new file with mode: 0644]
src/s_remquol.c [new file with mode: 0644]
src/s_rint.c [new file with mode: 0644]
src/s_rintf.c [new file with mode: 0644]
src/s_rintl.c [new file with mode: 0644]
src/s_round.c [new file with mode: 0644]
src/s_roundf.c [new file with mode: 0644]
src/s_roundl.c [new file with mode: 0644]
src/s_scalbln.c [new file with mode: 0644]
src/s_scalbn.c [new file with mode: 0644]
src/s_scalbnf.c [new file with mode: 0644]
src/s_scalbnl.c [new file with mode: 0644]
src/s_signbit.c [new file with mode: 0644]
src/s_signgam.c [new file with mode: 0644]
src/s_sin.c [new file with mode: 0644]
src/s_sincos.c [new file with mode: 0644]
src/s_sincosf.c [new file with mode: 0644]
src/s_sincosl.c [new file with mode: 0644]
src/s_sinf.c [new file with mode: 0644]
src/s_sinl.c [new file with mode: 0644]
src/s_tan.c [new file with mode: 0644]
src/s_tanf.c [new file with mode: 0644]
src/s_tanh.c [new file with mode: 0644]
src/s_tanhf.c [new file with mode: 0644]
src/s_tanl.c [new file with mode: 0644]
src/s_tgammaf.c [new file with mode: 0644]
src/s_trunc.c [new file with mode: 0644]
src/s_truncf.c [new file with mode: 0644]
src/s_truncl.c [new file with mode: 0644]
src/types-compat.h [new file with mode: 0644]
src/w_cabs.c [new file with mode: 0644]
src/w_cabsf.c [new file with mode: 0644]
src/w_cabsl.c [new file with mode: 0644]
test/.gitignore [new file with mode: 0644]
test/Makefile [new file with mode: 0644]
test/inf_torture.c [new file with mode: 0644]
test/libm-bench.cpp [new file with mode: 0644]
test/libm-test-ulps.h [new file with mode: 0644]
test/libm-test.c [new file with mode: 0644]
test/test-double.c [new file with mode: 0644]
test/test-float.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e7e0c44
--- /dev/null
@@ -0,0 +1,7 @@
+*.o
+*~
+*.a
+*.dll*
+*.so*
+*.dylib*
+*.pc
diff --git a/.mailmap b/.mailmap
new file mode 100644 (file)
index 0000000..637106f
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,61 @@
+JuliaLang <julia-dev@googlegroups.com> <julia-dev@googlegroups.com>
+JuliaLang <julia-dev@googlegroups.com> <julia-math@googlegroups.com>
+
+Jeff Bezanson <jeff.bezanson@gmail.com> <jeff.bezanson@gmail.com>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@beagle.darwinproject.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@caspian.caspian.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@evolution.local>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation045.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation049.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@mathstation186.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@post.harvard.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@scooby-doo.csail.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <bezanson@shaggy.csail.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <jeff@lagann.(none)>
+Jeff Bezanson <jeff.bezanson@gmail.com> <julia@beowulf1.csail.mit.edu>
+Jeff Bezanson <jeff.bezanson@gmail.com> <vcloud@julia02.domain.local>
+
+Stefan Karpinski <stefan@karpinski.org> <stefan@karpinski.org>
+Stefan Karpinski <stefan@karpinski.org> <stefan.karpinski@gmail.com>
+Stefan Karpinski <stefan@karpinski.org> <stefan.karpinski@post.harvard.edu>
+
+Viral B. Shah <viral@mayin.org> <viral@mayin.org>
+Viral B. Shah <viral@mayin.org> <viral@beowulf1.csail.mit.edu>
+Viral B. Shah <viral@mayin.org> <viral@neumann.cs.ucsb.edu>
+Viral B. Shah <viral@mayin.org> <viral@ubuntu-VirtualBox.(none)>
+
+George Xing <gxing@mit.edu> <gxing@mit.edu>
+George Xing <gxing@mit.edu> <noobiecubie@gmail.com>
+
+Stephan Boyer <boyers@mit.edu> <boyers@mit.edu>
+Stephan Boyer <boyers@mit.edu> <stephan@julialang.xvm.mit.edu>
+Stephan Boyer <boyers@mit.edu> <stephan@ubuntu.(none)>
+Stephan Boyer <boyers@mit.edu> <stephan@ubuntu.ubuntu-domain>
+
+Giuseppe Zingales <giuseppe.pet.zingales@gmail.com> <giuseppe.pet.zingales@gmail.com>
+Giuseppe Zingales <giuseppe.pet.zingales@gmail.com> <g3@ubuntu.ubuntu-domain>
+
+Jameson Nash <jameson@mit.edu> <jameson@mit.edu>
+Jameson Nash <jameson@mit.edu> <vtjnash@comcast.net>
+Jameson Nash <jameson@mit.edu> <vtjnash@gmail.com>
+
+Alan Edelman <mit.edelman@gmail.com> <mit.edelman@gmail.com>
+
+PlayMyCode <joe@playmycode.com> <joe@playmycode.com>
+PlayMyCode <joe@playmycode.com> <hello@playmycode.com>
+
+Corey M. Hoffstein <corey@hoffstein.com> <corey@hoffstein.com>
+Corey M. Hoffstein <corey@hoffstein.com> <corey@newfoundresearch.com>
+
+Stefan Kroboth <stefan.kroboth@gmail.com> <stefan.kroboth@gmail.com>
+
+Tim Holy <tim.holy@gmail.com> <tim.holy@gmail.com>
+Tim Holy <tim.holy@gmail.com> <holy@wustl.edu>
+
+Patrick O'Leary <patrick.oleary@gmail.com> <patrick.oleary@gmail.com>
+
+Ivan Mantova <horphus@gmail.com> <horphus@gmail.com>
+
+Keno Fischer <kfischer@college.harvard.edu> <kfischer@college.harvard.edu>
+Keno Fischer <kfischer@college.harvard.edu> <kfischer+github@college.harvard.edu>
+Keno Fischer <kfischer@college.harvard.edu> <kenof@stanford.edu>
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..3a900c0
--- /dev/null
@@ -0,0 +1,106 @@
+# We require a full (virtual) machine to load the kernel module for
+# binfmt support, which is needed to test other architectures besides
+# x86 using qemu user emulation. (This will not work in a container.)
+sudo: required
+dist: trusty
+language: c
+
+script:
+    - make $FLAGS
+    - make check $FLAGS $TEST_FLAGS
+    - make clean && git status --ignored --porcelain && test -z "$(git status --ignored --porcelain)"
+
+matrix:
+    include:
+        - compiler: clang
+          os: linux
+          addons:
+              apt:
+                  sources:
+                      - ubuntu-toolchain-r-test
+                      - llvm-toolchain-precise-3.7
+                  packages:
+                      - clang-3.7
+          env: FLAGS="CC=clang-3.7 CXX=clang++-3.7"
+
+        - os: osx
+          env: FLAGS="CC=clang"
+
+        - os: linux
+          env: FLAGS="CC=gcc"
+
+        - os: linux
+          env: FLAGS="CC=gcc ARCH=i686"  # implies -m32 -march=i686
+          addons:
+              apt:
+                  packages:
+                      - gcc-multilib
+
+        - os: linux
+          env: FLAGS="CC=aarch64-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  packages:
+                      - gcc-aarch64-linux-gnu
+                      - libc6-dev-arm64-cross
+                      - qemu-user-static
+                      - binfmt-support
+
+        - os: linux
+          env: FLAGS="CC=arm-linux-gnueabihf-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  packages:
+                      - gcc-arm-linux-gnueabihf
+                      - libc6-dev-armhf-cross
+                      - qemu-user-static
+                      - binfmt-support
+
+        # This works, but only if qemu-user-static is >= v2.4.  This is not the
+        # case on the default trusty images, so we add a PPA that has qemu 2.5
+        - os: linux
+          env: FLAGS="CC=powerpc64le-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  sources:
+                      - sourceline: "ppa:gns3/qemu"
+                  packages:
+                      - gcc-powerpc64le-linux-gnu
+                      - libc6-dev-ppc64el-cross
+                      - qemu-user-static
+                      - binfmt-support
+
+        - os: linux
+          env: FLAGS="CC=mips-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  sources:
+                      - sourceline: "deb http://archive.ubuntu.com/ubuntu/ xenial main universe"
+                  packages:
+                      - gcc-mips-linux-gnu
+                      - libc6-dev-mips-cross
+                      - qemu-user-binfmt
+
+        - os: linux
+          env: FLAGS="CC=mipsel-linux-gnu-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  sources:
+                      - sourceline: "deb http://archive.ubuntu.com/ubuntu/ xenial main universe"
+                  packages:
+                      - gcc-mipsel-linux-gnu
+                      - libc6-dev-mipsel-cross
+                      - qemu-user-binfmt
+
+        - os: linux
+          env: FLAGS="CC=mips64el-linux-gnuabi64-gcc" TEST_FLAGS="LDFLAGS=-static"
+          addons:
+              apt:
+                  sources:
+                      - sourceline: "deb http://archive.ubuntu.com/ubuntu/ xenial main universe"
+                  packages:
+                      - gcc-mips64el-linux-gnuabi64
+                      - libc6-dev-mips64el-cross
+                      - qemu-user-binfmt
+notifications:
+    email: false
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644 (file)
index 0000000..869ae16
--- /dev/null
@@ -0,0 +1,115 @@
+## OpenLibm
+
+OpenLibm contains code that is covered by various licenses.
+
+The OpenLibm code derives from the FreeBSD msun and OpenBSD libm
+implementations, which in turn derives from FDLIBM 5.3. As a result, it
+has a number of fixes and updates that have accumulated over the years
+in msun, and also optimized assembly versions of many functions. These
+improvements are provided under the BSD and ISC licenses. The msun
+library also includes work placed under the public domain, which is
+noted in the individual files. Further work on making a standalone
+OpenLibm library from msun, as part of the Julia project is covered
+under the MIT license. The test files, test-double.c and test-float.c
+are under the LGPL.
+
+## Parts copyrighted by the Julia project (MIT License)
+
+>       Copyright (c) 2011-14 The Julia Project.
+>       https://github.com/JuliaLang/openlibm/graphs/contributors
+>
+>       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.
+
+## Parts copyrighted by Stephen L. Moshier (ISC License)
+
+> Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+>
+> Permission to use, copy, modify, and distribute this software for any
+> purpose with or without fee is hereby granted, provided that the above
+> copyright notice and this permission notice appear in all copies.
+>
+> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+## FREEBSD MSUN (FreeBSD/2-clause BSD/Simplified BSD License)
+
+>       Copyright 1992-2011 The FreeBSD Project. 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 FREEBSD PROJECT ``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 FREEBSD PROJECT 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.
+>
+>       The views and conclusions contained in the software and documentation
+>       are those of the authors and should not be interpreted as representing
+>       official policies, either expressed or implied, of the FreeBSD
+>       Project.
+
+## FDLIBM
+
+>      Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+>
+>      Developed at SunPro, a Sun Microsystems, Inc. business.
+>      Permission to use, copy, modify, and distribute this
+>      software is freely granted, provided that this notice
+>      is preserved.
+
+## Tests
+
+>   Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+>   This file is part of the GNU C Library.
+>   Contributed by Andreas Jaeger <aj@suse.de>, 1997.
+>
+>   The GNU C Library is free software; you can redistribute it and/or
+>   modify it under the terms of the GNU Lesser General Public
+>   License as published by the Free Software Foundation; either
+>   version 2.1 of the License, or (at your option) any later version.
+>
+>   The GNU C Library is distributed in the hope that it will be useful,
+>   but WITHOUT ANY WARRANTY; without even the implied warranty of
+>   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+>   Lesser General Public License for more details.
+>
+>   You should have received a copy of the GNU Lesser General Public
+>   License along with the GNU C Library; if not, write to the Free
+>   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+>   02111-1307 USA.
diff --git a/Make.inc b/Make.inc
new file mode 100644 (file)
index 0000000..7eab90d
--- /dev/null
+++ b/Make.inc
@@ -0,0 +1,145 @@
+# -*- mode: makefile-gmake -*-
+
+# Default build rule for any Makefile in this project: all
+default: all
+
+OS := $(shell uname)
+# Do not forget to bump SOMINOR when changing VERSION,
+# and SOMAJOR when breaking ABI in a backward-incompatible way
+VERSION = 0.6.0
+SOMAJOR = 2
+SOMINOR = 5
+DESTDIR =
+prefix = /usr/local
+bindir = $(prefix)/bin
+libdir = $(prefix)/lib
+includedir = $(prefix)/include
+
+ifeq ($(OS), FreeBSD)
+pkgconfigdir = $(prefix)/libdata/pkgconfig
+else
+pkgconfigdir = $(libdir)/pkgconfig
+endif
+
+USEGCC = 1
+USECLANG = 0
+
+ifneq (,$(findstring $(OS),Darwin FreeBSD OpenBSD))
+USEGCC = 0
+USECLANG = 1
+endif
+
+AR = $(TOOLPREFIX)ar
+
+ifeq ($(USECLANG),1)
+USEGCC = 0
+CC = clang
+CFLAGS_add += -fno-builtin -fno-strict-aliasing
+endif
+
+ifeq ($(USEGCC),1)
+CC = $(TOOLPREFIX)gcc
+CFLAGS_add += -fno-gnu89-inline -fno-builtin
+endif
+
+ARCH ?= $(shell $(CC) -dumpmachine | sed "s/\([^-]*\).*$$/\1/")
+
+ifeq ($(ARCH),mingw32)
+$(error "the mingw32 compiler you are using fails the openblas testsuite. please see the Julia README.windows.md document for a replacement")
+endif
+
+# OS-specific stuff
+ifeq ($(findstring arm,$(ARCH)),arm)
+override ARCH := arm
+MARCH ?= armv7-a
+CFLAGS_add += -mhard-float
+endif
+ifeq ($(findstring powerpc,$(ARCH)),powerpc)
+override ARCH := powerpc
+endif
+ifeq ($(findstring ppc,$(ARCH)),ppc)
+override ARCH := powerpc
+endif
+ifneq ($(filter $(ARCH),i386 i486 i586 i686 i387 i487 i587 i687),)
+override ARCH := i387
+MARCH ?= i686
+endif
+ifeq ($(ARCH),x86_64)
+override ARCH := amd64
+endif
+ifeq ($(findstring mips,$(ARCH)),mips)
+override ARCH := mips
+endif
+
+# If CFLAGS does not contain a -O optimization flag, default to -O3
+ifeq ($(findstring -O,$(CFLAGS)),)
+CFLAGS_add += -O3
+endif
+
+ifneq (,$(findstring MINGW,$(OS)))
+override OS=WINNT
+endif
+
+#keep these if statements separate
+ifeq ($(OS), WINNT)
+SHLIB_EXT = dll
+SONAME_FLAG = -soname
+CFLAGS_add += -nodefaultlibs
+shlibdir = $(bindir)
+else
+ifeq ($(OS), Darwin)
+SHLIB_EXT = dylib
+SONAME_FLAG = -install_name
+else
+SHLIB_EXT = so
+SONAME_FLAG = -soname
+endif
+CFLAGS_add += -fPIC
+shlibdir = $(libdir)
+endif
+
+# Add `-march` to our CFLAGS if it's defined
+ifneq ($(MARCH),)
+CFLAGS_arch += -march=$(MARCH)
+endif
+
+ifeq ($(ARCH),i387)
+CFLAGS_arch  += -m32
+SFLAGS_arch  += -m32
+LDFLAGS_arch += -m32
+endif
+
+ifeq ($(ARCH),amd64)
+CFLAGS_arch  += -m64
+SFLAGS_arch  += -m64
+LDFLAGS_arch += -m64
+endif
+
+# Add our "arch"-related FLAGS in.  We separate arch-related flags out so that
+# we can conveniently get at them for targets that don't want the rest of
+# *FLAGS_add, such as the testing Makefile targets
+CFLAGS_add  += $(CFLAGS_arch)
+SFLAGS_add  += $(SFLAGS_arch)
+LDFLAGS_add += $(LDFLAGS_arch)
+
+CFLAGS_add += -std=c99 -Wall -I$(OPENLIBM_HOME) -I$(OPENLIBM_HOME)/include -I$(OPENLIBM_HOME)/$(ARCH) -I$(OPENLIBM_HOME)/src -DASSEMBLER -D__BSD_VISIBLE -Wno-implicit-function-declaration
+ifneq ($(filter $(ARCH),i387 amd64 powerpc),)
+CFLAGS_add += -I$(OPENLIBM_HOME)/ld80
+else
+ifneq ($(filter $(ARCH),aarch64),)
+CFLAGS_add += -I$(OPENLIBM_HOME)/ld128
+endif
+endif
+
+
+%.c.o: %.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) -c $< -o $@
+
+%.S.o: %.S
+       $(CC) $(CPPFLAGS) $(SFLAGS) $(SFLAGS_add) $(filter -m% -B% -I% -D%,$(CFLAGS_add)) -c $< -o $@
+
+
+# Makefile debugging trick:
+# call print-VARIABLE to see the runtime value of any variable
+print-%:
+       @echo '$*=$($*)'
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..8494afb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,101 @@
+OPENLIBM_HOME=$(abspath .)
+include ./Make.inc
+
+SUBDIRS = src $(ARCH) bsdsrc
+# Add ld80 directory on x86 and x64
+ifneq ($(filter $(ARCH),i387 amd64),)
+SUBDIRS += ld80
+else
+ifneq ($(filter $(ARCH),aarch64),)
+SUBDIRS += ld128
+else
+endif
+endif
+
+define INC_template
+TEST=test
+override CUR_SRCS = $(1)_SRCS
+include $(1)/Make.files
+SRCS += $$(addprefix $(1)/,$$($(1)_SRCS))
+endef
+
+DIR=test
+
+$(foreach dir,$(SUBDIRS),$(eval $(call INC_template,$(dir))))
+
+DUPLICATE_NAMES = $(filter $(patsubst %.S,%,$($(ARCH)_SRCS)),$(patsubst %.c,%,$(src_SRCS)))
+DUPLICATE_SRCS = $(addsuffix .c,$(DUPLICATE_NAMES))
+
+OBJS =  $(patsubst %.f,%.f.o,\
+       $(patsubst %.S,%.S.o,\
+       $(patsubst %.c,%.c.o,$(filter-out $(addprefix src/,$(DUPLICATE_SRCS)),$(SRCS)))))
+
+# If we're on windows, don't do versioned shared libraries. Also, generate an import library
+# for the DLL. If we're on OSX, put the version number before the .dylib.  Otherwise,
+# put it after.
+ifeq ($(OS), WINNT)
+OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT)
+LDFLAGS_add += -Wl,--out-implib,libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT).a
+else
+ifeq ($(OS), Darwin)
+OLM_MAJOR_MINOR_SHLIB_EXT := $(SOMAJOR).$(SOMINOR).$(SHLIB_EXT)
+OLM_MAJOR_SHLIB_EXT := $(SOMAJOR).$(SHLIB_EXT)
+else
+OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR).$(SOMINOR)
+OLM_MAJOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR)
+endif
+endif
+
+.PHONY: all check test clean distclean \
+       install install-static install-shared install-pkgconfig install-headers
+
+all: libopenlibm.a libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
+
+check test: test/test-double test/test-float
+       test/test-double
+       test/test-float
+
+libopenlibm.a: $(OBJS)
+       $(AR) -rcs libopenlibm.a $(OBJS)
+
+libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT): $(OBJS)
+       $(CC) -shared $(OBJS) $(LDFLAGS) $(LDFLAGS_add) -Wl,$(SONAME_FLAG),libopenlibm.$(OLM_MAJOR_SHLIB_EXT) -o $@
+ifneq ($(OS),WINNT)
+       ln -sf $@ libopenlibm.$(OLM_MAJOR_SHLIB_EXT)
+       ln -sf $@ libopenlibm.$(SHLIB_EXT)
+endif
+
+test/test-double: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
+       $(MAKE) -C test test-double
+
+test/test-float: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
+       $(MAKE) -C test test-float
+
+clean:
+       rm -f aarch64/*.o amd64/*.o arm/*.o bsdsrc/*.o i387/*.o ld80/*.o ld128/*.o src/*.o powerpc/*.o mips/*.o
+       rm -f libopenlibm.a libopenlibm.*$(SHLIB_EXT)*
+       $(MAKE) -C test clean
+
+openlibm.pc: openlibm.pc.in Make.inc Makefile
+       echo "prefix=${prefix}" > openlibm.pc
+       echo "version=${VERSION}" >> openlibm.pc
+       cat openlibm.pc.in >> openlibm.pc
+
+install-static: libopenlibm.a
+       mkdir -p $(DESTDIR)$(libdir)
+       cp -RpP -f libopenlibm.a $(DESTDIR)$(libdir)/
+
+install-shared: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT)
+       mkdir -p $(DESTDIR)$(shlibdir)
+       cp -RpP -f libopenlibm.*$(SHLIB_EXT)* $(DESTDIR)$(shlibdir)/
+
+install-pkgconfig: openlibm.pc
+       mkdir -p $(DESTDIR)$(pkgconfigdir)
+       cp -RpP -f openlibm.pc $(DESTDIR)$(pkgconfigdir)/
+
+install-headers:
+       mkdir -p $(DESTDIR)$(includedir)/openlibm
+       cp -RpP -f include/*.h $(DESTDIR)$(includedir)/openlibm
+       cp -RpP -f src/*.h $(DESTDIR)$(includedir)/openlibm
+
+install: install-static install-shared install-pkgconfig install-headers
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..9452006
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# OpenLibm
+
+[![Travis](https://travis-ci.org/JuliaLang/openlibm.svg?branch=master)](https://travis-ci.org/JuliaLang/openlibm)
+[![AppVeyor](https://ci.appveyor.com/api/projects/status/30kn644g79f0x6va/branch/master?svg=true)](https://ci.appveyor.com/project/ararslan/openlibm/branch/master)
+
+[OpenLibm](http://www.openlibm.org) is an effort to have a high quality, portable, standalone
+C mathematical library ([`libm`](http://en.wikipedia.org/wiki/libm)).
+It can be used standalone in applications and programming language
+implementations.
+
+The project was born out of a need to have a good `libm` for the
+[Julia programming langage](http://www.julialang.org) that worked
+consistently across compilers and operating systems, and in 32-bit and
+64-bit environments.
+
+## Platform support
+
+OpenLibm builds on Linux, Mac OS X, Windows, FreeBSD, OpenBSD, and DragonFly BSD.
+It builds with both GCC and clang. Although largely tested and widely
+used on x86 architectures, OpenLibm also supports ARM and
+PowerPC.
+
+## Build instructions
+
+1. Use GNU Make to build OpenLibm. This is `make` on most systems, but `gmake` on BSDs.
+2. Use `make USEGCC=1` to build with GCC. This is the default on
+   Linux and Windows.
+3. Use `make USECLANG=1` to build with clang. This is the default on OS X, FreeBSD,
+   and OpenBSD.
+4. Architectures are auto-detected. Use `make ARCH=i386` to force a
+   build for i386. Other supported architectures are i486, i586, and
+   i686. GCC 4.8 is the minimum requirement for correct codegen on
+   older 32-bit architectures.
+
+## Acknowledgements
+
+PowerPC support for openlibm was graciously sponsored by IBM.
diff --git a/aarch64/Make.files b/aarch64/Make.files
new file mode 100644 (file)
index 0000000..483a7cc
--- /dev/null
@@ -0,0 +1 @@
+$(CUR_SRCS) = fenv.c
diff --git a/aarch64/fenv.c b/aarch64/fenv.c
new file mode 100644 (file)
index 0000000..c9abf14
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.3 2011/10/16 05:37:56 das Exp $
+ */
+
+#define        __fenv_static
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+/*
+ * Hopefully the system ID byte is immutable, so it's valid to use
+ * this as a default environment.
+ */
+const fenv_t __fe_dfl_env = 0;
+
+extern inline int feclearexcept(int __excepts);
+extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+extern inline int feraiseexcept(int __excepts);
+extern inline int fetestexcept(int __excepts);
+extern inline int fegetround(void);
+extern inline int fesetround(int __round);
+extern inline int fegetenv(fenv_t *__envp);
+extern inline int feholdexcept(fenv_t *__envp);
+extern inline int fesetenv(const fenv_t *__envp);
+extern inline int feupdateenv(const fenv_t *__envp);
diff --git a/amd64/Make.files b/amd64/Make.files
new file mode 100644 (file)
index 0000000..6dc21c6
--- /dev/null
@@ -0,0 +1,6 @@
+$(CUR_SRCS) = fenv.c e_remainder.S e_remainderf.S e_remainderl.S \
+           e_sqrt.S e_sqrtf.S e_sqrtl.S \
+           s_llrint.S s_llrintf.S s_llrintl.S \
+           s_logbl.S s_lrint.S s_lrintf.S s_lrintl.S \
+           s_remquo.S s_remquof.S s_remquol.S \
+           s_rintl.S s_scalbn.S s_scalbnf.S s_scalbnl.S
diff --git a/amd64/bsd_asm.h b/amd64/bsd_asm.h
new file mode 100644 (file)
index 0000000..b9c815b
--- /dev/null
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)DEFS.h        5.1 (Berkeley) 4/23/90
+ * $FreeBSD: src/sys/amd64/include/asm.h,v 1.18 2007/08/22 04:26:07 jkoshy Exp $
+ */
+
+#ifndef _BSD_ASM_H_
+#define _BSD_ASM_H_
+
+#ifdef __APPLE__
+#include "../i387/osx_asm.h"
+#define CNAME(x) EXT(x)
+#else
+#include "bsd_cdefs.h"
+
+#ifdef PIC
+#define        PIC_PLT(x)      x@PLT
+#define        PIC_GOT(x)      x@GOTPCREL(%rip)
+#else
+#define        PIC_PLT(x)      x
+#define        PIC_GOT(x)      x
+#endif
+
+/*
+ * CNAME and HIDENAME manage the relationship between symbol names in C
+ * and the equivalent assembly language names.  CNAME is given a name as
+ * it would be used in a C program.  It expands to the equivalent assembly
+ * language name.  HIDENAME is given an assembly-language name, and expands
+ * to a possibly-modified form that will be invisible to C programs.
+ */
+#define CNAME(csym)            csym
+#define HIDENAME(asmsym)       .asmsym
+
+#define _START_ENTRY   .p2align 4,0x90
+
+#if defined(__ELF__)
+#define _ENTRY(x)      .text; _START_ENTRY; \
+                       .globl CNAME(x); .type CNAME(x),@function; CNAME(x):
+#define        END(x)          .size x, . - x
+
+#elif defined(_WIN32)
+#ifndef _MSC_VER
+#define END(x) .end
+#define _START_ENTRY_WIN .text; _START_ENTRY
+#else
+#define END(x) end
+#define _START_ENTRY_WIN .code; _START_ENTRY
+#endif
+#define _ENTRY(x)      _START_ENTRY_WIN; \
+            .globl CNAME(x); .section .drectve; .ascii " -export:", #x; \
+            .section .text; .def CNAME(x); .scl 2; .type 32; .endef; CNAME(x):
+#endif
+
+#ifdef PROF
+#define        ALTENTRY(x)     _ENTRY(x); \
+                       pushq %rbp; movq %rsp,%rbp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popq %rbp; \
+                       jmp 9f
+#define        ENTRY(x)        _ENTRY(x); \
+                       pushq %rbp; movq %rsp,%rbp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popq %rbp; \
+                       9:
+#else
+#define        ALTENTRY(x)     _ENTRY(x)
+#define        ENTRY(x)        _ENTRY(x)
+#endif
+
+
+#define RCSID(x)       .text; .asciz x
+
+#undef __FBSDID
+#if !defined(lint) && !defined(STRIP_FBSDID)
+#define __FBSDID(s)    .ident s
+#else
+#define __FBSDID(s)    /* nothing */
+#endif /* not lint and not STRIP_FBSDID */
+
+#endif
+#endif /* !_BSD_ASM_H_ */
diff --git a/amd64/bsd_fpu.h b/amd64/bsd_fpu.h
new file mode 100644 (file)
index 0000000..513b345
--- /dev/null
@@ -0,0 +1,218 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $FreeBSD: src/sys/x86/include/fpu.h,v 1.1 2012/03/16 20:24:30 tijl Exp $
+ */
+
+/*
+ * Floating Point Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef _BSD_FPU_H_
+#define        _BSD_FPU_H_
+
+#include "types-compat.h"
+
+/* Environment information of floating point unit. */
+struct env87 {
+       int32_t         en_cw;          /* control word (16bits) */
+       int32_t         en_sw;          /* status word (16bits) */
+       int32_t         en_tw;          /* tag word (16bits) */
+       int32_t         en_fip;         /* fp instruction pointer */
+       uint16_t        en_fcs;         /* fp code segment selector */
+       uint16_t        en_opcode;      /* opcode last executed (11 bits) */
+       int32_t         en_foo;         /* fp operand offset */
+       int32_t         en_fos;         /* fp operand segment selector */
+};
+
+/* Contents of each x87 floating point accumulator. */
+struct fpacc87 {
+       uint8_t         fp_bytes[10];
+};
+
+/* Floating point context. (i386 fnsave/frstor) */
+struct save87 {
+       struct env87    sv_env;         /* floating point control/status */
+       struct fpacc87  sv_ac[8];       /* accumulator contents, 0-7 */
+       uint8_t         sv_pad0[4];     /* saved status word (now unused) */
+       /*
+        * Bogus padding for emulators.  Emulators should use their own
+        * struct and arrange to store into this struct (ending here)
+        * before it is inspected for ptracing or for core dumps.  Some
+        * emulators overwrite the whole struct.  We have no good way of
+        * knowing how much padding to leave.  Leave just enough for the
+        * GPL emulator's i387_union (176 bytes total).
+        */
+       uint8_t         sv_pad[64];     /* padding; used by emulators */
+};
+
+/* Contents of each SSE extended accumulator. */
+struct xmmacc {
+       uint8_t         xmm_bytes[16];
+};
+
+/* Contents of the upper 16 bytes of each AVX extended accumulator. */
+struct ymmacc {
+       uint8_t         ymm_bytes[16];
+};
+
+/* Rename structs below depending on machine architecture. */
+#ifdef __i386__
+#define        __envxmm32      envxmm
+#else
+#define        __envxmm32      envxmm32
+#define        __envxmm64      envxmm
+#endif
+
+struct __envxmm32 {
+       uint16_t        en_cw;          /* control word (16bits) */
+       uint16_t        en_sw;          /* status word (16bits) */
+       uint16_t        en_tw;          /* tag word (16bits) */
+       uint16_t        en_opcode;      /* opcode last executed (11 bits) */
+       uint32_t        en_fip;         /* fp instruction pointer */
+       uint16_t        en_fcs;         /* fp code segment selector */
+       uint16_t        en_pad0;        /* padding */
+       uint32_t        en_foo;         /* fp operand offset */
+       uint16_t        en_fos;         /* fp operand segment selector */
+       uint16_t        en_pad1;        /* padding */
+       uint32_t        en_mxcsr;       /* SSE control/status register */
+       uint32_t        en_mxcsr_mask;  /* valid bits in mxcsr */
+};
+
+struct __envxmm64 {
+       uint16_t        en_cw;          /* control word (16bits) */
+       uint16_t        en_sw;          /* status word (16bits) */
+       uint8_t         en_tw;          /* tag word (8bits) */
+       uint8_t         en_zero;
+       uint16_t        en_opcode;      /* opcode last executed (11 bits ) */
+       uint64_t        en_rip;         /* fp instruction pointer */
+       uint64_t        en_rdp;         /* fp operand pointer */
+       uint32_t        en_mxcsr;       /* SSE control/status register */
+       uint32_t        en_mxcsr_mask;  /* valid bits in mxcsr */
+};
+
+/* Floating point context. (i386 fxsave/fxrstor) */
+struct savexmm {
+       struct __envxmm32       sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               uint8_t         fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc           sv_xmm[8];
+       uint8_t                 sv_pad[224];
+} __attribute__ ((aligned(16)));
+
+#ifdef __i386__
+union savefpu {
+       struct save87   sv_87;
+       struct savexmm  sv_xmm;
+};
+#else
+/* Floating point context. (amd64 fxsave/fxrstor) */
+struct savefpu {
+       struct __envxmm64       sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               uint8_t         fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc           sv_xmm[16];
+       uint8_t                 sv_pad[96];
+} __attribute__ ((aligned(16)));
+#endif
+
+struct xstate_hdr {
+       uint64_t        xstate_bv;
+       uint8_t         xstate_rsrv0[16];
+       uint8_t         xstate_rsrv[40];
+};
+
+struct savexmm_xstate {
+       struct xstate_hdr       sx_hd;
+       struct ymmacc           sx_ymm[16];
+};
+
+struct savexmm_ymm {
+       struct __envxmm32       sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               int8_t          fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc           sv_xmm[16];
+       uint8_t                 sv_pad[96];
+       struct savexmm_xstate   sv_xstate;
+} __attribute__ ((aligned(16)));
+
+struct savefpu_xstate {
+       struct xstate_hdr       sx_hd;
+       struct ymmacc           sx_ymm[16];
+};
+
+struct savefpu_ymm {
+       struct __envxmm64       sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               int8_t          fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc           sv_xmm[16];
+       uint8_t                 sv_pad[96];
+       struct savefpu_xstate   sv_xstate;
+} __attribute__ ((aligned(64)));
+
+#undef __envxmm32
+#undef __envxmm64
+
+/*
+ * The hardware default control word for i387's and later coprocessors is
+ * 0x37F, giving:
+ *
+ *     round to nearest
+ *     64-bit precision
+ *     all exceptions masked.
+ *
+ * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc
+ * because of the difference between memory and fpu register stack arguments.
+ * If its using an intermediate fpu register, it has 80/64 bits to work
+ * with.  If it uses memory, it has 64/53 bits to work with.  However,
+ * gcc is aware of this and goes to a fair bit of trouble to make the
+ * best use of it.
+ *
+ * This is mostly academic for AMD64, because the ABI prefers the use
+ * SSE2 based math.  For FreeBSD/amd64, we go with the default settings.
+ */
+#define        __INITIAL_FPUCW__       0x037F
+#define        __INITIAL_FPUCW_I386__  0x127F
+#define        __INITIAL_NPXCW__       __INITIAL_FPUCW_I386__
+#define        __INITIAL_MXCSR__       0x1F80
+#define        __INITIAL_MXCSR_MASK__  0xFFBF
+
+#endif /* !_BSD_FPU_H_ */
diff --git a/amd64/bsd_ieeefp.h b/amd64/bsd_ieeefp.h
new file mode 100644 (file)
index 0000000..6103d50
--- /dev/null
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1990 Andrew Moore, Talke Studio
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#) ieeefp.h     1.0 (Berkeley) 9/23/93
+ * $FreeBSD: src/sys/amd64/include/ieeefp.h,v 1.14 2005/04/12 23:12:00 jhb Exp $
+ */
+
+/*
+ *     IEEE floating point type and constant definitions.
+ */
+
+#ifndef _BSD_IEEEFP_H_
+#define _BSD_IEEEFP_H_
+
+/*
+ * FP rounding modes
+ */
+typedef enum {
+       FP_RN=0,        /* round to nearest */
+       FP_RM,          /* round down to minus infinity */
+       FP_RP,          /* round up to plus infinity */
+       FP_RZ           /* truncate */
+} fp_rnd_t;
+
+/*
+ * FP precision modes
+ */
+typedef enum {
+       FP_PS=0,        /* 24 bit (single-precision) */
+       FP_PRS,         /* reserved */
+       FP_PD,          /* 53 bit (double-precision) */
+       FP_PE           /* 64 bit (extended-precision) */
+} fp_prec_t;
+
+#define fp_except_t    int
+
+/*
+ * FP exception masks
+ */
+#define FP_X_INV       0x01    /* invalid operation */
+#define FP_X_DNML      0x02    /* denormal */
+#define FP_X_DZ                0x04    /* zero divide */
+#define FP_X_OFL       0x08    /* overflow */
+#define FP_X_UFL       0x10    /* underflow */
+#define FP_X_IMP       0x20    /* (im)precision */
+#define FP_X_STK       0x40    /* stack fault */
+
+/*
+ * FP registers
+ */
+#define FP_MSKS_REG    0       /* exception masks */
+#define FP_PRC_REG     0       /* precision */
+#define FP_RND_REG     0       /* direction */
+#define FP_STKY_REG    1       /* sticky flags */
+
+/*
+ * FP register bit field masks
+ */
+#define FP_MSKS_FLD    0x3f    /* exception masks field */
+#define FP_PRC_FLD     0x300   /* precision control field */
+#define FP_RND_FLD     0xc00   /* round control field */
+#define FP_STKY_FLD    0x3f    /* sticky flags field */
+
+/*
+ * SSE mxcsr register bit field masks
+ */
+#define        SSE_STKY_FLD    0x3f    /* exception flags */
+#define        SSE_DAZ_FLD     0x40    /* Denormals are zero */
+#define        SSE_MSKS_FLD    0x1f80  /* exception masks field */
+#define        SSE_RND_FLD     0x6000  /* rounding control */
+#define        SSE_FZ_FLD      0x8000  /* flush to zero on underflow */
+
+/*
+ * FP register bit field offsets
+ */
+#define FP_MSKS_OFF    0       /* exception masks offset */
+#define FP_PRC_OFF     8       /* precision control offset */
+#define FP_RND_OFF     10      /* round control offset */
+#define FP_STKY_OFF    0       /* sticky flags offset */
+
+/*
+ * SSE mxcsr register bit field offsets
+ */
+#define        SSE_STKY_OFF    0       /* exception flags offset */
+#define        SSE_DAZ_OFF     6       /* DAZ exception mask offset */
+#define        SSE_MSKS_OFF    7       /* other exception masks offset */
+#define        SSE_RND_OFF     13      /* rounding control offset */
+#define        SSE_FZ_OFF      15      /* flush to zero offset */
+
+#if (defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE__)) || defined(_WIN32) \
+    && !defined(__cplusplus)
+
+#define        __fldenv(addr)  __asm __volatile("fldenv %0" : : "m" (*(addr)))
+#define        __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
+#define        __fldcw(addr)   __asm __volatile("fldcw %0" : : "m" (*(addr)))
+#define        __fnstcw(addr)  __asm __volatile("fnstcw %0" : "=m" (*(addr)))
+#define        __fnstsw(addr)  __asm __volatile("fnstsw %0" : "=m" (*(addr)))
+#define        __ldmxcsr(addr) __asm __volatile("ldmxcsr %0" : : "m" (*(addr)))
+#define        __stmxcsr(addr) __asm __volatile("stmxcsr %0" : "=m" (*(addr)))
+
+/*
+ * General notes about conflicting SSE vs FP status bits.
+ * This code assumes that software will not fiddle with the control
+ * bits of the SSE and x87 in such a way to get them out of sync and
+ * still expect this to work.  Break this at your peril.
+ * Because I based this on the i386 port, the x87 state is used for
+ * the fpget*() functions, and is shadowed into the SSE state for
+ * the fpset*() functions.  For dual source fpget*() functions, I
+ * merge the two together.  I think.
+ */
+
+/* Set rounding control */
+static __inline__ fp_rnd_t
+__fpgetround(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((_cw & FP_RND_FLD) >> FP_RND_OFF);
+}
+
+static __inline__ fp_rnd_t
+__fpsetround(fp_rnd_t _m)
+{
+       unsigned short _cw;
+       unsigned int _mxcsr;
+       fp_rnd_t _p;
+
+       __fnstcw(&_cw);
+       _p = (_cw & FP_RND_FLD) >> FP_RND_OFF;
+       _cw &= ~FP_RND_FLD;
+       _cw |= (_m << FP_RND_OFF) & FP_RND_FLD;
+       __fldcw(&_cw);
+       __stmxcsr(&_mxcsr);
+       _mxcsr &= ~SSE_RND_FLD;
+       _mxcsr |= (_m << SSE_RND_OFF) & SSE_RND_FLD;
+       __ldmxcsr(&_mxcsr);
+       return (_p);
+}
+
+/*
+ * Set precision for fadd/fsub/fsqrt etc x87 instructions
+ * There is no equivalent SSE mode or control.
+ */
+static __inline__ fp_prec_t
+__fpgetprec(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((_cw & FP_PRC_FLD) >> FP_PRC_OFF);
+}
+
+static __inline__ fp_prec_t
+__fpsetprec(fp_rnd_t _m)
+{
+       unsigned short _cw;
+       fp_prec_t _p;
+
+       __fnstcw(&_cw);
+       _p = (_cw & FP_PRC_FLD) >> FP_PRC_OFF;
+       _cw &= ~FP_PRC_FLD;
+       _cw |= (_m << FP_PRC_OFF) & FP_PRC_FLD;
+       __fldcw(&_cw);
+       return (_p);
+}
+
+/*
+ * Look at the exception masks
+ * Note that x87 masks are inverse of the fp*() functions
+ * API.  ie: mask = 1 means disable for x87 and SSE, but
+ * for the fp*() api, mask = 1 means enabled.
+ */
+static __inline__ fp_except_t
+__fpgetmask(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((~_cw) & FP_MSKS_FLD);
+}
+
+static __inline__ fp_except_t
+__fpsetmask(fp_except_t _m)
+{
+       unsigned short _cw;
+       unsigned int _mxcsr;
+       fp_except_t _p;
+
+       __fnstcw(&_cw);
+       _p = (~_cw) & FP_MSKS_FLD;
+       _cw &= ~FP_MSKS_FLD;
+       _cw |= (~_m) & FP_MSKS_FLD;
+       __fldcw(&_cw);
+       __stmxcsr(&_mxcsr);
+       /* XXX should we clear non-ieee SSE_DAZ_FLD and SSE_FZ_FLD ? */
+       _mxcsr &= ~SSE_MSKS_FLD;
+       _mxcsr |= ((~_m) << SSE_MSKS_OFF) & SSE_MSKS_FLD;
+       __ldmxcsr(&_mxcsr);
+       return (_p);
+}
+
+/* See which sticky exceptions are pending, and reset them */
+static __inline__ fp_except_t
+__fpgetsticky(void)
+{
+       unsigned short _sw;
+       unsigned int _mxcsr;
+       fp_except_t _ex;
+
+       __fnstsw(&_sw);
+       _ex = _sw & FP_STKY_FLD;
+       __stmxcsr(&_mxcsr);
+       _ex |= _mxcsr & SSE_STKY_FLD;
+       return (_ex);
+}
+
+#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE__ && !__cplusplus */
+
+#if !defined(__IEEEFP_NOINLINES__) && !defined(__cplusplus) \
+    && defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE__)
+
+#define        fpgetround()    __fpgetround()
+#define        fpsetround(_m)  __fpsetround(_m)
+#define        fpgetprec()     __fpgetprec()
+#define        fpsetprec(_m)   __fpsetprec(_m)
+#define        fpgetmask()     __fpgetmask()
+#define        fpsetmask(_m)   __fpsetmask(_m)
+#define        fpgetsticky()   __fpgetsticky()
+
+/* Suppress prototypes in the MI header. */
+#define        _IEEEFP_INLINED_        1
+
+#else /* !__IEEEFP_NOINLINES__ && !__cplusplus && __GNUCLIKE_ASM
+         && __CC_SUPPORTS___INLINE__ */
+
+/* Augment the userland declarations */
+__BEGIN_DECLS
+extern fp_prec_t fpgetprec(void);
+extern fp_prec_t fpsetprec(fp_prec_t);
+__END_DECLS
+
+#endif /* !__IEEEFP_NOINLINES__ && !__cplusplus && __GNUCLIKE_ASM
+          && __CC_SUPPORTS___INLINE__ */
+
+#endif /* !_BSD_IEEEFP_H_ */
diff --git a/amd64/e_remainder.S b/amd64/e_remainder.S
new file mode 100644 (file)
index 0000000..a0b4900
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Based on the i387 version written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+
+//RCSID("from: FreeBSD: src/lib/msun/i387/e_remainder.S,v 1.8 2005/02/04 14:08:32 das Exp")
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainder.S,v 1.2 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(remainder)
+       movsd   %xmm0,-8(%rsp)
+       movsd   %xmm1,-16(%rsp)
+       fldl    -16(%rsp)
+       fldl    -8(%rsp)
+1:     fprem1
+       fstsw   %ax
+       testw   $0x400,%ax
+       jne     1b
+       fstpl   -8(%rsp)
+       movsd   -8(%rsp),%xmm0
+       fstp    %st
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/e_remainderf.S b/amd64/e_remainderf.S
new file mode 100644 (file)
index 0000000..c63e97e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Based on the i387 version written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+
+//RCSID("from: $NetBSD: e_remainderf.S,v 1.2 1995/05/08 23:49:47 jtc Exp $")
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainderf.S,v 1.2 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(remainderf)
+       movss   %xmm0,-4(%rsp)
+       movss   %xmm1,-8(%rsp)
+       flds    -8(%rsp)
+       flds    -4(%rsp)
+1:     fprem1
+       fstsw   %ax
+       testw   $0x400,%ax
+       jne     1b
+       fstps   -4(%rsp)
+       movss   -4(%rsp),%xmm0
+       fstp    %st
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/e_remainderl.S b/amd64/e_remainderl.S
new file mode 100644 (file)
index 0000000..5f21b93
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Based on the i387 version written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainderl.S,v 1.2 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(remainderl)
+#ifndef _WIN64
+       fldt    24(%rsp)
+       fldt    8(%rsp)
+#else
+    fldt    (%r8)
+    fldt    (%rdx)
+#endif
+1:     fprem1
+       fstsw   %ax
+       testw   $0x400,%ax
+       jne     1b
+       fstp    %st(1)
+#ifdef _WIN64
+    mov     %rcx,%rax
+    movq    $0x0,0x8(%rcx)
+    fstpt   (%rcx)
+#endif
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/e_sqrt.S b/amd64/e_sqrt.S
new file mode 100644 (file)
index 0000000..a44e41f
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrt.S,v 1.4 2011/01/07 16:13:12 kib Exp $")
+       
+ENTRY(sqrt)
+       sqrtsd  %xmm0, %xmm0
+       ret
+END(sqrt)
+
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/e_sqrtf.S b/amd64/e_sqrtf.S
new file mode 100644 (file)
index 0000000..f74175b
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrtf.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+       
+ENTRY(sqrtf)
+       sqrtss  %xmm0, %xmm0
+       ret
+END(sqrtf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/e_sqrtl.S b/amd64/e_sqrtl.S
new file mode 100644 (file)
index 0000000..6e7eac0
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrtl.S,v 1.2 2011/01/07 16:13:12 kib Exp $")
+       
+ENTRY(sqrtl)
+#ifndef _WIN64
+       fldt    8(%rsp)
+       fsqrt
+#else
+    fldt    (%rdx)
+    fsqrt
+    mov     %rcx,%rax
+    movq    $0x0,0x8(%rcx)
+    fstpt   (%rcx)
+#endif
+       ret
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/fenv.c b/amd64/fenv.c
new file mode 100644 (file)
index 0000000..ddf7dba
--- /dev/null
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/amd64/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $
+ */
+
+#include "bsd_fpu.h"
+#include "math_private.h"
+
+#ifdef _WIN32
+#define __fenv_static OLM_DLLEXPORT
+#endif
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+const fenv_t __fe_dfl_env = {
+       { 0xffff0000 | __INITIAL_FPUCW__,
+         0xffff0000,
+         0xffffffff,
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
+       },
+       __INITIAL_MXCSR__
+};
+
+extern inline OLM_DLLEXPORT int feclearexcept(int __excepts);
+extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+
+OLM_DLLEXPORT int
+fesetexceptflag(const fexcept_t *flagp, int excepts)
+{
+       fenv_t env;
+
+       __fnstenv(&env.__x87);
+       env.__x87.__status &= ~excepts;
+       env.__x87.__status |= *flagp & excepts;
+       __fldenv(env.__x87);
+
+       __stmxcsr(&env.__mxcsr);
+       env.__mxcsr &= ~excepts;
+       env.__mxcsr |= *flagp & excepts;
+       __ldmxcsr(env.__mxcsr);
+
+       return (0);
+}
+
+OLM_DLLEXPORT int
+feraiseexcept(int excepts)
+{
+       fexcept_t ex = excepts;
+
+       fesetexceptflag(&ex, excepts);
+       __fwait();
+       return (0);
+}
+
+extern inline OLM_DLLEXPORT int fetestexcept(int __excepts);
+extern inline OLM_DLLEXPORT int fegetround(void);
+extern inline OLM_DLLEXPORT int fesetround(int __round);
+
+OLM_DLLEXPORT int
+fegetenv(fenv_t *envp)
+{
+
+       __fnstenv(&envp->__x87);
+       __stmxcsr(&envp->__mxcsr);
+       /*
+        * fnstenv masks all exceptions, so we need to restore the
+        * control word to avoid this side effect.
+        */
+       __fldcw(envp->__x87.__control);
+       return (0);
+}
+
+OLM_DLLEXPORT int
+feholdexcept(fenv_t *envp)
+{
+       uint32_t mxcsr;
+
+       __stmxcsr(&mxcsr);
+       __fnstenv(&envp->__x87);
+       __fnclex();
+       envp->__mxcsr = mxcsr;
+       mxcsr &= ~FE_ALL_EXCEPT;
+       mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
+       __ldmxcsr(mxcsr);
+       return (0);
+}
+
+extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp);
+
+OLM_DLLEXPORT int
+feupdateenv(const fenv_t *envp)
+{
+       uint32_t mxcsr;
+       uint16_t status;
+
+       __fnstsw(&status);
+       __stmxcsr(&mxcsr);
+       fesetenv(envp);
+       feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
+       return (0);
+}
+
+int
+feenableexcept(int mask)
+{
+       uint32_t mxcsr, omask;
+       uint16_t control;
+
+       mask &= FE_ALL_EXCEPT;
+       __fnstcw(&control);
+       __stmxcsr(&mxcsr);
+       omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+       control &= ~mask;
+       __fldcw(control);
+       mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
+       __ldmxcsr(mxcsr);
+       return (omask);
+}
+
+int
+fedisableexcept(int mask)
+{
+       uint32_t mxcsr, omask;
+       uint16_t control;
+
+       mask &= FE_ALL_EXCEPT;
+       __fnstcw(&control);
+       __stmxcsr(&mxcsr);
+       omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+       control |= mask;
+       __fldcw(control);
+       mxcsr |= mask << _SSE_EMASK_SHIFT;
+       __ldmxcsr(mxcsr);
+       return (omask);
+}
diff --git a/amd64/s_llrint.S b/amd64/s_llrint.S
new file mode 100644 (file)
index 0000000..d7a0f74
--- /dev/null
@@ -0,0 +1,12 @@
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrint.S,v 1.3 2011/02/04 21:54:06 kib Exp $")
+       
+ENTRY(llrint)
+       cvtsd2si %xmm0, %rax
+       ret
+END(llrint)
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_llrintf.S b/amd64/s_llrintf.S
new file mode 100644 (file)
index 0000000..f5d39b3
--- /dev/null
@@ -0,0 +1,12 @@
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrintf.S,v 1.3 2011/02/04 21:54:06 kib Exp $")
+       
+ENTRY(llrintf)
+       cvtss2si %xmm0, %rax
+       ret
+END(llrintf)
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_llrintl.S b/amd64/s_llrintl.S
new file mode 100644 (file)
index 0000000..12f2d33
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(llrintl)
+#ifndef _WIN64
+       fldt    8(%rsp)
+#else
+    fldt    (%rcx)
+#endif
+       subq    $8,%rsp
+       fistpll (%rsp)
+       popq    %rax
+       ret
+
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_logbl.S b/amd64/s_logbl.S
new file mode 100644 (file)
index 0000000..d22afeb
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_logbl.S,v 1.4 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(logbl)
+#ifndef _WIN64
+       fldt    8(%rsp)
+#else
+    fldt    (%rdx)
+#endif
+       fxtract
+       fstp    %st
+#ifdef _WIN64
+    mov     %rcx,%rax
+    movq    $0x0,0x8(%rcx)
+       fstpt   (%rcx)
+#endif
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_lrint.S b/amd64/s_lrint.S
new file mode 100644 (file)
index 0000000..9e1b917
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(lrint)
+#ifndef _WIN64
+       cvtsd2si %xmm0, %rax
+#else
+       cvtsd2si %xmm0, %eax
+#endif
+       ret
+END(lrint)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_lrintf.S b/amd64/s_lrintf.S
new file mode 100644 (file)
index 0000000..8e0b0c2
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(lrintf)
+#ifndef _WIN64
+       cvtss2si %xmm0, %rax
+#else
+       cvtss2si %xmm0, %eax
+#endif
+       ret
+END(lrintf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_lrintl.S b/amd64/s_lrintl.S
new file mode 100644 (file)
index 0000000..288c0bb
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(lrintl)
+#ifndef _WIN64
+       fldt    8(%rsp)
+#else
+       fldt    (%rcx)
+#endif
+       subq    $8,%rsp
+       fistpll (%rsp)
+       popq    %rax
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_remquo.S b/amd64/s_remquo.S
new file mode 100644 (file)
index 0000000..8ef8425
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquo.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquo)
+       movsd   %xmm0,-8(%rsp)
+       movsd   %xmm1,-16(%rsp)
+       fldl    -16(%rsp)
+       fldl    -8(%rsp)
+1:     fprem1
+       fstsw   %ax
+       btw     $10,%ax
+       jc      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    -12(%rsp),%ecx
+       xorl    -4(%rsp),%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+#ifndef _WIN64
+       movl    %eax,(%rdi)
+#else
+    movl    %eax,(%r8)
+#endif
+       fstpl   -8(%rsp)
+       movsd   -8(%rsp),%xmm0
+       ret
+END(remquo)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_remquof.S b/amd64/s_remquof.S
new file mode 100644 (file)
index 0000000..129a807
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquof.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquof)
+       movss   %xmm0,-4(%rsp)
+       movss   %xmm1,-8(%rsp)
+       flds    -8(%rsp)
+       flds    -4(%rsp)
+1:     fprem1
+       fstsw   %ax
+       btw     $10,%ax
+       jc      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    -8(%rsp),%ecx
+       xorl    -4(%rsp),%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+#ifndef _WIN64
+       movl    %eax,(%rdi)
+#else
+    movl    %eax,(%r8)
+#endif
+       fstps   -4(%rsp)
+       movss   -4(%rsp),%xmm0
+       ret
+END(remquof)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_remquol.S b/amd64/s_remquol.S
new file mode 100644 (file)
index 0000000..344e1fb
--- /dev/null
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2005-2008 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquol.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquol)
+#ifndef _WIN64
+       fldt    24(%rsp)
+       fldt    8(%rsp)
+#else
+    fldt    (%r8)
+    fldt    (%rdx)
+    mov     %rcx,%r8
+#endif
+1:     fprem1
+       fstsw   %ax
+       btw     $10,%ax
+       jc      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    32(%rsp),%ecx
+       xorl    16(%rsp),%ecx
+       movsx   %cx,%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+#ifndef _WIN64
+       movl    %eax,(%rdi)
+#else
+    movl    %eax,(%r9)
+    mov     %r8,%rax
+    movq    $0x0,0x8(%r8)
+    fstpt   (%r8)
+#endif
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_rintl.S b/amd64/s_rintl.S
new file mode 100644 (file)
index 0000000..479e836
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+
+ENTRY(rintl)
+#ifndef _WIN64
+       fldt    8(%rsp)
+       frndint
+#else
+    fldt    (%rdx)
+    frndint
+    mov     %rcx,%rax
+    movq    $0x0,0x8(%rcx)
+    fstpt   (%rcx)
+#endif
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_scalbn.S b/amd64/s_scalbn.S
new file mode 100644 (file)
index 0000000..9d4152b
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbn.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(scalbn)
+       movsd   %xmm0,-8(%rsp)
+#ifndef _WIN64
+       movl    %edi,-12(%rsp)
+#else
+       movl    %edx,-12(%rsp)
+#endif
+       fildl   -12(%rsp)
+       fldl    -8(%rsp)
+       fscale
+       fstp    %st(1)
+       fstpl   -8(%rsp)
+       movsd   -8(%rsp),%xmm0
+       ret
+#ifndef _WIN64
+END(scalbn)
+.globl CNAME(ldexp)
+#else
+.globl CNAME(ldexp); .section .drectve; .ascii " -export:ldexp"
+#endif
+.set   CNAME(ldexp),CNAME(scalbn)
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_scalbnf.S b/amd64/s_scalbnf.S
new file mode 100644 (file)
index 0000000..75b4bb2
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbnf.S,v 1.4 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(scalbnf)
+       movss   %xmm0,-8(%rsp)
+#ifndef _WIN64
+       movl    %edi,-4(%rsp)
+#else
+       movl    %edx,-4(%rsp)
+#endif
+       fildl   -4(%rsp)
+       flds    -8(%rsp)
+       fscale
+       fstp    %st(1)
+       fstps   -8(%rsp)
+       movss   -8(%rsp),%xmm0
+       ret
+#ifndef _WIN64
+END(scalbnf)
+.globl CNAME(ldexpf)
+#else
+.globl CNAME(ldexpf); .section .drectve; .ascii " -export:ldexpf"
+#endif
+.set   CNAME(ldexpf),CNAME(scalbnf)
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/amd64/s_scalbnl.S b/amd64/s_scalbnl.S
new file mode 100644 (file)
index 0000000..fa0d2bf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <amd64/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbnl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+/* //RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnl)
+#ifndef _WIN64
+       movl    %edi,-4(%rsp)
+       fildl   -4(%rsp)
+       fldt    8(%rsp)
+#else
+    mov     %r8,%rax
+       movl    %eax,-4(%rsp)
+       fildl   -4(%rsp)
+       fldt    (%rdx)
+#endif
+       fscale
+       fstp    %st(1)
+#ifdef _WIN64
+    mov     %rcx,%rax
+    movq    $0x0,0x8(%rcx)
+    fstpt   (%rcx)
+#endif
+       ret
+#ifndef _WIN64
+END(scalbnl)
+.globl CNAME(ldexpl)
+#else
+.globl CNAME(ldexpl); .section .drectve; .ascii " -export:ldexpl"
+#endif
+.set   CNAME(ldexpl),CNAME(scalbnl)
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644 (file)
index 0000000..1da6654
--- /dev/null
@@ -0,0 +1,37 @@
+environment:
+  matrix:
+    - ARCH: "x86_64"
+
+branches:
+  only:
+    - master
+    - /release-.*/
+
+skip_commits:
+  message: /\[av skip\]/
+
+notifications:
+  - provider: Email
+    on_build_success: false
+    on_build_failure: false
+    on_build_status_changed: false
+
+init:
+  - git config --global core.autocrlf input
+
+build_script:
+  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
+      https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
+      Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
+      throw "There are newer queued builds for this pull request, failing early." }
+  - if %ARCH%==i686 ( set EXCEPT=dwarf ) else set EXCEPT=seh
+  - if %ARCH%==i686 ( set MINGW=mingw32 ) else set MINGW=mingw64
+  - set PATH=C:\MinGW-w64\%ARCH%-6.3.0-posix-%EXCEPT%-rt_v5-rev1\%MINGW%\bin;%PATH%
+  - mingw32-make.exe ARCH=%ARCH% CC=%ARCH%-w64-mingw32-gcc
+  - mingw32-make.exe test ARCH=%ARCH% CC=%ARCH%-w64-mingw32-gcc
+
+on_finish:
+  # Uncomment the following line for interactive debugging, which
+  # will print login data for a temporary remote session after the
+  # build. This requires an RDP version 6 client, e.g., FreeRDP.
+  #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
diff --git a/arm/Make.files b/arm/Make.files
new file mode 100644 (file)
index 0000000..483a7cc
--- /dev/null
@@ -0,0 +1 @@
+$(CUR_SRCS) = fenv.c
diff --git a/arm/fenv.c b/arm/fenv.c
new file mode 100644 (file)
index 0000000..c9abf14
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.3 2011/10/16 05:37:56 das Exp $
+ */
+
+#define        __fenv_static
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+/*
+ * Hopefully the system ID byte is immutable, so it's valid to use
+ * this as a default environment.
+ */
+const fenv_t __fe_dfl_env = 0;
+
+extern inline int feclearexcept(int __excepts);
+extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+extern inline int feraiseexcept(int __excepts);
+extern inline int fetestexcept(int __excepts);
+extern inline int fegetround(void);
+extern inline int fesetround(int __round);
+extern inline int fegetenv(fenv_t *__envp);
+extern inline int feholdexcept(fenv_t *__envp);
+extern inline int fesetenv(const fenv_t *__envp);
+extern inline int feupdateenv(const fenv_t *__envp);
diff --git a/bsdsrc/Make.files b/bsdsrc/Make.files
new file mode 100644 (file)
index 0000000..6777fe2
--- /dev/null
@@ -0,0 +1 @@
+$(CUR_SRCS) += b_exp.c    b_log.c    b_tgamma.c
diff --git a/bsdsrc/b_exp.c b/bsdsrc/b_exp.c
new file mode 100644 (file)
index 0000000..6af8dd7
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1985, 1993
+ *     The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/* @(#)exp.c   8.1 (Berkeley) 6/4/93 */
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_exp.c,v 1.9 2011/10/16 05:37:20 das Exp $");
+
+#include <openlibm_math.h>
+
+/* EXP(X)
+ * RETURN THE EXPONENTIAL OF X
+ * DOUBLE PRECISION (IEEE 53 bits, VAX D FORMAT 56 BITS)
+ * CODED IN C BY K.C. NG, 1/19/85;
+ * REVISED BY K.C. NG on 2/6/85, 2/15/85, 3/7/85, 3/24/85, 4/16/85, 6/14/86.
+ *
+ * Required system supported functions:
+ *     scalb(x,n)
+ *     copysign(x,y)
+ *     finite(x)
+ *
+ * Method:
+ *     1. Argument Reduction: given the input x, find r and integer k such
+ *        that
+ *                        x = k*ln2 + r,  |r| <= 0.5*ln2 .
+ *        r will be represented as r := z+c for better accuracy.
+ *
+ *     2. Compute exp(r) by
+ *
+ *             exp(r) = 1 + r + r*R1/(2-R1),
+ *        where
+ *             R1 = x - x^2*(p1+x^2*(p2+x^2*(p3+x^2*(p4+p5*x^2)))).
+ *
+ *     3. exp(x) = 2^k * exp(r) .
+ *
+ * Special cases:
+ *     exp(INF) is INF, exp(NaN) is NaN;
+ *     exp(-INF)=  0;
+ *     for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ *     exp(x) returns the exponential of x nearly rounded. In a test run
+ *     with 1,156,000 random arguments on a VAX, the maximum observed
+ *     error was 0.869 ulps (units in the last place).
+ */
+
+#include "mathimpl.h"
+
+static const double p1 = 0x1.555555555553ep-3;
+static const double p2 = -0x1.6c16c16bebd93p-9;
+static const double p3 = 0x1.1566aaf25de2cp-14;
+static const double p4 = -0x1.bbd41c5d26bf1p-20;
+static const double p5 = 0x1.6376972bea4d0p-25;
+static const double ln2hi = 0x1.62e42fee00000p-1;
+static const double ln2lo = 0x1.a39ef35793c76p-33;
+static const double lnhuge = 0x1.6602b15b7ecf2p9;
+static const double lntiny = -0x1.77af8ebeae354p9;
+static const double invln2 = 0x1.71547652b82fep0;
+
+#if 0
+OLM_DLLEXPORT double exp(x)
+double x;
+{
+       double  z,hi,lo,c;
+       int k;
+
+#if !defined(vax)&&!defined(tahoe)
+       if(x!=x) return(x);     /* x is NaN */
+#endif /* !defined(vax)&&!defined(tahoe) */
+       if( x <= lnhuge ) {
+               if( x >= lntiny ) {
+
+                   /* argument reduction : x --> x - k*ln2 */
+
+                       k=invln2*x+copysign(0.5,x);     /* k=NINT(x/ln2) */
+
+                   /* express x-k*ln2 as hi-lo and let x=hi-lo rounded */
+
+                       hi=x-k*ln2hi;
+                       x=hi-(lo=k*ln2lo);
+
+                   /* return 2^k*[1+x+x*c/(2+c)]  */
+                       z=x*x;
+                       c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5))));
+                       return  scalb(1.0+(hi-(lo-(x*c)/(2.0-c))),k);
+
+               }
+               /* end of x > lntiny */
+
+               else
+                    /* exp(-big#) underflows to zero */
+                    if(finite(x))  return(scalb(1.0,-5000));
+
+                    /* exp(-INF) is zero */
+                    else return(0.0);
+       }
+       /* end of x < lnhuge */
+
+       else
+       /* exp(INF) is INF, exp(+big#) overflows to INF */
+           return( finite(x) ?  scalb(1.0,5000)  : x);
+}
+#endif
+
+/* returns exp(r = x + c) for |c| < |x| with no overlap.  */
+
+double __exp__D(x, c)
+double x, c;
+{
+       double  z,hi,lo;
+       int k;
+
+       if (x != x)     /* x is NaN */
+               return(x);
+       if ( x <= lnhuge ) {
+               if ( x >= lntiny ) {
+
+                   /* argument reduction : x --> x - k*ln2 */
+                       z = invln2*x;
+                       k = z + copysign(.5, x);
+
+                   /* express (x+c)-k*ln2 as hi-lo and let x=hi-lo rounded */
+
+                       hi=(x-k*ln2hi);                 /* Exact. */
+                       x= hi - (lo = k*ln2lo-c);
+                   /* return 2^k*[1+x+x*c/(2+c)]  */
+                       z=x*x;
+                       c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5))));
+                       c = (x*c)/(2.0-c);
+
+                       return  scalbn(1.+(hi-(lo - c)), k);
+               }
+               /* end of x > lntiny */
+
+               else
+                    /* exp(-big#) underflows to zero */
+                    if(isfinite(x))  return(scalbn(1.0,-5000));
+
+                    /* exp(-INF) is zero */
+                    else return(0.0);
+       }
+       /* end of x < lnhuge */
+
+       else
+       /* exp(INF) is INF, exp(+big#) overflows to INF */
+           return( isfinite(x) ?  scalbn(1.0,5000)  : x);
+}
diff --git a/bsdsrc/b_log.c b/bsdsrc/b_log.c
new file mode 100644 (file)
index 0000000..c20d290
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/* @(#)log.c   8.2 (Berkeley) 11/30/93 */
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_log.c,v 1.9 2008/02/22 02:26:51 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "mathimpl.h"
+
+/* Table-driven natural logarithm.
+ *
+ * This code was derived, with minor modifications, from:
+ *     Peter Tang, "Table-Driven Implementation of the
+ *     Logarithm in IEEE Floating-Point arithmetic." ACM Trans.
+ *     Math Software, vol 16. no 4, pp 378-400, Dec 1990).
+ *
+ * Calculates log(2^m*F*(1+f/F)), |f/j| <= 1/256,
+ * where F = j/128 for j an integer in [0, 128].
+ *
+ * log(2^m) = log2_hi*m + log2_tail*m
+ * since m is an integer, the dominant term is exact.
+ * m has at most 10 digits (for subnormal numbers),
+ * and log2_hi has 11 trailing zero bits.
+ *
+ * log(F) = logF_hi[j] + logF_lo[j] is in tabular form in log_table.h
+ * logF_hi[] + 512 is exact.
+ *
+ * log(1+f/F) = 2*f/(2*F + f) + 1/12 * (2*f/(2*F + f))**3 + ...
+ * the leading term is calculated to extra precision in two
+ * parts, the larger of which adds exactly to the dominant
+ * m and F terms.
+ * There are two cases:
+ *     1. when m, j are non-zero (m | j), use absolute
+ *        precision for the leading term.
+ *     2. when m = j = 0, |1-x| < 1/256, and log(x) ~= (x-1).
+ *        In this case, use a relative precision of 24 bits.
+ * (This is done differently in the original paper)
+ *
+ * Special cases:
+ *     0       return signalling -Inf
+ *     neg     return signalling NaN
+ *     +Inf    return +Inf
+*/
+
+#define N 128
+
+/* Table of log(Fj) = logF_head[j] + logF_tail[j], for Fj = 1+j/128.
+ * Used for generation of extend precision logarithms.
+ * The constant 35184372088832 is 2^45, so the divide is exact.
+ * It ensures correct reading of logF_head, even for inaccurate
+ * decimal-to-binary conversion routines.  (Everybody gets the
+ * right answer for integers less than 2^53.)
+ * Values for log(F) were generated using error < 10^-57 absolute
+ * with the bc -l package.
+*/
+static double  A1 =      .08333333333333178827;
+static double  A2 =      .01250000000377174923;
+static double  A3 =     .002232139987919447809;
+static double  A4 =    .0004348877777076145742;
+
+static double logF_head[N+1] = {
+       0.,
+       .007782140442060381246,
+       .015504186535963526694,
+       .023167059281547608406,
+       .030771658666765233647,
+       .038318864302141264488,
+       .045809536031242714670,
+       .053244514518837604555,
+       .060624621816486978786,
+       .067950661908525944454,
+       .075223421237524235039,
+       .082443669210988446138,
+       .089612158689760690322,
+       .096729626458454731618,
+       .103796793681567578460,
+       .110814366340264314203,
+       .117783035656430001836,
+       .124703478501032805070,
+       .131576357788617315236,
+       .138402322859292326029,
+       .145182009844575077295,
+       .151916042025732167530,
+       .158605030176659056451,
+       .165249572895390883786,
+       .171850256926518341060,
+       .178407657472689606947,
+       .184922338493834104156,
+       .191394852999565046047,
+       .197825743329758552135,
+       .204215541428766300668,
+       .210564769107350002741,
+       .216873938300523150246,
+       .223143551314024080056,
+       .229374101064877322642,
+       .235566071312860003672,
+       .241719936886966024758,
+       .247836163904594286577,
+       .253915209980732470285,
+       .259957524436686071567,
+       .265963548496984003577,
+       .271933715484010463114,
+       .277868451003087102435,
+       .283768173130738432519,
+       .289633292582948342896,
+       .295464212893421063199,
+       .301261330578199704177,
+       .307025035294827830512,
+       .312755710004239517729,
+       .318453731118097493890,
+       .324119468654316733591,
+       .329753286372579168528,
+       .335355541920762334484,
+       .340926586970454081892,
+       .346466767346100823488,
+       .351976423156884266063,
+       .357455888922231679316,
+       .362905493689140712376,
+       .368325561158599157352,
+       .373716409793814818840,
+       .379078352934811846353,
+       .384411698910298582632,
+       .389716751140440464951,
+       .394993808240542421117,
+       .400243164127459749579,
+       .405465108107819105498,
+       .410659924985338875558,
+       .415827895143593195825,
+       .420969294644237379543,
+       .426084395310681429691,
+       .431173464818130014464,
+       .436236766774527495726,
+       .441274560805140936281,
+       .446287102628048160113,
+       .451274644139630254358,
+       .456237433481874177232,
+       .461175715122408291790,
+       .466089729924533457960,
+       .470979715219073113985,
+       .475845904869856894947,
+       .480688529345570714212,
+       .485507815781602403149,
+       .490303988045525329653,
+       .495077266798034543171,
+       .499827869556611403822,
+       .504556010751912253908,
+       .509261901790523552335,
+       .513945751101346104405,
+       .518607764208354637958,
+       .523248143765158602036,
+       .527867089620485785417,
+       .532464798869114019908,
+       .537041465897345915436,
+       .541597282432121573947,
+       .546132437597407260909,
+       .550647117952394182793,
+       .555141507540611200965,
+       .559615787935399566777,
+       .564070138285387656651,
+       .568504735352689749561,
+       .572919753562018740922,
+       .577315365035246941260,
+       .581691739635061821900,
+       .586049045003164792433,
+       .590387446602107957005,
+       .594707107746216934174,
+       .599008189645246602594,
+       .603290851438941899687,
+       .607555250224322662688,
+       .611801541106615331955,
+       .616029877215623855590,
+       .620240409751204424537,
+       .624433288012369303032,
+       .628608659422752680256,
+       .632766669570628437213,
+       .636907462236194987781,
+       .641031179420679109171,
+       .645137961373620782978,
+       .649227946625615004450,
+       .653301272011958644725,
+       .657358072709030238911,
+       .661398482245203922502,
+       .665422632544505177065,
+       .669430653942981734871,
+       .673422675212350441142,
+       .677398823590920073911,
+       .681359224807238206267,
+       .685304003098281100392,
+       .689233281238557538017,
+       .693147180560117703862
+};
+
+static double logF_tail[N+1] = {
+       0.,
+       -.00000000000000543229938420049,
+        .00000000000000172745674997061,
+       -.00000000000001323017818229233,
+       -.00000000000001154527628289872,
+       -.00000000000000466529469958300,
+        .00000000000005148849572685810,
+       -.00000000000002532168943117445,
+       -.00000000000005213620639136504,
+       -.00000000000001819506003016881,
+        .00000000000006329065958724544,
+        .00000000000008614512936087814,
+       -.00000000000007355770219435028,
+        .00000000000009638067658552277,
+        .00000000000007598636597194141,
+        .00000000000002579999128306990,
+       -.00000000000004654729747598444,
+       -.00000000000007556920687451336,
+        .00000000000010195735223708472,
+       -.00000000000017319034406422306,
+       -.00000000000007718001336828098,
+        .00000000000010980754099855238,
+       -.00000000000002047235780046195,
+       -.00000000000008372091099235912,
+        .00000000000014088127937111135,
+        .00000000000012869017157588257,
+        .00000000000017788850778198106,
+        .00000000000006440856150696891,
+        .00000000000016132822667240822,
+       -.00000000000007540916511956188,
+       -.00000000000000036507188831790,
+        .00000000000009120937249914984,
+        .00000000000018567570959796010,
+       -.00000000000003149265065191483,
+       -.00000000000009309459495196889,
+        .00000000000017914338601329117,
+       -.00000000000001302979717330866,
+        .00000000000023097385217586939,
+        .00000000000023999540484211737,
+        .00000000000015393776174455408,
+       -.00000000000036870428315837678,
+        .00000000000036920375082080089,
+       -.00000000000009383417223663699,
+        .00000000000009433398189512690,
+        .00000000000041481318704258568,
+       -.00000000000003792316480209314,
+        .00000000000008403156304792424,
+       -.00000000000034262934348285429,
+        .00000000000043712191957429145,
+       -.00000000000010475750058776541,
+       -.00000000000011118671389559323,
+        .00000000000037549577257259853,
+        .00000000000013912841212197565,
+        .00000000000010775743037572640,
+        .00000000000029391859187648000,
+       -.00000000000042790509060060774,
+        .00000000000022774076114039555,
+        .00000000000010849569622967912,
+       -.00000000000023073801945705758,
+        .00000000000015761203773969435,
+        .00000000000003345710269544082,
+       -.00000000000041525158063436123,
+        .00000000000032655698896907146,
+       -.00000000000044704265010452446,
+        .00000000000034527647952039772,
+       -.00000000000007048962392109746,
+        .00000000000011776978751369214,
+       -.00000000000010774341461609578,
+        .00000000000021863343293215910,
+        .00000000000024132639491333131,
+        .00000000000039057462209830700,
+       -.00000000000026570679203560751,
+        .00000000000037135141919592021,
+       -.00000000000017166921336082431,
+       -.00000000000028658285157914353,
+       -.00000000000023812542263446809,
+        .00000000000006576659768580062,
+       -.00000000000028210143846181267,
+        .00000000000010701931762114254,
+        .00000000000018119346366441110,
+        .00000000000009840465278232627,
+       -.00000000000033149150282752542,
+       -.00000000000018302857356041668,
+       -.00000000000016207400156744949,
+        .00000000000048303314949553201,
+       -.00000000000071560553172382115,
+        .00000000000088821239518571855,
+       -.00000000000030900580513238244,
+       -.00000000000061076551972851496,
+        .00000000000035659969663347830,
+        .00000000000035782396591276383,
+       -.00000000000046226087001544578,
+        .00000000000062279762917225156,
+        .00000000000072838947272065741,
+        .00000000000026809646615211673,
+       -.00000000000010960825046059278,
+        .00000000000002311949383800537,
+       -.00000000000058469058005299247,
+       -.00000000000002103748251144494,
+       -.00000000000023323182945587408,
+       -.00000000000042333694288141916,
+       -.00000000000043933937969737844,
+        .00000000000041341647073835565,
+        .00000000000006841763641591466,
+        .00000000000047585534004430641,
+        .00000000000083679678674757695,
+       -.00000000000085763734646658640,
+        .00000000000021913281229340092,
+       -.00000000000062242842536431148,
+       -.00000000000010983594325438430,
+        .00000000000065310431377633651,
+       -.00000000000047580199021710769,
+       -.00000000000037854251265457040,
+        .00000000000040939233218678664,
+        .00000000000087424383914858291,
+        .00000000000025218188456842882,
+       -.00000000000003608131360422557,
+       -.00000000000050518555924280902,
+        .00000000000078699403323355317,
+       -.00000000000067020876961949060,
+        .00000000000016108575753932458,
+        .00000000000058527188436251509,
+       -.00000000000035246757297904791,
+       -.00000000000018372084495629058,
+        .00000000000088606689813494916,
+        .00000000000066486268071468700,
+        .00000000000063831615170646519,
+        .00000000000025144230728376072,
+       -.00000000000017239444525614834
+};
+
+#if 0
+OLM_DLLEXPORT double
+#ifdef _ANSI_SOURCE
+log(double x)
+#else
+log(x) double x;
+#endif
+{
+       int m, j;
+       double F, f, g, q, u, u2, v, zero = 0.0, one = 1.0;
+       volatile double u1;
+
+       /* Catch special cases */
+       if (x <= 0)
+               if (x == zero)  /* log(0) = -Inf */
+                       return (-one/zero);
+               else            /* log(neg) = NaN */
+                       return (zero/zero);
+       else if (!finite(x))
+               return (x+x);           /* x = NaN, Inf */
+
+       /* Argument reduction: 1 <= g < 2; x/2^m = g;   */
+       /* y = F*(1 + f/F) for |f| <= 2^-8              */
+
+       m = logb(x);
+       g = ldexp(x, -m);
+       if (m == -1022) {
+               j = logb(g), m += j;
+               g = ldexp(g, -j);
+       }
+       j = N*(g-1) + .5;
+       F = (1.0/N) * j + 1;    /* F*128 is an integer in [128, 512] */
+       f = g - F;
+
+       /* Approximate expansion for log(1+f/F) ~= u + q */
+       g = 1/(2*F+f);
+       u = 2*f*g;
+       v = u*u;
+       q = u*v*(A1 + v*(A2 + v*(A3 + v*A4)));
+
+    /* case 1: u1 = u rounded to 2^-43 absolute.  Since u < 2^-8,
+     *                u1 has at most 35 bits, and F*u1 is exact, as F has < 8 bits.
+     *         It also adds exactly to |m*log2_hi + log_F_head[j] | < 750
+    */
+       if (m | j)
+               u1 = u + 513, u1 -= 513;
+
+    /* case 2: |1-x| < 1/256. The m- and j- dependent terms are zero;
+     *                 u1 = u to 24 bits.
+    */
+       else
+               u1 = u, TRUNC(u1);
+       u2 = (2.0*(f - F*u1) - u1*f) * g;
+                       /* u1 + u2 = 2f/(2F+f) to extra precision.      */
+
+       /* log(x) = log(2^m*F*(1+f/F)) =                                */
+       /* (m*log2_hi+logF_head[j]+u1) + (m*log2_lo+logF_tail[j]+q);    */
+       /* (exact) + (tiny)                                             */
+
+       u1 += m*logF_head[N] + logF_head[j];            /* exact */
+       u2 = (u2 + logF_tail[j]) + q;                   /* tiny */
+       u2 += logF_tail[N]*m;
+       return (u1 + u2);
+}
+#endif
+
+/*
+ * Extra precision variant, returning struct {double a, b;};
+ * log(x) = a+b to 63 bits, with a rounded to 26 bits.
+ */
+struct Double
+#ifdef _ANSI_SOURCE
+__log__D(double x)
+#else
+__log__D(x) double x;
+#endif
+{
+       int m, j;
+       double F, f, g, q, u, v, u2;
+       volatile double u1;
+       struct Double r;
+
+       /* Argument reduction: 1 <= g < 2; x/2^m = g;   */
+       /* y = F*(1 + f/F) for |f| <= 2^-8              */
+
+       m = logb(x);
+       g = ldexp(x, -m);
+       if (m == -1022) {
+               j = logb(g), m += j;
+               g = ldexp(g, -j);
+       }
+       j = N*(g-1) + .5;
+       F = (1.0/N) * j + 1;
+       f = g - F;
+
+       g = 1/(2*F+f);
+       u = 2*f*g;
+       v = u*u;
+       q = u*v*(A1 + v*(A2 + v*(A3 + v*A4)));
+       if (m | j)
+               u1 = u + 513, u1 -= 513;
+       else
+               u1 = u, TRUNC(u1);
+       u2 = (2.0*(f - F*u1) - u1*f) * g;
+
+       u1 += m*logF_head[N] + logF_head[j];
+
+       u2 +=  logF_tail[j]; u2 += q;
+       u2 += logF_tail[N]*m;
+       r.a = u1 + u2;                  /* Only difference is here */
+       TRUNC(r.a);
+       r.b = (u1 - r.a) + u2;
+       return (r);
+}
diff --git a/bsdsrc/b_tgamma.c b/bsdsrc/b_tgamma.c
new file mode 100644 (file)
index 0000000..7f5f094
--- /dev/null
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/* @(#)gamma.c 8.1 (Berkeley) 6/4/93 */
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_tgamma.c,v 1.10 2008/02/22 02:26:51 das Exp $");
+
+/*
+ * This code by P. McIlroy, Oct 1992;
+ *
+ * The financial support of UUNET Communications Services is greatfully
+ * acknowledged.
+ */
+
+#include <openlibm_math.h>
+
+#include "mathimpl.h"
+
+/* METHOD:
+ * x < 0: Use reflection formula, G(x) = pi/(sin(pi*x)*x*G(x))
+ *     At negative integers, return NaN and raise invalid.
+ *
+ * x < 6.5:
+ *     Use argument reduction G(x+1) = xG(x) to reach the
+ *     range [1.066124,2.066124].  Use a rational
+ *     approximation centered at the minimum (x0+1) to
+ *     ensure monotonicity.
+ *
+ * x >= 6.5: Use the asymptotic approximation (Stirling's formula)
+ *     adjusted for equal-ripples:
+ *
+ *     log(G(x)) ~= (x-.5)*(log(x)-1) + .5(log(2*pi)-1) + 1/x*P(1/(x*x))
+ *
+ *     Keep extra precision in multiplying (x-.5)(log(x)-1), to
+ *     avoid premature round-off.
+ *
+ * Special values:
+ *     -Inf:                   return NaN and raise invalid;
+ *     negative integer:       return NaN and raise invalid;
+ *     other x ~< 177.79:      return +-0 and raise underflow;
+ *     +-0:                    return +-Inf and raise divide-by-zero;
+ *     finite x ~> 171.63:     return +Inf and raise overflow;
+ *     +Inf:                   return +Inf;
+ *     NaN:                    return NaN.
+ *
+ * Accuracy: tgamma(x) is accurate to within
+ *     x > 0:  error provably < 0.9ulp.
+ *     Maximum observed in 1,000,000 trials was .87ulp.
+ *     x < 0:
+ *     Maximum observed error < 4ulp in 1,000,000 trials.
+ */
+
+static double neg_gam(double);
+static double small_gam(double);
+static double smaller_gam(double);
+static struct Double large_gam(double);
+static struct Double ratfun_gam(double, double);
+
+/*
+ * Rational approximation, A0 + x*x*P(x)/Q(x), on the interval
+ * [1.066.., 2.066..] accurate to 4.25e-19.
+ */
+#define LEFT -.3955078125      /* left boundary for rat. approx */
+#define x0 .461632144968362356785      /* xmin - 1 */
+
+#define a0_hi 0.88560319441088874992
+#define a0_lo -.00000000000000004996427036469019695
+#define P0      6.21389571821820863029017800727e-01
+#define P1      2.65757198651533466104979197553e-01
+#define P2      5.53859446429917461063308081748e-03
+#define P3      1.38456698304096573887145282811e-03
+#define P4      2.40659950032711365819348969808e-03
+#define Q0      1.45019531250000000000000000000e+00
+#define Q1      1.06258521948016171343454061571e+00
+#define Q2     -2.07474561943859936441469926649e-01
+#define Q3     -1.46734131782005422506287573015e-01
+#define Q4      3.07878176156175520361557573779e-02
+#define Q5      5.12449347980666221336054633184e-03
+#define Q6     -1.76012741431666995019222898833e-03
+#define Q7      9.35021023573788935372153030556e-05
+#define Q8      6.13275507472443958924745652239e-06
+/*
+ * Constants for large x approximation (x in [6, Inf])
+ * (Accurate to 2.8*10^-19 absolute)
+ */
+#define lns2pi_hi 0.418945312500000
+#define lns2pi_lo -.000006779295327258219670263595
+#define Pa0     8.33333333333333148296162562474e-02
+#define Pa1    -2.77777777774548123579378966497e-03
+#define Pa2     7.93650778754435631476282786423e-04
+#define Pa3    -5.95235082566672847950717262222e-04
+#define Pa4     8.41428560346653702135821806252e-04
+#define Pa5    -1.89773526463879200348872089421e-03
+#define Pa6     5.69394463439411649408050664078e-03
+#define Pa7    -1.44705562421428915453880392761e-02
+
+static const double zero = 0., one = 1.0, tiny = 1e-300;
+
+OLM_DLLEXPORT double
+tgamma(x)
+       double x;
+{
+       struct Double u;
+
+       if (isgreaterequal(x, 6)) {
+               if(x > 171.63)
+                       return (x / zero);
+               u = large_gam(x);
+               return(__exp__D(u.a, u.b));
+       } else if (isgreaterequal(x, 1.0 + LEFT + x0))
+               return (small_gam(x));
+       else if (isgreater(x, 1.e-17))
+               return (smaller_gam(x));
+       else if (isgreater(x, -1.e-17)) {
+               if (x != 0.0)
+                       u.a = one - tiny;       /* raise inexact */
+               return (one/x);
+       } else if (!isfinite(x))
+               return (x - x);         /* x is NaN or -Inf */
+       else
+               return (neg_gam(x));
+}
+/*
+ * Accurate to max(ulp(1/128) absolute, 2^-66 relative) error.
+ */
+static struct Double
+large_gam(x)
+       double x;
+{
+       double z, p;
+       struct Double t, u, v;
+
+       z = one/(x*x);
+       p = Pa0+z*(Pa1+z*(Pa2+z*(Pa3+z*(Pa4+z*(Pa5+z*(Pa6+z*Pa7))))));
+       p = p/x;
+
+       u = __log__D(x);
+       u.a -= one;
+       v.a = (x -= .5);
+       TRUNC(v.a);
+       v.b = x - v.a;
+       t.a = v.a*u.a;                  /* t = (x-.5)*(log(x)-1) */
+       t.b = v.b*u.a + x*u.b;
+       /* return t.a + t.b + lns2pi_hi + lns2pi_lo + p */
+       t.b += lns2pi_lo; t.b += p;
+       u.a = lns2pi_hi + t.b; u.a += t.a;
+       u.b = t.a - u.a;
+       u.b += lns2pi_hi; u.b += t.b;
+       return (u);
+}
+/*
+ * Good to < 1 ulp.  (provably .90 ulp; .87 ulp on 1,000,000 runs.)
+ * It also has correct monotonicity.
+ */
+static double
+small_gam(x)
+       double x;
+{
+       double y, ym1, t;
+       struct Double yy, r;
+       y = x - one;
+       ym1 = y - one;
+       if (y <= 1.0 + (LEFT + x0)) {
+               yy = ratfun_gam(y - x0, 0);
+               return (yy.a + yy.b);
+       }
+       r.a = y;
+       TRUNC(r.a);
+       yy.a = r.a - one;
+       y = ym1;
+       yy.b = r.b = y - yy.a;
+       /* Argument reduction: G(x+1) = x*G(x) */
+       for (ym1 = y-one; ym1 > LEFT + x0; y = ym1--, yy.a--) {
+               t = r.a*yy.a;
+               r.b = r.a*yy.b + y*r.b;
+               r.a = t;
+               TRUNC(r.a);
+               r.b += (t - r.a);
+       }
+       /* Return r*tgamma(y). */
+       yy = ratfun_gam(y - x0, 0);
+       y = r.b*(yy.a + yy.b) + r.a*yy.b;
+       y += yy.a*r.a;
+       return (y);
+}
+/*
+ * Good on (0, 1+x0+LEFT].  Accurate to 1ulp.
+ */
+static double
+smaller_gam(x)
+       double x;
+{
+       double t, d;
+       struct Double r, xx;
+       if (x < x0 + LEFT) {
+               t = x, TRUNC(t);
+               d = (t+x)*(x-t);
+               t *= t;
+               xx.a = (t + x), TRUNC(xx.a);
+               xx.b = x - xx.a; xx.b += t; xx.b += d;
+               t = (one-x0); t += x;
+               d = (one-x0); d -= t; d += x;
+               x = xx.a + xx.b;
+       } else {
+               xx.a =  x, TRUNC(xx.a);
+               xx.b = x - xx.a;
+               t = x - x0;
+               d = (-x0 -t); d += x;
+       }
+       r = ratfun_gam(t, d);
+       d = r.a/x, TRUNC(d);
+       r.a -= d*xx.a; r.a -= d*xx.b; r.a += r.b;
+       return (d + r.a/x);
+}
+/*
+ * returns (z+c)^2 * P(z)/Q(z) + a0
+ */
+static struct Double
+ratfun_gam(z, c)
+       double z, c;
+{
+       double p, q;
+       struct Double r, t;
+
+       q = Q0 +z*(Q1+z*(Q2+z*(Q3+z*(Q4+z*(Q5+z*(Q6+z*(Q7+z*Q8)))))));
+       p = P0 + z*(P1 + z*(P2 + z*(P3 + z*P4)));
+
+       /* return r.a + r.b = a0 + (z+c)^2*p/q, with r.a truncated to 26 bits. */
+       p = p/q;
+       t.a = z, TRUNC(t.a);            /* t ~= z + c */
+       t.b = (z - t.a) + c;
+       t.b *= (t.a + z);
+       q = (t.a *= t.a);               /* t = (z+c)^2 */
+       TRUNC(t.a);
+       t.b += (q - t.a);
+       r.a = p, TRUNC(r.a);            /* r = P/Q */
+       r.b = p - r.a;
+       t.b = t.b*p + t.a*r.b + a0_lo;
+       t.a *= r.a;                     /* t = (z+c)^2*(P/Q) */
+       r.a = t.a + a0_hi, TRUNC(r.a);
+       r.b = ((a0_hi-r.a) + t.a) + t.b;
+       return (r);                     /* r = a0 + t */
+}
+
+static double
+neg_gam(x)
+       double x;
+{
+       int sgn = 1;
+       struct Double lg, lsine;
+       double y, z;
+
+       y = ceil(x);
+       if (y == x)             /* Negative integer. */
+               return ((x - x) / zero);
+       z = y - x;
+       if (z > 0.5)
+               z = one - z;
+       y = 0.5 * y;
+       if (y == ceil(y))
+               sgn = -1;
+       if (z < .25)
+               z = sin(M_PI*z);
+       else
+               z = cos(M_PI*(0.5-z));
+       /* Special case: G(1-x) = Inf; G(x) may be nonzero. */
+       if (x < -170) {
+               if (x < -190)
+                       return ((double)sgn*tiny*tiny);
+               y = one - x;            /* exact: 128 < |x| < 255 */
+               lg = large_gam(y);
+               lsine = __log__D(M_PI/z);       /* = TRUNC(log(u)) + small */
+               lg.a -= lsine.a;                /* exact (opposite signs) */
+               lg.b -= lsine.b;
+               y = -(lg.a + lg.b);
+               z = (y + lg.a) + lg.b;
+               y = __exp__D(y, z);
+               if (sgn < 0) y = -y;
+               return (y);
+       }
+       y = one-x;
+       if (one-y == x)
+               y = tgamma(y);
+       else            /* 1-x is inexact */
+               y = -x*tgamma(-x);
+       if (sgn < 0) y = -y;
+       return (M_PI / (y*z));
+}
diff --git a/bsdsrc/mathimpl.h b/bsdsrc/mathimpl.h
new file mode 100644 (file)
index 0000000..983c4eb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)mathimpl.h  8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/lib/msun/bsdsrc/mathimpl.h,v 1.7 2005/11/18 05:03:12 bde Exp $
+ */
+
+#ifndef _MATHIMPL_H_
+#define        _MATHIMPL_H_
+
+#include "cdefs-compat.h"
+#include "math_private.h"
+
+/*
+ * TRUNC() is a macro that sets the trailing 27 bits in the mantissa of an
+ * IEEE double variable to zero.  It must be expression-like for syntactic
+ * reasons, and we implement this expression using an inline function
+ * instead of a pure macro to avoid depending on the gcc feature of
+ * statement-expressions.
+ */
+#define        TRUNC(d)        (_b_trunc(&(d)))
+
+static __inline void
+_b_trunc(volatile double *_dp)
+{
+        //VBS
+        //u_int32_t _lw;
+       u_int32_t _lw;
+
+       GET_LOW_WORD(_lw, *_dp);
+       SET_LOW_WORD(*_dp, _lw & 0xf8000000);
+}
+
+struct Double {
+       double  a;
+       double  b;
+};
+
+/*
+ * Functions internal to the math package, yet not static.
+ */
+double __exp__D(double, double);
+struct Double __log__D(double);
+
+#endif /* !_MATHIMPL_H_ */
diff --git a/i387/Make.files b/i387/Make.files
new file mode 100644 (file)
index 0000000..369c541
--- /dev/null
@@ -0,0 +1,21 @@
+$(CUR_SRCS) = e_exp.S e_fmod.S e_log.S e_log10.S \
+           e_remainder.S e_sqrt.S s_ceil.S s_copysign.S \
+           s_floor.S s_llrint.S s_logb.S s_lrint.S \
+           s_remquo.S s_rint.S  s_tan.S s_trunc.S
+
+ifneq ($(OS), WINNT)
+$(CUR_SRCS) += s_scalbn.S s_scalbnf.S s_scalbnl.S
+endif          
+               
+# float counterparts
+$(CUR_SRCS)+= e_log10f.S e_logf.S e_remainderf.S \
+           e_sqrtf.S s_ceilf.S s_copysignf.S s_floorf.S \
+           s_llrintf.S s_logbf.S s_lrintf.S \
+           s_remquof.S s_rintf.S s_truncf.S
+
+# long double counterparts
+$(CUR_SRCS)+= e_remainderl.S e_sqrtl.S s_ceill.S s_copysignl.S \
+           s_floorl.S s_llrintl.S \
+           s_logbl.S s_lrintl.S s_remquol.S s_rintl.S s_truncl.S
+
+$(CUR_SRCS)+= fenv.c
diff --git a/i387/bsd_asm.h b/i387/bsd_asm.h
new file mode 100644 (file)
index 0000000..93ac617
--- /dev/null
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)DEFS.h        5.1 (Berkeley) 4/23/90
+ * $FreeBSD: src/sys/i386/include/asm.h,v 1.14 2007/08/22 04:26:07 jkoshy Exp $
+ */
+
+#ifndef _MACHINE_ASM_H_
+#define        _MACHINE_ASM_H_
+
+#if defined(__APPLE__)
+#include "osx_asm.h"
+#define CNAME(x) EXT(x)
+#else
+#include "cdefs-compat.h"
+
+#ifdef PIC
+#define        PIC_PROLOGUE    \
+       pushl   %ebx;   \
+       call    1f;     \
+1:                     \
+       popl    %ebx;   \
+       addl    $_GLOBAL_OFFSET_TABLE_+[.-1b],%ebx
+#define        PIC_EPILOGUE    \
+       popl    %ebx
+#define        PIC_PLT(x)      x@PLT
+#define        PIC_GOT(x)      x@GOT(%ebx)
+#else
+#define        PIC_PROLOGUE
+#define        PIC_EPILOGUE
+#define        PIC_PLT(x)      x
+#define        PIC_GOT(x)      x
+#endif
+
+/*
+ * CNAME and HIDENAME manage the relationship between symbol names in C
+ * and the equivalent assembly language names.  CNAME is given a name as
+ * it would be used in a C program.  It expands to the equivalent assembly
+ * language name.  HIDENAME is given an assembly-language name, and expands
+ * to a possibly-modified form that will be invisible to C programs.
+ */
+
+
+/* XXX should use .p2align 4,0x90 for -m486. */
+#define _START_ENTRY .p2align 2,0x90
+
+#if defined(__ELF__)
+#define CNAME(csym)            csym
+#define HIDENAME(asmsym)       .asmsym
+#define _ENTRY(x) .text; _START_ENTRY; \
+                       .globl CNAME(x); .type CNAME(x),@function; CNAME(x):
+#define        END(x)          .size x, . - x
+#elif defined(_WIN32)
+#ifndef _MSC_VER
+#define END(x) .end
+#define _START_ENTRY_WIN .text; _START_ENTRY
+#else
+#define END(x) end
+#define _START_ENTRY_WIN .code; _START_ENTRY
+#endif
+#define CNAME(csym)            _##csym
+#define HIDENAME(asmsym)       .asmsym
+#define _ENTRY(x) _START_ENTRY_WIN; \
+            .globl CNAME(x); .section .drectve; .ascii " -export:", #x; \
+            .section .text; .def CNAME(x); .scl 2; .type 32; .endef; CNAME(x):
+#endif
+
+#ifdef PROF
+#define        ALTENTRY(x)     _ENTRY(x); \
+                       pushl %ebp; movl %esp,%ebp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popl %ebp; \
+                       jmp 9f
+#define        ENTRY(x)        _ENTRY(x); \
+                       pushl %ebp; movl %esp,%ebp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popl %ebp; \
+                       9:
+#else
+#define        ALTENTRY(x)     _ENTRY(x)
+#define        ENTRY(x)        _ENTRY(x)
+#endif
+
+#define RCSID(x)       .text; .asciz x
+
+#undef __FBSDID
+#define __FBSDID(s)    /* nothing */
+
+#endif
+#endif /* !_MACHINE_ASM_H_ */
diff --git a/i387/bsd_ieeefp.h b/i387/bsd_ieeefp.h
new file mode 100644 (file)
index 0000000..79c7bf3
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1990 Andrew Moore, Talke Studio
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#) ieeefp.h     1.0 (Berkeley) 9/23/93
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_IEEEFP_H_
+#define _MACHINE_IEEEFP_H_
+
+/*
+ * Deprecated historical FPU control interface
+ *
+ * IEEE floating point type, constant and function definitions.
+ * XXX: FP*FLD and FP*OFF are undocumented pollution.
+ */
+
+/* VBS
+
+#ifndef _SYS_CDEFS_H_
+#error this file needs sys/cdefs.h as a prerequisite
+#endif
+
+*/
+
+/*
+ * Rounding modes.
+ */
+typedef enum {
+       FP_RN=0,        /* round to nearest */
+       FP_RM,          /* round down towards minus infinity */
+       FP_RP,          /* round up towards plus infinity */
+       FP_RZ           /* truncate */
+} fp_rnd_t;
+
+/*
+ * Precision (i.e., rounding precision) modes.
+ */
+typedef enum {
+       FP_PS=0,        /* 24 bit (single-precision) */
+       FP_PRS,         /* reserved */
+       FP_PD,          /* 53 bit (double-precision) */
+       FP_PE           /* 64 bit (extended-precision) */
+} fp_prec_t;
+
+#define fp_except_t    int
+
+/*
+ * Exception bit masks.
+ */
+#define FP_X_INV       0x01    /* invalid operation */
+#define FP_X_DNML      0x02    /* denormal */
+#define FP_X_DZ                0x04    /* zero divide */
+#define FP_X_OFL       0x08    /* overflow */
+#define FP_X_UFL       0x10    /* underflow */
+#define FP_X_IMP       0x20    /* (im)precision */
+#define FP_X_STK       0x40    /* stack fault */
+
+/*
+ * FPU control word bit-field masks.
+ */
+#define FP_MSKS_FLD    0x3f    /* exception masks field */
+#define FP_PRC_FLD     0x300   /* precision control field */
+#define        FP_RND_FLD      0xc00   /* rounding control field */
+
+/*
+ * FPU status word bit-field masks.
+ */
+#define FP_STKY_FLD    0x3f    /* sticky flags field */
+
+/*
+ * FPU control word bit-field offsets (shift counts).
+ */
+#define FP_MSKS_OFF    0       /* exception masks offset */
+#define FP_PRC_OFF     8       /* precision control offset */
+#define        FP_RND_OFF      10      /* rounding control offset */
+
+/*
+ * FPU status word bit-field offsets (shift counts).
+ */
+#define FP_STKY_OFF    0       /* sticky flags offset */
+
+//VBS
+//#ifdef __GNUCLIKE_ASM
+
+#define        __fldcw(addr)   __asm __volatile("fldcw %0" : : "m" (*(addr)))
+#define        __fldenv(addr)  __asm __volatile("fldenv %0" : : "m" (*(addr)))
+#define        __fnclex()      __asm __volatile("fnclex")
+#define        __fnstcw(addr)  __asm __volatile("fnstcw %0" : "=m" (*(addr)))
+#define        __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr)))
+#define        __fnstsw(addr)  __asm __volatile("fnstsw %0" : "=m" (*(addr)))
+
+/*
+ * Load the control word.  Be careful not to trap if there is a currently
+ * unmasked exception (ones that will become freshly unmasked are not a
+ * problem).  This case must be handled by a save/restore of the
+ * environment or even of the full x87 state.  Accessing the environment
+ * is very inefficient, so only do it when necessary.
+ */
+static __inline void
+__fnldcw(unsigned short _cw, unsigned short _newcw)
+{
+       struct {
+               unsigned _cw;
+               unsigned _other[6];
+       } _env;
+       unsigned short _sw;
+
+       if ((_cw & FP_MSKS_FLD) != FP_MSKS_FLD) {
+               __fnstsw(&_sw);
+               if (((_sw & ~_cw) & FP_STKY_FLD) != 0) {
+                       __fnstenv(&_env);
+                       _env._cw = _newcw;
+                       __fldenv(&_env);
+                       return;
+               }
+       }
+       __fldcw(&_newcw);
+}
+
+static __inline fp_rnd_t
+fpgetround(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF));
+}
+
+static __inline fp_rnd_t
+fpsetround(fp_rnd_t _m)
+{
+       fp_rnd_t _p;
+       unsigned short _cw, _newcw;
+
+       __fnstcw(&_cw);
+       _p = (fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF);
+       _newcw = _cw & ~FP_RND_FLD;
+       _newcw |= (_m << FP_RND_OFF) & FP_RND_FLD;
+       __fnldcw(_cw, _newcw);
+       return (_p);
+}
+
+//static __inline fp_prec_t
+OLM_DLLEXPORT fp_prec_t
+fpgetprec(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF));
+}
+
+//static __inline fp_prec_t
+OLM_DLLEXPORT fp_prec_t
+fpsetprec(fp_prec_t _m)
+{
+       fp_prec_t _p;
+       unsigned short _cw, _newcw;
+
+       __fnstcw(&_cw);
+       _p = (fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF);
+       _newcw = _cw & ~FP_PRC_FLD;
+       _newcw |= (_m << FP_PRC_OFF) & FP_PRC_FLD;
+       __fnldcw(_cw, _newcw);
+       return (_p);
+}
+
+/*
+ * Get or set the exception mask.
+ * Note that the x87 mask bits are inverted by the API -- a mask bit of 1
+ * means disable for x87 and SSE, but for fp*mask() it means enable.
+ */
+
+static __inline fp_except_t
+fpgetmask(void)
+{
+       unsigned short _cw;
+
+       __fnstcw(&_cw);
+       return ((~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF);
+}
+
+static __inline fp_except_t
+fpsetmask(fp_except_t _m)
+{
+       fp_except_t _p;
+       unsigned short _cw, _newcw;
+
+       __fnstcw(&_cw);
+       _p = (~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF;
+       _newcw = _cw & ~FP_MSKS_FLD;
+       _newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD;
+       __fnldcw(_cw, _newcw);
+       return (_p);
+}
+
+static __inline fp_except_t
+fpgetsticky(void)
+{
+       unsigned _ex;
+       unsigned short _sw;
+
+       __fnstsw(&_sw);
+       _ex = (_sw & FP_STKY_FLD) >> FP_STKY_OFF;
+       return ((fp_except_t)_ex);
+}
+
+static __inline fp_except_t
+fpresetsticky(fp_except_t _m)
+{
+       struct {
+               unsigned _cw;
+               unsigned _sw;
+               unsigned _other[5];
+       } _env;
+       fp_except_t _p;
+
+       _m &= FP_STKY_FLD >> FP_STKY_OFF;
+       _p = fpgetsticky();
+       if ((_p & ~_m) == _p)
+               return (_p);
+       if ((_p & ~_m) == 0) {
+               __fnclex();
+               return (_p);
+       }
+       __fnstenv(&_env);
+       _env._sw &= ~_m;
+       __fldenv(&_env);
+       return (_p);
+}
+
+//#endif /* __GNUCLIKE_ASM */
+
+#endif /* !_MACHINE_IEEEFP_H_ */
diff --git a/i387/bsd_npx.h b/i387/bsd_npx.h
new file mode 100644 (file)
index 0000000..78c5cbe
--- /dev/null
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $FreeBSD: src/sys/i386/include/npx.h,v 1.29.2.1 2006/07/01 00:57:55 davidxu Exp $
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef _MACHINE_NPX_H_
+#define        _MACHINE_NPX_H_
+
+/* Environment information of floating point unit */
+struct env87 {
+       long    en_cw;          /* control word (16bits) */
+       long    en_sw;          /* status word (16bits) */
+       long    en_tw;          /* tag word (16bits) */
+       long    en_fip;         /* floating point instruction pointer */
+       unsigned short  en_fcs;         /* floating code segment selector */
+       unsigned short  en_opcode;      /* opcode last executed (11 bits ) */
+       long    en_foo;         /* floating operand offset */
+       long    en_fos;         /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+       unsigned long   fp_mantlo;      /* mantissa low (31:0) */
+       unsigned long   fp_manthi;      /* mantissa high (63:32) */
+       int     fp_exp:15;      /* exponent */
+       int     fp_sgn:1;       /* mantissa sign */
+#else
+       unsigned char   fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+       struct  env87 sv_env;   /* floating point control/status */
+       struct  fpacc87 sv_ac[8];       /* accumulator contents, 0-7 */
+       unsigned char   sv_pad0[4];     /* padding for (now unused) saved status word */
+       /*
+        * Bogus padding for emulators.  Emulators should use their own
+        * struct and arrange to store into this struct (ending here)
+        * before it is inspected for ptracing or for core dumps.  Some
+        * emulators overwrite the whole struct.  We have no good way of
+        * knowing how much padding to leave.  Leave just enough for the
+        * GPL emulator's i387_union (176 bytes total).
+        */
+       unsigned char   sv_pad[64];     /* padding; used by emulators */
+};
+
+struct  envxmm {
+       uint16_t        en_cw;          /* control word (16bits) */
+       uint16_t        en_sw;          /* status word (16bits) */
+       uint16_t        en_tw;          /* tag word (16bits) */
+       uint16_t        en_opcode;      /* opcode last executed (11 bits ) */
+       uint32_t        en_fip;         /* floating point instruction pointer */
+       uint16_t        en_fcs;         /* floating code segment selector */
+       uint16_t        en_pad0;        /* padding */
+       uint32_t        en_foo;         /* floating operand offset */
+       uint16_t        en_fos;         /* floating operand segment selector */
+       uint16_t        en_pad1;        /* padding */
+       uint32_t        en_mxcsr;       /* SSE sontorol/status register */
+       uint32_t        en_mxcsr_mask;  /* valid bits in mxcsr */
+};
+
+/* Contents of each SSE extended accumulator */
+struct  xmmacc {
+       unsigned char   xmm_bytes[16];
+};
+
+struct  savexmm {
+       struct  envxmm  sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               unsigned char           fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc   sv_xmm[8];
+       unsigned char sv_pad[224];
+}  __attribute__((__aligned__(16)));
+
+union  savefpu {
+       struct  save87  sv_87;
+       struct  savexmm sv_xmm;
+};
+
+/*
+ * The hardware default control word for i387's and later coprocessors is
+ * 0x37F, giving:
+ *
+ *     round to nearest
+ *     64-bit precision
+ *     all exceptions masked.
+ *
+ * We modify the affine mode bit and precision bits in this to give:
+ *
+ *     affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ *     53-bit precision (2 in bitfield 3<<8)
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ */
+#define        __INITIAL_NPXCW__       0x127F
+#define        __INITIAL_MXCSR__       0x1F80
+
+#ifdef _KERNEL
+
+#define        IO_NPX          0x0F0           /* Numeric Coprocessor */
+#define        IO_NPXSIZE      16              /* 80387/80487 NPX registers */
+
+#define        IRQ_NPX         13
+
+/* full reset on some systems, NOP on others */
+#define npx_full_reset() outb(IO_NPX + 1, 0)
+
+int    npxdna(void);
+void   npxdrop(void);
+void   npxexit(struct thread *td);
+int    npxformat(void);
+int    npxgetregs(struct thread *td, union savefpu *addr);
+void   npxinit(unsigned short control);
+void   npxsave(union savefpu *addr);
+void   npxsetregs(struct thread *td, union savefpu *addr);
+int    npxtrap(void);
+#endif
+
+#endif /* !_MACHINE_NPX_H_ */
\ No newline at end of file
diff --git a/i387/e_exp.S b/i387/e_exp.S
new file mode 100644 (file)
index 0000000..0f03f9e
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+/* e^x = 2^(x * log2(e)) */
+
+ENTRY(exp)
+       /*
+        * If x is +-Inf, then the subtraction would give Inf-Inf = NaN.
+        * Avoid this.  Also avoid it if x is NaN for convenience.
+        */
+       movl    8(%esp),%eax
+       andl    $0x7fffffff,%eax
+       cmpl    $0x7ff00000,%eax
+       jae     x_Inf_or_NaN
+
+       fldl    4(%esp)
+
+       /*
+        * Extended precision is needed to reduce the maximum error from
+        * hundreds of ulps to less than 1 ulp.  Switch to it if necessary.
+        * We may as well set the rounding mode to to-nearest and mask traps
+        * if we switch.
+        */
+       fstcw   4(%esp)
+       movl    4(%esp),%eax
+       andl    $0x0300,%eax
+       cmpl    $0x0300,%eax            /* RC == 0 && PC == 3? */
+       je      1f                      /* jump if mode is good */
+       movl    $0x137f,8(%esp)
+       fldcw   8(%esp)
+1:
+       fldl2e
+       fmulp                           /* x * log2(e) */
+       fst     %st(1)
+       frndint                         /* int(x * log2(e)) */
+       fst     %st(2)
+       fsubrp                          /* fract(x * log2(e)) */
+       f2xm1                           /* 2^(fract(x * log2(e))) - 1 */ 
+       fld1
+       faddp                           /* 2^(fract(x * log2(e))) */
+       fscale                          /* e^x */
+       fstp    %st(1)
+       je      1f
+       fldcw   4(%esp)
+1:
+       ret
+
+x_Inf_or_NaN:
+       /*
+        * Return 0 if x is -Inf.  Otherwise just return x; when x is Inf
+        * this gives Inf, and when x is a NaN this gives the same result
+        * as (x + x) (x quieted).
+        */
+       cmpl    $0xfff00000,8(%esp)
+       jne     x_not_minus_Inf
+       cmpl    $0,4(%esp)
+       jne     x_not_minus_Inf
+       fldz
+       ret
+
+x_not_minus_Inf:
+       fldl    4(%esp)
+       ret
+END(exp)
+
+    //
+
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_fmod.S b/i387/e_fmod.S
new file mode 100644 (file)
index 0000000..44e52e5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_fmod.S,v 1.11 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(fmod)
+       fldl    12(%esp)
+       fldl    4(%esp)
+1:     fprem
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+       ret
+END(fmod)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_log.S b/i387/e_log.S
new file mode 100644 (file)
index 0000000..ebd6ae7
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(log)
+       fldln2
+       fldl    4(%esp)
+       fyl2x
+       ret
+END(log)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_log10.S b/i387/e_log10.S
new file mode 100644 (file)
index 0000000..b559a74
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log10.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(log10)
+       fldlg2
+       fldl    4(%esp)
+       fyl2x
+       ret
+END(log10)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_log10f.S b/i387/e_log10f.S
new file mode 100644 (file)
index 0000000..afdf1b0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log10f.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: e_log10f.S,v 1.1 1996/07/03 16:50:22 jtc Exp $") */
+
+ENTRY(log10f)
+       fldlg2
+       flds    4(%esp)
+       fyl2x
+       ret
+END(log10f)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_logf.S b/i387/e_logf.S
new file mode 100644 (file)
index 0000000..af06fd8
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_logf.S,v 1.3 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: e_logf.S,v 1.2 1996/07/06 00:15:45 jtc Exp $") */
+
+ENTRY(logf)
+       fldln2
+       flds    4(%esp)
+       fyl2x
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_remainder.S b/i387/e_remainder.S
new file mode 100644 (file)
index 0000000..2aa3113
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainder.S,v 1.11 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(remainder)
+       fldl    12(%esp)
+       fldl    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+       ret
+END(remainder)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_remainderf.S b/i387/e_remainderf.S
new file mode 100644 (file)
index 0000000..2b7b597
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainderf.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: e_remainderf.S,v 1.2 1995/05/08 23:49:47 jtc Exp $") */
+
+ENTRY(remainderf)
+       flds    8(%esp)
+       flds    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+       ret
+END(remainderf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_remainderl.S b/i387/e_remainderl.S
new file mode 100644 (file)
index 0000000..04d460b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainderl.S,v 1.2 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(remainderl)
+       fldt    16(%esp)
+       fldt    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_sqrt.S b/i387/e_sqrt.S
new file mode 100644 (file)
index 0000000..7c36dfe
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrt.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(sqrt)
+       fldl    4(%esp)
+       fsqrt
+       ret
+END(sqrt)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_sqrtf.S b/i387/e_sqrtf.S
new file mode 100644 (file)
index 0000000..05fb77f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrtf.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: e_sqrtf.S,v 1.2 1995/05/08 23:50:14 jtc Exp $") */
+
+ENTRY(sqrtf)
+       flds    4(%esp)
+       fsqrt
+       ret
+END(sqrtf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/e_sqrtl.S b/i387/e_sqrtl.S
new file mode 100644 (file)
index 0000000..5317f95
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrtl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(sqrtl)
+       fldt    4(%esp)
+       fsqrt
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/fenv.c b/i387/fenv.c
new file mode 100644 (file)
index 0000000..6afe766
--- /dev/null
@@ -0,0 +1,226 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/i387/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $
+ */
+
+#include "cdefs-compat.h"
+#include "types-compat.h"
+#include "math_private.h"
+#include "i387/bsd_npx.h"
+
+#define        __fenv_static
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+const fenv_t __fe_dfl_env = {
+       __INITIAL_NPXCW__,
+       0x0000,
+       0x0000,
+       0x1f80,
+       0xffffffff,
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
+};
+
+enum __sse_support __has_sse =
+#ifdef __SSE__
+       __SSE_YES;
+#else
+       __SSE_UNK;
+#endif
+
+#define        getfl(x)        __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x)))
+#define        setfl(x)        __asm __volatile("pushl %0\n\tpopfl" : : "g" (x))
+#define        cpuid_dx(x)     __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t"  \
+                                        "cpuid\n\tpopl %%ebx"                \
+                                       : "=d" (*(x)) : : "eax", "ecx")
+
+/*
+ * Test for SSE support on this processor.  We need to do this because
+ * we need to use ldmxcsr/stmxcsr to get correct results if any part
+ * of the program was compiled to use SSE floating-point, but we can't
+ * use SSE on older processors.
+ */
+int
+__test_sse(void)
+{
+       int flag, nflag;
+       int dx_features;
+
+       /* Am I a 486? */
+       getfl(&flag);
+       nflag = flag ^ 0x200000;
+       setfl(nflag);
+       getfl(&nflag);
+       if (flag != nflag) {
+               /* Not a 486, so CPUID should work. */
+               cpuid_dx(&dx_features);
+               if (dx_features & 0x2000000) {
+                       __has_sse = __SSE_YES;
+                       return (1);
+               }
+       }
+       __has_sse = __SSE_NO;
+       return (0);
+}
+
+extern inline OLM_DLLEXPORT int feclearexcept(int __excepts);
+extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+
+OLM_DLLEXPORT int
+fesetexceptflag(const fexcept_t *flagp, int excepts)
+{
+       fenv_t env;
+       uint32_t mxcsr;
+
+       __fnstenv(&env);
+       env.__status &= ~excepts;
+       env.__status |= *flagp & excepts;
+       __fldenv(env);
+
+       if (__HAS_SSE()) {
+               __stmxcsr(&mxcsr);
+               mxcsr &= ~excepts;
+               mxcsr |= *flagp & excepts;
+               __ldmxcsr(mxcsr);
+       }
+
+       return (0);
+}
+
+OLM_DLLEXPORT int
+feraiseexcept(int excepts)
+{
+       fexcept_t ex = excepts;
+
+       fesetexceptflag(&ex, excepts);
+       __fwait();
+       return (0);
+}
+
+extern inline OLM_DLLEXPORT int fetestexcept(int __excepts);
+extern inline OLM_DLLEXPORT int fegetround(void);
+extern inline OLM_DLLEXPORT int fesetround(int __round);
+
+int
+fegetenv(fenv_t *envp)
+{
+       uint32_t mxcsr;
+
+       __fnstenv(envp);
+       /*
+        * fnstenv masks all exceptions, so we need to restore
+        * the old control word to avoid this side effect.
+        */
+       __fldcw(envp->__control);
+       if (__HAS_SSE()) {
+               __stmxcsr(&mxcsr);
+               __set_mxcsr(*envp, mxcsr);
+       }
+       return (0);
+}
+
+int
+feholdexcept(fenv_t *envp)
+{
+       uint32_t mxcsr;
+
+       __fnstenv(envp);
+       __fnclex();
+       if (__HAS_SSE()) {
+               __stmxcsr(&mxcsr);
+               __set_mxcsr(*envp, mxcsr);
+               mxcsr &= ~FE_ALL_EXCEPT;
+               mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
+               __ldmxcsr(mxcsr);
+       }
+       return (0);
+}
+
+extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp);
+
+OLM_DLLEXPORT int
+feupdateenv(const fenv_t *envp)
+{
+       uint32_t mxcsr;
+       uint16_t status;
+
+       __fnstsw(&status);
+       if (__HAS_SSE())
+               __stmxcsr(&mxcsr);
+       else
+               mxcsr = 0;
+       fesetenv(envp);
+       feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
+       return (0);
+}
+
+int
+feenableexcept(int mask)
+{
+       uint32_t mxcsr, omask;
+       uint16_t control;
+
+       mask &= FE_ALL_EXCEPT;
+       __fnstcw(&control);
+       if (__HAS_SSE())
+               __stmxcsr(&mxcsr);
+       else
+               mxcsr = 0;
+       omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+       control &= ~mask;
+       __fldcw(control);
+       if (__HAS_SSE()) {
+               mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
+               __ldmxcsr(mxcsr);
+       }
+       return (omask);
+}
+
+int
+fedisableexcept(int mask)
+{
+       uint32_t mxcsr, omask;
+       uint16_t control;
+
+       mask &= FE_ALL_EXCEPT;
+       __fnstcw(&control);
+       if (__HAS_SSE())
+               __stmxcsr(&mxcsr);
+       else
+               mxcsr = 0;
+       omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
+       control |= mask;
+       __fldcw(control);
+       if (__HAS_SSE()) {
+               mxcsr |= mask << _SSE_EMASK_SHIFT;
+               __ldmxcsr(mxcsr);
+       }
+       return (omask);
+}
diff --git a/i387/invtrig.c b/i387/invtrig.c
new file mode 100644 (file)
index 0000000..4afd832
--- /dev/null
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <sys/cdefs.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/invtrig.c,v 1.1 2008/08/02 03:56:22 das Exp $");
+
+#include <stdint.h>
+
+#define STRUCT_DECLS
+#include "invtrig.h"
+
+/*
+ * asinl() and acosl()
+ */
+const LONGDOUBLE
+pS0 = { 0xaaaaaaaaaaaaaaa8ULL, 0x3ffcU }, /*  1.66666666666666666631e-01L */
+pS1 = { 0xd5271b6699b48bfaULL, 0xbffdU }, /* -4.16313987993683104320e-01L */
+pS2 = { 0xbcf67ca9e9f669cfULL, 0x3ffdU }, /*  3.69068046323246813704e-01L */
+pS3 = { 0x8b7baa3d15f9830dULL, 0xbffcU }, /* -1.36213932016738603108e-01L */
+pS4 = { 0x92154b093a3bff1cULL, 0x3ff9U }, /*  1.78324189708471965733e-02L */
+pS5 = { 0xe5dd76401964508cULL, 0xbff2U }, /* -2.19216428382605211588e-04L */
+pS6 = { 0xee69c5b0fdb76951ULL, 0xbfedU }, /* -7.10526623669075243183e-06L */
+qS1 = { 0xbcaa2159c01436a0ULL, 0xc000U }, /* -2.94788392796209867269e+00L */
+qS2 = { 0xd17a73d1e1564c29ULL, 0x4000U }, /*  3.27309890266528636716e+00L */
+qS3 = { 0xd767e411c9cf4c2cULL, 0xbfffU }, /* -1.68285799854822427013e+00L */
+qS4 = { 0xc809c0dfb9b0d0b7ULL, 0x3ffdU }, /*  3.90699412641738801874e-01L */
+qS5 = { 0x80c3a2197c8ced57ULL, 0xbffaU }; /* -3.14365703596053263322e-02L */
+
+/*
+ * atanl()
+ */
+const LONGDOUBLE atanhi[] = {
+       { 0xed63382b0dda7b45ULL, 0x3ffdU }, /*  4.63647609000806116202e-01L */
+       { 0xc90fdaa22168c235ULL, 0x3ffeU }, /*  7.85398163397448309628e-01L */
+       { 0xfb985e940fb4d900ULL, 0x3ffeU }, /*  9.82793723247329067960e-01L */
+       { 0xc90fdaa22168c235ULL, 0x3fffU }, /*  1.57079632679489661926e+00L */
+};
+
+const LONGDOUBLE atanlo[] = {
+       { 0xdfc88bd978751a07ULL, 0x3fbcU }, /*  1.18469937025062860669e-20L */
+       { 0xece675d1fc8f8cbbULL, 0xbfbcU }, /* -1.25413940316708300586e-20L */
+       { 0xf10f5e197793c283ULL, 0x3fbdU }, /*  2.55232234165405176172e-20L */
+       { 0xece675d1fc8f8cbbULL, 0xbfbdU }, /* -2.50827880633416601173e-20L */
+};
+
+const LONGDOUBLE aT[] = {
+       { 0xaaaaaaaaaaaaaa9fULL, 0x3ffdU }, /*  3.33333333333333333017e-01L */
+       { 0xcccccccccccc62bcULL, 0xbffcU }, /* -1.99999999999999632011e-01L */
+       { 0x9249249248b81e3fULL, 0x3ffcU }, /*  1.42857142857046531280e-01L */
+       { 0xe38e38e3316f3de5ULL, 0xbffbU }, /* -1.11111111100562372733e-01L */
+       { 0xba2e8b8dc280726aULL, 0x3ffbU }, /*  9.09090902935647302252e-02L */
+       { 0x9d89d5b4c6847ec4ULL, 0xbffbU }, /* -7.69230552476207730353e-02L */
+       { 0x8888461d3099c677ULL, 0x3ffbU }, /*  6.66661718042406260546e-02L */
+       { 0xf0e8ee0f5328dc29ULL, 0xbffaU }, /* -5.88158892835030888692e-02L */
+       { 0xd73ea84d24bae54aULL, 0x3ffaU }, /*  5.25499891539726639379e-02L */
+       { 0xc08fa381dcd9213aULL, 0xbffaU }, /* -4.70119845393155721494e-02L */
+       { 0xa54a26f4095f2a3aULL, 0x3ffaU }, /*  4.03539201366454414072e-02L */
+       { 0xeea2d8d059ef3ad6ULL, 0xbff9U }, /* -2.91303858419364158725e-02L */
+       { 0xcc82292ab894b051ULL, 0x3ff8U }, /*  1.24822046299269234080e-02L */
+};
+
+const LONGDOUBLE
+pi_lo = { 0xece675d1fc8f8cbbULL, 0xbfbeU }; /* -5.01655761266833202345e-20L */
diff --git a/i387/s_ceil.S b/i387/s_ceil.S
new file mode 100644 (file)
index 0000000..80de70a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+ENTRY(ceil)
+    pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0800,%dx             /* round towards +oo */
+       andw    $0xfbff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldl    8(%ebp);                /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(ceil)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_ceilf.S b/i387/s_ceilf.S
new file mode 100644 (file)
index 0000000..7ea898a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_ceilf.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_ceilf.S,v 1.3 1995/05/08 23:52:44 jtc Exp $") */
+
+ENTRY(ceilf)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0800,%dx             /* round towards +oo */
+       andw    $0xfbff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       flds    8(%ebp);                /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(ceilf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_ceill.S b/i387/s_ceill.S
new file mode 100644 (file)
index 0000000..838edd1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+       
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_ceill.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(ceill)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0800,%dx             /* round towards +oo */
+       andw    $0xfbff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldt    8(%ebp)                 /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(ceill)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_copysign.S b/i387/s_copysign.S
new file mode 100644 (file)
index 0000000..4386747
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysign.S,v 1.9 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(copysign)
+       movl    16(%esp),%edx
+       andl    $0x80000000,%edx
+       movl    8(%esp),%eax
+       andl    $0x7fffffff,%eax
+       orl     %edx,%eax
+       movl    %eax,8(%esp)
+       fldl    4(%esp)
+       ret
+END(copysign)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_copysignf.S b/i387/s_copysignf.S
new file mode 100644 (file)
index 0000000..5d0169b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysignf.S,v 1.3 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_copysignf.S,v 1.3 1995/05/08 23:53:25 jtc Exp $") */
+
+ENTRY(copysignf)
+       movl    8(%esp),%edx
+       andl    $0x80000000,%edx
+       movl    4(%esp),%eax
+       andl    $0x7fffffff,%eax
+       orl     %edx,%eax
+       movl    %eax,4(%esp)
+       flds    4(%esp)
+       ret
+END(copysignf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_copysignl.S b/i387/s_copysignl.S
new file mode 100644 (file)
index 0000000..1a9a06a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysignl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(copysignl)
+       movl    24(%esp),%edx
+       andl    $0x8000,%edx
+       movl    12(%esp),%eax
+       andl    $0x7fff,%eax
+       orl     %edx,%eax
+       movl    %eax,12(%esp)
+       fldt    4(%esp)
+       ret
+END(copysignl)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_cos.S b/i387/s_cos.S
new file mode 100644 (file)
index 0000000..4e29ec3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_cos.S,v 1.9 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(cos)
+       fldl    4(%esp)
+       fcos
+       fnstsw  %ax
+       andw    $0x400,%ax
+       jnz     1f
+       ret     
+1:     fldpi
+       fadd    %st(0)
+       fxch    %st(1)
+2:     fprem1
+       fnstsw  %ax
+       andw    $0x400,%ax
+       jnz     2b
+       fstp    %st(1)
+       fcos
+       ret
+END(cos)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_floor.S b/i387/s_floor.S
new file mode 100644 (file)
index 0000000..13097eb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floor.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(floor)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0400,%dx             /* round towards -oo */
+       andw    $0xf7ff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldl    8(%ebp);                /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(floor)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_floorf.S b/i387/s_floorf.S
new file mode 100644 (file)
index 0000000..c3a4e09
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floorf.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_floorf.S,v 1.3 1995/05/09 00:04:32 jtc Exp $") */
+
+ENTRY(floorf)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0400,%dx             /* round towards -oo */
+       andw    $0xf7ff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       flds    8(%ebp);                /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(floorf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_floorl.S b/i387/s_floorl.S
new file mode 100644 (file)
index 0000000..949116f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floorl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(floorl)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0400,%dx             /* round towards -oo */
+       andw    $0xf7ff,%dx
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldt    8(%ebp)                 /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(floorl)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_llrint.S b/i387/s_llrint.S
new file mode 100644 (file)
index 0000000..97c292e
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(llrint)
+       fldl    4(%esp)
+       subl    $8,%esp
+       fistpll (%esp)
+       popl    %eax
+       popl    %edx
+       ret
+END(llrint)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_llrintf.S b/i387/s_llrintf.S
new file mode 100644 (file)
index 0000000..447e77a
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+       
+ENTRY(llrintf)
+       flds    4(%esp)
+       subl    $8,%esp
+       fistpll (%esp)
+       popl    %eax
+       popl    %edx
+       ret
+END(llrintf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_llrintl.S b/i387/s_llrintl.S
new file mode 100644 (file)
index 0000000..ad6a7c9
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(llrintl)
+       fldt    4(%esp)
+       subl    $8,%esp
+       fistpll (%esp)
+       popl    %eax
+       popl    %edx
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_logb.S b/i387/s_logb.S
new file mode 100644 (file)
index 0000000..d0fc5d6
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logb.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(logb)
+       fldl    4(%esp)
+       fxtract
+       fstp    %st
+       ret
+END(logb)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_logbf.S b/i387/s_logbf.S
new file mode 100644 (file)
index 0000000..3e3568c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logbf.S,v 1.3 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_logbf.S,v 1.3 1995/05/09 00:15:12 jtc Exp $") */
+
+ENTRY(logbf)
+       flds    4(%esp)
+       fxtract
+       fstp    %st
+       ret
+END(logbf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_logbl.S b/i387/s_logbl.S
new file mode 100644 (file)
index 0000000..6d2de64
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logbl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(logbl)
+       fldt    4(%esp)
+       fxtract
+       fstp    %st
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_lrint.S b/i387/s_lrint.S
new file mode 100644 (file)
index 0000000..1e12539
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(lrint)
+       fldl    4(%esp)
+       subl    $4,%esp
+       fistpl  (%esp)
+       popl    %eax
+       ret
+END(lrint)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_lrintf.S b/i387/s_lrintf.S
new file mode 100644 (file)
index 0000000..b588c1a
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+       
+ENTRY(lrintf)
+       flds    4(%esp)
+       subl    $4,%esp
+       fistpl  (%esp)
+       popl    %eax
+       ret
+END(lrintf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_lrintl.S b/i387/s_lrintl.S
new file mode 100644 (file)
index 0000000..94cc6cb
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(lrintl)
+       fldt    4(%esp)
+       subl    $4,%esp
+       fistpl  (%esp)
+       popl    %eax
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_remquo.S b/i387/s_remquo.S
new file mode 100644 (file)
index 0000000..78a588d
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquo.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquo)
+       fldl    12(%esp)
+       fldl    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    16(%esp),%ecx
+       xorl    8(%esp),%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+       movl    20(%esp),%ecx
+       movl    %eax,(%ecx)
+       ret
+END(remquo)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_remquof.S b/i387/s_remquof.S
new file mode 100644 (file)
index 0000000..8f532c3
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquof.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquof)
+       flds    8(%esp)
+       flds    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    8(%esp),%ecx
+       xorl    4(%esp),%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+       movl    12(%esp),%ecx
+       movl    %eax,(%ecx)
+       ret
+END(remquof)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_remquol.S b/i387/s_remquol.S
new file mode 100644 (file)
index 0000000..b89563c
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2005-2008 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.
+ */
+
+/*
+ * Based on public-domain remainder routine by J.T. Conklin <jtc@NetBSD.org>.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquol.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); 
+       
+ENTRY(remquol)
+       fldt    16(%esp)
+       fldt    4(%esp)
+1:     fprem1
+       fstsw   %ax
+       sahf
+       jp      1b
+       fstp    %st(1)
+/* Extract the three low-order bits of the quotient from C0,C3,C1. */
+       shrl    $6,%eax
+       movl    %eax,%ecx
+       andl    $0x108,%eax
+       rorl    $7,%eax
+       orl     %eax,%ecx
+       roll    $4,%eax
+       orl     %ecx,%eax
+       andl    $7,%eax
+/* Negate the quotient bits if x*y<0.  Avoid using an unpredictable branch. */
+       movl    24(%esp),%ecx
+       xorl    12(%esp),%ecx
+       movsx   %cx,%ecx
+       sarl    $16,%ecx
+       sarl    $16,%ecx
+       xorl    %ecx,%eax
+       andl    $1,%ecx
+       addl    %ecx,%eax
+/* Store the quotient and return. */
+       movl    28(%esp),%ecx
+       movl    %eax,(%ecx)
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_rint.S b/i387/s_rint.S
new file mode 100644 (file)
index 0000000..a8109cd
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rint.S,v 1.9 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(rint)
+       fldl    4(%esp)
+       frndint
+       ret
+END(rint)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_rintf.S b/i387/s_rintf.S
new file mode 100644 (file)
index 0000000..184a16f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_rintf.S,v 1.3 1995/05/09 00:17:22 jtc Exp $") */
+
+ENTRY(rintf)
+       flds    4(%esp)
+       frndint
+       ret
+END(rintf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_rintl.S b/i387/s_rintl.S
new file mode 100644 (file)
index 0000000..8727322
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rintl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(rintl)
+       fldt    4(%esp)
+       frndint
+       ret
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_scalbn.S b/i387/s_scalbn.S
new file mode 100644 (file)
index 0000000..d690ff1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbn.S,v 1.10 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(scalbn)
+       fildl   12(%esp)
+       fldl    4(%esp)
+       fscale
+       fstp    %st(1)
+       ret
+END(scalbn)
+
+.globl CNAME(ldexp)
+.set   CNAME(ldexp),CNAME(scalbn)
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_scalbnf.S b/i387/s_scalbnf.S
new file mode 100644 (file)
index 0000000..7f4a2bc
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbnf.S,v 1.4 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnf)
+       fildl   8(%esp)
+       flds    4(%esp)
+       fscale
+       fstp    %st(1)          /* bug fix for fp stack overflow */
+       ret
+END(scalbnf)
+
+.globl CNAME(ldexpf)
+.set   CNAME(ldexpf),CNAME(scalbnf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_scalbnl.S b/i387/s_scalbnl.S
new file mode 100644 (file)
index 0000000..5d359eb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbnl.S,v 1.3 2011/01/07 16:13:12 kib Exp $");
+/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */
+
+ENTRY(scalbnl)
+       fildl   16(%esp)
+       fldt    4(%esp)
+       fscale
+       fstp    %st(1)
+       ret
+END(scalbnl)
+
+.globl CNAME(ldexpl)
+.set   CNAME(ldexpl),CNAME(scalbnl)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_sin.S b/i387/s_sin.S
new file mode 100644 (file)
index 0000000..6b71455
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_sin.S,v 1.9 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(sin)
+       fldl    4(%esp)
+       fsin
+       fnstsw  %ax
+       andw    $0x400,%ax
+       jnz     1f
+       ret
+1:     fldpi
+       fadd    %st(0)
+       fxch    %st(1)
+2:     fprem1
+       fnstsw  %ax
+       andw    $0x400,%ax
+       jnz     2b
+       fstp    %st(1)
+       fsin
+       ret
+END(sin)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_tan.S b/i387/s_tan.S
new file mode 100644 (file)
index 0000000..7b25c3a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Written by:
+ *     J.T. Conklin (jtc@netbsd.org)
+ *     Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_tan.S,v 1.9 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(tan)
+       fldl    4(%esp)
+       fptan
+       fnstsw  %ax
+       andw    $0x400,%ax
+       jnz     1f
+       fstp    %st(0)
+       ret
+1:     fldpi
+       fadd    %st(0)
+       fxch    %st(1)
+2:     fprem1
+       fstsw   %ax
+       andw    $0x400,%ax
+       jnz     2b
+       fstp    %st(1)
+       fptan
+       fstp    %st(0)
+       ret
+END(tan)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_trunc.S b/i387/s_trunc.S
new file mode 100644 (file)
index 0000000..5422770
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_trunc.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(trunc)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0c00,%dx             /* round towards -oo */
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldl    8(%ebp)                 /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(trunc)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_truncf.S b/i387/s_truncf.S
new file mode 100644 (file)
index 0000000..c9d32bb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_truncf.S,v 1.4 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(truncf)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0c00,%dx             /* round towards -oo */
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       flds    8(%ebp)                 /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(truncf)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/i387/s_truncl.S b/i387/s_truncl.S
new file mode 100644 (file)
index 0000000..7152638
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Based on code written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#include <i387/bsd_asm.h>
+//__FBSDID("$FreeBSD: src/lib/msun/i387/s_truncl.S,v 1.3 2011/01/07 16:13:12 kib Exp $")
+
+ENTRY(truncl)
+       pushl   %ebp
+       movl    %esp,%ebp
+       subl    $8,%esp
+
+       fstcw   -4(%ebp)                /* store fpu control word */
+       movw    -4(%ebp),%dx
+       orw     $0x0c00,%dx             /* round towards -oo */
+       movw    %dx,-8(%ebp)
+       fldcw   -8(%ebp)                /* load modfied control word */
+
+       fldt    8(%ebp)                 /* round */
+       frndint
+
+       fldcw   -4(%ebp)                /* restore original control word */
+
+       leave
+       ret
+END(truncl)
+
+       
+/* Enable stack protection */
+#if defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/include/openlibm.h b/include/openlibm.h
new file mode 100644 (file)
index 0000000..d851945
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef OPENLIBM_H
+#define OPENLIBM_H
+
+#include <openlibm_complex.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#endif /* !OPENLIBM_H */
diff --git a/include/openlibm_complex.h b/include/openlibm_complex.h
new file mode 100644 (file)
index 0000000..7afc992
--- /dev/null
@@ -0,0 +1,179 @@
+/*     $OpenBSD: complex.h,v 1.5 2014/03/16 18:38:30 guenther Exp $    */
+/*
+ * Copyright (c) 2008 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef OPENLIBM_USE_HOST_COMPLEX_H
+#include <complex.h>
+#else /* !OPENLIBM_USE_HOST_COMPLEX_H */
+
+#ifndef OPENLIBM_COMPLEX_H
+#define        OPENLIBM_COMPLEX_H
+
+#define complex _Complex
+
+#define _Complex_I 1.0fi
+#define I _Complex_I
+
+/*
+ * Macros that can be used to construct complex values.
+ *
+ * The C99 standard intends x+I*y to be used for this, but x+I*y is
+ * currently unusable in general since gcc introduces many overflow,
+ * underflow, sign and efficiency bugs by rewriting I*y as
+ * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product.
+ * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted
+ * to -0.0+I*0.0.
+ *
+ * In C11, a CMPLX(x,y) macro was added to circumvent this limitation,
+ * and gcc 4.7 added a __builtin_complex feature to simplify implementation
+ * of CMPLX in libc, so we can take advantage of these features if they
+ * are available. Clang simply allows complex values to be constructed
+ * using a compound literal.
+ *
+ * If __builtin_complex is not available, resort to using inline
+ * functions instead. These can unfortunately not be used to construct
+ * compile-time constants.
+ *
+ * C99 specifies that complex numbers have the same representation as
+ * an array of two elements, where the first element is the real part
+ * and the second element is the imaginary part.
+ */
+
+#ifdef __clang__
+#  define CMPLXF(x, y) ((float complex){x, y})
+#  define CMPLX(x, y) ((double complex){x, y})
+#  define CMPLXL(x, y) ((long double complex){x, y})
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__INTEL_COMPILER)
+#  define CMPLXF(x,y) __builtin_complex ((float) (x), (float) (y))
+#  define CMPLX(x,y) __builtin_complex ((double) (x), (double) (y))
+#  define CMPLXL(x,y) __builtin_complex ((long double) (x), (long double) (y))
+#else
+static inline float complex
+CMPLXF(float x, float y)
+{
+       union {
+               float a[2];
+               float complex f;
+       } z = {{ x, y }};
+
+       return (z.f);
+}
+
+static inline double complex
+CMPLX(double x, double y)
+{
+       union {
+               double a[2];
+               double complex f;
+       } z = {{ x, y }};
+
+       return (z.f);
+}
+
+static inline long double complex
+CMPLXL(long double x, long double y)
+{
+       union {
+               long double a[2];
+               long double complex f;
+       } z = {{ x, y }};
+
+       return (z.f);
+}
+#endif
+
+/*
+ * Double versions of C99 functions
+ */
+double complex cacos(double complex);
+double complex casin(double complex);
+double complex catan(double complex);
+double complex ccos(double complex);
+double complex csin(double complex);
+double complex ctan(double complex);
+double complex cacosh(double complex);
+double complex casinh(double complex);
+double complex catanh(double complex);
+double complex ccosh(double complex);
+double complex csinh(double complex);
+double complex ctanh(double complex);
+double complex cexp(double complex);
+double complex clog(double complex);
+double cabs(double complex);
+double complex cpow(double complex, double complex);
+double complex csqrt(double complex);
+double carg(double complex);
+double cimag(double complex);
+double complex conj(double complex);
+double complex cproj(double complex);
+double creal(double complex);
+
+/*
+ * Float versions of C99 functions
+ */
+float complex cacosf(float complex);
+float complex casinf(float complex);
+float complex catanf(float complex);
+float complex ccosf(float complex);
+float complex csinf(float complex);
+float complex ctanf(float complex);
+float complex cacoshf(float complex);
+float complex casinhf(float complex);
+float complex catanhf(float complex);
+float complex ccoshf(float complex);
+float complex csinhf(float complex);
+float complex ctanhf(float complex);
+float complex cexpf(float complex);
+float complex clogf(float complex);
+float cabsf(float complex);
+float complex cpowf(float complex, float complex);
+float complex csqrtf(float complex);
+float cargf(float complex);
+float cimagf(float complex);
+float complex conjf(float complex);
+float complex cprojf(float complex);
+float crealf(float complex);
+
+/*
+ * Long double versions of C99 functions
+ */
+long double complex cacosl(long double complex);
+long double complex casinl(long double complex);
+long double complex catanl(long double complex);
+long double complex ccosl(long double complex);
+long double complex csinl(long double complex);
+long double complex ctanl(long double complex);
+long double complex cacoshl(long double complex);
+long double complex casinhl(long double complex);
+long double complex catanhl(long double complex);
+long double complex ccoshl(long double complex);
+long double complex csinhl(long double complex);
+long double complex ctanhl(long double complex);
+long double complex cexpl(long double complex);
+long double complex clogl(long double complex);
+long double cabsl(long double complex);
+long double complex cpowl(long double complex,
+       long double complex);
+long double complex csqrtl(long double complex);
+long double cargl(long double complex);
+long double cimagl(long double complex);
+long double complex conjl(long double complex);
+long double complex cprojl(long double complex);
+long double creall(long double complex);
+
+#endif /* !OPENLIBM_COMPLEX_H */
+
+#endif /* OPENLIBM_USE_HOST_COMPLEX_H */
diff --git a/include/openlibm_fenv.h b/include/openlibm_fenv.h
new file mode 100644 (file)
index 0000000..3abf193
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef OPENLIBM_USE_HOST_FENV_H
+#include <fenv.h>
+#else /* !OPENLIBM_USE_HOST_FENV_H */
+
+#if defined(__aarch64__) || defined(__arm__)
+#include <openlibm_fenv_arm.h>
+#elif defined(__x86_64__)
+#include <openlibm_fenv_amd64.h>
+#elif defined(__i386__)
+#include <openlibm_fenv_i387.h>
+#elif defined(__powerpc__)
+#include <openlibm_fenv_powerpc.h>
+#elif defined(__mips__)
+#include <openlibm_fenv_mips.h>
+#else
+#error "Unsupported platform"
+#endif
+
+#endif /* OPENLIBM_USE_HOST_FENV_H */
diff --git a/include/openlibm_fenv_amd64.h b/include/openlibm_fenv_amd64.h
new file mode 100644 (file)
index 0000000..9e302bd
--- /dev/null
@@ -0,0 +1,224 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/amd64/fenv.h,v 1.8 2011/10/10 15:43:09 das Exp $
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include "cdefs-compat.h"
+#include "types-compat.h"
+
+#include "math_private.h"
+
+#ifndef        __fenv_static
+#define        __fenv_static   static
+#endif
+
+typedef struct {
+       struct {
+               uint32_t        __control;
+               uint32_t        __status;
+               uint32_t        __tag;
+               char            __other[16];
+       } __x87;
+       uint32_t                __mxcsr;
+} fenv_t;
+
+typedef        uint16_t        fexcept_t;
+
+/* Exception flags */
+#define        FE_INVALID      0x01
+#define        FE_DENORMAL     0x02
+#define        FE_DIVBYZERO    0x04
+#define        FE_OVERFLOW     0x08
+#define        FE_UNDERFLOW    0x10
+#define        FE_INEXACT      0x20
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+                        FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_DOWNWARD     0x0400
+#define        FE_UPWARD       0x0800
+#define        FE_TOWARDZERO   0x0c00
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+
+/*
+ * As compared to the x87 control word, the SSE unit's control word
+ * has the rounding control bits offset by 3 and the exception mask
+ * bits offset by 7.
+ */
+#define        _SSE_ROUND_SHIFT        3
+#define        _SSE_EMASK_SHIFT        7
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+#define        __fldcw(__cw)           __asm __volatile("fldcw %0" : : "m" (__cw))
+#define        __fldenv(__env)         __asm __volatile("fldenv %0" : : "m" (__env))
+#define        __fldenvx(__env)        __asm __volatile("fldenv %0" : : "m" (__env)  \
+                               : "st", "st(1)", "st(2)", "st(3)", "st(4)",   \
+                               "st(5)", "st(6)", "st(7)")
+#define        __fnclex()              __asm __volatile("fnclex")
+#define        __fnstenv(__env)        __asm __volatile("fnstenv %0" : "=m" (*(__env)))
+#define        __fnstcw(__cw)          __asm __volatile("fnstcw %0" : "=m" (*(__cw)))
+#define        __fnstsw(__sw)          __asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define        __fwait()               __asm __volatile("fwait")
+#define        __ldmxcsr(__csr)        __asm __volatile("ldmxcsr %0" : : "m" (__csr))
+#define        __stmxcsr(__csr)        __asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
+
+__fenv_static __attribute__((always_inline)) inline int
+feclearexcept(int __excepts)
+{
+       fenv_t __env;
+
+       if (__excepts == FE_ALL_EXCEPT) {
+               __fnclex();
+       } else {
+               __fnstenv(&__env.__x87);
+               __env.__x87.__status &= ~__excepts;
+               __fldenv(__env.__x87);
+       }
+       __stmxcsr(&__env.__mxcsr);
+       __env.__mxcsr &= ~__excepts;
+       __ldmxcsr(__env.__mxcsr);
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       uint32_t __mxcsr;
+       uint16_t __status;
+
+       __stmxcsr(&__mxcsr);
+       __fnstsw(&__status);
+       *__flagp = (__mxcsr | __status) & __excepts;
+       return (0);
+}
+
+OLM_DLLEXPORT int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+OLM_DLLEXPORT int feraiseexcept(int __excepts);
+
+__fenv_static __attribute__((always_inline)) inline int
+fetestexcept(int __excepts)
+{
+       uint32_t __mxcsr;
+       uint16_t __status;
+
+       __stmxcsr(&__mxcsr);
+       __fnstsw(&__status);
+       return ((__status | __mxcsr) & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+       uint16_t __control;
+
+       /*
+        * We assume that the x87 and the SSE unit agree on the
+        * rounding mode.  Reading the control word on the x87 turns
+        * out to be about 5 times faster than reading it on the SSE
+        * unit on an Opteron 244.
+        */
+       __fnstcw(&__control);
+       return (__control & _ROUND_MASK);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+       uint32_t __mxcsr;
+       uint16_t __control;
+
+       if (__round & ~_ROUND_MASK)
+               return (-1);
+
+       __fnstcw(&__control);
+       __control &= ~_ROUND_MASK;
+       __control |= __round;
+       __fldcw(__control);
+
+       __stmxcsr(&__mxcsr);
+       __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
+       __mxcsr |= __round << _SSE_ROUND_SHIFT;
+       __ldmxcsr(__mxcsr);
+
+       return (0);
+}
+
+OLM_DLLEXPORT int fegetenv(fenv_t *__envp);
+OLM_DLLEXPORT int feholdexcept(fenv_t *__envp);
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+
+       /*
+        * XXX Using fldenvx() instead of fldenv() tells the compiler that this
+        * instruction clobbers the i387 register stack.  This happens because
+        * we restore the tag word from the saved environment.  Normally, this
+        * would happen anyway and we wouldn't care, because the ABI allows
+        * function calls to clobber the i387 regs.  However, fesetenv() is
+        * inlined, so we need to be more careful.
+        */
+       __fldenvx(__envp->__x87);
+       __ldmxcsr(__envp->__mxcsr);
+       return (0);
+}
+
+OLM_DLLEXPORT int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+OLM_DLLEXPORT int feenableexcept(int __mask);
+OLM_DLLEXPORT int fedisableexcept(int __mask);
+
+/* We currently provide no external definition of fegetexcept(). */
+static inline int
+fegetexcept(void)
+{
+       uint16_t __control;
+
+       /*
+        * We assume that the masks for the x87 and the SSE unit are
+        * the same.
+        */
+       __fnstcw(&__control);
+       return (~__control & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/openlibm_fenv_arm.h b/include/openlibm_fenv_arm.h
new file mode 100644 (file)
index 0000000..ff1946f
--- /dev/null
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/arm/fenv.h,v 1.6 2011/10/10 15:43:09 das Exp $
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include <stdint.h>
+
+#include "cdefs-compat.h"
+
+#ifndef        __fenv_static
+#define        __fenv_static   static
+#endif
+
+typedef        uint32_t        fenv_t;
+typedef        uint32_t        fexcept_t;
+
+/* Exception flags */
+#define        FE_INVALID      0x0001
+#define        FE_DIVBYZERO    0x0002
+#define        FE_OVERFLOW     0x0004
+#define        FE_UNDERFLOW    0x0008
+#define        FE_INEXACT      0x0010
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_INEXACT | \
+                        FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_TOWARDZERO   0x0001
+#define        FE_UPWARD       0x0002
+#define        FE_DOWNWARD     0x0003
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define _FPUSW_SHIFT   16
+#define        _ENABLE_MASK    (FE_ALL_EXCEPT << _FPUSW_SHIFT)
+
+#if defined(__aarch64__)
+#define __rfs(__fpsr)   __asm __volatile("mrs %0,fpsr" : "=r" (*(__fpsr)))
+#define __wfs(__fpsr)   __asm __volatile("msr fpsr,%0" : : "r" (__fpsr))
+/* Test for hardware support for ARM floating point operations, explicitly
+checking for float and double support, see "ARM C Language Extensions", 6.5.1 */
+#elif defined(__ARM_FP) && (__ARM_FP & 0x0C) != 0
+#define __rfs(__fpsr)   __asm __volatile("vmrs %0,fpscr" : "=&r" (*(__fpsr)))
+#define __wfs(__fpsr)   __asm __volatile("vmsr fpscr,%0" : : "r" (__fpsr))
+#else
+#define __rfs(__fpsr)  (*(__fpsr) = 0)
+#define __wfs(__fpsr)
+#endif
+
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+       fexcept_t __fpsr;
+
+       __rfs(&__fpsr);
+       __fpsr &= ~__excepts;
+       __wfs(__fpsr);
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       fexcept_t __fpsr;
+
+       __rfs(&__fpsr);
+       *__flagp = __fpsr & __excepts;
+       return (0);
+}
+
+__fenv_static inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+       fexcept_t __fpsr;
+
+       __rfs(&__fpsr);
+       __fpsr &= ~__excepts;
+       __fpsr |= *__flagp & __excepts;
+       __wfs(__fpsr);
+       return (0);
+}
+
+__fenv_static inline int
+feraiseexcept(int __excepts)
+{
+       fexcept_t __ex = __excepts;
+
+       fesetexceptflag(&__ex, __excepts);      /* XXX */
+       return (0);
+}
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+       fexcept_t __fpsr;
+
+       __rfs(&__fpsr);
+       return (__fpsr & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+
+       /*
+        * Apparently, the rounding mode is specified as part of the
+        * instruction format on ARM, so the dynamic rounding mode is
+        * indeterminate.  Some FPUs may differ.
+        */
+       return (-1);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+
+       return (-1);
+}
+
+__fenv_static inline int
+fegetenv(fenv_t *__envp)
+{
+
+       __rfs(__envp);
+       return (0);
+}
+
+__fenv_static inline int
+feholdexcept(fenv_t *__envp)
+{
+       fenv_t __env;
+
+       __rfs(&__env);
+       *__envp = __env;
+       __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+       __wfs(__env);
+       return (0);
+}
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+
+       __wfs(*__envp);
+       return (0);
+}
+
+__fenv_static inline int
+feupdateenv(const fenv_t *__envp)
+{
+       fexcept_t __fpsr;
+
+       __rfs(&__fpsr);
+       __wfs(*__envp);
+       feraiseexcept(__fpsr & FE_ALL_EXCEPT);
+       return (0);
+}
+
+#if __BSD_VISIBLE
+
+/* We currently provide no external definitions of the functions below. */
+
+static inline int
+feenableexcept(int __mask)
+{
+       fenv_t __old_fpsr, __new_fpsr;
+
+       __rfs(&__old_fpsr);
+       __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
+       __wfs(__new_fpsr);
+       return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static inline int
+fedisableexcept(int __mask)
+{
+       fenv_t __old_fpsr, __new_fpsr;
+
+       __rfs(&__old_fpsr);
+       __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
+       __wfs(__new_fpsr);
+       return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static inline int
+fegetexcept(void)
+{
+       fenv_t __fpsr;
+
+       __rfs(&__fpsr);
+       return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/openlibm_fenv_i387.h b/include/openlibm_fenv_i387.h
new file mode 100644 (file)
index 0000000..c3a987c
--- /dev/null
@@ -0,0 +1,259 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/i387/fenv.h,v 1.8 2011/10/10 15:43:09 das Exp $
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include "cdefs-compat.h"
+#include "types-compat.h"
+
+#ifndef        __fenv_static
+#define        __fenv_static   static
+#endif
+
+/*                   
+ * To preserve binary compatibility with FreeBSD 5.3, we pack the
+ * mxcsr into some reserved fields, rather than changing sizeof(fenv_t).
+ */
+typedef struct {
+       uint16_t        __control;
+       uint16_t      __mxcsr_hi;
+       uint16_t        __status;
+       uint16_t      __mxcsr_lo;
+       uint32_t        __tag;
+       char            __other[16];
+} fenv_t;
+
+#define        __get_mxcsr(env)        (((env).__mxcsr_hi << 16) |     \
+                                ((env).__mxcsr_lo))
+#define        __set_mxcsr(env, x)     do {                            \
+       (env).__mxcsr_hi = (uint32_t)(x) >> 16;         \
+       (env).__mxcsr_lo = (uint16_t)(x);                       \
+} while (0)
+
+typedef        uint16_t        fexcept_t;
+
+/* Exception flags */
+#define        FE_INVALID      0x01
+#define        FE_DENORMAL     0x02
+#define        FE_DIVBYZERO    0x04
+#define        FE_OVERFLOW     0x08
+#define        FE_UNDERFLOW    0x10
+#define        FE_INEXACT      0x20
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+                        FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_DOWNWARD     0x0400
+#define        FE_UPWARD       0x0800
+#define        FE_TOWARDZERO   0x0c00
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+
+/*
+ * As compared to the x87 control word, the SSE unit's control word
+ * has the rounding control bits offset by 3 and the exception mask
+ * bits offset by 7.
+ */
+#define        _SSE_ROUND_SHIFT        3
+#define        _SSE_EMASK_SHIFT        7
+
+__BEGIN_DECLS
+
+/* After testing for SSE support once, we cache the result in __has_sse. */
+enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK };
+extern enum __sse_support __has_sse;
+int __test_sse(void);
+#ifdef __SSE__
+#define        __HAS_SSE()     1
+#else
+#define        __HAS_SSE()     (__has_sse == __SSE_YES ||                      \
+                        (__has_sse == __SSE_UNK && __test_sse()))
+#endif
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+#define        __fldcw(__cw)           __asm __volatile("fldcw %0" : : "m" (__cw))
+#define        __fldenv(__env)         __asm __volatile("fldenv %0" : : "m" (__env))
+#define        __fldenvx(__env)        __asm __volatile("fldenv %0" : : "m" (__env)  \
+                               : "st", "st(1)", "st(2)", "st(3)", "st(4)",   \
+                               "st(5)", "st(6)", "st(7)")
+#define        __fnclex()              __asm __volatile("fnclex")
+#define        __fnstenv(__env)        __asm __volatile("fnstenv %0" : "=m" (*(__env)))
+#define        __fnstcw(__cw)          __asm __volatile("fnstcw %0" : "=m" (*(__cw)))
+#define        __fnstsw(__sw)          __asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define        __fwait()               __asm __volatile("fwait")
+#define        __ldmxcsr(__csr)        __asm __volatile("ldmxcsr %0" : : "m" (__csr))
+#define        __stmxcsr(__csr)        __asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
+
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+       fenv_t __env;
+       uint32_t __mxcsr;
+
+       if (__excepts == FE_ALL_EXCEPT) {
+               __fnclex();
+       } else {
+               __fnstenv(&__env);
+               __env.__status &= ~__excepts;
+               __fldenv(__env);
+       }
+       if (__HAS_SSE()) {
+               __stmxcsr(&__mxcsr);
+               __mxcsr &= ~__excepts;
+               __ldmxcsr(__mxcsr);
+       }
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       uint32_t __mxcsr;
+       uint16_t __status;
+
+       __fnstsw(&__status);
+       if (__HAS_SSE())
+               __stmxcsr(&__mxcsr);
+       else
+               __mxcsr = 0;
+       *__flagp = (__mxcsr | __status) & __excepts;
+       return (0);
+}
+
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+       uint32_t __mxcsr;
+       uint16_t __status;
+
+       __fnstsw(&__status);
+       if (__HAS_SSE())
+               __stmxcsr(&__mxcsr);
+       else
+               __mxcsr = 0;
+       return ((__status | __mxcsr) & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+       uint16_t __control;
+
+       /*
+        * We assume that the x87 and the SSE unit agree on the
+        * rounding mode.  Reading the control word on the x87 turns
+        * out to be about 5 times faster than reading it on the SSE
+        * unit on an Opteron 244.
+        */
+       __fnstcw(&__control);
+       return (__control & _ROUND_MASK);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+       uint32_t __mxcsr;
+       uint16_t __control;
+
+       if (__round & ~_ROUND_MASK)
+               return (-1);
+
+       __fnstcw(&__control);
+       __control &= ~_ROUND_MASK;
+       __control |= __round;
+       __fldcw(__control);
+
+       if (__HAS_SSE()) {
+               __stmxcsr(&__mxcsr);
+               __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
+               __mxcsr |= __round << _SSE_ROUND_SHIFT;
+               __ldmxcsr(__mxcsr);
+       }
+
+       return (0);
+}
+
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+       fenv_t __env = *__envp;
+       uint32_t __mxcsr;
+
+       __mxcsr = __get_mxcsr(__env);
+       __set_mxcsr(__env, 0xffffffff);
+       /*
+        * XXX Using fldenvx() instead of fldenv() tells the compiler that this
+        * instruction clobbers the i387 register stack.  This happens because
+        * we restore the tag word from the saved environment.  Normally, this
+        * would happen anyway and we wouldn't care, because the ABI allows
+        * function calls to clobber the i387 regs.  However, fesetenv() is
+        * inlined, so we need to be more careful.
+        */
+       __fldenvx(__env);
+       if (__HAS_SSE())
+               __ldmxcsr(__mxcsr);
+       return (0);
+}
+
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+
+/* We currently provide no external definition of fegetexcept(). */
+static inline int
+fegetexcept(void)
+{
+       uint16_t __control;
+
+       /*
+        * We assume that the masks for the x87 and the SSE unit are
+        * the same.
+        */
+       __fnstcw(&__control);
+       return (~__control & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/openlibm_fenv_mips.h b/include/openlibm_fenv_mips.h
new file mode 100644 (file)
index 0000000..980252f
--- /dev/null
@@ -0,0 +1,278 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include <stdint.h>
+#include "cdefs-compat.h"
+
+#ifndef        __fenv_static
+#define        __fenv_static   static
+#endif
+
+typedef        uint32_t        fenv_t;
+typedef        uint32_t        fexcept_t;
+
+/* Exception flags */
+#ifdef __mips_soft_float
+#define        _FPUSW_SHIFT    16
+#define        FE_INVALID      0x0001
+#define        FE_DIVBYZERO    0x0002
+#define        FE_OVERFLOW     0x0004
+#define        FE_UNDERFLOW    0x0008
+#define        FE_INEXACT      0x0010
+#else
+#define        _FCSR_CAUSE_SHIFT       10
+#define        FE_INVALID      0x0040
+#define        FE_DIVBYZERO    0x0020
+#define        FE_OVERFLOW     0x0010
+#define        FE_UNDERFLOW    0x0008
+#define        FE_INEXACT      0x0004
+#endif
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_INEXACT | \
+                        FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_TOWARDZERO   0x0001
+#define        FE_UPWARD       0x0002
+#define        FE_DOWNWARD     0x0003
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define        _ENABLE_SHIFT   5
+#define        _ENABLE_MASK    (FE_ALL_EXCEPT << _ENABLE_SHIFT)
+
+#ifndef __mips_soft_float
+#define        __cfc1(__fcsr)  __asm __volatile("cfc1 %0, $31" : "=r" (__fcsr))
+#define        __ctc1(__fcsr)  __asm __volatile("ctc1 %0, $31" :: "r" (__fcsr))
+#endif
+
+#ifdef __mips_soft_float
+int feclearexcept(int __excepts);
+int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+int fetestexcept(int __excepts);
+int fegetround(void);
+int fesetround(int __round);
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+int fesetenv(const fenv_t *__envp);
+int feupdateenv(const fenv_t *__envp);
+#else
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+       fexcept_t fcsr;
+
+       __excepts &= FE_ALL_EXCEPT;
+       __cfc1(fcsr);
+       fcsr &= ~(__excepts | (__excepts << _FCSR_CAUSE_SHIFT));
+       __ctc1(fcsr);
+
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       fexcept_t fcsr;
+
+       __excepts &= FE_ALL_EXCEPT;
+       __cfc1(fcsr);
+       *__flagp = fcsr & __excepts;
+
+       return (0);
+}
+
+__fenv_static inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+       fexcept_t fcsr;
+
+       __excepts &= FE_ALL_EXCEPT;
+       __cfc1(fcsr);
+       fcsr &= ~__excepts;
+       fcsr |= *__flagp & __excepts;
+       __ctc1(fcsr);
+
+       return (0);
+}
+
+__fenv_static inline int
+feraiseexcept(int __excepts)
+{
+       fexcept_t fcsr;
+
+       __excepts &= FE_ALL_EXCEPT;
+       __cfc1(fcsr);
+       fcsr |= __excepts | (__excepts << _FCSR_CAUSE_SHIFT);
+       __ctc1(fcsr);
+
+       return (0);
+}
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+       fexcept_t fcsr;
+
+       __excepts &= FE_ALL_EXCEPT;
+       __cfc1(fcsr);
+
+       return (fcsr & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+       fexcept_t fcsr;
+
+       __cfc1(fcsr);
+
+       return (fcsr & _ROUND_MASK);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+       fexcept_t fcsr;
+
+       if (__round & ~_ROUND_MASK)
+               return (-1);
+
+       __cfc1(fcsr);
+       fcsr &= ~_ROUND_MASK;
+       fcsr |= __round;
+       __ctc1(fcsr);
+
+       return (0);
+}
+
+__fenv_static inline int
+fegetenv(fenv_t *__envp)
+{
+
+       __cfc1(*__envp);
+
+       return (0);
+}
+
+__fenv_static inline int
+feholdexcept(fenv_t *__envp)
+{
+       fexcept_t fcsr;
+
+       __cfc1(fcsr);
+       *__envp = fcsr;
+       fcsr &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+       __ctc1(fcsr);
+
+       return (0);
+}
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+
+       __ctc1(*__envp);
+
+       return (0);
+}
+
+__fenv_static inline int
+feupdateenv(const fenv_t *__envp)
+{
+       fexcept_t fcsr;
+
+       __cfc1(fcsr);
+       fesetenv(__envp);
+       feraiseexcept(fcsr);
+
+       return (0);
+}
+#endif /* !__mips_soft_float */
+
+#if __BSD_VISIBLE
+
+/* We currently provide no external definitions of the functions below. */
+
+#ifdef __mips_soft_float
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+int fegetexcept(void);
+#else
+static inline int
+feenableexcept(int __mask)
+{
+       fenv_t __old_fcsr, __new_fcsr;
+
+       __cfc1(__old_fcsr);
+       __new_fcsr = __old_fcsr | (__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT;
+       __ctc1(__new_fcsr);
+
+       return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static inline int
+fedisableexcept(int __mask)
+{
+       fenv_t __old_fcsr, __new_fcsr;
+
+       __cfc1(__old_fcsr);
+       __new_fcsr = __old_fcsr & ~((__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT);
+       __ctc1(__new_fcsr);
+
+       return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT);
+}
+
+static inline int
+fegetexcept(void)
+{
+       fexcept_t fcsr;
+
+       __cfc1(fcsr);
+
+       return ((fcsr & _ENABLE_MASK) >> _ENABLE_SHIFT);
+}
+
+#endif /* !__mips_soft_float */
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/openlibm_fenv_powerpc.h b/include/openlibm_fenv_powerpc.h
new file mode 100644 (file)
index 0000000..2b05bd4
--- /dev/null
@@ -0,0 +1,279 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include <sys/types.h>
+
+#ifndef        __fenv_static
+#define        __fenv_static   static
+#endif
+
+typedef        __uint32_t      fenv_t;
+typedef        __uint32_t      fexcept_t;
+
+/* Exception flags */
+#define        FE_INEXACT      0x02000000
+#define        FE_DIVBYZERO    0x04000000
+#define        FE_UNDERFLOW    0x08000000
+#define        FE_OVERFLOW     0x10000000
+#define        FE_INVALID      0x20000000      /* all types of invalid FP ops */
+
+/*
+ * The PowerPC architecture has extra invalid flags that indicate the
+ * specific type of invalid operation occurred.  These flags may be
+ * tested, set, and cleared---but not masked---separately.  All of
+ * these bits are cleared when FE_INVALID is cleared, but only
+ * FE_VXSOFT is set when FE_INVALID is explicitly set in software.
+ */
+#define        FE_VXCVI        0x00000100      /* invalid integer convert */
+#define        FE_VXSQRT       0x00000200      /* square root of a negative */
+#define        FE_VXSOFT       0x00000400      /* software-requested exception */
+#define        FE_VXVC         0x00080000      /* ordered comparison involving NaN */
+#define        FE_VXIMZ        0x00100000      /* inf * 0 */
+#define        FE_VXZDZ        0x00200000      /* 0 / 0 */
+#define        FE_VXIDI        0x00400000      /* inf / inf */
+#define        FE_VXISI        0x00800000      /* inf - inf */
+#define        FE_VXSNAN       0x01000000      /* operation on a signalling NaN */
+#define        FE_ALL_INVALID  (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \
+                        FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \
+                        FE_VXSNAN | FE_INVALID)
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_INEXACT | \
+                        FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_TOWARDZERO   0x0001
+#define        FE_UPWARD       0x0002
+#define        FE_DOWNWARD     0x0003
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+/* We need to be able to map status flag positions to mask flag positions */
+#define        _FPUSW_SHIFT    22
+#define        _ENABLE_MASK    ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
+                        FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT)
+
+#ifndef _SOFT_FLOAT
+#define        __mffs(__env)   __asm __volatile("mffs %0" : "=f" (*(__env)))
+#define        __mtfsf(__env)  __asm __volatile("mtfsf 255,%0" : : "f" (__env))
+#else
+#define        __mffs(__env)
+#define        __mtfsf(__env)
+#endif
+
+union __fpscr {
+       double __d;
+       struct {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+               fenv_t __reg;
+               __uint32_t __junk;
+#else
+               __uint32_t __junk;
+               fenv_t __reg;
+#endif
+       } __bits;
+};
+
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+       union __fpscr __r;
+
+       if (__excepts & FE_INVALID)
+               __excepts |= FE_ALL_INVALID;
+       __mffs(&__r.__d);
+       __r.__bits.__reg &= ~__excepts;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       *__flagp = __r.__bits.__reg & __excepts;
+       return (0);
+}
+
+__fenv_static inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+       union __fpscr __r;
+
+       if (__excepts & FE_INVALID)
+               __excepts |= FE_ALL_EXCEPT;
+       __mffs(&__r.__d);
+       __r.__bits.__reg &= ~__excepts;
+       __r.__bits.__reg |= *__flagp & __excepts;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+feraiseexcept(int __excepts)
+{
+       union __fpscr __r;
+
+       if (__excepts & FE_INVALID)
+               __excepts |= FE_VXSOFT;
+       __mffs(&__r.__d);
+       __r.__bits.__reg |= __excepts;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       return (__r.__bits.__reg & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       return (__r.__bits.__reg & _ROUND_MASK);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+       union __fpscr __r;
+
+       if (__round & ~_ROUND_MASK)
+               return (-1);
+       __mffs(&__r.__d);
+       __r.__bits.__reg &= ~_ROUND_MASK;
+       __r.__bits.__reg |= __round;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+fegetenv(fenv_t *__envp)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       *__envp = __r.__bits.__reg;
+       return (0);
+}
+
+__fenv_static inline int
+feholdexcept(fenv_t *__envp)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       *__envp = __r.__d;
+       __r.__bits.__reg &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+       union __fpscr __r;
+
+       __r.__bits.__reg = *__envp;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+__fenv_static inline int
+feupdateenv(const fenv_t *__envp)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       __r.__bits.__reg &= FE_ALL_EXCEPT;
+       __r.__bits.__reg |= *__envp;
+       __mtfsf(__r.__d);
+       return (0);
+}
+
+#if __BSD_VISIBLE
+
+/* We currently provide no external definitions of the functions below. */
+
+static inline int
+feenableexcept(int __mask)
+{
+       union __fpscr __r;
+       fenv_t __oldmask;
+
+       __mffs(&__r.__d);
+       __oldmask = __r.__bits.__reg;
+       __r.__bits.__reg |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT;
+       __mtfsf(__r.__d);
+       return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static inline int
+fedisableexcept(int __mask)
+{
+       union __fpscr __r;
+       fenv_t __oldmask;
+
+       __mffs(&__r.__d);
+       __oldmask = __r.__bits.__reg;
+       __r.__bits.__reg &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT);
+       __mtfsf(__r.__d);
+       return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+static inline int
+fegetexcept(void)
+{
+       union __fpscr __r;
+
+       __mffs(&__r.__d);
+       return ((__r.__bits.__reg & _ENABLE_MASK) << _FPUSW_SHIFT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/openlibm_math.h b/include/openlibm_math.h
new file mode 100644 (file)
index 0000000..e17e6ad
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ * $FreeBSD: src/lib/msun/src/openlibm.h,v 1.82 2011/11/12 19:55:48 theraven Exp $
+ */
+
+#ifdef OPENLIBM_USE_HOST_MATH_H
+#include <math.h>
+#else /* !OPENLIBM_USE_HOST_MATH_H */
+
+#ifndef OPENLIBM_MATH_H
+#define        OPENLIBM_MATH_H
+
+#if (defined(_WIN32) || defined (_MSC_VER)) && !defined(__WIN32__)
+    #define __WIN32__
+#endif
+
+#ifndef __arm__
+#define LONG_DOUBLE
+#endif
+
+#ifndef __pure2
+#define __pure2
+#endif
+
+#ifdef _WIN32
+# ifdef IMPORT_EXPORTS
+#  define OLM_DLLEXPORT __declspec(dllimport)
+# else
+#  define OLM_DLLEXPORT __declspec(dllexport)
+# endif
+#else
+#define OLM_DLLEXPORT __attribute__ ((visibility("default")))
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+extern const union __infinity_un {
+       unsigned char   __uc[8];
+       double          __ud;
+} __infinity;
+
+extern const union __nan_un {
+       unsigned char   __uc[sizeof(float)];
+       float           __uf;
+} __nan;
+
+/* VBS
+#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
+#define        __MATH_BUILTIN_CONSTANTS
+#endif
+
+#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER)
+#define        __MATH_BUILTIN_RELOPS
+#endif
+*/
+
+//VBS begin
+#define __MATH_BUILTIN_CONSTANTS
+#define        __MATH_BUILTIN_RELOPS
+#ifndef __ISO_C_VISIBLE
+#define __ISO_C_VISIBLE 1999
+#endif
+//VBS end
+
+#ifdef __MATH_BUILTIN_CONSTANTS
+#define        HUGE_VAL        __builtin_huge_val()
+#else
+#define        HUGE_VAL        (__infinity.__ud)
+#endif
+
+#if __ISO_C_VISIBLE >= 1999
+#define        FP_ILOGB0       (-INT_MAX)
+#define        FP_ILOGBNAN     INT_MAX
+
+#ifdef __MATH_BUILTIN_CONSTANTS
+#define        HUGE_VALF       __builtin_huge_valf()
+#define        HUGE_VALL       __builtin_huge_vall()
+#define        INFINITY        __builtin_inff()
+#define        NAN             __builtin_nanf("")
+#else
+#define        HUGE_VALF       (float)HUGE_VAL
+#define        HUGE_VALL       (long double)HUGE_VAL
+#define        INFINITY        HUGE_VALF
+#define        NAN             (__nan.__uf)
+#endif /* __MATH_BUILTIN_CONSTANTS */
+
+#define        MATH_ERRNO      1
+#define        MATH_ERREXCEPT  2
+#define        math_errhandling        MATH_ERREXCEPT
+
+#define        FP_FAST_FMAF    1
+#ifdef __ia64__
+#define        FP_FAST_FMA     1
+#define        FP_FAST_FMAL    1
+#endif
+
+/* Symbolic constants to classify floating point numbers. */
+#define        FP_INFINITE     0x01
+#define        FP_NAN          0x02
+#define        FP_NORMAL       0x04
+#define        FP_SUBNORMAL    0x08
+#define        FP_ZERO         0x10
+#define        fpclassify(x) \
+    ((sizeof (x) == sizeof (float)) ? __fpclassifyf(x) \
+    : (sizeof (x) == sizeof (double)) ? __fpclassifyd(x) \
+    : __fpclassifyl(x))
+
+#define        isfinite(x)                                     \
+    ((sizeof (x) == sizeof (float)) ? __isfinitef(x)   \
+    : (sizeof (x) == sizeof (double)) ? __isfinite(x)  \
+    : __isfinitel(x))
+#define        isinf(x)                                        \
+    ((sizeof (x) == sizeof (float)) ? __isinff(x)      \
+    : (sizeof (x) == sizeof (double)) ? isinf(x)       \
+    : __isinfl(x))
+#define        isnan(x)                                        \
+    ((sizeof (x) == sizeof (float)) ? __isnanf(x)      \
+    : (sizeof (x) == sizeof (double)) ? isnan(x)       \
+    : __isnanl(x))
+#define        isnormal(x)                                     \
+    ((sizeof (x) == sizeof (float)) ? __isnormalf(x)   \
+    : (sizeof (x) == sizeof (double)) ? __isnormal(x)  \
+    : __isnormall(x))
+
+#ifdef __MATH_BUILTIN_RELOPS
+#define        isgreater(x, y)         __builtin_isgreater((x), (y))
+#define        isgreaterequal(x, y)    __builtin_isgreaterequal((x), (y))
+#define        isless(x, y)            __builtin_isless((x), (y))
+#define        islessequal(x, y)       __builtin_islessequal((x), (y))
+#define        islessgreater(x, y)     __builtin_islessgreater((x), (y))
+#define        isunordered(x, y)       __builtin_isunordered((x), (y))
+#else
+#define        isgreater(x, y)         (!isunordered((x), (y)) && (x) > (y))
+#define        isgreaterequal(x, y)    (!isunordered((x), (y)) && (x) >= (y))
+#define        isless(x, y)            (!isunordered((x), (y)) && (x) < (y))
+#define        islessequal(x, y)       (!isunordered((x), (y)) && (x) <= (y))
+#define        islessgreater(x, y)     (!isunordered((x), (y)) && \
+                                       ((x) > (y) || (y) > (x)))
+#define        isunordered(x, y)       (isnan(x) || isnan(y))
+#endif /* __MATH_BUILTIN_RELOPS */
+
+#define        signbit(x)                                      \
+    ((sizeof (x) == sizeof (float)) ? __signbitf(x)    \
+    : (sizeof (x) == sizeof (double)) ? __signbit(x)   \
+    : __signbitl(x))
+
+//VBS
+//typedef      __double_t      double_t;
+//typedef      __float_t       float_t;
+#endif /* __ISO_C_VISIBLE >= 1999 */
+
+/*
+ * XOPEN/SVID
+ */
+#if __BSD_VISIBLE || __XSI_VISIBLE
+#define        M_E             2.7182818284590452354   /* e */
+#define        M_LOG2E         1.4426950408889634074   /* log 2e */
+#define        M_LOG10E        0.43429448190325182765  /* log 10e */
+#define        M_LN2           0.69314718055994530942  /* log e2 */
+#define        M_LN10          2.30258509299404568402  /* log e10 */
+#define        M_PI            3.14159265358979323846  /* pi */
+#define        M_PI_2          1.57079632679489661923  /* pi/2 */
+#define        M_PI_4          0.78539816339744830962  /* pi/4 */
+#define        M_1_PI          0.31830988618379067154  /* 1/pi */
+#define        M_2_PI          0.63661977236758134308  /* 2/pi */
+#define        M_2_SQRTPI      1.12837916709551257390  /* 2/sqrt(pi) */
+#define        M_SQRT2         1.41421356237309504880  /* sqrt(2) */
+#define        M_SQRT1_2       0.70710678118654752440  /* 1/sqrt(2) */
+
+#define        MAXFLOAT        ((float)3.40282346638528860e+38)
+
+#ifndef OPENLIBM_ONLY_THREAD_SAFE
+extern int signgam;
+#endif
+#endif /* __BSD_VISIBLE || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE
+#if 0
+/* Old value from 4.4BSD-Lite openlibm.h; this is probably better. */
+#define        HUGE            HUGE_VAL
+#else
+#define        HUGE            MAXFLOAT
+#endif
+#endif /* __BSD_VISIBLE */
+
+/*
+ * Most of these functions depend on the rounding mode and have the side
+ * effect of raising floating-point exceptions, so they are not declared
+ * as __pure2.  In C99, FENV_ACCESS affects the purity of these functions.
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/* Symbol present when OpenLibm is used. */
+int isopenlibm(void);
+
+/*
+ * ANSI/POSIX
+ */
+OLM_DLLEXPORT int      __fpclassifyd(double) __pure2;
+OLM_DLLEXPORT int      __fpclassifyf(float) __pure2;
+OLM_DLLEXPORT int      __fpclassifyl(long double) __pure2;
+OLM_DLLEXPORT int      __isfinitef(float) __pure2;
+OLM_DLLEXPORT int      __isfinite(double) __pure2;
+OLM_DLLEXPORT int      __isfinitel(long double) __pure2;
+OLM_DLLEXPORT int      __isinff(float) __pure2;
+OLM_DLLEXPORT int      __isinfl(long double) __pure2;
+OLM_DLLEXPORT int      __isnanf(float) __pure2;
+OLM_DLLEXPORT int      __isnanl(long double) __pure2;
+OLM_DLLEXPORT int      __isnormalf(float) __pure2;
+OLM_DLLEXPORT int      __isnormal(double) __pure2;
+OLM_DLLEXPORT int      __isnormall(long double) __pure2;
+OLM_DLLEXPORT int      __signbit(double) __pure2;
+OLM_DLLEXPORT int      __signbitf(float) __pure2;
+OLM_DLLEXPORT int      __signbitl(long double) __pure2;
+
+OLM_DLLEXPORT double   acos(double);
+OLM_DLLEXPORT double   asin(double);
+OLM_DLLEXPORT double   atan(double);
+OLM_DLLEXPORT double   atan2(double, double);
+OLM_DLLEXPORT double   cos(double);
+OLM_DLLEXPORT double   sin(double);
+OLM_DLLEXPORT double   tan(double);
+
+OLM_DLLEXPORT double   cosh(double);
+OLM_DLLEXPORT double   sinh(double);
+OLM_DLLEXPORT double   tanh(double);
+
+OLM_DLLEXPORT double   exp(double);
+OLM_DLLEXPORT double   frexp(double, int *);   /* fundamentally !__pure2 */
+OLM_DLLEXPORT double   ldexp(double, int);
+OLM_DLLEXPORT double   log(double);
+OLM_DLLEXPORT double   log10(double);
+OLM_DLLEXPORT double   modf(double, double *); /* fundamentally !__pure2 */
+
+OLM_DLLEXPORT double   pow(double, double);
+OLM_DLLEXPORT double   sqrt(double);
+
+OLM_DLLEXPORT double   ceil(double);
+OLM_DLLEXPORT double   fabs(double) __pure2;
+OLM_DLLEXPORT double   floor(double);
+OLM_DLLEXPORT double   fmod(double, double);
+
+/*
+ * These functions are not in C90.
+ */
+#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE
+OLM_DLLEXPORT double   acosh(double);
+OLM_DLLEXPORT double   asinh(double);
+OLM_DLLEXPORT double   atanh(double);
+OLM_DLLEXPORT double   cbrt(double);
+OLM_DLLEXPORT double   erf(double);
+OLM_DLLEXPORT double   erfc(double);
+OLM_DLLEXPORT double   exp2(double);
+OLM_DLLEXPORT double   expm1(double);
+OLM_DLLEXPORT double   fma(double, double, double);
+OLM_DLLEXPORT double   hypot(double, double);
+OLM_DLLEXPORT int      ilogb(double) __pure2;
+OLM_DLLEXPORT int      (isinf)(double) __pure2;
+OLM_DLLEXPORT int      (isnan)(double) __pure2;
+OLM_DLLEXPORT double   lgamma(double);
+OLM_DLLEXPORT long long llrint(double);
+OLM_DLLEXPORT long long llround(double);
+OLM_DLLEXPORT double   log1p(double);
+OLM_DLLEXPORT double   log2(double);
+OLM_DLLEXPORT double   logb(double);
+OLM_DLLEXPORT long     lrint(double);
+OLM_DLLEXPORT long     lround(double);
+OLM_DLLEXPORT double   nan(const char *) __pure2;
+OLM_DLLEXPORT double   nextafter(double, double);
+OLM_DLLEXPORT double   remainder(double, double);
+OLM_DLLEXPORT double   remquo(double, double, int *);
+OLM_DLLEXPORT double   rint(double);
+#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE || __XSI_VISIBLE
+OLM_DLLEXPORT double   j0(double);
+OLM_DLLEXPORT double   j1(double);
+OLM_DLLEXPORT double   jn(int, double);
+OLM_DLLEXPORT double   y0(double);
+OLM_DLLEXPORT double   y1(double);
+OLM_DLLEXPORT double   yn(int, double);
+#endif /* __BSD_VISIBLE || __XSI_VISIBLE */
+
+#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999
+OLM_DLLEXPORT double   copysign(double, double) __pure2;
+OLM_DLLEXPORT double   fdim(double, double);
+OLM_DLLEXPORT double   fmax(double, double) __pure2;
+OLM_DLLEXPORT double   fmin(double, double) __pure2;
+OLM_DLLEXPORT double   nearbyint(double);
+OLM_DLLEXPORT double   round(double);
+OLM_DLLEXPORT double   scalbln(double, long);
+OLM_DLLEXPORT double   scalbn(double, int);
+OLM_DLLEXPORT double   tgamma(double);
+OLM_DLLEXPORT double   trunc(double);
+#endif
+
+/*
+ * BSD math library entry points
+ */
+#if __BSD_VISIBLE
+OLM_DLLEXPORT int      isnanf(float) __pure2;
+
+/*
+ * Reentrant version of lgamma; passes signgam back by reference as the
+ * second argument; user must allocate space for signgam.
+ */
+OLM_DLLEXPORT double   lgamma_r(double, int *);
+
+/*
+ * Single sine/cosine function.
+ */
+OLM_DLLEXPORT void     sincos(double, double *, double *);
+#endif /* __BSD_VISIBLE */
+
+/* float versions of ANSI/POSIX functions */
+#if __ISO_C_VISIBLE >= 1999
+OLM_DLLEXPORT float    acosf(float);
+OLM_DLLEXPORT float    asinf(float);
+OLM_DLLEXPORT float    atanf(float);
+OLM_DLLEXPORT float    atan2f(float, float);
+OLM_DLLEXPORT float    cosf(float);
+OLM_DLLEXPORT float    sinf(float);
+OLM_DLLEXPORT float    tanf(float);
+
+OLM_DLLEXPORT float    coshf(float);
+OLM_DLLEXPORT float    sinhf(float);
+OLM_DLLEXPORT float    tanhf(float);
+
+OLM_DLLEXPORT float    exp2f(float);
+OLM_DLLEXPORT float    expf(float);
+OLM_DLLEXPORT float    expm1f(float);
+OLM_DLLEXPORT float    frexpf(float, int *);   /* fundamentally !__pure2 */
+OLM_DLLEXPORT int      ilogbf(float) __pure2;
+OLM_DLLEXPORT float    ldexpf(float, int);
+OLM_DLLEXPORT float    log10f(float);
+OLM_DLLEXPORT float    log1pf(float);
+OLM_DLLEXPORT float    log2f(float);
+OLM_DLLEXPORT float    logf(float);
+OLM_DLLEXPORT float    modff(float, float *);  /* fundamentally !__pure2 */
+
+OLM_DLLEXPORT float    powf(float, float);
+OLM_DLLEXPORT float    sqrtf(float);
+
+OLM_DLLEXPORT float    ceilf(float);
+OLM_DLLEXPORT float    fabsf(float) __pure2;
+OLM_DLLEXPORT float    floorf(float);
+OLM_DLLEXPORT float    fmodf(float, float);
+OLM_DLLEXPORT float    roundf(float);
+
+OLM_DLLEXPORT float    erff(float);
+OLM_DLLEXPORT float    erfcf(float);
+OLM_DLLEXPORT float    hypotf(float, float);
+OLM_DLLEXPORT float    lgammaf(float);
+OLM_DLLEXPORT float    tgammaf(float);
+
+OLM_DLLEXPORT float    acoshf(float);
+OLM_DLLEXPORT float    asinhf(float);
+OLM_DLLEXPORT float    atanhf(float);
+OLM_DLLEXPORT float    cbrtf(float);
+OLM_DLLEXPORT float    logbf(float);
+OLM_DLLEXPORT float    copysignf(float, float) __pure2;
+OLM_DLLEXPORT long long llrintf(float);
+OLM_DLLEXPORT long long llroundf(float);
+OLM_DLLEXPORT long     lrintf(float);
+OLM_DLLEXPORT long     lroundf(float);
+OLM_DLLEXPORT float    nanf(const char *) __pure2;
+OLM_DLLEXPORT float    nearbyintf(float);
+OLM_DLLEXPORT float    nextafterf(float, float);
+OLM_DLLEXPORT float    remainderf(float, float);
+OLM_DLLEXPORT float    remquof(float, float, int *);
+OLM_DLLEXPORT float    rintf(float);
+OLM_DLLEXPORT float    scalblnf(float, long);
+OLM_DLLEXPORT float    scalbnf(float, int);
+OLM_DLLEXPORT float    truncf(float);
+
+OLM_DLLEXPORT float    fdimf(float, float);
+OLM_DLLEXPORT float    fmaf(float, float, float);
+OLM_DLLEXPORT float    fmaxf(float, float) __pure2;
+OLM_DLLEXPORT float    fminf(float, float) __pure2;
+#endif
+
+/*
+ * float versions of BSD math library entry points
+ */
+#if __BSD_VISIBLE
+OLM_DLLEXPORT float    dremf(float, float);
+OLM_DLLEXPORT float    j0f(float);
+OLM_DLLEXPORT float    j1f(float);
+OLM_DLLEXPORT float    jnf(int, float);
+OLM_DLLEXPORT float    y0f(float);
+OLM_DLLEXPORT float    y1f(float);
+OLM_DLLEXPORT float    ynf(int, float);
+
+/*
+ * Float versions of reentrant version of lgamma; passes signgam back by
+ * reference as the second argument; user must allocate space for signgam.
+ */
+OLM_DLLEXPORT float    lgammaf_r(float, int *);
+
+/*
+ * Single sine/cosine function.
+ */
+OLM_DLLEXPORT void     sincosf(float, float *, float *);
+#endif /* __BSD_VISIBLE */
+
+/*
+ * long double versions of ISO/POSIX math functions
+ */
+#if __ISO_C_VISIBLE >= 1999
+OLM_DLLEXPORT long double      acoshl(long double);
+OLM_DLLEXPORT long double      acosl(long double);
+OLM_DLLEXPORT long double      asinhl(long double);
+OLM_DLLEXPORT long double      asinl(long double);
+OLM_DLLEXPORT long double      atan2l(long double, long double);
+OLM_DLLEXPORT long double      atanhl(long double);
+OLM_DLLEXPORT long double      atanl(long double);
+OLM_DLLEXPORT long double      cbrtl(long double);
+OLM_DLLEXPORT long double      ceill(long double);
+OLM_DLLEXPORT long double      copysignl(long double, long double) __pure2;
+OLM_DLLEXPORT long double      coshl(long double);
+OLM_DLLEXPORT long double      cosl(long double);
+OLM_DLLEXPORT long double      erfcl(long double);
+OLM_DLLEXPORT long double      erfl(long double);
+OLM_DLLEXPORT long double      exp2l(long double);
+OLM_DLLEXPORT long double      expl(long double);
+OLM_DLLEXPORT long double      expm1l(long double);
+OLM_DLLEXPORT long double      fabsl(long double) __pure2;
+OLM_DLLEXPORT long double      fdiml(long double, long double);
+OLM_DLLEXPORT long double      floorl(long double);
+OLM_DLLEXPORT long double      fmal(long double, long double, long double);
+OLM_DLLEXPORT long double      fmaxl(long double, long double) __pure2;
+OLM_DLLEXPORT long double      fminl(long double, long double) __pure2;
+OLM_DLLEXPORT long double      fmodl(long double, long double);
+OLM_DLLEXPORT long double      frexpl(long double value, int *); /* fundamentally !__pure2 */
+OLM_DLLEXPORT long double      hypotl(long double, long double);
+OLM_DLLEXPORT int              ilogbl(long double) __pure2;
+OLM_DLLEXPORT long double      ldexpl(long double, int);
+OLM_DLLEXPORT long double      lgammal(long double);
+OLM_DLLEXPORT long long        llrintl(long double);
+OLM_DLLEXPORT long long        llroundl(long double);
+OLM_DLLEXPORT long double      log10l(long double);
+OLM_DLLEXPORT long double      log1pl(long double);
+OLM_DLLEXPORT long double      log2l(long double);
+OLM_DLLEXPORT long double      logbl(long double);
+OLM_DLLEXPORT long double      logl(long double);
+OLM_DLLEXPORT long             lrintl(long double);
+OLM_DLLEXPORT long             lroundl(long double);
+OLM_DLLEXPORT long double      modfl(long double, long double *); /* fundamentally !__pure2 */
+OLM_DLLEXPORT long double      nanl(const char *) __pure2;
+OLM_DLLEXPORT long double      nearbyintl(long double);
+OLM_DLLEXPORT long double      nextafterl(long double, long double);
+OLM_DLLEXPORT double           nexttoward(double, long double);
+OLM_DLLEXPORT float            nexttowardf(float, long double);
+OLM_DLLEXPORT long double      nexttowardl(long double, long double);
+OLM_DLLEXPORT long double      powl(long double, long double);
+OLM_DLLEXPORT long double      remainderl(long double, long double);
+OLM_DLLEXPORT long double      remquol(long double, long double, int *);
+OLM_DLLEXPORT long double      rintl(long double);
+OLM_DLLEXPORT long double      roundl(long double);
+OLM_DLLEXPORT long double      scalblnl(long double, long);
+OLM_DLLEXPORT long double      scalbnl(long double, int);
+OLM_DLLEXPORT long double      sinhl(long double);
+OLM_DLLEXPORT long double      sinl(long double);
+OLM_DLLEXPORT long double      sqrtl(long double);
+OLM_DLLEXPORT long double      tanhl(long double);
+OLM_DLLEXPORT long double      tanl(long double);
+OLM_DLLEXPORT long double      tgammal(long double);
+OLM_DLLEXPORT long double      truncl(long double);
+#endif /* __ISO_C_VISIBLE >= 1999 */
+
+/* Reentrant version of lgammal. */
+#if __BSD_VISIBLE
+OLM_DLLEXPORT long double      lgammal_r(long double, int *);
+
+/*
+ * Single sine/cosine function.
+ */
+OLM_DLLEXPORT void     sincosl(long double, long double *, long double *);
+#endif /* __BSD_VISIBLE */
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* !OPENLIBM_MATH_H */
+
+#endif /* OPENLIBM_USE_HOST_MATH_H */
diff --git a/ld128/Make.files b/ld128/Make.files
new file mode 100644 (file)
index 0000000..1198cfb
--- /dev/null
@@ -0,0 +1,13 @@
+$(CUR_SRCS) +=         invtrig.c \
+            e_acoshl.c     e_powl.c       k_tanl.c       s_exp2l.c \
+            e_atanhl.c     e_lgammal_r.c  e_sinhl.c      s_asinhl.c     s_expm1l.c \
+            e_coshl.c      e_log10l.c     e_tgammal.c \
+            e_expl.c       e_log2l.c      k_cosl.c       s_log1pl.c     s_tanhl.c \
+            e_logl.c       k_sinl.c       s_erfl.c
+
+#           s_remquol.c    e_fmodl.c      s_truncl.c
+#           e_hypotl.c     s_floorl.c     s_nextafterl.c s_ceill.c      s_modfl.c
+
+ifneq ($(OS), WINNT)
+$(CUR_SRCS) += s_nanl.c
+endif
diff --git a/ld128/e_acoshl.c b/ld128/e_acoshl.c
new file mode 100644 (file)
index 0000000..e7cfd03
--- /dev/null
@@ -0,0 +1,58 @@
+/* @(#)e_acosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* acoshl(x)
+ * Method :
+ *     Based on
+ *             acoshl(x) = logl [ x + sqrtl(x*x-1) ]
+ *     we have
+ *             acoshl(x) := logl(x)+ln2,       if x is large; else
+ *             acoshl(x) := logl(2x-1/(sqrtl(x*x-1)+x)) if x>2; else
+ *             acoshl(x) := log1pl(t+sqrtl(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *     acoshl(x) is NaN with signal if x<1.
+ *     acoshl(NaN) is NaN without signal.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+one    = 1.0,
+ln2    = 0.6931471805599453094172321214581766L;
+
+long double
+acoshl(long double x)
+{
+       long double t;
+       u_int64_t lx;
+       int64_t hx;
+       GET_LDOUBLE_WORDS64(hx,lx,x);
+       if(hx<0x3fff000000000000LL) {           /* x < 1 */
+           return (x-x)/(x-x);
+       } else if(hx >=0x4035000000000000LL) {  /* x > 2**54 */
+           if(hx >=0x7fff000000000000LL) {     /* x is inf of NaN */
+               return x+x;
+           } else
+               return logl(x)+ln2;     /* acoshl(huge)=logl(2x) */
+       } else if(((hx-0x3fff000000000000LL)|lx)==0) {
+           return 0.0L;                        /* acosh(1) = 0 */
+       } else if (hx > 0x4000000000000000LL) { /* 2**28 > x > 2 */
+           t=x*x;
+           return logl(2.0L*x-one/(x+sqrtl(t-one)));
+       } else {                        /* 1<x<2 */
+           t = x-one;
+           return log1pl(t+sqrtl(2.0L*t+t*t));
+       }
+}
diff --git a/ld128/e_atanhl.c b/ld128/e_atanhl.c
new file mode 100644 (file)
index 0000000..70d9805
--- /dev/null
@@ -0,0 +1,65 @@
+/* @(#)e_atanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* atanhl(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                   1              2x                          x
+ *     atanhl(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                   2             1 - x                      1 - x
+ *
+ *     For x<0.5
+ *     atanhl(x) = 0.5*log1pl(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *     atanhl(x) is NaN if |x| > 1 with signal;
+ *     atanhl(NaN) is that NaN with no signal;
+ *     atanhl(+-1) is +-INF with signal.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0L, huge = 1e4900L;
+
+static const long double zero = 0.0L;
+
+long double
+atanhl(long double x)
+{
+       long double t;
+       u_int32_t jx, ix;
+       ieee_quad_shape_type u;
+
+       u.value = x;
+       jx = u.parts32.mswhi;
+       ix = jx & 0x7fffffff;
+       u.parts32.mswhi = ix;
+       if (ix >= 0x3fff0000) /* |x| >= 1.0 or infinity or NaN */
+         {
+           if (u.value == one)
+             return x/zero;
+           else
+             return (x-x)/(x-x);
+         }
+       if(ix<0x3fc60000 && (huge+x)>zero) return x;    /* x < 2^-57 */
+
+       if(ix<0x3ffe0000) {             /* x < 0.5 */
+           t = u.value+u.value;
+           t = 0.5*log1pl(t+t*u.value/(one-u.value));
+       } else
+           t = 0.5*log1pl((u.value+u.value)/(one-u.value));
+       if(jx & 0x80000000) return -t; else return t;
+}
diff --git a/ld128/e_coshl.c b/ld128/e_coshl.c
new file mode 100644 (file)
index 0000000..955c378
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* coshl(x)
+ * Method :
+ * mathematically coshl(x) if defined to be (exp(x)+exp(-x))/2
+ *      1. Replace x by |x| (coshl(x) = coshl(-x)).
+ *      2.
+ *                                                      [ exp(x) - 1 ]^2
+ *          0        <= x <= ln2/2  :  coshl(x) := 1 + -------------------
+ *                                                         2*exp(x)
+ *
+ *                                                 exp(x) +  1/exp(x)
+ *          ln2/2    <= x <= 22     :  coshl(x) := -------------------
+ *                                                         2
+ *          22       <= x <= lnovft :  coshl(x) := expl(x)/2
+ *          lnovft   <= x <= ln2ovft:  coshl(x) := expl(x/2)/2 * expl(x/2)
+ *          ln2ovft  <  x           :  coshl(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ *      coshl(x) is |x| if x is +INF, -INF, or NaN.
+ *      only coshl(0)=1 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, half = 0.5, huge = 1.0e4900L,
+ovf_thresh = 1.1357216553474703894801348310092223067821E4L;
+
+long double
+coshl(long double x)
+{
+  long double t, w;
+  int32_t ex;
+  ieee_quad_shape_type u;
+
+  u.value = x;
+  ex = u.parts32.mswhi & 0x7fffffff;
+
+  /* Absolute value of x.  */
+  u.parts32.mswhi = ex;
+
+  /* x is INF or NaN */
+  if (ex >= 0x7fff0000)
+    return x * x;
+
+  /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */
+  if (ex < 0x3ffd62e4) /* 0.3465728759765625 */
+    {
+      t = expm1l (u.value);
+      w = one + t;
+      if (ex < 0x3fb80000) /* |x| < 2^-116 */
+       return w;               /* cosh(tiny) = 1 */
+
+      return one + (t * t) / (w + w);
+    }
+
+  /* |x| in [0.5*ln2,40], return (exp(|x|)+1/exp(|x|)/2; */
+  if (ex < 0x40044000)
+    {
+      t = expl (u.value);
+      return half * t + half / t;
+    }
+
+  /* |x| in [22, ln(maxdouble)] return half*exp(|x|) */
+  if (ex <= 0x400c62e3) /* 11356.375 */
+    return half * expl (u.value);
+
+  /* |x| in [log(maxdouble), overflowthresold] */
+  if (u.value <= ovf_thresh)
+    {
+      w = expl (half * u.value);
+      t = half * w;
+      return t * w;
+    }
+
+  /* |x| > overflowthresold, cosh(x) overflow */
+  return huge * huge;
+}
diff --git a/ld128/e_expl.c b/ld128/e_expl.c
new file mode 100644 (file)
index 0000000..24c7b50
--- /dev/null
@@ -0,0 +1,145 @@
+/*     $OpenBSD: e_expl.c,v 1.3 2013/11/12 20:35:18 martynas Exp $     */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     expl.c
+ *
+ *     Exponential function, 128-bit long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, expl();
+ *
+ * y = expl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns e (2.71828...) raised to the x power.
+ *
+ * Range reduction is accomplished by separating the argument
+ * into an integer k and fraction f such that
+ *
+ *     x    k  f
+ *    e  = 2  e.
+ *
+ * A Pade' form of degree 2/3 is used to approximate exp(f) - 1
+ * in the basic range [-0.5 ln 2, 0.5 ln 2].
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      +-MAXLOG    100,000     2.6e-34     8.6e-35
+ *
+ *
+ * Error amplification in the exponential function can be
+ * a serious matter.  The error propagation involves
+ * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ),
+ * which shows that a 1 lsb error in representing X produces
+ * a relative error of X times 1 lsb in the function.
+ * While the routine gives an accurate result for arguments
+ * that are exactly represented by a long double precision
+ * computer number, the result contains amplified roundoff
+ * error for large arguments not exactly represented.
+ *
+ *
+ * ERROR MESSAGES:
+ *
+ *   message         condition      value returned
+ * exp underflow    x < MINLOG         0.0
+ * exp overflow     x > MAXLOG         MAXNUM
+ *
+ */
+
+/*     Exponential function    */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Pade' coefficients for exp(x) - 1
+   Theoretical peak relative error = 2.2e-37,
+   relative peak error spread = 9.2e-38
+ */
+static long double P[5] = {
+ 3.279723985560247033712687707263393506266E-10L,
+ 6.141506007208645008909088812338454698548E-7L,
+ 2.708775201978218837374512615596512792224E-4L,
+ 3.508710990737834361215404761139478627390E-2L,
+ 9.999999999999999999999999999999999998502E-1L
+};
+static long double Q[6] = {
+ 2.980756652081995192255342779918052538681E-12L,
+ 1.771372078166251484503904874657985291164E-8L,
+ 1.504792651814944826817779302637284053660E-5L,
+ 3.611828913847589925056132680618007270344E-3L,
+ 2.368408864814233538909747618894558968880E-1L,
+ 2.000000000000000000000000000000000000150E0L
+};
+/* C1 + C2 = ln 2 */
+static const long double C1 = -6.93145751953125E-1L;
+static const long double C2 = -1.428606820309417232121458176568075500134E-6L;
+
+static const long double LOG2EL = 1.442695040888963407359924681001892137426646L;
+static const long double MAXLOGL = 1.1356523406294143949491931077970764891253E4L;
+static const long double MINLOGL = -1.143276959615573793352782661133116431383730e4L;
+static const long double huge = 0x1p10000L;
+#if 0 /* XXX Prevent gcc from erroneously constant folding this. */
+static const long double twom10000 = 0x1p-10000L;
+#else
+static volatile long double twom10000 = 0x1p-10000L;
+#endif
+
+long double
+expl(long double x)
+{
+long double px, xx;
+int n;
+
+if( x > MAXLOGL)
+       return (huge*huge);             /* overflow */
+
+if( x < MINLOGL )
+       return (twom10000*twom10000);   /* underflow */
+
+/* Express e**x = e**g 2**n
+ *   = e**g e**( n loge(2) )
+ *   = e**( g + n loge(2) )
+ */
+px = floorl( LOG2EL * x + 0.5L ); /* floor() truncates toward -infinity. */
+n = px;
+x += px * C1;
+x += px * C2;
+/* rational approximation for exponential
+ * of the fractional part:
+ * e**x =  1 + 2x P(x**2)/( Q(x**2) - P(x**2) )
+ */
+xx = x * x;
+px = x * __polevll( xx, P, 4 );
+xx = __polevll( xx, Q, 5 );
+x =  px/( xx - px );
+x = 1.0L + x + x;
+
+x = ldexpl( x, n );
+return(x);
+}
diff --git a/ld128/e_fmodl.c b/ld128/e_fmodl.c
new file mode 100644 (file)
index 0000000..698fa3a
--- /dev/null
@@ -0,0 +1,129 @@
+/* @(#)e_fmod.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fmodl(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, Zero[] = {0.0, -0.0,};
+
+long double
+fmodl(long double x, long double y)
+{
+       int64_t n,hx,hy,hz,ix,iy,sx,i;
+       u_int64_t lx,ly,lz;
+
+       GET_LDOUBLE_WORDS64(hx,lx,x);
+       GET_LDOUBLE_WORDS64(hy,ly,y);
+       sx = hx&0x8000000000000000ULL;          /* sign of x */
+       hx ^=sx;                                /* |x| */
+       hy &= 0x7fffffffffffffffLL;             /* |y| */
+
+    /* purge off exception values */
+       if((hy|ly)==0||(hx>=0x7fff000000000000LL)|| /* y=0,or x not finite */
+         ((hy|((ly|-ly)>>63))>0x7fff000000000000LL))   /* or y is NaN */
+           return (x*y)/(x*y);
+       if(hx<=hy) {
+           if((hx<hy)||(lx<ly)) return x;      /* |x|<|y| return x */
+           if(lx==ly)
+               return Zero[(u_int64_t)sx>>63]; /* |x|=|y| return x*0*/
+       }
+
+    /* determine ix = ilogb(x) */
+       if(hx<0x0001000000000000LL) {   /* subnormal x */
+           if(hx==0) {
+               for (ix = -16431, i=lx; i>0; i<<=1) ix -=1;
+           } else {
+               for (ix = -16382, i=hx<<15; i>0; i<<=1) ix -=1;
+           }
+       } else ix = (hx>>48)-0x3fff;
+
+    /* determine iy = ilogb(y) */
+       if(hy<0x0001000000000000LL) {   /* subnormal y */
+           if(hy==0) {
+               for (iy = -16431, i=ly; i>0; i<<=1) iy -=1;
+           } else {
+               for (iy = -16382, i=hy<<15; i>0; i<<=1) iy -=1;
+           }
+       } else iy = (hy>>48)-0x3fff;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       if(ix >= -16382)
+           hx = 0x0001000000000000LL|(0x0000ffffffffffffLL&hx);
+       else {          /* subnormal x, shift x to normal */
+           n = -16382-ix;
+           if(n<=63) {
+               hx = (hx<<n)|(lx>>(64-n));
+               lx <<= n;
+           } else {
+               hx = lx<<(n-64);
+               lx = 0;
+           }
+       }
+       if(iy >= -16382)
+           hy = 0x0001000000000000LL|(0x0000ffffffffffffLL&hy);
+       else {          /* subnormal y, shift y to normal */
+           n = -16382-iy;
+           if(n<=63) {
+               hy = (hy<<n)|(ly>>(64-n));
+               ly <<= n;
+           } else {
+               hy = ly<<(n-64);
+               ly = 0;
+           }
+       }
+
+    /* fix point fmod */
+       n = ix - iy;
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
+           else {
+               if((hz|lz)==0)          /* return sign(x)*0 */
+                   return Zero[(u_int64_t)sx>>63];
+               hx = hz+hz+(lz>>63); lx = lz+lz;
+           }
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0)                  /* return sign(x)*0 */
+           return Zero[(u_int64_t)sx>>63];     
+       while(hx<0x0001000000000000LL) {        /* normalize x */
+           hx = hx+hx+(lx>>63); lx = lx+lx;
+           iy -= 1;
+       }
+       if(iy>= -16382) {       /* normalize output */
+           hx = ((hx-0x0001000000000000LL)|((iy+16383)<<48));
+           SET_LDOUBLE_WORDS64(x,hx|sx,lx);
+       } else {                /* subnormal output */
+           n = -16382 - iy;
+           if(n<=48) {
+               lx = (lx>>n)|((u_int64_t)hx<<(64-n));
+               hx >>= n;
+           } else if (n<=63) {
+               lx = (hx<<(64-n))|(lx>>n); hx = sx;
+           } else {
+               lx = hx>>(n-64); hx = sx;
+           }
+           SET_LDOUBLE_WORDS64(x,hx|sx,lx);
+           x *= one;           /* create necessary signal */
+       }
+       return x;               /* exact output */
+}
diff --git a/ld128/e_hypotl.c b/ld128/e_hypotl.c
new file mode 100644 (file)
index 0000000..1cdf3d8
--- /dev/null
@@ -0,0 +1,122 @@
+/* @(#)e_hypot.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* hypotl(x,y)
+ *
+ * Method :
+ *     If (assume round-to-nearest) z=x*x+y*y
+ *     has error less than sqrtl(2)/2 ulp, than
+ *     sqrtl(z) has error less than 1 ulp (exercise).
+ *
+ *     So, compute sqrtl(x*x+y*y) with some care as
+ *     follows to get the error below 1 ulp:
+ *
+ *     Assume x>y>0;
+ *     (if possible, set rounding to round-to-nearest)
+ *     1. if x > 2y  use
+ *             x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *     where x1 = x with lower 64 bits cleared, x2 = x-x1; else
+ *     2. if x <= 2y use
+ *             t1*yy1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *     where t1 = 2x with lower 64 bits cleared, t2 = 2x-t1,
+ *     yy1= y with lower 64 bits chopped, y2 = y-yy1.
+ *
+ *     NOTE: scaling may be necessary if some argument is too
+ *           large or too tiny
+ *
+ * Special cases:
+ *     hypotl(x,y) is INF if x or y is +INF or -INF; else
+ *     hypotl(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ *     hypotl(x,y) returns sqrtl(x^2+y^2) with error less
+ *     than 1 ulps (units in the last place)
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+long double
+hypotl(long double x, long double y)
+{
+       long double a,b,t1,t2,yy1,y2,w;
+       int64_t j,k,ha,hb;
+
+       GET_LDOUBLE_MSW64(ha,x);
+       ha &= 0x7fffffffffffffffLL;
+       GET_LDOUBLE_MSW64(hb,y);
+       hb &= 0x7fffffffffffffffLL;
+       if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+       SET_LDOUBLE_MSW64(a,ha);        /* a <- |a| */
+       SET_LDOUBLE_MSW64(b,hb);        /* b <- |b| */
+       if((ha-hb)>0x78000000000000LL) {return a+b;} /* x/y > 2**120 */
+       k=0;
+       if(ha > 0x5f3f000000000000LL) { /* a>2**8000 */
+          if(ha >= 0x7fff000000000000LL) {     /* Inf or NaN */
+              u_int64_t low;
+              w = a+b;                 /* for sNaN */
+              GET_LDOUBLE_LSW64(low,a);
+              if(((ha&0xffffffffffffLL)|low)==0) w = a;
+              GET_LDOUBLE_LSW64(low,b);
+              if(((hb^0x7fff000000000000LL)|low)==0) w = b;
+              return w;
+          }
+          /* scale a and b by 2**-9600 */
+          ha -= 0x2580000000000000LL;
+          hb -= 0x2580000000000000LL;  k += 9600;
+          SET_LDOUBLE_MSW64(a,ha);
+          SET_LDOUBLE_MSW64(b,hb);
+       }
+       if(hb < 0x20bf000000000000LL) { /* b < 2**-8000 */
+           if(hb <= 0x0000ffffffffffffLL) {    /* subnormal b or 0 */
+               u_int64_t low;
+               GET_LDOUBLE_LSW64(low,b);
+               if((hb|low)==0) return a;
+               t1=0;
+               SET_LDOUBLE_MSW64(t1,0x7ffd000000000000LL); /* t1=2^16382 */
+               b *= t1;
+               a *= t1;
+               k -= 16382;
+           } else {            /* scale a and b by 2^9600 */
+               ha += 0x2580000000000000LL;     /* a *= 2^9600 */
+               hb += 0x2580000000000000LL;     /* b *= 2^9600 */
+               k -= 9600;
+               SET_LDOUBLE_MSW64(a,ha);
+               SET_LDOUBLE_MSW64(b,hb);
+           }
+       }
+    /* medium size a and b */
+       w = a-b;
+       if (w>b) {
+           t1 = 0;
+           SET_LDOUBLE_MSW64(t1,ha);
+           t2 = a-t1;
+           w  = sqrtl(t1*t1-(b*(-b)-t2*(a+t1)));
+       } else {
+           a  = a+a;
+           yy1 = 0;
+           SET_LDOUBLE_MSW64(yy1,hb);
+           y2 = b - yy1;
+           t1 = 0;
+           SET_LDOUBLE_MSW64(t1,ha+0x0001000000000000LL);
+           t2 = a - t1;
+           w  = sqrtl(t1*yy1-(w*(-w)-(t1*y2+t2*b)));
+       }
+       if(k!=0) {
+           u_int64_t high;
+           t1 = 1.0L;
+           GET_LDOUBLE_MSW64(high,t1);
+           SET_LDOUBLE_MSW64(t1,high+(k<<48));
+           return t1*w;
+       } else return w;
+}
diff --git a/ld128/e_lgammal_r.c b/ld128/e_lgammal_r.c
new file mode 100644 (file)
index 0000000..dd8ea5d
--- /dev/null
@@ -0,0 +1,1037 @@
+/*     $OpenBSD: e_lgammal.c,v 1.3 2011/07/09 05:29:06 martynas Exp $  */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                      lgammal_r
+ *
+ *      Natural logarithm of gamma function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, lgammal_r();
+ * int signgam;
+ *
+ * y = lgammal_r(x, &signgam);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base e (2.718...) logarithm of the absolute
+ * value of the gamma function of the argument.
+ * The sign (+1 or -1) of the gamma function is returned through signgamp.
+ *
+ * The positive domain is partitioned into numerous segments for approximation.
+ * For x > 10,
+ *   log gamma(x) = (x - 0.5) log(x) - x + log sqrt(2 pi) + 1/x R(1/x^2)
+ * Near the minimum at x = x0 = 1.46... the approximation is
+ *   log gamma(x0 + z) = log gamma(x0) + z^2 P(z)/Q(z)
+ * for small z.
+ * Elsewhere between 0 and 10,
+ *   log gamma(n + z) = log gamma(n) + z P(z)/Q(z)
+ * for various selected n and small z.
+ *
+ * The cosecant reflection formula is employed for negative arguments.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *
+ * arithmetic      domain        # trials     peak         rms
+ *                                            Relative error:
+ *    IEEE         10, 30         100000     3.9e-34     9.8e-35
+ *    IEEE          0, 10         100000     3.8e-34     5.3e-35
+ *                                            Absolute error:
+ *    IEEE         -10, 0         100000     8.0e-34     8.0e-35
+ *    IEEE         -30, -10       100000     4.4e-34     1.0e-34
+ *    IEEE        -100, 100       100000                 1.0e-34
+ *
+ * The absolute error criterion is the same as relative error
+ * when the function magnitude is greater than one but it is absolute
+ * when the magnitude is less than one.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double PIL = 3.1415926535897932384626433832795028841972E0L;
+static const long double MAXLGM = 1.0485738685148938358098967157129705071571E4928L;
+static const long double one = 1.0L;
+static const long double huge = 1.0e4000L;
+
+/* log gamma(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x P(1/x^2)
+   1/x <= 0.0741 (x >= 13.495...)
+   Peak relative error 1.5e-36  */
+static const long double ls2pi = 9.1893853320467274178032973640561763986140E-1L;
+#define NRASY 12
+static const long double RASY[NRASY + 1] =
+{
+  8.333333333333333333333333333310437112111E-2L,
+ -2.777777777777777777777774789556228296902E-3L,
+  7.936507936507936507795933938448586499183E-4L,
+ -5.952380952380952041799269756378148574045E-4L,
+  8.417508417507928904209891117498524452523E-4L,
+ -1.917526917481263997778542329739806086290E-3L,
+  6.410256381217852504446848671499409919280E-3L,
+ -2.955064066900961649768101034477363301626E-2L,
+  1.796402955865634243663453415388336954675E-1L,
+ -1.391522089007758553455753477688592767741E0L,
+  1.326130089598399157988112385013829305510E1L,
+ -1.420412699593782497803472576479997819149E2L,
+  1.218058922427762808938869872528846787020E3L
+};
+
+
+/* log gamma(x+13) = log gamma(13) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   12.5 <= x+13 <= 13.5
+   Peak relative error 1.1e-36  */
+static const long double lgam13a = 1.9987213134765625E1L;
+static const long double lgam13b = 1.3608962611495173623870550785125024484248E-6L;
+#define NRN13 7
+static const long double RN13[NRN13 + 1] =
+{
+  8.591478354823578150238226576156275285700E11L,
+  2.347931159756482741018258864137297157668E11L,
+  2.555408396679352028680662433943000804616E10L,
+  1.408581709264464345480765758902967123937E9L,
+  4.126759849752613822953004114044451046321E7L,
+  6.133298899622688505854211579222889943778E5L,
+  3.929248056293651597987893340755876578072E3L,
+  6.850783280018706668924952057996075215223E0L
+};
+#define NRD13 6
+static const long double RD13[NRD13 + 1] =
+{
+  3.401225382297342302296607039352935541669E11L,
+  8.756765276918037910363513243563234551784E10L,
+  8.873913342866613213078554180987647243903E9L,
+  4.483797255342763263361893016049310017973E8L,
+  1.178186288833066430952276702931512870676E7L,
+  1.519928623743264797939103740132278337476E5L,
+  7.989298844938119228411117593338850892311E2L
+ /* 1.0E0L */
+};
+
+
+/* log gamma(x+12) = log gamma(12) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   11.5 <= x+12 <= 12.5
+   Peak relative error 4.1e-36  */
+static const long double lgam12a = 1.75023040771484375E1L;
+static const long double lgam12b = 3.7687254483392876529072161996717039575982E-6L;
+#define NRN12 7
+static const long double RN12[NRN12 + 1] =
+{
+  4.709859662695606986110997348630997559137E11L,
+  1.398713878079497115037857470168777995230E11L,
+  1.654654931821564315970930093932954900867E10L,
+  9.916279414876676861193649489207282144036E8L,
+  3.159604070526036074112008954113411389879E7L,
+  5.109099197547205212294747623977502492861E5L,
+  3.563054878276102790183396740969279826988E3L,
+  6.769610657004672719224614163196946862747E0L
+};
+#define NRD12 6
+static const long double RD12[NRD12 + 1] =
+{
+  1.928167007860968063912467318985802726613E11L,
+  5.383198282277806237247492369072266389233E10L,
+  5.915693215338294477444809323037871058363E9L,
+  3.241438287570196713148310560147925781342E8L,
+  9.236680081763754597872713592701048455890E6L,
+  1.292246897881650919242713651166596478850E5L,
+  7.366532445427159272584194816076600211171E2L
+ /* 1.0E0L */
+};
+
+
+/* log gamma(x+11) = log gamma(11) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   10.5 <= x+11 <= 11.5
+   Peak relative error 1.8e-35  */
+static const long double lgam11a = 1.5104400634765625E1L;
+static const long double lgam11b = 1.1938309890295225709329251070371882250744E-5L;
+#define NRN11 7
+static const long double RN11[NRN11 + 1] =
+{
+  2.446960438029415837384622675816736622795E11L,
+  7.955444974446413315803799763901729640350E10L,
+  1.030555327949159293591618473447420338444E10L,
+  6.765022131195302709153994345470493334946E8L,
+  2.361892792609204855279723576041468347494E7L,
+  4.186623629779479136428005806072176490125E5L,
+  3.202506022088912768601325534149383594049E3L,
+  6.681356101133728289358838690666225691363E0L
+};
+#define NRD11 6
+static const long double RD11[NRD11 + 1] =
+{
+  1.040483786179428590683912396379079477432E11L,
+  3.172251138489229497223696648369823779729E10L,
+  3.806961885984850433709295832245848084614E9L,
+  2.278070344022934913730015420611609620171E8L,
+  7.089478198662651683977290023829391596481E6L,
+  1.083246385105903533237139380509590158658E5L,
+  6.744420991491385145885727942219463243597E2L
+ /* 1.0E0L */
+};
+
+
+/* log gamma(x+10) = log gamma(10) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   9.5 <= x+10 <= 10.5
+   Peak relative error 5.4e-37  */
+static const long double lgam10a = 1.280181884765625E1L;
+static const long double lgam10b = 8.6324252196112077178745667061642811492557E-6L;
+#define NRN10 7
+static const long double RN10[NRN10 + 1] =
+{
+  -1.239059737177249934158597996648808363783E14L,
+  -4.725899566371458992365624673357356908719E13L,
+  -7.283906268647083312042059082837754850808E12L,
+  -5.802855515464011422171165179767478794637E11L,
+  -2.532349691157548788382820303182745897298E10L,
+  -5.884260178023777312587193693477072061820E8L,
+  -6.437774864512125749845840472131829114906E6L,
+  -2.350975266781548931856017239843273049384E4L
+};
+#define NRD10 7
+static const long double RD10[NRD10 + 1] =
+{
+  -5.502645997581822567468347817182347679552E13L,
+  -1.970266640239849804162284805400136473801E13L,
+  -2.819677689615038489384974042561531409392E12L,
+  -2.056105863694742752589691183194061265094E11L,
+  -8.053670086493258693186307810815819662078E9L,
+  -1.632090155573373286153427982504851867131E8L,
+  -1.483575879240631280658077826889223634921E6L,
+  -4.002806669713232271615885826373550502510E3L
+ /* 1.0E0L */
+};
+
+
+/* log gamma(x+9) = log gamma(9) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   8.5 <= x+9 <= 9.5
+   Peak relative error 3.6e-36  */
+static const long double lgam9a = 1.06045989990234375E1L;
+static const long double lgam9b = 3.9037218127284172274007216547549861681400E-6L;
+#define NRN9 7
+static const long double RN9[NRN9 + 1] =
+{
+  -4.936332264202687973364500998984608306189E13L,
+  -2.101372682623700967335206138517766274855E13L,
+  -3.615893404644823888655732817505129444195E12L,
+  -3.217104993800878891194322691860075472926E11L,
+  -1.568465330337375725685439173603032921399E10L,
+  -4.073317518162025744377629219101510217761E8L,
+  -4.983232096406156139324846656819246974500E6L,
+  -2.036280038903695980912289722995505277253E4L
+};
+#define NRD9 7
+static const long double RD9[NRD9 + 1] =
+{
+  -2.306006080437656357167128541231915480393E13L,
+  -9.183606842453274924895648863832233799950E12L,
+  -1.461857965935942962087907301194381010380E12L,
+  -1.185728254682789754150068652663124298303E11L,
+  -5.166285094703468567389566085480783070037E9L,
+  -1.164573656694603024184768200787835094317E8L,
+  -1.177343939483908678474886454113163527909E6L,
+  -3.529391059783109732159524500029157638736E3L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+8) = log gamma(8) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   7.5 <= x+8 <= 8.5
+   Peak relative error 2.4e-37  */
+static const long double lgam8a = 8.525146484375E0L;
+static const long double lgam8b = 1.4876690414300165531036347125050759667737E-5L;
+#define NRN8 8
+static const long double RN8[NRN8 + 1] =
+{
+  6.600775438203423546565361176829139703289E11L,
+  3.406361267593790705240802723914281025800E11L,
+  7.222460928505293914746983300555538432830E10L,
+  8.102984106025088123058747466840656458342E9L,
+  5.157620015986282905232150979772409345927E8L,
+  1.851445288272645829028129389609068641517E7L,
+  3.489261702223124354745894067468953756656E5L,
+  2.892095396706665774434217489775617756014E3L,
+  6.596977510622195827183948478627058738034E0L
+};
+#define NRD8 7
+static const long double RD8[NRD8 + 1] =
+{
+  3.274776546520735414638114828622673016920E11L,
+  1.581811207929065544043963828487733970107E11L,
+  3.108725655667825188135393076860104546416E10L,
+  3.193055010502912617128480163681842165730E9L,
+  1.830871482669835106357529710116211541839E8L,
+  5.790862854275238129848491555068073485086E6L,
+  9.305213264307921522842678835618803553589E4L,
+  6.216974105861848386918949336819572333622E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+7) = log gamma(7) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   6.5 <= x+7 <= 7.5
+   Peak relative error 3.2e-36  */
+static const long double lgam7a = 6.5792388916015625E0L;
+static const long double lgam7b = 1.2320408538495060178292903945321122583007E-5L;
+#define NRN7 8
+static const long double RN7[NRN7 + 1] =
+{
+  2.065019306969459407636744543358209942213E11L,
+  1.226919919023736909889724951708796532847E11L,
+  2.996157990374348596472241776917953749106E10L,
+  3.873001919306801037344727168434909521030E9L,
+  2.841575255593761593270885753992732145094E8L,
+  1.176342515359431913664715324652399565551E7L,
+  2.558097039684188723597519300356028511547E5L,
+  2.448525238332609439023786244782810774702E3L,
+  6.460280377802030953041566617300902020435E0L
+};
+#define NRD7 7
+static const long double RD7[NRD7 + 1] =
+{
+  1.102646614598516998880874785339049304483E11L,
+  6.099297512712715445879759589407189290040E10L,
+  1.372898136289611312713283201112060238351E10L,
+  1.615306270420293159907951633566635172343E9L,
+  1.061114435798489135996614242842561967459E8L,
+  3.845638971184305248268608902030718674691E6L,
+  7.081730675423444975703917836972720495507E4L,
+  5.423122582741398226693137276201344096370E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+6) = log gamma(6) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   5.5 <= x+6 <= 6.5
+   Peak relative error 6.2e-37  */
+static const long double lgam6a = 4.7874908447265625E0L;
+static const long double lgam6b = 8.9805548349424770093452324304839959231517E-7L;
+#define NRN6 8
+static const long double RN6[NRN6 + 1] =
+{
+  -3.538412754670746879119162116819571823643E13L,
+  -2.613432593406849155765698121483394257148E13L,
+  -8.020670732770461579558867891923784753062E12L,
+  -1.322227822931250045347591780332435433420E12L,
+  -1.262809382777272476572558806855377129513E11L,
+  -7.015006277027660872284922325741197022467E9L,
+  -2.149320689089020841076532186783055727299E8L,
+  -3.167210585700002703820077565539658995316E6L,
+  -1.576834867378554185210279285358586385266E4L
+};
+#define NRD6 8
+static const long double RD6[NRD6 + 1] =
+{
+  -2.073955870771283609792355579558899389085E13L,
+  -1.421592856111673959642750863283919318175E13L,
+  -4.012134994918353924219048850264207074949E12L,
+  -6.013361045800992316498238470888523722431E11L,
+  -5.145382510136622274784240527039643430628E10L,
+  -2.510575820013409711678540476918249524123E9L,
+  -6.564058379709759600836745035871373240904E7L,
+  -7.861511116647120540275354855221373571536E5L,
+  -2.821943442729620524365661338459579270561E3L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+5) = log gamma(5) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   4.5 <= x+5 <= 5.5
+   Peak relative error 3.4e-37  */
+static const long double lgam5a = 3.17803955078125E0L;
+static const long double lgam5b = 1.4279566695619646941601297055408873990961E-5L;
+#define NRN5 9
+static const long double RN5[NRN5 + 1] =
+{
+  2.010952885441805899580403215533972172098E11L,
+  1.916132681242540921354921906708215338584E11L,
+  7.679102403710581712903937970163206882492E10L,
+  1.680514903671382470108010973615268125169E10L,
+  2.181011222911537259440775283277711588410E9L,
+  1.705361119398837808244780667539728356096E8L,
+  7.792391565652481864976147945997033946360E6L,
+  1.910741381027985291688667214472560023819E5L,
+  2.088138241893612679762260077783794329559E3L,
+  6.330318119566998299106803922739066556550E0L
+};
+#define NRD5 8
+static const long double RD5[NRD5 + 1] =
+{
+  1.335189758138651840605141370223112376176E11L,
+  1.174130445739492885895466097516530211283E11L,
+  4.308006619274572338118732154886328519910E10L,
+  8.547402888692578655814445003283720677468E9L,
+  9.934628078575618309542580800421370730906E8L,
+  6.847107420092173812998096295422311820672E7L,
+  2.698552646016599923609773122139463150403E6L,
+  5.526516251532464176412113632726150253215E4L,
+  4.772343321713697385780533022595450486932E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+4) = log gamma(4) +  x P(x)/Q(x)
+   -0.5 <= x <= 0.5
+   3.5 <= x+4 <= 4.5
+   Peak relative error 6.7e-37  */
+static const long double lgam4a = 1.791748046875E0L;
+static const long double lgam4b = 1.1422353055000812477358380702272722990692E-5L;
+#define NRN4 9
+static const long double RN4[NRN4 + 1] =
+{
+  -1.026583408246155508572442242188887829208E13L,
+  -1.306476685384622809290193031208776258809E13L,
+  -7.051088602207062164232806511992978915508E12L,
+  -2.100849457735620004967624442027793656108E12L,
+  -3.767473790774546963588549871673843260569E11L,
+  -4.156387497364909963498394522336575984206E10L,
+  -2.764021460668011732047778992419118757746E9L,
+  -1.036617204107109779944986471142938641399E8L,
+  -1.895730886640349026257780896972598305443E6L,
+  -1.180509051468390914200720003907727988201E4L
+};
+#define NRD4 9
+static const long double RD4[NRD4 + 1] =
+{
+  -8.172669122056002077809119378047536240889E12L,
+  -9.477592426087986751343695251801814226960E12L,
+  -4.629448850139318158743900253637212801682E12L,
+  -1.237965465892012573255370078308035272942E12L,
+  -1.971624313506929845158062177061297598956E11L,
+  -1.905434843346570533229942397763361493610E10L,
+  -1.089409357680461419743730978512856675984E9L,
+  -3.416703082301143192939774401370222822430E7L,
+  -4.981791914177103793218433195857635265295E5L,
+  -2.192507743896742751483055798411231453733E3L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+3) = log gamma(3) +  x P(x)/Q(x)
+   -0.25 <= x <= 0.5
+   2.75 <= x+3 <= 3.5
+   Peak relative error 6.0e-37  */
+static const long double lgam3a = 6.93145751953125E-1L;
+static const long double lgam3b = 1.4286068203094172321214581765680755001344E-6L;
+
+#define NRN3 9
+static const long double RN3[NRN3 + 1] =
+{
+  -4.813901815114776281494823863935820876670E11L,
+  -8.425592975288250400493910291066881992620E11L,
+  -6.228685507402467503655405482985516909157E11L,
+  -2.531972054436786351403749276956707260499E11L,
+  -6.170200796658926701311867484296426831687E10L,
+  -9.211477458528156048231908798456365081135E9L,
+  -8.251806236175037114064561038908691305583E8L,
+  -4.147886355917831049939930101151160447495E7L,
+  -1.010851868928346082547075956946476932162E6L,
+  -8.333374463411801009783402800801201603736E3L
+};
+#define NRD3 9
+static const long double RD3[NRD3 + 1] =
+{
+  -5.216713843111675050627304523368029262450E11L,
+  -8.014292925418308759369583419234079164391E11L,
+  -5.180106858220030014546267824392678611990E11L,
+  -1.830406975497439003897734969120997840011E11L,
+  -3.845274631904879621945745960119924118925E10L,
+  -4.891033385370523863288908070309417710903E9L,
+  -3.670172254411328640353855768698287474282E8L,
+  -1.505316381525727713026364396635522516989E7L,
+  -2.856327162923716881454613540575964890347E5L,
+  -1.622140448015769906847567212766206894547E3L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+2.5) = log gamma(2.5) +  x P(x)/Q(x)
+   -0.125 <= x <= 0.25
+   2.375 <= x+2.5 <= 2.75  */
+static const long double lgam2r5a = 2.8466796875E-1L;
+static const long double lgam2r5b = 1.4901722919159632494669682701924320137696E-5L;
+#define NRN2r5 8
+static const long double RN2r5[NRN2r5 + 1] =
+{
+  -4.676454313888335499356699817678862233205E9L,
+  -9.361888347911187924389905984624216340639E9L,
+  -7.695353600835685037920815799526540237703E9L,
+  -3.364370100981509060441853085968900734521E9L,
+  -8.449902011848163568670361316804900559863E8L,
+  -1.225249050950801905108001246436783022179E8L,
+  -9.732972931077110161639900388121650470926E6L,
+  -3.695711763932153505623248207576425983573E5L,
+  -4.717341584067827676530426007495274711306E3L
+};
+#define NRD2r5 8
+static const long double RD2r5[NRD2r5 + 1] =
+{
+  -6.650657966618993679456019224416926875619E9L,
+  -1.099511409330635807899718829033488771623E10L,
+  -7.482546968307837168164311101447116903148E9L,
+  -2.702967190056506495988922973755870557217E9L,
+  -5.570008176482922704972943389590409280950E8L,
+  -6.536934032192792470926310043166993233231E7L,
+  -4.101991193844953082400035444146067511725E6L,
+  -1.174082735875715802334430481065526664020E5L,
+  -9.932840389994157592102947657277692978511E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+2) = x P(x)/Q(x)
+   -0.125 <= x <= +0.375
+   1.875 <= x+2 <= 2.375
+   Peak relative error 4.6e-36  */
+#define NRN2 9
+static const long double RN2[NRN2 + 1] =
+{
+  -3.716661929737318153526921358113793421524E9L,
+  -1.138816715030710406922819131397532331321E10L,
+  -1.421017419363526524544402598734013569950E10L,
+  -9.510432842542519665483662502132010331451E9L,
+  -3.747528562099410197957514973274474767329E9L,
+  -8.923565763363912474488712255317033616626E8L,
+  -1.261396653700237624185350402781338231697E8L,
+  -9.918402520255661797735331317081425749014E6L,
+  -3.753996255897143855113273724233104768831E5L,
+  -4.778761333044147141559311805999540765612E3L
+};
+#define NRD2 9
+static const long double RD2[NRD2 + 1] =
+{
+  -8.790916836764308497770359421351673950111E9L,
+  -2.023108608053212516399197678553737477486E10L,
+  -1.958067901852022239294231785363504458367E10L,
+  -1.035515043621003101254252481625188704529E10L,
+  -3.253884432621336737640841276619272224476E9L,
+  -6.186383531162456814954947669274235815544E8L,
+  -6.932557847749518463038934953605969951466E7L,
+  -4.240731768287359608773351626528479703758E6L,
+  -1.197343995089189188078944689846348116630E5L,
+  -1.004622911670588064824904487064114090920E3L
+/* 1.0E0 */
+};
+
+
+/* log gamma(x+1.75) = log gamma(1.75) +  x P(x)/Q(x)
+   -0.125 <= x <= +0.125
+   1.625 <= x+1.75 <= 1.875
+   Peak relative error 9.2e-37 */
+static const long double lgam1r75a = -8.441162109375E-2L;
+static const long double lgam1r75b = 1.0500073264444042213965868602268256157604E-5L;
+#define NRN1r75 8
+static const long double RN1r75[NRN1r75 + 1] =
+{
+  -5.221061693929833937710891646275798251513E7L,
+  -2.052466337474314812817883030472496436993E8L,
+  -2.952718275974940270675670705084125640069E8L,
+  -2.132294039648116684922965964126389017840E8L,
+  -8.554103077186505960591321962207519908489E7L,
+  -1.940250901348870867323943119132071960050E7L,
+  -2.379394147112756860769336400290402208435E6L,
+  -1.384060879999526222029386539622255797389E5L,
+  -2.698453601378319296159355612094598695530E3L
+};
+#define NRD1r75 8
+static const long double RD1r75[NRD1r75 + 1] =
+{
+  -2.109754689501705828789976311354395393605E8L,
+  -5.036651829232895725959911504899241062286E8L,
+  -4.954234699418689764943486770327295098084E8L,
+  -2.589558042412676610775157783898195339410E8L,
+  -7.731476117252958268044969614034776883031E7L,
+  -1.316721702252481296030801191240867486965E7L,
+  -1.201296501404876774861190604303728810836E6L,
+  -5.007966406976106636109459072523610273928E4L,
+  -6.155817990560743422008969155276229018209E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+x0) = y0 +  x^2 P(x)/Q(x)
+   -0.0867 <= x <= +0.1634
+   1.374932... <= x+x0 <= 1.625032...
+   Peak relative error 4.0e-36  */
+static const long double x0a = 1.4616241455078125L;
+static const long double x0b = 7.9994605498412626595423257213002588621246E-6L;
+static const long double y0a = -1.21490478515625E-1L;
+static const long double y0b = 4.1879797753919044854428223084178486438269E-6L;
+#define NRN1r5 8
+static const long double RN1r5[NRN1r5 + 1] =
+{
+  6.827103657233705798067415468881313128066E5L,
+  1.910041815932269464714909706705242148108E6L,
+  2.194344176925978377083808566251427771951E6L,
+  1.332921400100891472195055269688876427962E6L,
+  4.589080973377307211815655093824787123508E5L,
+  8.900334161263456942727083580232613796141E4L,
+  9.053840838306019753209127312097612455236E3L,
+  4.053367147553353374151852319743594873771E2L,
+  5.040631576303952022968949605613514584950E0L
+};
+#define NRD1r5 8
+static const long double RD1r5[NRD1r5 + 1] =
+{
+  1.411036368843183477558773688484699813355E6L,
+  4.378121767236251950226362443134306184849E6L,
+  5.682322855631723455425929877581697918168E6L,
+  3.999065731556977782435009349967042222375E6L,
+  1.653651390456781293163585493620758410333E6L,
+  4.067774359067489605179546964969435858311E5L,
+  5.741463295366557346748361781768833633256E4L,
+  4.226404539738182992856094681115746692030E3L,
+  1.316980975410327975566999780608618774469E2L,
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x+1.25) = log gamma(1.25) +  x P(x)/Q(x)
+   -.125 <= x <= +.125
+   1.125 <= x+1.25 <= 1.375
+   Peak relative error = 4.9e-36 */
+static const long double lgam1r25a = -9.82818603515625E-2L;
+static const long double lgam1r25b = 1.0023929749338536146197303364159774377296E-5L;
+#define NRN1r25 9
+static const long double RN1r25[NRN1r25 + 1] =
+{
+  -9.054787275312026472896002240379580536760E4L,
+  -8.685076892989927640126560802094680794471E4L,
+  2.797898965448019916967849727279076547109E5L,
+  6.175520827134342734546868356396008898299E5L,
+  5.179626599589134831538516906517372619641E5L,
+  2.253076616239043944538380039205558242161E5L,
+  5.312653119599957228630544772499197307195E4L,
+  6.434329437514083776052669599834938898255E3L,
+  3.385414416983114598582554037612347549220E2L,
+  4.907821957946273805080625052510832015792E0L
+};
+#define NRD1r25 8
+static const long double RD1r25[NRD1r25 + 1] =
+{
+  3.980939377333448005389084785896660309000E5L,
+  1.429634893085231519692365775184490465542E6L,
+  2.145438946455476062850151428438668234336E6L,
+  1.743786661358280837020848127465970357893E6L,
+  8.316364251289743923178092656080441655273E5L,
+  2.355732939106812496699621491135458324294E5L,
+  3.822267399625696880571810137601310855419E4L,
+  3.228463206479133236028576845538387620856E3L,
+  1.152133170470059555646301189220117965514E2L
+  /* 1.0E0L */
+};
+
+
+/* log gamma(x + 1) = x P(x)/Q(x)
+   0.0 <= x <= +0.125
+   1.0 <= x+1 <= 1.125
+   Peak relative error 1.1e-35  */
+#define NRN1 8
+static const long double RN1[NRN1 + 1] =
+{
+  -9.987560186094800756471055681088744738818E3L,
+  -2.506039379419574361949680225279376329742E4L,
+  -1.386770737662176516403363873617457652991E4L,
+  1.439445846078103202928677244188837130744E4L,
+  2.159612048879650471489449668295139990693E4L,
+  1.047439813638144485276023138173676047079E4L,
+  2.250316398054332592560412486630769139961E3L,
+  1.958510425467720733041971651126443864041E2L,
+  4.516830313569454663374271993200291219855E0L
+};
+#define NRD1 7
+static const long double RD1[NRD1 + 1] =
+{
+  1.730299573175751778863269333703788214547E4L,
+  6.807080914851328611903744668028014678148E4L,
+  1.090071629101496938655806063184092302439E5L,
+  9.124354356415154289343303999616003884080E4L,
+  4.262071638655772404431164427024003253954E4L,
+  1.096981664067373953673982635805821283581E4L,
+  1.431229503796575892151252708527595787588E3L,
+  7.734110684303689320830401788262295992921E1L
+ /* 1.0E0 */
+};
+
+
+/* log gamma(x + 1) = x P(x)/Q(x)
+   -0.125 <= x <= 0
+   0.875 <= x+1 <= 1.0
+   Peak relative error 7.0e-37  */
+#define NRNr9 8
+static const long double RNr9[NRNr9 + 1] =
+{
+  4.441379198241760069548832023257571176884E5L,
+  1.273072988367176540909122090089580368732E6L,
+  9.732422305818501557502584486510048387724E5L,
+  -5.040539994443998275271644292272870348684E5L,
+  -1.208719055525609446357448132109723786736E6L,
+  -7.434275365370936547146540554419058907156E5L,
+  -2.075642969983377738209203358199008185741E5L,
+  -2.565534860781128618589288075109372218042E4L,
+  -1.032901669542994124131223797515913955938E3L,
+};
+#define NRDr9 8
+static const long double RDr9[NRDr9 + 1] =
+{
+  -7.694488331323118759486182246005193998007E5L,
+  -3.301918855321234414232308938454112213751E6L,
+  -5.856830900232338906742924836032279404702E6L,
+  -5.540672519616151584486240871424021377540E6L,
+  -3.006530901041386626148342989181721176919E6L,
+  -9.350378280513062139466966374330795935163E5L,
+  -1.566179100031063346901755685375732739511E5L,
+  -1.205016539620260779274902967231510804992E4L,
+  -2.724583156305709733221564484006088794284E2L
+/* 1.0E0 */
+};
+
+
+/* Evaluate P[n] x^n  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+neval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+/* Evaluate x^n+1  +  P[n] x^(n)  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+deval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = x + *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+long double
+lgammal_r(long double x, int *signgamp)
+{
+  long double p, q, w, z, nx;
+  int i, nn;
+
+  *signgamp = 1;
+
+  if (!isfinite (x))
+    return x * x;
+
+  if (x == 0.0L)
+    {
+      if (signbit (x))
+       *signgamp = -1;
+      return one / fabsl (x);
+    }
+
+  if (x < 0.0L)
+    {
+      q = -x;
+      p = floorl (q);
+      if (p == q)
+       return (one / (p - p));
+      i = p;
+      if ((i & 1) == 0)
+       *signgamp = -1;
+      else
+       *signgamp = 1;
+      z = q - p;
+      if (z > 0.5L)
+       {
+         p += 1.0L;
+         z = p - q;
+       }
+      z = q * sinl (PIL * z);
+      if (z == 0.0L)
+       return (*signgamp * huge * huge);
+      w = lgammal (q);
+      z = logl (PIL / z) - w;
+      return (z);
+    }
+
+  if (x < 13.5L)
+    {
+      p = 0.0L;
+      nx = floorl (x + 0.5L);
+      nn = nx;
+      switch (nn)
+       {
+       case 0:
+         /* log gamma (x + 1) = log(x) + log gamma(x) */
+         if (x <= 0.125)
+           {
+             p = x * neval (x, RN1, NRN1) / deval (x, RD1, NRD1);
+           }
+         else if (x <= 0.375)
+           {
+             z = x - 0.25L;
+             p = z * neval (z, RN1r25, NRN1r25) / deval (z, RD1r25, NRD1r25);
+             p += lgam1r25b;
+             p += lgam1r25a;
+           }
+         else if (x <= 0.625)
+           {
+             z = x + (1.0L - x0a);
+             z = z - x0b;
+             p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5);
+             p = p * z * z;
+             p = p + y0b;
+             p = p + y0a;
+           }
+         else if (x <= 0.875)
+           {
+             z = x - 0.75L;
+             p = z * neval (z, RN1r75, NRN1r75) / deval (z, RD1r75, NRD1r75);
+             p += lgam1r75b;
+             p += lgam1r75a;
+           }
+         else
+           {
+             z = x - 1.0L;
+             p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2);
+           }
+         p = p - logl (x);
+         break;
+
+       case 1:
+         if (x < 0.875L)
+           {
+             if (x <= 0.625)
+               {
+                 z = x + (1.0L - x0a);
+                 z = z - x0b;
+                 p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5);
+                 p = p * z * z;
+                 p = p + y0b;
+                 p = p + y0a;
+               }
+             else if (x <= 0.875)
+               {
+                 z = x - 0.75L;
+                 p = z * neval (z, RN1r75, NRN1r75)
+                       / deval (z, RD1r75, NRD1r75);
+                 p += lgam1r75b;
+                 p += lgam1r75a;
+               }
+             else
+               {
+                 z = x - 1.0L;
+                 p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2);
+               }
+             p = p - logl (x);
+           }
+         else if (x < 1.0L)
+           {
+             z = x - 1.0L;
+             p = z * neval (z, RNr9, NRNr9) / deval (z, RDr9, NRDr9);
+           }
+         else if (x == 1.0L)
+           p = 0.0L;
+         else if (x <= 1.125L)
+           {
+             z = x - 1.0L;
+             p = z * neval (z, RN1, NRN1) / deval (z, RD1, NRD1);
+           }
+         else if (x <= 1.375)
+           {
+             z = x - 1.25L;
+             p = z * neval (z, RN1r25, NRN1r25) / deval (z, RD1r25, NRD1r25);
+             p += lgam1r25b;
+             p += lgam1r25a;
+           }
+         else
+           {
+             /* 1.375 <= x+x0 <= 1.625 */
+             z = x - x0a;
+             z = z - x0b;
+             p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5);
+             p = p * z * z;
+             p = p + y0b;
+             p = p + y0a;
+           }
+         break;
+
+       case 2:
+         if (x < 1.625L)
+           {
+             z = x - x0a;
+             z = z - x0b;
+             p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5);
+             p = p * z * z;
+             p = p + y0b;
+             p = p + y0a;
+           }
+         else if (x < 1.875L)
+           {
+             z = x - 1.75L;
+             p = z * neval (z, RN1r75, NRN1r75) / deval (z, RD1r75, NRD1r75);
+             p += lgam1r75b;
+             p += lgam1r75a;
+           }
+         else if (x == 2.0L)
+           p = 0.0L;
+         else if (x < 2.375L)
+           {
+             z = x - 2.0L;
+             p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2);
+           }
+         else
+           {
+             z = x - 2.5L;
+             p = z * neval (z, RN2r5, NRN2r5) / deval (z, RD2r5, NRD2r5);
+             p += lgam2r5b;
+             p += lgam2r5a;
+           }
+         break;
+
+       case 3:
+         if (x < 2.75)
+           {
+             z = x - 2.5L;
+             p = z * neval (z, RN2r5, NRN2r5) / deval (z, RD2r5, NRD2r5);
+             p += lgam2r5b;
+             p += lgam2r5a;
+           }
+         else
+           {
+             z = x - 3.0L;
+             p = z * neval (z, RN3, NRN3) / deval (z, RD3, NRD3);
+             p += lgam3b;
+             p += lgam3a;
+           }
+         break;
+
+       case 4:
+         z = x - 4.0L;
+         p = z * neval (z, RN4, NRN4) / deval (z, RD4, NRD4);
+         p += lgam4b;
+         p += lgam4a;
+         break;
+
+       case 5:
+         z = x - 5.0L;
+         p = z * neval (z, RN5, NRN5) / deval (z, RD5, NRD5);
+         p += lgam5b;
+         p += lgam5a;
+         break;
+
+       case 6:
+         z = x - 6.0L;
+         p = z * neval (z, RN6, NRN6) / deval (z, RD6, NRD6);
+         p += lgam6b;
+         p += lgam6a;
+         break;
+
+       case 7:
+         z = x - 7.0L;
+         p = z * neval (z, RN7, NRN7) / deval (z, RD7, NRD7);
+         p += lgam7b;
+         p += lgam7a;
+         break;
+
+       case 8:
+         z = x - 8.0L;
+         p = z * neval (z, RN8, NRN8) / deval (z, RD8, NRD8);
+         p += lgam8b;
+         p += lgam8a;
+         break;
+
+       case 9:
+         z = x - 9.0L;
+         p = z * neval (z, RN9, NRN9) / deval (z, RD9, NRD9);
+         p += lgam9b;
+         p += lgam9a;
+         break;
+
+       case 10:
+         z = x - 10.0L;
+         p = z * neval (z, RN10, NRN10) / deval (z, RD10, NRD10);
+         p += lgam10b;
+         p += lgam10a;
+         break;
+
+       case 11:
+         z = x - 11.0L;
+         p = z * neval (z, RN11, NRN11) / deval (z, RD11, NRD11);
+         p += lgam11b;
+         p += lgam11a;
+         break;
+
+       case 12:
+         z = x - 12.0L;
+         p = z * neval (z, RN12, NRN12) / deval (z, RD12, NRD12);
+         p += lgam12b;
+         p += lgam12a;
+         break;
+
+       case 13:
+         z = x - 13.0L;
+         p = z * neval (z, RN13, NRN13) / deval (z, RD13, NRD13);
+         p += lgam13b;
+         p += lgam13a;
+         break;
+       }
+      return p;
+    }
+
+  if (x > MAXLGM)
+    return (*signgamp * huge * huge);
+
+  q = ls2pi - x;
+  q = (x - 0.5L) * logl (x) + q;
+  if (x > 1.0e18L)
+    return (q);
+
+  p = 1.0L / (x * x);
+  q += neval (p, RASY, NRASY) / x;
+  return (q);
+}
diff --git a/ld128/e_log10l.c b/ld128/e_log10l.c
new file mode 100644 (file)
index 0000000..9448101
--- /dev/null
@@ -0,0 +1,255 @@
+/*     $OpenBSD: e_log10l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     log10l.c
+ *
+ *     Common logarithm, 128-bit long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log10l();
+ *
+ * y = log10l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base 10 logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the logarithm
+ * of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z^3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      0.5, 2.0     30000      2.3e-34     4.9e-35
+ *    IEEE     exp(+-10000)  30000      1.0e-34     4.1e-35
+ *
+ * In the tests over the interval exp(+-10000), the logarithms
+ * of the random arguments were uniformly distributed over
+ * [-10000, +10000].
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 5.3e-37,
+ * relative peak error spread = 2.3e-14
+ */
+static const long double P[13] =
+{
+  1.313572404063446165910279910527789794488E4L,
+  7.771154681358524243729929227226708890930E4L,
+  2.014652742082537582487669938141683759923E5L,
+  3.007007295140399532324943111654767187848E5L,
+  2.854829159639697837788887080758954924001E5L,
+  1.797628303815655343403735250238293741397E5L,
+  7.594356839258970405033155585486712125861E4L,
+  2.128857716871515081352991964243375186031E4L,
+  3.824952356185897735160588078446136783779E3L,
+  4.114517881637811823002128927449878962058E2L,
+  2.321125933898420063925789532045674660756E1L,
+  4.998469661968096229986658302195402690910E-1L,
+  1.538612243596254322971797716843006400388E-6L
+};
+static const long double Q[12] =
+{
+  3.940717212190338497730839731583397586124E4L,
+  2.626900195321832660448791748036714883242E5L,
+  7.777690340007566932935753241556479363645E5L,
+  1.347518538384329112529391120390701166528E6L,
+  1.514882452993549494932585972882995548426E6L,
+  1.158019977462989115839826904108208787040E6L,
+  6.132189329546557743179177159925690841200E5L,
+  2.248234257620569139969141618556349415120E5L,
+  5.605842085972455027590989944010492125825E4L,
+  9.147150349299596453976674231612674085381E3L,
+  9.104928120962988414618126155557301584078E2L,
+  4.839208193348159620282142911143429644326E1L
+/* 1.000000000000000000000000000000000000000E0L, */
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 1.1e-35,
+ * relative peak error spread 1.1e-9
+ */
+static const long double R[6] =
+{
+  1.418134209872192732479751274970992665513E5L,
+ -8.977257995689735303686582344659576526998E4L,
+  2.048819892795278657810231591630928516206E4L,
+ -2.024301798136027039250415126250455056397E3L,
+  8.057002716646055371965756206836056074715E1L,
+ -8.828896441624934385266096344596648080902E-1L
+};
+static const long double S[6] =
+{
+  1.701761051846631278975701529965589676574E6L,
+ -1.332535117259762928288745111081235577029E6L,
+  4.001557694070773974936904547424676279307E5L,
+ -5.748542087379434595104154610899551484314E4L,
+  3.998526750980007367835804959888064681098E3L,
+ -1.186359407982897997337150403816839480438E2L
+/* 1.000000000000000000000000000000000000000E0L, */
+};
+
+static const long double
+/* log10(2) */
+L102A = 0.3125L,
+L102B = -1.14700043360188047862611052755069732318101185E-2L,
+/* log10(e) */
+L10EA = 0.5L,
+L10EB = -6.570551809674817234887108108339491770560299E-2L,
+/* sqrt(2)/2 */
+SQRTH = 7.071067811865475244008443621048490392848359E-1L;
+
+
+
+/* Evaluate P[n] x^n  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+neval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+/* Evaluate x^n+1  +  P[n] x^(n)  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+deval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = x + *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+
+long double
+log10l(long double x)
+{
+  long double z;
+  long double y;
+  int e;
+  int64_t hx, lx;
+
+/* Test for domain */
+  GET_LDOUBLE_WORDS64 (hx, lx, x);
+  if (((hx & 0x7fffffffffffffffLL) | lx) == 0)
+    return (-1.0L / (x - x));
+  if (hx < 0)
+    return (x - x) / (x - x);
+  if (hx >= 0x7fff000000000000LL)
+    return (x + x);
+
+/* separate mantissa from exponent */
+
+/* Note, frexp is used so that denormal numbers
+ * will be handled properly.
+ */
+  x = frexpl (x, &e);
+
+
+/* logarithm using log(x) = z + z**3 P(z)/Q(z),
+ * where z = 2(x-1)/x+1)
+ */
+  if ((e > 2) || (e < -2))
+    {
+      if (x < SQRTH)
+       {                       /* 2( 2x-1 )/( 2x+1 ) */
+         e -= 1;
+         z = x - 0.5L;
+         y = 0.5L * z + 0.5L;
+       }
+      else
+       {                       /*  2 (x-1)/(x+1)   */
+         z = x - 0.5L;
+         z -= 0.5L;
+         y = 0.5L * x + 0.5L;
+       }
+      x = z / y;
+      z = x * x;
+      y = x * (z * neval (z, R, 5) / deval (z, S, 5));
+      goto done;
+    }
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+  if (x < SQRTH)
+    {
+      e -= 1;
+      x = 2.0 * x - 1.0L;      /*  2x - 1  */
+    }
+  else
+    {
+      x = x - 1.0L;
+    }
+  z = x * x;
+  y = x * (z * neval (x, P, 12) / deval (x, Q, 11));
+  y = y - 0.5 * z;
+
+done:
+
+  /* Multiply log of fraction by log10(e)
+   * and base 2 exponent by log10(2).
+   */
+  z = y * L10EB;
+  z += x * L10EB;
+  z += e * L102B;
+  z += y * L10EA;
+  z += x * L10EA;
+  z += e * L102A;
+  return (z);
+}
diff --git a/ld128/e_log2l.c b/ld128/e_log2l.c
new file mode 100644 (file)
index 0000000..2ce4d94
--- /dev/null
@@ -0,0 +1,248 @@
+/*     $OpenBSD: e_log2l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                      log2l.c
+ *      Base 2 logarithm, 128-bit long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log2l();
+ *
+ * y = log2l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base 2 logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the (natural)
+ * logarithm of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z^3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      0.5, 2.0     100,000    2.6e-34     4.9e-35
+ *    IEEE     exp(+-10000)  100,000    9.6e-35     4.0e-35
+ *
+ * In the tests over the interval exp(+-10000), the logarithms
+ * of the random arguments were uniformly distributed over
+ * [-10000, +10000].
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 5.3e-37,
+ * relative peak error spread = 2.3e-14
+ */
+static const long double P[13] =
+{
+  1.313572404063446165910279910527789794488E4L,
+  7.771154681358524243729929227226708890930E4L,
+  2.014652742082537582487669938141683759923E5L,
+  3.007007295140399532324943111654767187848E5L,
+  2.854829159639697837788887080758954924001E5L,
+  1.797628303815655343403735250238293741397E5L,
+  7.594356839258970405033155585486712125861E4L,
+  2.128857716871515081352991964243375186031E4L,
+  3.824952356185897735160588078446136783779E3L,
+  4.114517881637811823002128927449878962058E2L,
+  2.321125933898420063925789532045674660756E1L,
+  4.998469661968096229986658302195402690910E-1L,
+  1.538612243596254322971797716843006400388E-6L
+};
+static const long double Q[12] =
+{
+  3.940717212190338497730839731583397586124E4L,
+  2.626900195321832660448791748036714883242E5L,
+  7.777690340007566932935753241556479363645E5L,
+  1.347518538384329112529391120390701166528E6L,
+  1.514882452993549494932585972882995548426E6L,
+  1.158019977462989115839826904108208787040E6L,
+  6.132189329546557743179177159925690841200E5L,
+  2.248234257620569139969141618556349415120E5L,
+  5.605842085972455027590989944010492125825E4L,
+  9.147150349299596453976674231612674085381E3L,
+  9.104928120962988414618126155557301584078E2L,
+  4.839208193348159620282142911143429644326E1L
+/* 1.000000000000000000000000000000000000000E0L, */
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 1.1e-35,
+ * relative peak error spread 1.1e-9
+ */
+static const long double R[6] =
+{
+  1.418134209872192732479751274970992665513E5L,
+ -8.977257995689735303686582344659576526998E4L,
+  2.048819892795278657810231591630928516206E4L,
+ -2.024301798136027039250415126250455056397E3L,
+  8.057002716646055371965756206836056074715E1L,
+ -8.828896441624934385266096344596648080902E-1L
+};
+static const long double S[6] =
+{
+  1.701761051846631278975701529965589676574E6L,
+ -1.332535117259762928288745111081235577029E6L,
+  4.001557694070773974936904547424676279307E5L,
+ -5.748542087379434595104154610899551484314E4L,
+  3.998526750980007367835804959888064681098E3L,
+ -1.186359407982897997337150403816839480438E2L
+/* 1.000000000000000000000000000000000000000E0L, */
+};
+
+static const long double
+/* log2(e) - 1 */
+LOG2EA = 4.4269504088896340735992468100189213742664595E-1L,
+/* sqrt(2)/2 */
+SQRTH = 7.071067811865475244008443621048490392848359E-1L;
+
+
+/* Evaluate P[n] x^n  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+neval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+/* Evaluate x^n+1  +  P[n] x^(n)  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+deval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = x + *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+
+long double
+log2l(long double x)
+{
+  long double z;
+  long double y;
+  int e;
+  int64_t hx, lx;
+
+/* Test for domain */
+  GET_LDOUBLE_WORDS64 (hx, lx, x);
+  if (((hx & 0x7fffffffffffffffLL) | lx) == 0)
+    return (-1.0L / (x - x));
+  if (hx < 0)
+    return (x - x) / (x - x);
+  if (hx >= 0x7fff000000000000LL)
+    return (x + x);
+
+/* separate mantissa from exponent */
+
+/* Note, frexp is used so that denormal numbers
+ * will be handled properly.
+ */
+  x = frexpl (x, &e);
+
+
+/* logarithm using log(x) = z + z**3 P(z)/Q(z),
+ * where z = 2(x-1)/x+1)
+ */
+  if ((e > 2) || (e < -2))
+    {
+      if (x < SQRTH)
+       {                       /* 2( 2x-1 )/( 2x+1 ) */
+         e -= 1;
+         z = x - 0.5L;
+         y = 0.5L * z + 0.5L;
+       }
+      else
+       {                       /*  2 (x-1)/(x+1)   */
+         z = x - 0.5L;
+         z -= 0.5L;
+         y = 0.5L * x + 0.5L;
+       }
+      x = z / y;
+      z = x * x;
+      y = x * (z * neval (z, R, 5) / deval (z, S, 5));
+      goto done;
+    }
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+  if (x < SQRTH)
+    {
+      e -= 1;
+      x = 2.0 * x - 1.0L;      /*  2x - 1  */
+    }
+  else
+    {
+      x = x - 1.0L;
+    }
+  z = x * x;
+  y = x * (z * neval (x, P, 12) / deval (x, Q, 11));
+  y = y - 0.5 * z;
+
+done:
+
+/* Multiply log of fraction by log2(e)
+ * and base 2 exponent by 1
+ */
+  z = y * LOG2EA;
+  z += x * LOG2EA;
+  z += y;
+  z += x;
+  z += e;
+  return (z);
+}
diff --git a/ld128/e_logl.c b/ld128/e_logl.c
new file mode 100644 (file)
index 0000000..f6da91f
--- /dev/null
@@ -0,0 +1,283 @@
+/*     $OpenBSD: e_logl.c,v 1.1 2011/07/06 00:02:42 martynas Exp $     */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     logl.c
+ *
+ * Natural logarithm for 128-bit long double precision.
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, logl();
+ *
+ * y = logl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base e (2.718...) logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  Use of a lookup table increases the speed of the routine.
+ * The program uses logarithms tabulated at intervals of 1/128 to
+ * cover the domain from approximately 0.7 to 1.4.
+ *
+ * On the interval [-1/128, +1/128] the logarithm of 1+x is approximated by
+ *     log(1+x) = x - 0.5 x^2 + x^3 P(x) .
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE   0.875, 1.125   100000      1.2e-34    4.1e-35
+ *    IEEE   0.125, 8       100000      1.2e-34    4.1e-35
+ *
+ *
+ * WARNING:
+ *
+ * This program uses integer operations on bit fields of floating-point
+ * numbers.  It does not work with data structures other than the
+ * structure assumed.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* log(1+x) = x - .5 x^2 + x^3 l(x)
+   -.0078125 <= x <= +.0078125
+   peak relative error 1.2e-37 */
+static const long double
+l3 =   3.333333333333333333333333333333336096926E-1L,
+l4 =  -2.499999999999999999999999999486853077002E-1L,
+l5 =   1.999999999999999999999999998515277861905E-1L,
+l6 =  -1.666666666666666666666798448356171665678E-1L,
+l7 =   1.428571428571428571428808945895490721564E-1L,
+l8 =  -1.249999999999999987884655626377588149000E-1L,
+l9 =   1.111111111111111093947834982832456459186E-1L,
+l10 = -1.000000000000532974938900317952530453248E-1L,
+l11 =  9.090909090915566247008015301349979892689E-2L,
+l12 = -8.333333211818065121250921925397567745734E-2L,
+l13 =  7.692307559897661630807048686258659316091E-2L,
+l14 = -7.144242754190814657241902218399056829264E-2L,
+l15 =  6.668057591071739754844678883223432347481E-2L;
+
+/* Lookup table of ln(t) - (t-1)
+    t = 0.5 + (k+26)/128)
+    k = 0, ..., 91   */
+static const long double logtbl[92] = {
+-5.5345593589352099112142921677820359632418E-2L,
+-5.2108257402767124761784665198737642086148E-2L,
+-4.8991686870576856279407775480686721935120E-2L,
+-4.5993270766361228596215288742353061431071E-2L,
+-4.3110481649613269682442058976885699556950E-2L,
+-4.0340872319076331310838085093194799765520E-2L,
+-3.7682072451780927439219005993827431503510E-2L,
+-3.5131785416234343803903228503274262719586E-2L,
+-3.2687785249045246292687241862699949178831E-2L,
+-3.0347913785027239068190798397055267411813E-2L,
+-2.8110077931525797884641940838507561326298E-2L,
+-2.5972247078357715036426583294246819637618E-2L,
+-2.3932450635346084858612873953407168217307E-2L,
+-2.1988775689981395152022535153795155900240E-2L,
+-2.0139364778244501615441044267387667496733E-2L,
+-1.8382413762093794819267536615342902718324E-2L,
+-1.6716169807550022358923589720001638093023E-2L,
+-1.5138929457710992616226033183958974965355E-2L,
+-1.3649036795397472900424896523305726435029E-2L,
+-1.2244881690473465543308397998034325468152E-2L,
+-1.0924898127200937840689817557742469105693E-2L,
+-9.6875626072830301572839422532631079809328E-3L,
+-8.5313926245226231463436209313499745894157E-3L,
+-7.4549452072765973384933565912143044991706E-3L,
+-6.4568155251217050991200599386801665681310E-3L,
+-5.5356355563671005131126851708522185605193E-3L,
+-4.6900728132525199028885749289712348829878E-3L,
+-3.9188291218610470766469347968659624282519E-3L,
+-3.2206394539524058873423550293617843896540E-3L,
+-2.5942708080877805657374888909297113032132E-3L,
+-2.0385211375711716729239156839929281289086E-3L,
+-1.5522183228760777967376942769773768850872E-3L,
+-1.1342191863606077520036253234446621373191E-3L,
+-7.8340854719967065861624024730268350459991E-4L,
+-4.9869831458030115699628274852562992756174E-4L,
+-2.7902661731604211834685052867305795169688E-4L,
+-1.2335696813916860754951146082826952093496E-4L,
+-3.0677461025892873184042490943581654591817E-5L,
+#define ZERO logtbl[38]
+ 0.0000000000000000000000000000000000000000E0L,
+-3.0359557945051052537099938863236321874198E-5L,
+-1.2081346403474584914595395755316412213151E-4L,
+-2.7044071846562177120083903771008342059094E-4L,
+-4.7834133324631162897179240322783590830326E-4L,
+-7.4363569786340080624467487620270965403695E-4L,
+-1.0654639687057968333207323853366578860679E-3L,
+-1.4429854811877171341298062134712230604279E-3L,
+-1.8753781835651574193938679595797367137975E-3L,
+-2.3618380914922506054347222273705859653658E-3L,
+-2.9015787624124743013946600163375853631299E-3L,
+-3.4938307889254087318399313316921940859043E-3L,
+-4.1378413103128673800485306215154712148146E-3L,
+-4.8328735414488877044289435125365629849599E-3L,
+-5.5782063183564351739381962360253116934243E-3L,
+-6.3731336597098858051938306767880719015261E-3L,
+-7.2169643436165454612058905294782949315193E-3L,
+-8.1090214990427641365934846191367315083867E-3L,
+-9.0486422112807274112838713105168375482480E-3L,
+-1.0035177140880864314674126398350812606841E-2L,
+-1.1067990155502102718064936259435676477423E-2L,
+-1.2146457974158024928196575103115488672416E-2L,
+-1.3269969823361415906628825374158424754308E-2L,
+-1.4437927104692837124388550722759686270765E-2L,
+-1.5649743073340777659901053944852735064621E-2L,
+-1.6904842527181702880599758489058031645317E-2L,
+-1.8202661505988007336096407340750378994209E-2L,
+-1.9542647000370545390701192438691126552961E-2L,
+-2.0924256670080119637427928803038530924742E-2L,
+-2.2346958571309108496179613803760727786257E-2L,
+-2.3810230892650362330447187267648486279460E-2L,
+-2.5313561699385640380910474255652501521033E-2L,
+-2.6856448685790244233704909690165496625399E-2L,
+-2.8438398935154170008519274953860128449036E-2L,
+-3.0058928687233090922411781058956589863039E-2L,
+-3.1717563112854831855692484086486099896614E-2L,
+-3.3413836095418743219397234253475252001090E-2L,
+-3.5147290019036555862676702093393332533702E-2L,
+-3.6917475563073933027920505457688955423688E-2L,
+-3.8723951502862058660874073462456610731178E-2L,
+-4.0566284516358241168330505467000838017425E-2L,
+-4.2444048996543693813649967076598766917965E-2L,
+-4.4356826869355401653098777649745233339196E-2L,
+-4.6304207416957323121106944474331029996141E-2L,
+-4.8285787106164123613318093945035804818364E-2L,
+-5.0301169421838218987124461766244507342648E-2L,
+-5.2349964705088137924875459464622098310997E-2L,
+-5.4431789996103111613753440311680967840214E-2L,
+-5.6546268881465384189752786409400404404794E-2L,
+-5.8693031345788023909329239565012647817664E-2L,
+-6.0871713627532018185577188079210189048340E-2L,
+-6.3081958078862169742820420185833800925568E-2L,
+-6.5323413029406789694910800219643791556918E-2L,
+-6.7595732653791419081537811574227049288168E-2L
+};
+
+/* ln(2) = ln2a + ln2b with extended precision. */
+static const long double
+  ln2a = 6.93145751953125e-1L,
+  ln2b = 1.4286068203094172321214581765680755001344E-6L;
+
+long double
+logl(long double x)
+{
+  long double z, y, w;
+  ieee_quad_shape_type u, t;
+  unsigned int m;
+  int k, e;
+
+  u.value = x;
+  m = u.parts32.mswhi;
+
+  /* Check for IEEE special cases.  */
+  k = m & 0x7fffffff;
+  /* log(0) = -infinity. */
+  if ((k | u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0)
+    {
+      return -0.5L / ZERO;
+    }
+  /* log ( x < 0 ) = NaN */
+  if (m & 0x80000000)
+    {
+      return (x - x) / ZERO;
+    }
+  /* log (infinity or NaN) */
+  if (k >= 0x7fff0000)
+    {
+      return x + x;
+    }
+
+  /* Extract exponent and reduce domain to 0.703125 <= u < 1.40625  */
+  e = (int) (m >> 16) - (int) 0x3ffe;
+  m &= 0xffff;
+  u.parts32.mswhi = m | 0x3ffe0000;
+  m |= 0x10000;
+  /* Find lookup table index k from high order bits of the significand. */
+  if (m < 0x16800)
+    {
+      k = (m - 0xff00) >> 9;
+      /* t is the argument 0.5 + (k+26)/128
+        of the nearest item to u in the lookup table.  */
+      t.parts32.mswhi = 0x3fff0000 + (k << 9);
+      t.parts32.mswlo = 0;
+      t.parts32.lswhi = 0;
+      t.parts32.lswlo = 0;
+      u.parts32.mswhi += 0x10000;
+      e -= 1;
+      k += 64;
+    }
+  else
+    {
+      k = (m - 0xfe00) >> 10;
+      t.parts32.mswhi = 0x3ffe0000 + (k << 10);
+      t.parts32.mswlo = 0;
+      t.parts32.lswhi = 0;
+      t.parts32.lswlo = 0;
+    }
+  /* On this interval the table is not used due to cancellation error.  */
+  if ((x <= 1.0078125L) && (x >= 0.9921875L))
+    {
+      z = x - 1.0L;
+      k = 64;
+      t.value  = 1.0L;
+      e = 0;
+    }
+  else
+    {
+      /* log(u) = log( t u/t ) = log(t) + log(u/t)
+        log(t) is tabulated in the lookup table.
+        Express log(u/t) = log(1+z),  where z = u/t - 1 = (u-t)/t.
+       cf. Cody & Waite. */
+      z = (u.value - t.value) / t.value;
+    }
+  /* Series expansion of log(1+z).  */
+  w = z * z;
+  y = ((((((((((((l15 * z
+                 + l14) * z
+                + l13) * z
+               + l12) * z
+              + l11) * z
+             + l10) * z
+            + l9) * z
+           + l8) * z
+          + l7) * z
+         + l6) * z
+        + l5) * z
+       + l4) * z
+       + l3) * z * w;
+  y -= 0.5 * w;
+  y += e * ln2b;  /* Base 2 exponent offset times ln(2).  */
+  y += z;
+  y += logtbl[k-26]; /* log(t) - (t-1) */
+  y += (t.value - 1.0L);
+  y += e * ln2a;
+  return y;
+}
diff --git a/ld128/e_powl.c b/ld128/e_powl.c
new file mode 100644 (file)
index 0000000..430b261
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* powl(x,y) return x**y
+ *
+ *                   n
+ * Method:  Let x =  2   * (1+f)
+ *     1. Compute and return log2(x) in two pieces:
+ *             log2(x) = w1 + w2,
+ *        where w1 has 113-53 = 60 bit trailing zeros.
+ *     2. Perform y*log2(x) = n+y' by simulating muti-precision
+ *        arithmetic, where |y'|<=0.5.
+ *     3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *     1.  (anything) ** 0  is 1
+ *     2.  (anything) ** 1  is itself
+ *     3.  (anything) ** NAN is NAN
+ *     4.  NAN ** (anything except 0) is NAN
+ *     5.  +-(|x| > 1) **  +INF is +INF
+ *     6.  +-(|x| > 1) **  -INF is +0
+ *     7.  +-(|x| < 1) **  +INF is +0
+ *     8.  +-(|x| < 1) **  -INF is +INF
+ *     9.  +-1         ** +-INF is NAN
+ *     10. +0 ** (+anything except 0, NAN)               is +0
+ *     11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *     12. +0 ** (-anything except 0, NAN)               is +INF
+ *     13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *     14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *     15. +INF ** (+anything except 0,NAN) is +INF
+ *     16. +INF ** (-anything except 0,NAN) is +0
+ *     17. -INF ** (anything)  = -0 ** (-anything)
+ *     18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *     19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double bp[] = {
+  1.0L,
+  1.5L,
+};
+
+/* log_2(1.5) */
+static const long double dp_h[] = {
+  0.0,
+  5.8496250072115607565592654282227158546448E-1L
+};
+
+/* Low part of log_2(1.5) */
+static const long double dp_l[] = {
+  0.0,
+  1.0579781240112554492329533686862998106046E-16L
+};
+
+static const long double zero = 0.0L,
+  one = 1.0L,
+  two = 2.0L,
+  two113 = 1.0384593717069655257060992658440192E34L,
+  huge = 1.0e3000L,
+  tiny = 1.0e-3000L;
+
+/* 3/2 log x = 3 z + z^3 + z^3 (z^2 R(z^2))
+   z = (x-1)/(x+1)
+   1 <= x <= 1.25
+   Peak relative error 2.3e-37 */
+static const long double LN[] =
+{
+ -3.0779177200290054398792536829702930623200E1L,
+  6.5135778082209159921251824580292116201640E1L,
+ -4.6312921812152436921591152809994014413540E1L,
+  1.2510208195629420304615674658258363295208E1L,
+ -9.9266909031921425609179910128531667336670E-1L
+};
+static const long double LD[] =
+{
+ -5.129862866715009066465422805058933131960E1L,
+  1.452015077564081884387441590064272782044E2L,
+ -1.524043275549860505277434040464085593165E2L,
+  7.236063513651544224319663428634139768808E1L,
+ -1.494198912340228235853027849917095580053E1L
+  /* 1.0E0 */
+};
+
+/* exp(x) = 1 + x - x / (1 - 2 / (x - x^2 R(x^2)))
+   0 <= x <= 0.5
+   Peak relative error 5.7e-38  */
+static const long double PN[] =
+{
+  5.081801691915377692446852383385968225675E8L,
+  9.360895299872484512023336636427675327355E6L,
+  4.213701282274196030811629773097579432957E4L,
+  5.201006511142748908655720086041570288182E1L,
+  9.088368420359444263703202925095675982530E-3L,
+};
+static const long double PD[] =
+{
+  3.049081015149226615468111430031590411682E9L,
+  1.069833887183886839966085436512368982758E8L,
+  8.259257717868875207333991924545445705394E5L,
+  1.872583833284143212651746812884298360922E3L,
+  /* 1.0E0 */
+};
+
+static const long double
+  /* ln 2 */
+  lg2 = 6.9314718055994530941723212145817656807550E-1L,
+  lg2_h = 6.9314718055994528622676398299518041312695E-1L,
+  lg2_l = 2.3190468138462996154948554638754786504121E-17L,
+  ovt = 8.0085662595372944372e-0017L,
+  /* 2/(3*log(2)) */
+  cp = 9.6179669392597560490661645400126142495110E-1L,
+  cp_h = 9.6179669392597555432899980587535537779331E-1L,
+  cp_l = 5.0577616648125906047157785230014751039424E-17L;
+
+long double
+powl(long double x, long double y)
+{
+  long double z, ax, z_h, z_l, p_h, p_l;
+  long double yy1, t1, t2, r, s, t, u, v, w;
+  long double s2, s_h, s_l, t_h, t_l;
+  int32_t i, j, k, yisint, n;
+  u_int32_t ix, iy;
+  int32_t hx, hy;
+  ieee_quad_shape_type o, p, q;
+
+  p.value = x;
+  hx = p.parts32.mswhi;
+  ix = hx & 0x7fffffff;
+
+  q.value = y;
+  hy = q.parts32.mswhi;
+  iy = hy & 0x7fffffff;
+
+
+  /* y==zero: x**0 = 1 */
+  if ((iy | q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
+    return one;
+
+  /* 1.0**y = 1; -1.0**+-Inf = 1 */
+  if (x == one)
+    return one;
+  if (x == -1.0L && iy == 0x7fff0000
+      && (q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
+    return one;
+
+  /* +-NaN return x+y */
+  if ((ix > 0x7fff0000)
+      || ((ix == 0x7fff0000)
+         && ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) != 0))
+      || (iy > 0x7fff0000)
+      || ((iy == 0x7fff0000)
+         && ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) != 0)))
+    return x + y;
+
+  /* determine if y is an odd int when x < 0
+   * yisint = 0       ... y is not an integer
+   * yisint = 1       ... y is an odd int
+   * yisint = 2       ... y is an even int
+   */
+  yisint = 0;
+  if (hx < 0)
+    {
+      if (iy >= 0x40700000)    /* 2^113 */
+       yisint = 2;             /* even integer y */
+      else if (iy >= 0x3fff0000)       /* 1.0 */
+       {
+         if (floorl (y) == y)
+           {
+             z = 0.5 * y;
+             if (floorl (z) == z)
+               yisint = 2;
+             else
+               yisint = 1;
+           }
+       }
+    }
+
+  /* special value of y */
+  if ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
+    {
+      if (iy == 0x7fff0000)    /* y is +-inf */
+       {
+         if (((ix - 0x3fff0000) | p.parts32.mswlo | p.parts32.lswhi |
+           p.parts32.lswlo) == 0)
+           return y - y;       /* +-1**inf is NaN */
+         else if (ix >= 0x3fff0000)    /* (|x|>1)**+-inf = inf,0 */
+           return (hy >= 0) ? y : zero;
+         else                  /* (|x|<1)**-,+inf = inf,0 */
+           return (hy < 0) ? -y : zero;
+       }
+      if (iy == 0x3fff0000)
+       {                       /* y is  +-1 */
+         if (hy < 0)
+           return one / x;
+         else
+           return x;
+       }
+      if (hy == 0x40000000)
+       return x * x;           /* y is  2 */
+      if (hy == 0x3ffe0000)
+       {                       /* y is  0.5 */
+         if (hx >= 0)          /* x >= +0 */
+           return sqrtl (x);
+       }
+    }
+
+  ax = fabsl (x);
+  /* special value of x */
+  if ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) == 0)
+    {
+      if (ix == 0x7fff0000 || ix == 0 || ix == 0x3fff0000)
+       {
+         z = ax;               /*x is +-0,+-inf,+-1 */
+         if (hy < 0)
+           z = one / z;        /* z = (1/|x|) */
+         if (hx < 0)
+           {
+             if (((ix - 0x3fff0000) | yisint) == 0)
+               {
+                 z = (z - z) / (z - z);        /* (-1)**non-int is NaN */
+               }
+             else if (yisint == 1)
+               z = -z;         /* (x<0)**odd = -(|x|**odd) */
+           }
+         return z;
+       }
+    }
+
+  /* (x<0)**(non-int) is NaN */
+  if (((((u_int32_t) hx >> 31) - 1) | yisint) == 0)
+    return (x - x) / (x - x);
+
+  /* |y| is huge.
+     2^-16495 = 1/2 of smallest representable value.
+     If (1 - 1/131072)^y underflows, y > 1.4986e9 */
+  if (iy > 0x401d654b)
+    {
+      /* if (1 - 2^-113)^y underflows, y > 1.1873e38 */
+      if (iy > 0x407d654b)
+       {
+         if (ix <= 0x3ffeffff)
+           return (hy < 0) ? huge * huge : tiny * tiny;
+         if (ix >= 0x3fff0000)
+           return (hy > 0) ? huge * huge : tiny * tiny;
+       }
+      /* over/underflow if x is not close to one */
+      if (ix < 0x3ffeffff)
+       return (hy < 0) ? huge * huge : tiny * tiny;
+      if (ix > 0x3fff0000)
+       return (hy > 0) ? huge * huge : tiny * tiny;
+    }
+
+  n = 0;
+  /* take care subnormal number */
+  if (ix < 0x00010000)
+    {
+      ax *= two113;
+      n -= 113;
+      o.value = ax;
+      ix = o.parts32.mswhi;
+    }
+  n += ((ix) >> 16) - 0x3fff;
+  j = ix & 0x0000ffff;
+  /* determine interval */
+  ix = j | 0x3fff0000;         /* normalize ix */
+  if (j <= 0x3988)
+    k = 0;                     /* |x|<sqrt(3/2) */
+  else if (j < 0xbb67)
+    k = 1;                     /* |x|<sqrt(3)   */
+  else
+    {
+      k = 0;
+      n += 1;
+      ix -= 0x00010000;
+    }
+
+  o.value = ax;
+  o.parts32.mswhi = ix;
+  ax = o.value;
+
+  /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+  u = ax - bp[k];              /* bp[0]=1.0, bp[1]=1.5 */
+  v = one / (ax + bp[k]);
+  s = u * v;
+  s_h = s;
+
+  o.value = s_h;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  s_h = o.value;
+  /* t_h=ax+bp[k] High */
+  t_h = ax + bp[k];
+  o.value = t_h;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  t_h = o.value;
+  t_l = ax - (t_h - bp[k]);
+  s_l = v * ((u - s_h * t_h) - s_h * t_l);
+  /* compute log(ax) */
+  s2 = s * s;
+  u = LN[0] + s2 * (LN[1] + s2 * (LN[2] + s2 * (LN[3] + s2 * LN[4])));
+  v = LD[0] + s2 * (LD[1] + s2 * (LD[2] + s2 * (LD[3] + s2 * (LD[4] + s2))));
+  r = s2 * s2 * u / v;
+  r += s_l * (s_h + s);
+  s2 = s_h * s_h;
+  t_h = 3.0 + s2 + r;
+  o.value = t_h;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  t_h = o.value;
+  t_l = r - ((t_h - 3.0) - s2);
+  /* u+v = s*(1+...) */
+  u = s_h * t_h;
+  v = s_l * t_h + t_l * s;
+  /* 2/(3log2)*(s+...) */
+  p_h = u + v;
+  o.value = p_h;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  p_h = o.value;
+  p_l = v - (p_h - u);
+  z_h = cp_h * p_h;            /* cp_h+cp_l = 2/(3*log2) */
+  z_l = cp_l * p_h + p_l * cp + dp_l[k];
+  /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+  t = (long double) n;
+  t1 = (((z_h + z_l) + dp_h[k]) + t);
+  o.value = t1;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  t1 = o.value;
+  t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
+
+  /* s (sign of result -ve**odd) = -1 else = 1 */
+  s = one;
+  if (((((u_int32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
+    s = -one;                  /* (-ve)**(odd int) */
+
+  /* split up y into yy1+y2 and compute (yy1+y2)*(t1+t2) */
+  yy1 = y;
+  o.value = yy1;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  yy1 = o.value;
+  p_l = (y - yy1) * t1 + y * t2;
+  p_h = yy1 * t1;
+  z = p_l + p_h;
+  o.value = z;
+  j = o.parts32.mswhi;
+  if (j >= 0x400d0000) /* z >= 16384 */
+    {
+      /* if z > 16384 */
+      if (((j - 0x400d0000) | o.parts32.mswlo | o.parts32.lswhi |
+       o.parts32.lswlo) != 0)
+       return s * huge * huge; /* overflow */
+      else
+       {
+         if (p_l + ovt > z - p_h)
+           return s * huge * huge;     /* overflow */
+       }
+    }
+  else if ((j & 0x7fffffff) >= 0x400d01b9)     /* z <= -16495 */
+    {
+      /* z < -16495 */
+      if (((j - 0xc00d01bc) | o.parts32.mswlo | o.parts32.lswhi |
+       o.parts32.lswlo)
+         != 0)
+       return s * tiny * tiny; /* underflow */
+      else
+       {
+         if (p_l <= z - p_h)
+           return s * tiny * tiny;     /* underflow */
+       }
+    }
+  /* compute 2**(p_h+p_l) */
+  i = j & 0x7fffffff;
+  k = (i >> 16) - 0x3fff;
+  n = 0;
+  if (i > 0x3ffe0000)
+    {                          /* if |z| > 0.5, set n = [z+0.5] */
+      n = floorl (z + 0.5L);
+      t = n;
+      p_h -= t;
+    }
+  t = p_l + p_h;
+  o.value = t;
+  o.parts32.lswlo = 0;
+  o.parts32.lswhi &= 0xf8000000;
+  t = o.value;
+  u = t * lg2_h;
+  v = (p_l - (t - p_h)) * lg2 + t * lg2_l;
+  z = u + v;
+  w = v - (z - u);
+  /*  exp(z) */
+  t = z * z;
+  u = PN[0] + t * (PN[1] + t * (PN[2] + t * (PN[3] + t * PN[4])));
+  v = PD[0] + t * (PD[1] + t * (PD[2] + t * (PD[3] + t)));
+  t1 = z - t * u / v;
+  r = (z * t1) / (t1 - two) - (w + z * w);
+  z = one - (r - z);
+  o.value = z;
+  j = o.parts32.mswhi;
+  j += (n << 16);
+  if ((j >> 16) <= 0)
+    z = scalbnl (z, n);        /* subnormal output */
+  else
+    {
+      o.parts32.mswhi = j;
+      z = o.value;
+    }
+  return s * z;
+}
diff --git a/ld128/e_rem_pio2l.h b/ld128/e_rem_pio2l.h
new file mode 100644 (file)
index 0000000..5224245
--- /dev/null
@@ -0,0 +1,144 @@
+/* From: @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ * Optimized by Bruce D. Evans.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/e_rem_pio2l.h,v 1.2 2011/05/30 19:41:28 kargl Exp $");
+
+/* ld128 version of __ieee754_rem_pio2l(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2()
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#include "fpmath.h"
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+
+/*
+ * XXX need to verify that nonzero integer multiples of pi/2 within the
+ * range get no closer to a long double than 2**-140, or that
+ * ilogb(x) + ilogb(min_delta) < 45 - -140.
+ */
+/*
+ * invpio2:  113 bits of 2/pi
+ * pio2_1:   first  68 bits of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 68 bits of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  68 bits of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+two24 =  1.67772160000000000000e+07; /* 0x41700000, 0x00000000 */
+
+static const long double
+invpio2 =  6.3661977236758134307553505349005747e-01L,  /*  0x145f306dc9c882a53f84eafa3ea6a.0p-113 */
+pio2_1  =  1.5707963267948966192292994253909555e+00L,  /*  0x1921fb54442d18469800000000000.0p-112 */
+pio2_1t =  2.0222662487959507323996846200947577e-21L,  /*  0x13198a2e03707344a4093822299f3.0p-181 */
+pio2_2  =  2.0222662487959507323994779168837751e-21L,  /*  0x13198a2e03707344a400000000000.0p-181 */
+pio2_2t =  2.0670321098263988236496903051604844e-43L,  /*  0x127044533e63a0105df531d89cd91.0p-254 */
+pio2_3  =  2.0670321098263988236499468110329591e-43L,  /*  0x127044533e63a0105e00000000000.0p-254 */
+pio2_3t = -2.5650587247459238361625433492959285e-65L;  /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */
+
+//VBS
+//static inline __always_inline int
+//__ieee754_rem_pio2l(long double x, long double *y)
+
+static inline int
+__ieee754_rem_pio2l(long double x, long double *y)
+{
+       union IEEEl2bits u,u1;
+       long double z,w,t,r,fn;
+       double tx[5],ty[3];
+       int64_t n;
+       int e0,ex,i,j,nx;
+       int16_t expsign;
+
+       u.e = x;
+       expsign = u.xbits.expsign;
+       ex = expsign & 0x7fff;
+       if (ex < BIAS + 45 || ex == BIAS + 45 &&
+           u.bits.manh < 0x921fb54442d1LL) {
+           /* |x| ~< 2^45*(pi/2), medium size */
+           /* Use a specialized rint() to get fn.  Assume round-to-nearest. */
+           fn = x*invpio2+0x1.8p112;
+           fn = fn-0x1.8p112;
+#ifdef HAVE_EFFICIENT_I64RINT
+           n  = i64rint(fn);
+#else
+           n  = fn;
+#endif
+           r  = x-fn*pio2_1;
+           w  = fn*pio2_1t;    /* 1st round good to 180 bit */
+           {
+               union IEEEl2bits u2;
+               int ex1;
+               j  = ex;
+               y[0] = r-w; 
+               u2.e = y[0];
+               ex1 = u2.xbits.expsign & 0x7fff;
+               i = j-ex1;
+               if(i>51) {  /* 2nd iteration needed, good to 248 */
+                   t  = r;
+                   w  = fn*pio2_2;     
+                   r  = t-w;
+                   w  = fn*pio2_2t-((t-r)-w);  
+                   y[0] = r-w;
+                   u2.e = y[0];
+                   ex1 = u2.xbits.expsign & 0x7fff;
+                   i = j-ex1;
+                   if(i>119) { /* 3rd iteration need, 316 bits acc */
+                       t  = r; /* will cover all possible cases */
+                       w  = fn*pio2_3; 
+                       r  = t-w;
+                       w  = fn*pio2_3t-((t-r)-w);      
+                       y[0] = r-w;
+                   }
+               }
+           }
+           y[1] = (r-y[0])-w;
+           return n;
+       }
+    /* 
+     * all other (large) arguments
+     */
+       if(ex==0x7fff) {                /* x is inf or NaN */
+           y[0]=y[1]=x-x; return 0;
+       }
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+       u1.e = x;
+       e0 = ex - BIAS - 23;            /* e0 = ilogb(|x|)-23; */
+       u1.xbits.expsign = ex - e0;
+       z = u1.e;
+       for(i=0;i<4;i++) {
+               tx[i] = (double)((int32_t)(z));
+               z     = (z-tx[i])*two24;
+       }
+       tx[4] = z;
+       nx = 5;
+       while(tx[nx-1]==zero) nx--;     /* skip zero term */
+       n  =  __kernel_rem_pio2(tx,ty,e0,nx,3);
+       t = (long double)ty[2] + ty[1];
+       r = t + ty[0];
+       w = ty[0] - (r - t);
+       if(expsign<0) {y[0] = -r; y[1] = -w; return -n;}
+       y[0] = r; y[1] = w; return n;
+}
diff --git a/ld128/e_sinhl.c b/ld128/e_sinhl.c
new file mode 100644 (file)
index 0000000..3bfdb5d
--- /dev/null
@@ -0,0 +1,104 @@
+/* @(#)e_sinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* sinhl(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *      1. Replace x by |x| (sinhl(-x) = -sinhl(x)).
+ *      2.
+ *                                                   E + E/(E+1)
+ *          0        <= x <= 25     :  sinhl(x) := --------------, E=expm1l(x)
+ *                                                       2
+ *
+ *          25       <= x <= lnovft :  sinhl(x) := expl(x)/2
+ *          lnovft   <= x <= ln2ovft:  sinhl(x) := expl(x/2)/2 * expl(x/2)
+ *          ln2ovft  <  x           :  sinhl(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ *      sinhl(x) is |x| if x is +INF, -INF, or NaN.
+ *      only sinhl(0)=0 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, shuge = 1.0e4931L,
+ovf_thresh = 1.1357216553474703894801348310092223067821E4L;
+
+long double
+sinhl(long double x)
+{
+  long double t, w, h;
+  u_int32_t jx, ix;
+  ieee_quad_shape_type u;
+
+  /* Words of |x|. */
+  u.value = x;
+  jx = u.parts32.mswhi;
+  ix = jx & 0x7fffffff;
+
+  /* x is INF or NaN */
+  if (ix >= 0x7fff0000)
+    return x + x;
+
+  h = 0.5;
+  if (jx & 0x80000000)
+    h = -h;
+
+  /* Absolute value of x.  */
+  u.parts32.mswhi = ix;
+
+  /* |x| in [0,40], return sign(x)*0.5*(E+E/(E+1))) */
+  if (ix <= 0x40044000)
+    {
+      if (ix < 0x3fc60000) /* |x| < 2^-57 */
+       if (shuge + x > one)
+         return x;             /* sinh(tiny) = tiny with inexact */
+      t = expm1l (u.value);
+      if (ix < 0x3fff0000)
+       return h * (2.0 * t - t * t / (t + one));
+      return h * (t + t / (t + one));
+    }
+
+  /* |x| in [40, log(maxdouble)] return 0.5*exp(|x|) */
+  if (ix <= 0x400c62e3) /* 11356.375 */
+    return h * expl (u.value);
+
+  /* |x| in [log(maxdouble), overflowthreshold]
+     Overflow threshold is log(2 * maxdouble).  */
+  if (u.value <= ovf_thresh)
+    {
+      w = expl (0.5 * u.value);
+      t = h * w;
+      return t * w;
+    }
+
+  /* |x| > overflowthreshold, sinhl(x) overflow */
+  return x * shuge;
+}
diff --git a/ld128/e_tgammal.c b/ld128/e_tgammal.c
new file mode 100644 (file)
index 0000000..6c78c24
--- /dev/null
@@ -0,0 +1,39 @@
+/*     $OpenBSD: e_tgammal.c,v 1.1 2011/07/06 00:02:42 martynas Exp $  */
+
+/*
+ * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+long double
+tgammal(long double x)
+{
+       int64_t i0,i1;
+
+       GET_LDOUBLE_WORDS64(i0,i1,x);
+       if (((i0&0x7fffffffffffffffLL)|i1) == 0)
+               return (1.0/x);
+
+       if (i0<0 && (u_int64_t)i0<0xffff000000000000ULL && rintl(x)==x)
+               return (x-x)/(x-x);
+
+       if (i0==0xffff000000000000ULL && i1==0)
+               return (x-x);
+
+       return expl(lgammal(x));
+}
diff --git a/ld128/invtrig.c b/ld128/invtrig.c
new file mode 100644 (file)
index 0000000..5a869c2
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/invtrig.c,v 1.1 2008/07/31 22:41:26 das Exp $");
+
+#include "ld128/invtrig.h"
+
+/*
+ * asinl() and acosl()
+ */
+const long double
+pS0 =  1.66666666666666666666666666666700314e-01L,
+pS1 = -7.32816946414566252574527475428622708e-01L,
+pS2 =  1.34215708714992334609030036562143589e+00L,
+pS3 = -1.32483151677116409805070261790752040e+00L,
+pS4 =  7.61206183613632558824485341162121989e-01L,
+pS5 = -2.56165783329023486777386833928147375e-01L,
+pS6 =  4.80718586374448793411019434585413855e-02L,
+pS7 = -4.42523267167024279410230886239774718e-03L,
+pS8 =  1.44551535183911458253205638280410064e-04L,
+pS9 = -2.10558957916600254061591040482706179e-07L,
+qS1 = -4.84690167848739751544716485245697428e+00L,
+qS2 =  9.96619113536172610135016921140206980e+00L,
+qS3 = -1.13177895428973036660836798461641458e+01L,
+qS4 =  7.74004374389488266169304117714658761e+00L,
+qS5 = -3.25871986053534084709023539900339905e+00L,
+qS6 =  8.27830318881232209752469022352928864e-01L,
+qS7 = -1.18768052702942805423330715206348004e-01L,
+qS8 =  8.32600764660522313269101537926539470e-03L,
+qS9 = -1.99407384882605586705979504567947007e-04L;
+
+/*
+ * atanl()
+ */
+const long double atanhi[] = {
+        4.63647609000806116214256231461214397e-01L,
+        7.85398163397448309615660845819875699e-01L,       
+        9.82793723247329067985710611014666038e-01L,       
+        1.57079632679489661923132169163975140e+00L,
+};
+
+const long double atanlo[] = {
+        4.89509642257333492668618435220297706e-36L,
+        2.16795253253094525619926100651083806e-35L,
+       -2.31288434538183565909319952098066272e-35L,
+        4.33590506506189051239852201302167613e-35L,
+};
+
+const long double aT[] = {
+        3.33333333333333333333333333333333125e-01L,
+       -1.99999999999999999999999999999180430e-01L,
+        1.42857142857142857142857142125269827e-01L,
+       -1.11111111111111111111110834490810169e-01L,
+        9.09090909090909090908522355708623681e-02L,
+       -7.69230769230769230696553844935357021e-02L,
+        6.66666666666666660390096773046256096e-02L,
+       -5.88235294117646671706582985209643694e-02L,
+        5.26315789473666478515847092020327506e-02L,
+       -4.76190476189855517021024424991436144e-02L,
+        4.34782608678695085948531993458097026e-02L,
+       -3.99999999632663469330634215991142368e-02L,
+        3.70370363987423702891250829918659723e-02L,
+       -3.44827496515048090726669907612335954e-02L,
+        3.22579620681420149871973710852268528e-02L,
+       -3.03020767654269261041647570626778067e-02L,
+        2.85641979882534783223403715930946138e-02L,
+       -2.69824879726738568189929461383741323e-02L,
+        2.54194698498808542954187110873675769e-02L,
+       -2.35083879708189059926183138130183215e-02L,
+        2.04832358998165364349957325067131428e-02L,
+       -1.54489555488544397858507248612362957e-02L,
+        8.64492360989278761493037861575248038e-03L,
+       -2.58521121597609872727919154569765469e-03L,
+};
+
+const long double pi_lo = 8.67181013012378102479704402604335225e-35L;
diff --git a/ld128/invtrig.h b/ld128/invtrig.h
new file mode 100644 (file)
index 0000000..c85a615
--- /dev/null
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2008 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.
+ *
+ * $FreeBSD: src/lib/msun/ld128/invtrig.h,v 1.1 2008/07/31 22:41:26 das Exp $
+ */
+
+#include <float.h>
+
+#include "fpmath.h"
+
+#define        BIAS            (LDBL_MAX_EXP - 1)
+#define        MANH_SIZE       (LDBL_MANH_SIZE + 1)
+
+/* Approximation thresholds. */
+#define        ASIN_LINEAR     (BIAS - 56)     /* 2**-56 */
+#define        ACOS_CONST      (BIAS - 113)    /* 2**-113 */
+#define        ATAN_CONST      (BIAS + 113)    /* 2**113 */
+#define        ATAN_LINEAR     (BIAS - 56)     /* 2**-56 */
+
+/* 0.95 */
+#define        THRESH  ((0xe666666666666666ULL>>(64-(MANH_SIZE-1)))|LDBL_NBIT)
+
+/* Constants shared by the long double inverse trig functions. */
+#define        pS0     _ItL_pS0
+#define        pS1     _ItL_pS1
+#define        pS2     _ItL_pS2
+#define        pS3     _ItL_pS3
+#define        pS4     _ItL_pS4
+#define        pS5     _ItL_pS5
+#define        pS6     _ItL_pS6
+#define        pS7     _ItL_pS7
+#define        pS8     _ItL_pS8
+#define        pS9     _ItL_pS9
+#define        qS1     _ItL_qS1
+#define        qS2     _ItL_qS2
+#define        qS3     _ItL_qS3
+#define        qS4     _ItL_qS4
+#define        qS5     _ItL_qS5
+#define        qS6     _ItL_qS6
+#define        qS7     _ItL_qS7
+#define        qS8     _ItL_qS8
+#define        qS9     _ItL_qS9
+#define        atanhi  _ItL_atanhi
+#define        atanlo  _ItL_atanlo
+#define        aT      _ItL_aT
+#define        pi_lo   _ItL_pi_lo
+
+#define        pio2_hi atanhi[3]
+#define        pio2_lo atanlo[3]
+#define        pio4_hi atanhi[1]
+
+/* Constants shared by the long double inverse trig functions. */
+extern const long double pS0, pS1, pS2, pS3, pS4, pS5, pS6, pS7, pS8, pS9;
+extern const long double qS1, qS2, qS3, qS4, qS5, qS6, qS7, qS8, qS9;
+extern const long double atanhi[], atanlo[], aT[];
+extern const long double pi_lo;
+
+static inline long double
+P(long double x)
+{
+
+       return (x * (pS0 + x * (pS1 + x * (pS2 + x * (pS3 + x * \
+               (pS4 + x * (pS5 + x * (pS6 + x * (pS7 + x * (pS8 + x * \
+               pS9))))))))));
+}
+
+static inline long double
+Q(long double x)
+{
+
+       return (1.0 + x * (qS1 + x * (qS2 + x * (qS3 + x * (qS4 + x * \
+               (qS5 + x * (qS6 + x * (qS7 + x * (qS8 + x * qS9)))))))));
+}
+
+static inline long double
+T_even(long double x)
+{
+
+       return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * \
+               (aT[8] + x * (aT[10] + x * (aT[12] + x * (aT[14] + x * \
+               (aT[16] + x * (aT[18] + x * (aT[20] + x * aT[22])))))))))));
+}
+
+static inline long double
+T_odd(long double x)
+{
+
+       return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * \
+               (aT[9] + x * (aT[11] + x * (aT[13] + x * (aT[15] + x * \
+               (aT[17] + x * (aT[19] + x * (aT[21] + x * aT[23])))))))))));
+}
diff --git a/ld128/k_cosl.c b/ld128/k_cosl.c
new file mode 100644 (file)
index 0000000..37666dc
--- /dev/null
@@ -0,0 +1,61 @@
+/* From: @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_cosl.c,v 1.1 2008/02/17 07:32:31 das Exp $");
+
+/*
+ * ld128 version of k_cos.c.  See ../src/k_cos.c for most comments.
+ */
+
+#include "math_private.h"
+
+/*
+ * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]:
+ * |cos(x) - c(x))| < 2**-122.0
+ *
+ * 113-bit precision requires more care than 64-bit precision, since
+ * simple methods give a minimax polynomial with coefficient for x^2
+ * that is 1 ulp below 0.5, but we want it to be precisely 0.5.  See
+ * ../ld80/k_cosl.c for more details.
+ */
+static const double
+one = 1.0;
+
+static const long double
+C1 =  0.04166666666666666666666666666666658424671L,
+C2 = -0.001388888888888888888888888888863490893732L,
+C3 =  0.00002480158730158730158730158600795304914210L,
+C4 = -0.2755731922398589065255474947078934284324e-6L,
+C5 =  0.2087675698786809897659225313136400793948e-8L,
+C6 = -0.1147074559772972315817149986812031204775e-10L,
+C7 =  0.4779477332386808976875457937252120293400e-13L;
+
+static const double
+C8 = -0.1561920696721507929516718307820958119868e-15,
+C9 =  0.4110317413744594971475941557607804508039e-18,
+C10 = -0.8896592467191938803288521958313920156409e-21,
+C11 =  0.1601061435794535138244346256065192782581e-23;
+
+long double
+__kernel_cosl(long double x, long double y)
+{
+       long double hz,z,r,w;
+
+       z  = x*x;
+       r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*(C7+
+           z*(C8+z*(C9+z*(C10+z*C11))))))))));
+       hz = 0.5*z;
+       w  = one-hz;
+       return w + (((one-w)-hz) + (z*r-x*y));
+}
diff --git a/ld128/k_sinl.c b/ld128/k_sinl.c
new file mode 100644 (file)
index 0000000..1079159
--- /dev/null
@@ -0,0 +1,59 @@
+/* From: @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_sinl.c,v 1.1 2008/02/17 07:32:31 das Exp $");
+
+/*
+ * ld128 version of k_sin.c.  See ../src/k_sin.c for most comments.
+ */
+
+#include "math_private.h"
+
+static const double
+half =  0.5;
+
+/*
+ * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37]
+ * |sin(x)/x - s(x)| < 2**-122.1
+ *
+ * See ../ld80/k_cosl.c for more details about the polynomial.
+ */
+static const long double
+S1 = -0.16666666666666666666666666666666666606732416116558L,
+S2 =  0.0083333333333333333333333333333331135404851288270047L,
+S3 = -0.00019841269841269841269841269839935785325638310428717L,
+S4 =  0.27557319223985890652557316053039946268333231205686e-5L,
+S5 = -0.25052108385441718775048214826384312253862930064745e-7L,
+S6 =  0.16059043836821614596571832194524392581082444805729e-9L,
+S7 = -0.76471637318198151807063387954939213287488216303768e-12L,
+S8 =  0.28114572543451292625024967174638477283187397621303e-14L;
+
+static const double
+S9  = -0.82206352458348947812512122163446202498005154296863e-17,
+S10 =  0.19572940011906109418080609928334380560135358385256e-19,
+S11 = -0.38680813379701966970673724299207480965452616911420e-22,
+S12 =  0.64038150078671872796678569586315881020659912139412e-25;
+
+long double
+__kernel_sinl(long double x, long double y, int iy)
+{
+       long double z,r,v;
+
+       z       =  x*x;
+       v       =  z*x;
+       r       =  S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*(S8+
+           z*(S9+z*(S10+z*(S11+z*S12)))))))));
+       if(iy==0) return x+v*(S1+z*r);
+       else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/ld128/k_tanl.c b/ld128/k_tanl.c
new file mode 100644 (file)
index 0000000..7255076
--- /dev/null
@@ -0,0 +1,120 @@
+/* From: @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_tanl.c,v 1.1 2008/02/17 07:32:31 das Exp $");
+
+/*
+ * ld128 version of k_tan.c.  See ../src/k_tan.c for most comments.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37]
+ * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37)
+ *
+ * See ../ld80/k_cosl.c for more details about the polynomial.
+ */
+static const long double
+T3 = 0x1.5555555555555555555555555553p-2L,
+T5 = 0x1.1111111111111111111111111eb5p-3L,
+T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L,
+T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L,
+T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L,
+T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L,
+T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L,
+T17 = 0x1.355824803674477dfcf726649efep-11L,
+T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L,
+T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L,
+T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L,
+T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L,
+T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L,
+T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L,
+T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L,
+T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L,
+T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L,
+T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L,
+pio4 = 0x1.921fb54442d18469898cc51701b8p-1L,
+pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L;
+
+static const double
+T39 =  0.000000028443389121318352,     /*  0x1e8a7592977938.0p-78 */
+T41 =  0.000000011981013102001973,     /*  0x19baa1b1223219.0p-79 */
+T43 =  0.0000000038303578044958070,    /*  0x107385dfb24529.0p-80 */
+T45 =  0.0000000034664378216909893,    /*  0x1dc6c702a05262.0p-81 */
+T47 = -0.0000000015090641701997785,    /* -0x19ecef3569ebb6.0p-82 */
+T49 =  0.0000000029449552300483952,    /*  0x194c0668da786a.0p-81 */
+T51 = -0.0000000022006995706097711,    /* -0x12e763b8845268.0p-81 */
+T53 =  0.0000000015468200913196612,    /*  0x1a92fc98c29554.0p-82 */
+T55 = -0.00000000061311613386849674,   /* -0x151106cbc779a9.0p-83 */
+T57 =  1.4912469681508012e-10;         /*  0x147edbdba6f43a.0p-85 */
+
+long double
+__kernel_tanl(long double x, long double y, int iy) {
+       long double z, r, v, w, s;
+       long double osign;
+       int i;
+
+       iy = (iy == 1 ? -1 : 1);        /* XXX recover original interface */
+       osign = (x >= 0 ? 1.0 : -1.0);  /* XXX slow, probably wrong for -0 */
+       if (fabsl(x) >= 0.67434) {
+               if (x < 0) {
+                       x = -x;
+                       y = -y;
+               }
+               z = pio4 - x;
+               w = pio4lo - y;
+               x = z + w;
+               y = 0.0;
+               i = 1;
+       } else
+               i = 0;
+       z = x * x;
+       w = z * z;
+       r = T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 +
+           w * (T25 + w * (T29 + w * (T33 +
+           w * (T37 + w * (T41 + w * (T45 + w * (T49 + w * (T53 +
+           w * T57))))))))))));
+       v = z * (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 +
+           w * (T27 + w * (T31 + w * (T35 +
+           w * (T39 + w * (T43 + w * (T47 + w * (T51 + w * T55))))))))))));
+       s = z * x;
+       r = y + z * (s * (r + v) + y);
+       r += T3 * s;
+       w = x + r;
+       if (i == 1) {
+               v = (long double) iy;
+               return osign *
+                       (v - 2.0 * (x - (w * w / (w + v) - r)));
+       }
+       if (iy == 1)
+               return w;
+       else {
+               /*
+                * if allow error up to 2 ulp, simply return
+                * -1.0 / (x+r) here
+                */
+               /* compute -1.0 / (x+r) accurately */
+               long double a, t;
+               z = w;
+               z = z + 0x1p32 - 0x1p32;
+               v = r - (z - x);        /* z+v = r+x */
+               t = a = -1.0 / w;       /* a = -1.0/w */
+               t = t + 0x1p32 - 0x1p32;
+               s = 1.0 + t * z;
+               return t + a * (s + t * v);
+       }
+}
diff --git a/ld128/s_asinhl.c b/ld128/s_asinhl.c
new file mode 100644 (file)
index 0000000..29791e8
--- /dev/null
@@ -0,0 +1,69 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinhl(x)
+ * Method :
+ *      Based on
+ *              asinhl(x) = signl(x) * logl [ |x| + sqrtl(x*x+1) ]
+ *      we have
+ *      asinhl(x) := x  if  1+x*x=1,
+ *                := signl(x)*(logl(x)+ln2)) for large |x|, else
+ *                := signl(x)*logl(2|x|+1/(|x|+sqrtl(x*x+1))) if|x|>2, else
+ *                := signl(x)*log1pl(|x| + x^2/(1 + sqrtl(1+x^2)))
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+  one = 1.0L,
+  ln2 = 6.931471805599453094172321214581765681e-1L,
+  huge = 1.0e+4900L;
+
+long double
+asinhl(long double x)
+{
+  long double t, w;
+  int32_t ix, sign;
+  ieee_quad_shape_type u;
+
+  u.value = x;
+  sign = u.parts32.mswhi;
+  ix = sign & 0x7fffffff;
+  if (ix == 0x7fff0000)
+    return x + x;              /* x is inf or NaN */
+  if (ix < 0x3fc70000)
+    {                          /* |x| < 2^ -56 */
+      if (huge + x > one)
+       return x;               /* return x inexact except 0 */
+    }
+  u.parts32.mswhi = ix;
+  if (ix > 0x40350000)
+    {                          /* |x| > 2 ^ 54 */
+      w = logl (u.value) + ln2;
+    }
+  else if (ix >0x40000000)
+    {                          /* 2^ 54 > |x| > 2.0 */
+      t = u.value;
+      w = logl (2.0 * t + one / (sqrtl (x * x + one) + t));
+    }
+  else
+    {                          /* 2.0 > |x| > 2 ^ -56 */
+      t = x * x;
+      w = log1pl (u.value + t / (one + sqrtl (one + t)));
+    }
+  if (sign & 0x80000000)
+    return -w;
+  else
+    return w;
+}
diff --git a/ld128/s_ceill.c b/ld128/s_ceill.c
new file mode 100644 (file)
index 0000000..719e7fc
--- /dev/null
@@ -0,0 +1,69 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceill(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double huge = 1.0e4930L;
+
+long double
+ceill(long double x)
+{
+       int64_t i0,i1,jj0;
+       u_int64_t i,j;
+       GET_LDOUBLE_WORDS64(i0,i1,x);
+       jj0 = ((i0>>48)&0x7fff)-0x3fff;
+       if(jj0<48) {
+           if(jj0<0) {         /* raise inexact if x != 0 */
+               if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0<0) {i0=0x8000000000000000ULL;i1=0;}
+                   else if((i0|i1)!=0) { i0=0x3fff000000000000ULL;i1=0;}
+               }
+           } else {
+               i = (0x0000ffffffffffffULL)>>jj0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(i0>0) i0 += (0x0001000000000000LL)>>jj0;
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (jj0>111) {
+           if(jj0==0x4000) return x+x; /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = -1ULL>>(jj0-48);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(i0>0) {
+                   if(jj0==48) i0+=1;
+                   else {
+                       j = i1+(1LL<<(112-jj0));
+                       if(j<i1) i0 +=1 ;       /* got a carry */
+                       i1=j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       SET_LDOUBLE_WORDS64(x,i0,i1);
+       return x;
+}
diff --git a/ld128/s_erfl.c b/ld128/s_erfl.c
new file mode 100644 (file)
index 0000000..e676234
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ *                          x
+ *                   2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *                sqrt(pi) \|
+ *                          0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that
+ *             erf(-x) = -erf(x)
+ *             erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *     1.  erf(x)  = x + x*R(x^2) for |x| in [0, 7/8]
+ *        Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *        and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *        is close to one.
+ *
+ *      1a. erf(x)  = 1 - erfc(x), for |x| > 1.0
+ *          erfc(x) = 1 - erf(x)  if |x| < 1/4
+ *
+ *      2. For |x| in [7/8, 1], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *     erf(s + c)  = sign(x) * (c  + P1(s)/Q1(s))
+ *        Remark: here we use the taylor series expansion at x=1.
+ *             erf(1+s) = erf(1) + s*Poly(s)
+ *                      = 0.845.. + P1(s)/Q1(s)
+ *        Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *
+ *      3. For x in [1/4, 5/4],
+ *     erfc(s + const)  = erfc(const)  + s P1(s)/Q1(s)
+ *              for const = 1/4, 3/8, ..., 9/8
+ *              and 0 <= s <= 1/8 .
+ *
+ *      4. For x in [5/4, 107],
+ *     erfc(x) = (1/x)*exp(-x*x-0.5625 + R(z))
+ *              z=1/x^2
+ *         The interval is partitioned into several segments
+ *         of width 1/8 in 1/x.
+ *
+ *      Note1:
+ *        To compute exp(-x*x-0.5625+R/S), let s be a single
+ *        precision number and s := x; then
+ *             -x*x = -s*s + (s-x)*(s+x)
+ *             exp(-x*x-0.5626+R/S) =
+ *                     exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *        Here 4 and 5 make use of the asymptotic series
+ *                       exp(-x*x)
+ *             erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *                       x*sqrt(pi)
+ *
+ *      5. For inf > x >= 107
+ *     erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *     erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *                     = 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *     erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *     erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ *             erfc/erf(NaN) is NaN
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Evaluate P[n] x^n  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+neval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+/* Evaluate x^n+1  +  P[n] x^(n)  +  P[n-1] x^(n-1)  +  ...  +  P[0] */
+
+static long double
+deval (long double x, const long double *p, int n)
+{
+  long double y;
+
+  p += n;
+  y = x + *p--;
+  do
+    {
+      y = y * x + *p--;
+    }
+  while (--n > 0);
+  return y;
+}
+
+
+
+static const long double
+tiny = 1e-4931L,
+  one = 1.0L,
+  two = 2.0L,
+  /* 2/sqrt(pi) - 1 */
+  efx = 1.2837916709551257389615890312154517168810E-1L,
+  /* 8 * (2/sqrt(pi) - 1) */
+  efx8 = 1.0270333367641005911692712249723613735048E0L;
+
+
+/* erf(x)  = x  + x R(x^2)
+   0 <= x <= 7/8
+   Peak relative error 1.8e-35  */
+#define NTN1 8
+static const long double TN1[NTN1 + 1] =
+{
+ -3.858252324254637124543172907442106422373E10L,
+  9.580319248590464682316366876952214879858E10L,
+  1.302170519734879977595901236693040544854E10L,
+  2.922956950426397417800321486727032845006E9L,
+  1.764317520783319397868923218385468729799E8L,
+  1.573436014601118630105796794840834145120E7L,
+  4.028077380105721388745632295157816229289E5L,
+  1.644056806467289066852135096352853491530E4L,
+  3.390868480059991640235675479463287886081E1L
+};
+#define NTD1 8
+static const long double TD1[NTD1 + 1] =
+{
+  -3.005357030696532927149885530689529032152E11L,
+  -1.342602283126282827411658673839982164042E11L,
+  -2.777153893355340961288511024443668743399E10L,
+  -3.483826391033531996955620074072768276974E9L,
+  -2.906321047071299585682722511260895227921E8L,
+  -1.653347985722154162439387878512427542691E7L,
+  -6.245520581562848778466500301865173123136E5L,
+  -1.402124304177498828590239373389110545142E4L,
+  -1.209368072473510674493129989468348633579E2L
+/* 1.0E0 */
+};
+
+
+/* erf(z+1)  = erf_const + P(z)/Q(z)
+   -.125 <= z <= 0
+   Peak relative error 7.3e-36  */
+static const long double erf_const = 0.845062911510467529296875L;
+#define NTN2 8
+static const long double TN2[NTN2 + 1] =
+{
+ -4.088889697077485301010486931817357000235E1L,
+  7.157046430681808553842307502826960051036E3L,
+ -2.191561912574409865550015485451373731780E3L,
+  2.180174916555316874988981177654057337219E3L,
+  2.848578658049670668231333682379720943455E2L,
+  1.630362490952512836762810462174798925274E2L,
+  6.317712353961866974143739396865293596895E0L,
+  2.450441034183492434655586496522857578066E1L,
+  5.127662277706787664956025545897050896203E-1L
+};
+#define NTD2 8
+static const long double TD2[NTD2 + 1] =
+{
+  1.731026445926834008273768924015161048885E4L,
+  1.209682239007990370796112604286048173750E4L,
+  1.160950290217993641320602282462976163857E4L,
+  5.394294645127126577825507169061355698157E3L,
+  2.791239340533632669442158497532521776093E3L,
+  8.989365571337319032943005387378993827684E2L,
+  2.974016493766349409725385710897298069677E2L,
+  6.148192754590376378740261072533527271947E1L,
+  1.178502892490738445655468927408440847480E1L
+ /* 1.0E0 */
+};
+
+
+/* erfc(x + 0.25) = erfc(0.25) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 1.4e-35  */
+#define NRNr13 8
+static const long double RNr13[NRNr13 + 1] =
+{
+ -2.353707097641280550282633036456457014829E3L,
+  3.871159656228743599994116143079870279866E2L,
+ -3.888105134258266192210485617504098426679E2L,
+ -2.129998539120061668038806696199343094971E1L,
+ -8.125462263594034672468446317145384108734E1L,
+  8.151549093983505810118308635926270319660E0L,
+ -5.033362032729207310462422357772568553670E0L,
+ -4.253956621135136090295893547735851168471E-2L,
+ -8.098602878463854789780108161581050357814E-2L
+};
+#define NRDr13 7
+static const long double RDr13[NRDr13 + 1] =
+{
+  2.220448796306693503549505450626652881752E3L,
+  1.899133258779578688791041599040951431383E2L,
+  1.061906712284961110196427571557149268454E3L,
+  7.497086072306967965180978101974566760042E1L,
+  2.146796115662672795876463568170441327274E2L,
+  1.120156008362573736664338015952284925592E1L,
+  2.211014952075052616409845051695042741074E1L,
+  6.469655675326150785692908453094054988938E-1L
+ /* 1.0E0 */
+};
+/* erfc(0.25) = C13a + C13b to extra precision.  */
+static const long double C13a = 0.723663330078125L;
+static const long double C13b = 1.0279753638067014931732235184287934646022E-5L;
+
+
+/* erfc(x + 0.375) = erfc(0.375) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 1.2e-35  */
+#define NRNr14 8
+static const long double RNr14[NRNr14 + 1] =
+{
+ -2.446164016404426277577283038988918202456E3L,
+  6.718753324496563913392217011618096698140E2L,
+ -4.581631138049836157425391886957389240794E2L,
+ -2.382844088987092233033215402335026078208E1L,
+ -7.119237852400600507927038680970936336458E1L,
+  1.313609646108420136332418282286454287146E1L,
+ -6.188608702082264389155862490056401365834E0L,
+ -2.787116601106678287277373011101132659279E-2L,
+ -2.230395570574153963203348263549700967918E-2L
+};
+#define NRDr14 7
+static const long double RDr14[NRDr14 + 1] =
+{
+  2.495187439241869732696223349840963702875E3L,
+  2.503549449872925580011284635695738412162E2L,
+  1.159033560988895481698051531263861842461E3L,
+  9.493751466542304491261487998684383688622E1L,
+  2.276214929562354328261422263078480321204E2L,
+  1.367697521219069280358984081407807931847E1L,
+  2.276988395995528495055594829206582732682E1L,
+  7.647745753648996559837591812375456641163E-1L
+ /* 1.0E0 */
+};
+/* erfc(0.375) = C14a + C14b to extra precision.  */
+static const long double C14a = 0.5958709716796875L;
+static const long double C14b = 1.2118885490201676174914080878232469565953E-5L;
+
+/* erfc(x + 0.5) = erfc(0.5) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 4.7e-36  */
+#define NRNr15 8
+static const long double RNr15[NRNr15 + 1] =
+{
+ -2.624212418011181487924855581955853461925E3L,
+  8.473828904647825181073831556439301342756E2L,
+ -5.286207458628380765099405359607331669027E2L,
+ -3.895781234155315729088407259045269652318E1L,
+ -6.200857908065163618041240848728398496256E1L,
+  1.469324610346924001393137895116129204737E1L,
+ -6.961356525370658572800674953305625578903E0L,
+  5.145724386641163809595512876629030548495E-3L,
+  1.990253655948179713415957791776180406812E-2L
+};
+#define NRDr15 7
+static const long double RDr15[NRDr15 + 1] =
+{
+  2.986190760847974943034021764693341524962E3L,
+  5.288262758961073066335410218650047725985E2L,
+  1.363649178071006978355113026427856008978E3L,
+  1.921707975649915894241864988942255320833E2L,
+  2.588651100651029023069013885900085533226E2L,
+  2.628752920321455606558942309396855629459E1L,
+  2.455649035885114308978333741080991380610E1L,
+  1.378826653595128464383127836412100939126E0L
+  /* 1.0E0 */
+};
+/* erfc(0.5) = C15a + C15b to extra precision.  */
+static const long double C15a = 0.4794921875L;
+static const long double C15b = 7.9346869534623172533461080354712635484242E-6L;
+
+/* erfc(x + 0.625) = erfc(0.625) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 5.1e-36  */
+#define NRNr16 8
+static const long double RNr16[NRNr16 + 1] =
+{
+ -2.347887943200680563784690094002722906820E3L,
+  8.008590660692105004780722726421020136482E2L,
+ -5.257363310384119728760181252132311447963E2L,
+ -4.471737717857801230450290232600243795637E1L,
+ -4.849540386452573306708795324759300320304E1L,
+  1.140885264677134679275986782978655952843E1L,
+ -6.731591085460269447926746876983786152300E0L,
+  1.370831653033047440345050025876085121231E-1L,
+  2.022958279982138755020825717073966576670E-2L,
+};
+#define NRDr16 7
+static const long double RDr16[NRDr16 + 1] =
+{
+  3.075166170024837215399323264868308087281E3L,
+  8.730468942160798031608053127270430036627E2L,
+  1.458472799166340479742581949088453244767E3L,
+  3.230423687568019709453130785873540386217E2L,
+  2.804009872719893612081109617983169474655E2L,
+  4.465334221323222943418085830026979293091E1L,
+  2.612723259683205928103787842214809134746E1L,
+  2.341526751185244109722204018543276124997E0L,
+  /* 1.0E0 */
+};
+/* erfc(0.625) = C16a + C16b to extra precision.  */
+static const long double C16a = 0.3767547607421875L;
+static const long double C16b = 4.3570693945275513594941232097252997287766E-6L;
+
+/* erfc(x + 0.75) = erfc(0.75) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 1.7e-35  */
+#define NRNr17 8
+static const long double RNr17[NRNr17 + 1] =
+{
+  -1.767068734220277728233364375724380366826E3L,
+  6.693746645665242832426891888805363898707E2L,
+  -4.746224241837275958126060307406616817753E2L,
+  -2.274160637728782675145666064841883803196E1L,
+  -3.541232266140939050094370552538987982637E1L,
+  6.988950514747052676394491563585179503865E0L,
+  -5.807687216836540830881352383529281215100E0L,
+  3.631915988567346438830283503729569443642E-1L,
+  -1.488945487149634820537348176770282391202E-2L
+};
+#define NRDr17 7
+static const long double RDr17[NRDr17 + 1] =
+{
+  2.748457523498150741964464942246913394647E3L,
+  1.020213390713477686776037331757871252652E3L,
+  1.388857635935432621972601695296561952738E3L,
+  3.903363681143817750895999579637315491087E2L,
+  2.784568344378139499217928969529219886578E2L,
+  5.555800830216764702779238020065345401144E1L,
+  2.646215470959050279430447295801291168941E1L,
+  2.984905282103517497081766758550112011265E0L,
+  /* 1.0E0 */
+};
+/* erfc(0.75) = C17a + C17b to extra precision.  */
+static const long double C17a = 0.2888336181640625L;
+static const long double C17b = 1.0748182422368401062165408589222625794046E-5L;
+
+
+/* erfc(x + 0.875) = erfc(0.875) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 2.2e-35  */
+#define NRNr18 8
+static const long double RNr18[NRNr18 + 1] =
+{
+ -1.342044899087593397419622771847219619588E3L,
+  6.127221294229172997509252330961641850598E2L,
+ -4.519821356522291185621206350470820610727E2L,
+  1.223275177825128732497510264197915160235E1L,
+ -2.730789571382971355625020710543532867692E1L,
+  4.045181204921538886880171727755445395862E0L,
+ -4.925146477876592723401384464691452700539E0L,
+  5.933878036611279244654299924101068088582E-1L,
+ -5.557645435858916025452563379795159124753E-2L
+};
+#define NRDr18 7
+static const long double RDr18[NRDr18 + 1] =
+{
+  2.557518000661700588758505116291983092951E3L,
+  1.070171433382888994954602511991940418588E3L,
+  1.344842834423493081054489613250688918709E3L,
+  4.161144478449381901208660598266288188426E2L,
+  2.763670252219855198052378138756906980422E2L,
+  5.998153487868943708236273854747564557632E1L,
+  2.657695108438628847733050476209037025318E1L,
+  3.252140524394421868923289114410336976512E0L,
+  /* 1.0E0 */
+};
+/* erfc(0.875) = C18a + C18b to extra precision.  */
+static const long double C18a = 0.215911865234375L;
+static const long double C18b = 1.3073705765341685464282101150637224028267E-5L;
+
+/* erfc(x + 1.0) = erfc(1.0) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 1.6e-35  */
+#define NRNr19 8
+static const long double RNr19[NRNr19 + 1] =
+{
+ -1.139180936454157193495882956565663294826E3L,
+  6.134903129086899737514712477207945973616E2L,
+ -4.628909024715329562325555164720732868263E2L,
+  4.165702387210732352564932347500364010833E1L,
+ -2.286979913515229747204101330405771801610E1L,
+  1.870695256449872743066783202326943667722E0L,
+ -4.177486601273105752879868187237000032364E0L,
+  7.533980372789646140112424811291782526263E-1L,
+ -8.629945436917752003058064731308767664446E-2L
+};
+#define NRDr19 7
+static const long double RDr19[NRDr19 + 1] =
+{
+  2.744303447981132701432716278363418643778E3L,
+  1.266396359526187065222528050591302171471E3L,
+  1.466739461422073351497972255511919814273E3L,
+  4.868710570759693955597496520298058147162E2L,
+  2.993694301559756046478189634131722579643E2L,
+  6.868976819510254139741559102693828237440E1L,
+  2.801505816247677193480190483913753613630E1L,
+  3.604439909194350263552750347742663954481E0L,
+  /* 1.0E0 */
+};
+/* erfc(1.0) = C19a + C19b to extra precision.  */
+static const long double C19a = 0.15728759765625L;
+static const long double C19b = 1.1609394035130658779364917390740703933002E-5L;
+
+/* erfc(x + 1.125) = erfc(1.125) + x R(x)
+   0 <= x < 0.125
+   Peak relative error 3.6e-36  */
+#define NRNr20 8
+static const long double RNr20[NRNr20 + 1] =
+{
+ -9.652706916457973956366721379612508047640E2L,
+  5.577066396050932776683469951773643880634E2L,
+ -4.406335508848496713572223098693575485978E2L,
+  5.202893466490242733570232680736966655434E1L,
+ -1.931311847665757913322495948705563937159E1L,
+ -9.364318268748287664267341457164918090611E-2L,
+ -3.306390351286352764891355375882586201069E0L,
+  7.573806045289044647727613003096916516475E-1L,
+ -9.611744011489092894027478899545635991213E-2L
+};
+#define NRDr20 7
+static const long double RDr20[NRDr20 + 1] =
+{
+  3.032829629520142564106649167182428189014E3L,
+  1.659648470721967719961167083684972196891E3L,
+  1.703545128657284619402511356932569292535E3L,
+  6.393465677731598872500200253155257708763E2L,
+  3.489131397281030947405287112726059221934E2L,
+  8.848641738570783406484348434387611713070E1L,
+  3.132269062552392974833215844236160958502E1L,
+  4.430131663290563523933419966185230513168E0L
+ /* 1.0E0 */
+};
+/* erfc(1.125) = C20a + C20b to extra precision.  */
+static const long double C20a = 0.111602783203125L;
+static const long double C20b = 8.9850951672359304215530728365232161564636E-6L;
+
+/* erfc(1/x) = 1/x exp (-1/x^2 - 0.5625 + R(1/x^2))
+   7/8 <= 1/x < 1
+   Peak relative error 1.4e-35  */
+#define NRNr8 9
+static const long double RNr8[NRNr8 + 1] =
+{
+  3.587451489255356250759834295199296936784E1L,
+  5.406249749087340431871378009874875889602E2L,
+  2.931301290625250886238822286506381194157E3L,
+  7.359254185241795584113047248898753470923E3L,
+  9.201031849810636104112101947312492532314E3L,
+  5.749697096193191467751650366613289284777E3L,
+  1.710415234419860825710780802678697889231E3L,
+  2.150753982543378580859546706243022719599E2L,
+  8.740953582272147335100537849981160931197E0L,
+  4.876422978828717219629814794707963640913E-2L
+};
+#define NRDr8 8
+static const long double RDr8[NRDr8 + 1] =
+{
+  6.358593134096908350929496535931630140282E1L,
+  9.900253816552450073757174323424051765523E2L,
+  5.642928777856801020545245437089490805186E3L,
+  1.524195375199570868195152698617273739609E4L,
+  2.113829644500006749947332935305800887345E4L,
+  1.526438562626465706267943737310282977138E4L,
+  5.561370922149241457131421914140039411782E3L,
+  9.394035530179705051609070428036834496942E2L,
+  6.147019596150394577984175188032707343615E1L
+  /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp (-1/x^2 - 0.5625 + R(1/x^2))
+   0.75 <= 1/x <= 0.875
+   Peak relative error 2.0e-36  */
+#define NRNr7 9
+static const long double RNr7[NRNr7 + 1] =
+{
+ 1.686222193385987690785945787708644476545E1L,
+ 1.178224543567604215602418571310612066594E3L,
+ 1.764550584290149466653899886088166091093E4L,
+ 1.073758321890334822002849369898232811561E5L,
+ 3.132840749205943137619839114451290324371E5L,
+ 4.607864939974100224615527007793867585915E5L,
+ 3.389781820105852303125270837910972384510E5L,
+ 1.174042187110565202875011358512564753399E5L,
+ 1.660013606011167144046604892622504338313E4L,
+ 6.700393957480661937695573729183733234400E2L
+};
+#define NRDr7 9
+static const long double RDr7[NRDr7 + 1] =
+{
+-1.709305024718358874701575813642933561169E3L,
+-3.280033887481333199580464617020514788369E4L,
+-2.345284228022521885093072363418750835214E5L,
+-8.086758123097763971926711729242327554917E5L,
+-1.456900414510108718402423999575992450138E6L,
+-1.391654264881255068392389037292702041855E6L,
+-6.842360801869939983674527468509852583855E5L,
+-1.597430214446573566179675395199807533371E5L,
+-1.488876130609876681421645314851760773480E4L,
+-3.511762950935060301403599443436465645703E2L
+ /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   5/8 <= 1/x < 3/4
+   Peak relative error 1.9e-35  */
+#define NRNr6 9
+static const long double RNr6[NRNr6 + 1] =
+{
+ 1.642076876176834390623842732352935761108E0L,
+ 1.207150003611117689000664385596211076662E2L,
+ 2.119260779316389904742873816462800103939E3L,
+ 1.562942227734663441801452930916044224174E4L,
+ 5.656779189549710079988084081145693580479E4L,
+ 1.052166241021481691922831746350942786299E5L,
+ 9.949798524786000595621602790068349165758E4L,
+ 4.491790734080265043407035220188849562856E4L,
+ 8.377074098301530326270432059434791287601E3L,
+ 4.506934806567986810091824791963991057083E2L
+};
+#define NRDr6 9
+static const long double RDr6[NRDr6 + 1] =
+{
+-1.664557643928263091879301304019826629067E2L,
+-3.800035902507656624590531122291160668452E3L,
+-3.277028191591734928360050685359277076056E4L,
+-1.381359471502885446400589109566587443987E5L,
+-3.082204287382581873532528989283748656546E5L,
+-3.691071488256738343008271448234631037095E5L,
+-2.300482443038349815750714219117566715043E5L,
+-6.873955300927636236692803579555752171530E4L,
+-8.262158817978334142081581542749986845399E3L,
+-2.517122254384430859629423488157361983661E2L
+ /* 1.00 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   1/2 <= 1/x < 5/8
+   Peak relative error 4.6e-36  */
+#define NRNr5 10
+static const long double RNr5[NRNr5 + 1] =
+{
+-3.332258927455285458355550878136506961608E-3L,
+-2.697100758900280402659586595884478660721E-1L,
+-6.083328551139621521416618424949137195536E0L,
+-6.119863528983308012970821226810162441263E1L,
+-3.176535282475593173248810678636522589861E2L,
+-8.933395175080560925809992467187963260693E2L,
+-1.360019508488475978060917477620199499560E3L,
+-1.075075579828188621541398761300910213280E3L,
+-4.017346561586014822824459436695197089916E2L,
+-5.857581368145266249509589726077645791341E1L,
+-2.077715925587834606379119585995758954399E0L
+};
+#define NRDr5 9
+static const long double RDr5[NRDr5 + 1] =
+{
+ 3.377879570417399341550710467744693125385E-1L,
+ 1.021963322742390735430008860602594456187E1L,
+ 1.200847646592942095192766255154827011939E2L,
+ 7.118915528142927104078182863387116942836E2L,
+ 2.318159380062066469386544552429625026238E3L,
+ 4.238729853534009221025582008928765281620E3L,
+ 4.279114907284825886266493994833515580782E3L,
+ 2.257277186663261531053293222591851737504E3L,
+ 5.570475501285054293371908382916063822957E2L,
+ 5.142189243856288981145786492585432443560E1L
+ /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   3/8 <= 1/x < 1/2
+   Peak relative error 2.0e-36  */
+#define NRNr4 10
+static const long double RNr4[NRNr4 + 1] =
+{
+ 3.258530712024527835089319075288494524465E-3L,
+ 2.987056016877277929720231688689431056567E-1L,
+ 8.738729089340199750734409156830371528862E0L,
+ 1.207211160148647782396337792426311125923E2L,
+ 8.997558632489032902250523945248208224445E2L,
+ 3.798025197699757225978410230530640879762E3L,
+ 9.113203668683080975637043118209210146846E3L,
+ 1.203285891339933238608683715194034900149E4L,
+ 8.100647057919140328536743641735339740855E3L,
+ 2.383888249907144945837976899822927411769E3L,
+ 2.127493573166454249221983582495245662319E2L
+};
+#define NRDr4 10
+static const long double RDr4[NRDr4 + 1] =
+{
+-3.303141981514540274165450687270180479586E-1L,
+-1.353768629363605300707949368917687066724E1L,
+-2.206127630303621521950193783894598987033E2L,
+-1.861800338758066696514480386180875607204E3L,
+-8.889048775872605708249140016201753255599E3L,
+-2.465888106627948210478692168261494857089E4L,
+-3.934642211710774494879042116768390014289E4L,
+-3.455077258242252974937480623730228841003E4L,
+-1.524083977439690284820586063729912653196E4L,
+-2.810541887397984804237552337349093953857E3L,
+-1.343929553541159933824901621702567066156E2L
+ /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   1/4 <= 1/x < 3/8
+   Peak relative error 8.4e-37  */
+#define NRNr3 11
+static const long double RNr3[NRNr3 + 1] =
+{
+-1.952401126551202208698629992497306292987E-6L,
+-2.130881743066372952515162564941682716125E-4L,
+-8.376493958090190943737529486107282224387E-3L,
+-1.650592646560987700661598877522831234791E-1L,
+-1.839290818933317338111364667708678163199E0L,
+-1.216278715570882422410442318517814388470E1L,
+-4.818759344462360427612133632533779091386E1L,
+-1.120994661297476876804405329172164436784E2L,
+-1.452850765662319264191141091859300126931E2L,
+-9.485207851128957108648038238656777241333E1L,
+-2.563663855025796641216191848818620020073E1L,
+-1.787995944187565676837847610706317833247E0L
+};
+#define NRDr3 10
+static const long double RDr3[NRDr3 + 1] =
+{
+ 1.979130686770349481460559711878399476903E-4L,
+ 1.156941716128488266238105813374635099057E-2L,
+ 2.752657634309886336431266395637285974292E-1L,
+ 3.482245457248318787349778336603569327521E0L,
+ 2.569347069372696358578399521203959253162E1L,
+ 1.142279000180457419740314694631879921561E2L,
+ 3.056503977190564294341422623108332700840E2L,
+ 4.780844020923794821656358157128719184422E2L,
+ 4.105972727212554277496256802312730410518E2L,
+ 1.724072188063746970865027817017067646246E2L,
+ 2.815939183464818198705278118326590370435E1L
+ /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   1/8 <= 1/x < 1/4
+   Peak relative error 1.5e-36  */
+#define NRNr2 11
+static const long double RNr2[NRNr2 + 1] =
+{
+-2.638914383420287212401687401284326363787E-8L,
+-3.479198370260633977258201271399116766619E-6L,
+-1.783985295335697686382487087502222519983E-4L,
+-4.777876933122576014266349277217559356276E-3L,
+-7.450634738987325004070761301045014986520E-2L,
+-7.068318854874733315971973707247467326619E-1L,
+-4.113919921935944795764071670806867038732E0L,
+-1.440447573226906222417767283691888875082E1L,
+-2.883484031530718428417168042141288943905E1L,
+-2.990886974328476387277797361464279931446E1L,
+-1.325283914915104866248279787536128997331E1L,
+-1.572436106228070195510230310658206154374E0L
+};
+#define NRDr2 10
+static const long double RDr2[NRDr2 + 1] =
+{
+ 2.675042728136731923554119302571867799673E-6L,
+ 2.170997868451812708585443282998329996268E-4L,
+ 7.249969752687540289422684951196241427445E-3L,
+ 1.302040375859768674620410563307838448508E-1L,
+ 1.380202483082910888897654537144485285549E0L,
+ 8.926594113174165352623847870299170069350E0L,
+ 3.521089584782616472372909095331572607185E1L,
+ 8.233547427533181375185259050330809105570E1L,
+ 1.072971579885803033079469639073292840135E2L,
+ 6.943803113337964469736022094105143158033E1L,
+ 1.775695341031607738233608307835017282662E1L
+ /* 1.0E0 */
+};
+
+/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2))
+   1/128 <= 1/x < 1/8
+   Peak relative error 2.2e-36  */
+#define NRNr1 9
+static const long double RNr1[NRNr1 + 1] =
+{
+-4.250780883202361946697751475473042685782E-8L,
+-5.375777053288612282487696975623206383019E-6L,
+-2.573645949220896816208565944117382460452E-4L,
+-6.199032928113542080263152610799113086319E-3L,
+-8.262721198693404060380104048479916247786E-2L,
+-6.242615227257324746371284637695778043982E-1L,
+-2.609874739199595400225113299437099626386E0L,
+-5.581967563336676737146358534602770006970E0L,
+-5.124398923356022609707490956634280573882E0L,
+-1.290865243944292370661544030414667556649E0L
+};
+#define NRDr1 8
+static const long double RDr1[NRDr1 + 1] =
+{
+ 4.308976661749509034845251315983612976224E-6L,
+ 3.265390126432780184125233455960049294580E-4L,
+ 9.811328839187040701901866531796570418691E-3L,
+ 1.511222515036021033410078631914783519649E-1L,
+ 1.289264341917429958858379585970225092274E0L,
+ 6.147640356182230769548007536914983522270E0L,
+ 1.573966871337739784518246317003956180750E1L,
+ 1.955534123435095067199574045529218238263E1L,
+ 9.472613121363135472247929109615785855865E0L
+  /* 1.0E0 */
+};
+
+
+long double
+erfl(long double x)
+{
+  long double a, y, z;
+  int32_t i, ix, sign;
+  ieee_quad_shape_type u;
+
+  u.value = x;
+  sign = u.parts32.mswhi;
+  ix = sign & 0x7fffffff;
+
+  if (ix >= 0x7fff0000)
+    {                          /* erf(nan)=nan */
+      i = ((sign & 0xffff0000) >> 31) << 1;
+      return (long double) (1 - i) + one / x;  /* erf(+-inf)=+-1 */
+    }
+
+  if (ix >= 0x3fff0000) /* |x| >= 1.0 */
+    {
+      y = erfcl (x);
+      return (one - y);
+      /*    return (one - erfcl (x)); */
+    }
+  u.parts32.mswhi = ix;
+  a = u.value;
+  z = x * x;
+  if (ix < 0x3ffec000)  /* a < 0.875 */
+    {
+      if (ix < 0x3fc60000) /* |x|<2**-57 */
+       {
+         if (ix < 0x00080000)
+           return 0.125 * (8.0 * x + efx8 * x);        /*avoid underflow */
+         return x + efx * x;
+       }
+      y = a + a * neval (z, TN1, NTN1) / deval (z, TD1, NTD1);
+    }
+  else
+    {
+      a = a - one;
+      y = erf_const + neval (a, TN2, NTN2) / deval (a, TD2, NTD2);
+    }
+
+  if (sign & 0x80000000) /* x < 0 */
+    y = -y;
+  return( y );
+}
+
+long double
+erfcl(long double x)
+{
+  long double y, z, p, r;
+  int32_t i, ix, sign;
+  ieee_quad_shape_type u;
+
+  u.value = x;
+  sign = u.parts32.mswhi;
+  ix = sign & 0x7fffffff;
+  u.parts32.mswhi = ix;
+
+  if (ix >= 0x7fff0000)
+    {                          /* erfc(nan)=nan */
+      /* erfc(+-inf)=0,2 */
+      return (long double) (((u_int32_t) sign >> 31) << 1) + one / x;
+    }
+
+  if (ix < 0x3ffd0000) /* |x| <1/4 */
+    {
+      if (ix < 0x3f8d0000) /* |x|<2**-114 */
+       return one - x;
+      return one - erfl (x);
+    }
+  if (ix < 0x3fff4000) /* 1.25 */
+    {
+      x = u.value;
+      i = 8.0 * x;
+      switch (i)
+       {
+       case 2:
+         z = x - 0.25L;
+         y = C13b + z * neval (z, RNr13, NRNr13) / deval (z, RDr13, NRDr13);
+         y += C13a;
+         break;
+       case 3:
+         z = x - 0.375L;
+         y = C14b + z * neval (z, RNr14, NRNr14) / deval (z, RDr14, NRDr14);
+         y += C14a;
+         break;
+       case 4:
+         z = x - 0.5L;
+         y = C15b + z * neval (z, RNr15, NRNr15) / deval (z, RDr15, NRDr15);
+         y += C15a;
+         break;
+       case 5:
+         z = x - 0.625L;
+         y = C16b + z * neval (z, RNr16, NRNr16) / deval (z, RDr16, NRDr16);
+         y += C16a;
+         break;
+       case 6:
+         z = x - 0.75L;
+         y = C17b + z * neval (z, RNr17, NRNr17) / deval (z, RDr17, NRDr17);
+         y += C17a;
+         break;
+       case 7:
+         z = x - 0.875L;
+         y = C18b + z * neval (z, RNr18, NRNr18) / deval (z, RDr18, NRDr18);
+         y += C18a;
+         break;
+       case 8:
+         z = x - 1.0L;
+         y = C19b + z * neval (z, RNr19, NRNr19) / deval (z, RDr19, NRDr19);
+         y += C19a;
+         break;
+       case 9:
+         z = x - 1.125L;
+         y = C20b + z * neval (z, RNr20, NRNr20) / deval (z, RDr20, NRDr20);
+         y += C20a;
+         break;
+       }
+      if (sign & 0x80000000)
+       y = 2.0L - y;
+      return y;
+    }
+  /* 1.25 < |x| < 107 */
+  if (ix < 0x4005ac00)
+    {
+      /* x < -9 */
+      if ((ix >= 0x40022000) && (sign & 0x80000000))
+       return two - tiny;
+
+      x = fabsl (x);
+      z = one / (x * x);
+      i = 8.0 / x;
+      switch (i)
+       {
+       default:
+       case 0:
+         p = neval (z, RNr1, NRNr1) / deval (z, RDr1, NRDr1);
+         break;
+       case 1:
+         p = neval (z, RNr2, NRNr2) / deval (z, RDr2, NRDr2);
+         break;
+       case 2:
+         p = neval (z, RNr3, NRNr3) / deval (z, RDr3, NRDr3);
+         break;
+       case 3:
+         p = neval (z, RNr4, NRNr4) / deval (z, RDr4, NRDr4);
+         break;
+       case 4:
+         p = neval (z, RNr5, NRNr5) / deval (z, RDr5, NRDr5);
+         break;
+       case 5:
+         p = neval (z, RNr6, NRNr6) / deval (z, RDr6, NRDr6);
+         break;
+       case 6:
+         p = neval (z, RNr7, NRNr7) / deval (z, RDr7, NRDr7);
+         break;
+       case 7:
+         p = neval (z, RNr8, NRNr8) / deval (z, RDr8, NRDr8);
+         break;
+       }
+      u.value = x;
+      u.parts32.lswlo = 0;
+      u.parts32.lswhi &= 0xfe000000;
+      z = u.value;
+      r = expl (-z * z - 0.5625) *
+       expl ((z - x) * (z + x) + p);
+      if ((sign & 0x80000000) == 0)
+       return r / x;
+      else
+       return two - r / x;
+    }
+  else
+    {
+      if ((sign & 0x80000000) == 0)
+       return tiny * tiny;
+      else
+       return two - tiny;
+    }
+}
diff --git a/ld128/s_exp2l.c b/ld128/s_exp2l.c
new file mode 100644 (file)
index 0000000..c5f997f
--- /dev/null
@@ -0,0 +1,431 @@
+/*-
+ * Copyright (c) 2005-2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld128/s_exp2l.c,v 1.3 2008/02/13 10:44:44 bde Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#define        TBLBITS 7
+#define        TBLSIZE (1 << TBLBITS)
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+#define        EXPMASK (BIAS + LDBL_MAX_EXP)
+
+#if 0 /* XXX Prevent gcc from erroneously constant folding this. */
+static const long double twom10000 = 0x1p-10000L;
+#else
+static volatile long double twom10000 = 0x1p-10000L;
+#endif
+
+static const long double
+    huge      = 0x1p10000L,
+    P1        = 0x1.62e42fefa39ef35793c7673007e6p-1L,
+    P2       = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L,
+    P3        = 0x1.c6b08d704a0bf8b33a762bad3459p-5L,
+    P4        = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L,
+    P5        = 0x1.5d87fe78a67311071dee13fd11d9p-10L,
+    P6        = 0x1.430912f86c7876f4b663b23c5fe5p-13L;
+
+static const double
+    P7        = 0x1.ffcbfc588b041p-17,
+    P8        = 0x1.62c0223a5c7c7p-20,
+    P9        = 0x1.b52541ff59713p-24,
+    P10       = 0x1.e4cf56a391e22p-28,
+    redux     = 0x1.8p112 / TBLSIZE;
+
+static const long double tbl[TBLSIZE] = {
+       0x1.6a09e667f3bcc908b2fb1366dfeap-1L,
+       0x1.6c012750bdabeed76a99800f4edep-1L,
+       0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L,
+       0x1.6ff7df9519483cf87e1b4f3e1e98p-1L,
+       0x1.71f75e8ec5f73dd2370f2ef0b148p-1L,
+       0x1.73f9a48a58173bd5c9a4e68ab074p-1L,
+       0x1.75feb564267c8bf6e9aa33a489a8p-1L,
+       0x1.780694fde5d3f619ae02808592a4p-1L,
+       0x1.7a11473eb0186d7d51023f6ccb1ap-1L,
+       0x1.7c1ed0130c1327c49334459378dep-1L,
+       0x1.7e2f336cf4e62105d02ba1579756p-1L,
+       0x1.80427543e1a11b60de67649a3842p-1L,
+       0x1.82589994cce128acf88afab34928p-1L,
+       0x1.8471a4623c7acce52f6b97c6444cp-1L,
+       0x1.868d99b4492ec80e41d90ac2556ap-1L,
+       0x1.88ac7d98a669966530bcdf2d4cc0p-1L,
+       0x1.8ace5422aa0db5ba7c55a192c648p-1L,
+       0x1.8cf3216b5448bef2aa1cd161c57ap-1L,
+       0x1.8f1ae991577362b982745c72eddap-1L,
+       0x1.9145b0b91ffc588a61b469f6b6a0p-1L,
+       0x1.93737b0cdc5e4f4501c3f2540ae8p-1L,
+       0x1.95a44cbc8520ee9b483695a0e7fep-1L,
+       0x1.97d829fde4e4f8b9e920f91e8eb6p-1L,
+       0x1.9a0f170ca07b9ba3109b8c467844p-1L,
+       0x1.9c49182a3f0901c7c46b071f28dep-1L,
+       0x1.9e86319e323231824ca78e64c462p-1L,
+       0x1.a0c667b5de564b29ada8b8cabbacp-1L,
+       0x1.a309bec4a2d3358c171f770db1f4p-1L,
+       0x1.a5503b23e255c8b424491caf88ccp-1L,
+       0x1.a799e1330b3586f2dfb2b158f31ep-1L,
+       0x1.a9e6b5579fdbf43eb243bdff53a2p-1L,
+       0x1.ac36bbfd3f379c0db966a3126988p-1L,
+       0x1.ae89f995ad3ad5e8734d17731c80p-1L,
+       0x1.b0e07298db66590842acdfc6fb4ep-1L,
+       0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L,
+       0x1.b59728de559398e3881111648738p-1L,
+       0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L,
+       0x1.ba5b030a10649840cb3c6af5b74cp-1L,
+       0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L,
+       0x1.bf2c25bd71e088408d7025190cd0p-1L,
+       0x1.c199bdd85529c2220cb12a0916bap-1L,
+       0x1.c40ab5fffd07a6d14df820f17deap-1L,
+       0x1.c67f12e57d14b4a2137fd20f2a26p-1L,
+       0x1.c8f6d9406e7b511acbc48805c3f6p-1L,
+       0x1.cb720dcef90691503cbd1e949d0ap-1L,
+       0x1.cdf0b555dc3f9c44f8958fac4f12p-1L,
+       0x1.d072d4a07897b8d0f22f21a13792p-1L,
+       0x1.d2f87080d89f18ade123989ea50ep-1L,
+       0x1.d5818dcfba48725da05aeb66dff8p-1L,
+       0x1.d80e316c98397bb84f9d048807a0p-1L,
+       0x1.da9e603db3285708c01a5b6d480cp-1L,
+       0x1.dd321f301b4604b695de3c0630c0p-1L,
+       0x1.dfc97337b9b5eb968cac39ed284cp-1L,
+       0x1.e264614f5a128a12761fa17adc74p-1L,
+       0x1.e502ee78b3ff6273d130153992d0p-1L,
+       0x1.e7a51fbc74c834b548b2832378a4p-1L,
+       0x1.ea4afa2a490d9858f73a18f5dab4p-1L,
+       0x1.ecf482d8e67f08db0312fb949d50p-1L,
+       0x1.efa1bee615a27771fd21a92dabb6p-1L,
+       0x1.f252b376bba974e8696fc3638f24p-1L,
+       0x1.f50765b6e4540674f84b762861a6p-1L,
+       0x1.f7bfdad9cbe138913b4bfe72bd78p-1L,
+       0x1.fa7c1819e90d82e90a7e74b26360p-1L,
+       0x1.fd3c22b8f71f10975ba4b32bd006p-1L,
+       0x1.0000000000000000000000000000p+0L,
+       0x1.0163da9fb33356d84a66ae336e98p+0L,
+       0x1.02c9a3e778060ee6f7caca4f7a18p+0L,
+       0x1.04315e86e7f84bd738f9a20da442p+0L,
+       0x1.059b0d31585743ae7c548eb68c6ap+0L,
+       0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L,
+       0x1.0874518759bc808c35f25d942856p+0L,
+       0x1.09e3ecac6f3834521e060c584d5cp+0L,
+       0x1.0b5586cf9890f6298b92b7184200p+0L,
+       0x1.0cc922b7247f7407b705b893dbdep+0L,
+       0x1.0e3ec32d3d1a2020742e4f8af794p+0L,
+       0x1.0fb66affed31af232091dd8a169ep+0L,
+       0x1.11301d0125b50a4ebbf1aed9321cp+0L,
+       0x1.12abdc06c31cbfb92bad324d6f84p+0L,
+       0x1.1429aaea92ddfb34101943b2588ep+0L,
+       0x1.15a98c8a58e512480d573dd562aep+0L,
+       0x1.172b83c7d517adcdf7c8c50eb162p+0L,
+       0x1.18af9388c8de9bbbf70b9a3c269cp+0L,
+       0x1.1a35beb6fcb753cb698f692d2038p+0L,
+       0x1.1bbe084045cd39ab1e72b442810ep+0L,
+       0x1.1d4873168b9aa7805b8028990be8p+0L,
+       0x1.1ed5022fcd91cb8819ff61121fbep+0L,
+       0x1.2063b88628cd63b8eeb0295093f6p+0L,
+       0x1.21f49917ddc962552fd29294bc20p+0L,
+       0x1.2387a6e75623866c1fadb1c159c0p+0L,
+       0x1.251ce4fb2a63f3582ab7de9e9562p+0L,
+       0x1.26b4565e27cdd257a673281d3068p+0L,
+       0x1.284dfe1f5638096cf15cf03c9fa0p+0L,
+       0x1.29e9df51fdee12c25d15f5a25022p+0L,
+       0x1.2b87fd0dad98ffddea46538fca24p+0L,
+       0x1.2d285a6e4030b40091d536d0733ep+0L,
+       0x1.2ecafa93e2f5611ca0f45d5239a4p+0L,
+       0x1.306fe0a31b7152de8d5a463063bep+0L,
+       0x1.32170fc4cd8313539cf1c3009330p+0L,
+       0x1.33c08b26416ff4c9c8610d96680ep+0L,
+       0x1.356c55f929ff0c94623476373be4p+0L,
+       0x1.371a7373aa9caa7145502f45452ap+0L,
+       0x1.38cae6d05d86585a9cb0d9bed530p+0L,
+       0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L,
+       0x1.3c32dc313a8e484001f228b58cf0p+0L,
+       0x1.3dea64c12342235b41223e13d7eep+0L,
+       0x1.3fa4504ac801ba0bf701aa417b9cp+0L,
+       0x1.4160a21f72e29f84325b8f3dbacap+0L,
+       0x1.431f5d950a896dc704439410b628p+0L,
+       0x1.44e086061892d03136f409df0724p+0L,
+       0x1.46a41ed1d005772512f459229f0ap+0L,
+       0x1.486a2b5c13cd013c1a3b69062f26p+0L,
+       0x1.4a32af0d7d3de672d8bcf46f99b4p+0L,
+       0x1.4bfdad5362a271d4397afec42e36p+0L,
+       0x1.4dcb299fddd0d63b36ef1a9e19dep+0L,
+       0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L,
+       0x1.516daa2cf6641c112f52c84d6066p+0L,
+       0x1.5342b569d4f81df0a83c49d86bf4p+0L,
+       0x1.551a4ca5d920ec52ec620243540cp+0L,
+       0x1.56f4736b527da66ecb004764e61ep+0L,
+       0x1.58d12d497c7fd252bc2b7343d554p+0L,
+       0x1.5ab07dd48542958c93015191e9a8p+0L,
+       0x1.5c9268a5946b701c4b1b81697ed4p+0L,
+       0x1.5e76f15ad21486e9be4c20399d12p+0L,
+       0x1.605e1b976dc08b076f592a487066p+0L,
+       0x1.6247eb03a5584b1f0fa06fd2d9eap+0L,
+       0x1.6434634ccc31fc76f8714c4ee122p+0L,
+       0x1.66238825522249127d9e29b92ea2p+0L,
+       0x1.68155d44ca973081c57227b9f69ep+0L,
+};
+
+static const float eps[TBLSIZE] = {
+       -0x1.5c50p-101,
+       -0x1.5d00p-106,
+        0x1.8e90p-102,
+       -0x1.5340p-103,
+        0x1.1bd0p-102,
+       -0x1.4600p-105,
+       -0x1.7a40p-104,
+        0x1.d590p-102,
+       -0x1.d590p-101,
+        0x1.b100p-103,
+       -0x1.0d80p-105,
+        0x1.6b00p-103,
+       -0x1.9f00p-105,
+        0x1.c400p-103,
+        0x1.e120p-103,
+       -0x1.c100p-104,
+       -0x1.9d20p-103,
+        0x1.a800p-108,
+        0x1.4c00p-106,
+       -0x1.9500p-106,
+        0x1.6900p-105,
+       -0x1.29d0p-100,
+        0x1.4c60p-103,
+        0x1.13a0p-102,
+       -0x1.5b60p-103,
+       -0x1.1c40p-103,
+        0x1.db80p-102,
+        0x1.91a0p-102,
+        0x1.dc00p-105,
+        0x1.44c0p-104,
+        0x1.9710p-102,
+        0x1.8760p-103,
+       -0x1.a720p-103,
+        0x1.ed20p-103,
+       -0x1.49c0p-102,
+       -0x1.e000p-111,
+        0x1.86a0p-103,
+        0x1.2b40p-103,
+       -0x1.b400p-108,
+        0x1.1280p-99,
+       -0x1.02d8p-102,
+       -0x1.e3d0p-103,
+       -0x1.b080p-105,
+       -0x1.f100p-107,
+       -0x1.16c0p-105,
+       -0x1.1190p-103,
+       -0x1.a7d2p-100,
+        0x1.3450p-103,
+       -0x1.67c0p-105,
+        0x1.4b80p-104,
+       -0x1.c4e0p-103,
+        0x1.6000p-108,
+       -0x1.3f60p-105,
+        0x1.93f0p-104,
+        0x1.5fe0p-105,
+        0x1.6f80p-107,
+       -0x1.7600p-106,
+        0x1.21e0p-106,
+       -0x1.3a40p-106,
+       -0x1.40c0p-104,
+       -0x1.9860p-105,
+       -0x1.5d40p-108,
+       -0x1.1d70p-106,
+        0x1.2760p-105,
+        0x0.0000p+0,
+        0x1.21e2p-104,
+       -0x1.9520p-108,
+       -0x1.5720p-106,
+       -0x1.4810p-106,
+       -0x1.be00p-109,
+        0x1.0080p-105,
+       -0x1.5780p-108,
+       -0x1.d460p-105,
+       -0x1.6140p-105,
+        0x1.4630p-104,
+        0x1.ad50p-103,
+        0x1.82e0p-105,
+        0x1.1d3cp-101,
+        0x1.6100p-107,
+        0x1.ec30p-104,
+        0x1.f200p-108,
+        0x1.0b40p-103,
+        0x1.3660p-102,
+        0x1.d9d0p-103,
+       -0x1.02d0p-102,
+        0x1.b070p-103,
+        0x1.b9c0p-104,
+       -0x1.01c0p-103,
+       -0x1.dfe0p-103,
+        0x1.1b60p-104,
+       -0x1.ae94p-101,
+       -0x1.3340p-104,
+        0x1.b3d8p-102,
+       -0x1.6e40p-105,
+       -0x1.3670p-103,
+        0x1.c140p-104,
+        0x1.1840p-101,
+        0x1.1ab0p-102,
+       -0x1.a400p-104,
+        0x1.1f00p-104,
+       -0x1.7180p-103,
+        0x1.4ce0p-102,
+        0x1.9200p-107,
+       -0x1.54c0p-103,
+        0x1.1b80p-105,
+       -0x1.1828p-101,
+        0x1.5720p-102,
+       -0x1.a060p-100,
+        0x1.9160p-102,
+        0x1.a280p-104,
+        0x1.3400p-107,
+        0x1.2b20p-102,
+        0x1.7800p-108,
+        0x1.cfd0p-101,
+        0x1.2ef0p-102,
+       -0x1.2760p-99,
+        0x1.b380p-104,
+        0x1.0048p-101,
+       -0x1.60b0p-102,
+        0x1.a1ccp-100,
+       -0x1.a640p-104,
+       -0x1.08a0p-101,
+        0x1.7e60p-102,
+        0x1.22c0p-103,
+       -0x1.7200p-106,
+        0x1.f0f0p-102,
+        0x1.eb4ep-99,
+        0x1.c6e0p-103,
+};
+
+/*
+ * exp2l(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.502 ulp.
+ *
+ * Method: (accurate tables)
+ *
+ *   Reduce x:
+ *     x = 2**k + y, for integer k and |y| <= 1/2.
+ *     Thus we have exp2(x) = 2**k * exp2(y).
+ *
+ *   Reduce y:
+ *     y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE.
+ *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]),
+ *     with |z - eps[i]| <= 2**-8 + 2**-98 for the table used.
+ *
+ *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via
+ *   a degree-10 minimax polynomial with maximum error under 2**-120.
+ *   The values in exp2t[] and eps[] are chosen such that
+ *   exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such
+ *   that exp2t[i] is accurate to 2**-122.
+ *
+ *   Note that the range of i is +-TBLSIZE/2, so we actually index the tables
+ *   by i0 = i + TBLSIZE/2.
+ *
+ *   This method is due to Gal, with many details due to Gal and Bachelis:
+ *
+ *     Gal, S. and Bachelis, B.  An Accurate Elementary Mathematical Library
+ *     for the IEEE Floating Point Standard.  TOMS 17(1), 26-46 (1991).
+ */
+OLM_DLLEXPORT long double
+exp2l(long double x)
+{
+       union IEEEl2bits u, v;
+       long double r, t, twopk, twopkp10000, z;
+       uint32_t hx, ix, i0;
+       int k;
+
+       u.e = x;
+
+       /* Filter out exceptional cases. */
+       hx = u.xbits.expsign;
+       ix = hx & EXPMASK;
+       if (ix >= BIAS + 14) {          /* |x| >= 16384 */
+               if (ix == BIAS + LDBL_MAX_EXP) {
+                       if (u.xbits.manh != 0
+                           || u.xbits.manl != 0
+                           || (hx & 0x8000) == 0)
+                               return (x + x); /* x is NaN or +Inf */
+                       else 
+                               return (0.0);   /* x is -Inf */
+               }
+               if (x >= 16384)
+                       return (huge * huge); /* overflow */
+               if (x <= -16495)
+                       return (twom10000 * twom10000); /* underflow */
+       } else if (ix <= BIAS - 115) {          /* |x| < 0x1p-115 */
+               return (1.0 + x);
+       }
+
+       /*
+        * Reduce x, computing z, i0, and k. The low bits of x + redux
+        * contain the 16-bit integer part of the exponent (k) followed by
+        * TBLBITS fractional bits (i0). We use bit tricks to extract these
+        * as integers, then set z to the remainder.
+        *
+        * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8.
+        * Then the low-order word of x + redux is 0x000abc12,
+        * We split this into k = 0xabc and i0 = 0x12 (adjusted to
+        * index into the table), then we compute z = 0x0.003456p0.
+        *
+        * XXX If the exponent is negative, the computation of k depends on
+        *     '>>' doing sign extension.
+        */
+       u.e = x + redux;
+       i0 = (u.bits.manl & 0xffffffff) + TBLSIZE / 2;
+       k = (int)i0 >> TBLBITS;
+       i0 = i0 & (TBLSIZE - 1);
+       u.e -= redux;
+       z = x - u.e;
+       v.xbits.manh = 0;
+       v.xbits.manl = 0;
+       if (k >= LDBL_MIN_EXP) {
+               v.xbits.expsign = LDBL_MAX_EXP - 1 + k;
+               twopk = v.e;
+       } else {
+               v.xbits.expsign = LDBL_MAX_EXP - 1 + k + 10000;
+               twopkp10000 = v.e;
+       }
+
+       /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
+       t = tbl[i0];            /* exp2t[i0] */
+       z -= eps[i0];           /* eps[i0]   */
+       r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6
+           + z * (P7 + z * (P8 + z * (P9 + z * P10)))))))));
+
+       /* Scale by 2**k. */
+       if(k >= LDBL_MIN_EXP) {
+               if (k == LDBL_MAX_EXP)
+                       return (r * 2.0 * 0x1p16383L);
+               return (r * twopk);
+       } else {
+               return (r * twopkp10000 * twom10000);
+       }
+}
diff --git a/ld128/s_expm1l.c b/ld128/s_expm1l.c
new file mode 100644 (file)
index 0000000..1c22696
--- /dev/null
@@ -0,0 +1,162 @@
+/*     $OpenBSD: s_expm1l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     expm1l.c
+ *
+ *     Exponential function, minus 1
+ *      128-bit long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, expm1l();
+ *
+ * y = expm1l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns e (2.71828...) raised to the x power, minus one.
+ *
+ * Range reduction is accomplished by separating the argument
+ * into an integer k and fraction f such that
+ *
+ *     x    k  f
+ *    e  = 2  e.
+ *
+ * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1
+ * in the basic range [-0.5 ln 2, 0.5 ln 2].
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE    -79,+MAXLOG    100,000     1.7e-34     4.5e-35
+ *
+ */
+
+#include <errno.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x)
+   -.5 ln 2  <  x  <  .5 ln 2
+   Theoretical peak relative error = 8.1e-36  */
+
+static const long double
+  P0 = 2.943520915569954073888921213330863757240E8L,
+  P1 = -5.722847283900608941516165725053359168840E7L,
+  P2 = 8.944630806357575461578107295909719817253E6L,
+  P3 = -7.212432713558031519943281748462837065308E5L,
+  P4 = 4.578962475841642634225390068461943438441E4L,
+  P5 = -1.716772506388927649032068540558788106762E3L,
+  P6 = 4.401308817383362136048032038528753151144E1L,
+  P7 = -4.888737542888633647784737721812546636240E-1L,
+  Q0 = 1.766112549341972444333352727998584753865E9L,
+  Q1 = -7.848989743695296475743081255027098295771E8L,
+  Q2 = 1.615869009634292424463780387327037251069E8L,
+  Q3 = -2.019684072836541751428967854947019415698E7L,
+  Q4 = 1.682912729190313538934190635536631941751E6L,
+  Q5 = -9.615511549171441430850103489315371768998E4L,
+  Q6 = 3.697714952261803935521187272204485251835E3L,
+  Q7 = -8.802340681794263968892934703309274564037E1L,
+  /* Q8 = 1.000000000000000000000000000000000000000E0 */
+/* C1 + C2 = ln 2 */
+
+  C1 = 6.93145751953125E-1L,
+  C2 = 1.428606820309417232121458176568075500134E-6L,
+/* ln (2^16384 * (1 - 2^-113)) */
+  maxlog = 1.1356523406294143949491931077970764891253E4L,
+/* ln 2^-114 */
+  minarg = -7.9018778583833765273564461846232128760607E1L, big = 1e4932L;
+
+
+long double
+expm1l(long double x)
+{
+  long double px, qx, xx;
+  int32_t ix, sign;
+  ieee_quad_shape_type u;
+  int k;
+
+  /* Detect infinity and NaN.  */
+  u.value = x;
+  ix = u.parts32.mswhi;
+  sign = ix & 0x80000000;
+  ix &= 0x7fffffff;
+  if (ix >= 0x7fff0000)
+    {
+      /* Infinity. */
+      if (((ix & 0xffff) | u.parts32.mswlo | u.parts32.lswhi |
+       u.parts32.lswlo) == 0)
+       {
+         if (sign)
+           return -1.0L;
+         else
+           return x;
+       }
+      /* NaN. No invalid exception. */
+      return x;
+    }
+
+  /* expm1(+- 0) = +- 0.  */
+  if ((ix == 0) && (u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0)
+    return x;
+
+  /* Overflow.  */
+  if (x > maxlog)
+      return (big * big);
+
+  /* Minimum value.  */
+  if (x < minarg)
+    return (4.0/big - 1.0L);
+
+  /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */
+  xx = C1 + C2;                        /* ln 2. */
+  px = floorl (0.5 + x / xx);
+  k = px;
+  /* remainder times ln 2 */
+  x -= px * C1;
+  x -= px * C2;
+
+  /* Approximate exp(remainder ln 2).  */
+  px = (((((((P7 * x
+             + P6) * x
+            + P5) * x + P4) * x + P3) * x + P2) * x + P1) * x + P0) * x;
+
+  qx = (((((((x
+             + Q7) * x
+            + Q6) * x + Q5) * x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0;
+
+  xx = x * x;
+  qx = x + (0.5 * xx + xx * px / qx);
+
+  /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2).
+
+  We have qx = exp(remainder ln 2) - 1, so
+  exp(x) - 1 = 2^k (qx + 1) - 1
+            = 2^k qx + 2^k - 1.  */
+
+  px = ldexpl (1.0L, k);
+  x = px * qx + (px - 1.0);
+  return x;
+}
diff --git a/ld128/s_floorl.c b/ld128/s_floorl.c
new file mode 100644 (file)
index 0000000..f00dcfa
--- /dev/null
@@ -0,0 +1,71 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floorl(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floor(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double huge = 1.0e4930L;
+
+long double
+floorl(long double x)
+{
+       int64_t i0,i1,jj0;
+       u_int64_t i,j;
+       GET_LDOUBLE_WORDS64(i0,i1,x);
+       jj0 = ((i0>>48)&0x7fff)-0x3fff;
+       if(jj0<48) {
+           if(jj0<0) {         /* raise inexact if x != 0 */
+               if(huge+x>0.0) {
+                   if(i0>=0)
+                       return 0.0L;
+                   else if(((i0&0x7fffffffffffffffLL)|i1)!=0)
+                       return -1.0L;
+               }
+           } else {
+               i = (0x0000ffffffffffffULL)>>jj0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(i0<0) i0 += (0x0001000000000000LL)>>jj0;
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (jj0>111) {
+           if(jj0==0x4000) return x+x; /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = -1ULL>>(jj0-48);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(i0<0) {
+                   if(jj0==48) i0+=1;
+                   else {
+                       j = i1+(1LL<<(112-jj0));
+                       if(j<i1) i0 +=1 ;       /* got a carry */
+                       i1=j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       SET_LDOUBLE_WORDS64(x,i0,i1);
+       return x;
+}
diff --git a/ld128/s_log1pl.c b/ld128/s_log1pl.c
new file mode 100644 (file)
index 0000000..d75c7ac
--- /dev/null
@@ -0,0 +1,247 @@
+/*     $OpenBSD: s_log1pl.c,v 1.1 2011/07/06 00:02:42 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     log1pl.c
+ *
+ *      Relative error logarithm
+ *     Natural logarithm of 1+x, 128-bit long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log1pl();
+ *
+ * y = log1pl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base e (2.718...) logarithm of 1+x.
+ *
+ * The argument 1+x is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the logarithm
+ * of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(w-1)/(w+1),
+ *
+ *     log(w) = z + z^3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -1, 8       100000      1.9e-34     4.3e-35
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x)
+ * 1/sqrt(2) <= 1+x < sqrt(2)
+ * Theoretical peak relative error = 5.3e-37,
+ * relative peak error spread = 2.3e-14
+ */
+static const long double
+  P12 = 1.538612243596254322971797716843006400388E-6L,
+  P11 = 4.998469661968096229986658302195402690910E-1L,
+  P10 = 2.321125933898420063925789532045674660756E1L,
+  P9 = 4.114517881637811823002128927449878962058E2L,
+  P8 = 3.824952356185897735160588078446136783779E3L,
+  P7 = 2.128857716871515081352991964243375186031E4L,
+  P6 = 7.594356839258970405033155585486712125861E4L,
+  P5 = 1.797628303815655343403735250238293741397E5L,
+  P4 = 2.854829159639697837788887080758954924001E5L,
+  P3 = 3.007007295140399532324943111654767187848E5L,
+  P2 = 2.014652742082537582487669938141683759923E5L,
+  P1 = 7.771154681358524243729929227226708890930E4L,
+  P0 = 1.313572404063446165910279910527789794488E4L,
+  /* Q12 = 1.000000000000000000000000000000000000000E0L, */
+  Q11 = 4.839208193348159620282142911143429644326E1L,
+  Q10 = 9.104928120962988414618126155557301584078E2L,
+  Q9 = 9.147150349299596453976674231612674085381E3L,
+  Q8 = 5.605842085972455027590989944010492125825E4L,
+  Q7 = 2.248234257620569139969141618556349415120E5L,
+  Q6 = 6.132189329546557743179177159925690841200E5L,
+  Q5 = 1.158019977462989115839826904108208787040E6L,
+  Q4 = 1.514882452993549494932585972882995548426E6L,
+  Q3 = 1.347518538384329112529391120390701166528E6L,
+  Q2 = 7.777690340007566932935753241556479363645E5L,
+  Q1 = 2.626900195321832660448791748036714883242E5L,
+  Q0 = 3.940717212190338497730839731583397586124E4L;
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 1.1e-35,
+ * relative peak error spread 1.1e-9
+ */
+static const long double
+  R5 = -8.828896441624934385266096344596648080902E-1L,
+  R4 = 8.057002716646055371965756206836056074715E1L,
+  R3 = -2.024301798136027039250415126250455056397E3L,
+  R2 = 2.048819892795278657810231591630928516206E4L,
+  R1 = -8.977257995689735303686582344659576526998E4L,
+  R0 = 1.418134209872192732479751274970992665513E5L,
+  /* S6 = 1.000000000000000000000000000000000000000E0L, */
+  S5 = -1.186359407982897997337150403816839480438E2L,
+  S4 = 3.998526750980007367835804959888064681098E3L,
+  S3 = -5.748542087379434595104154610899551484314E4L,
+  S2 = 4.001557694070773974936904547424676279307E5L,
+  S1 = -1.332535117259762928288745111081235577029E6L,
+  S0 = 1.701761051846631278975701529965589676574E6L;
+
+/* C1 + C2 = ln 2 */
+static const long double C1 = 6.93145751953125E-1L;
+static const long double C2 = 1.428606820309417232121458176568075500134E-6L;
+
+static const long double sqrth = 0.7071067811865475244008443621048490392848L;
+/* ln (2^16384 * (1 - 2^-113)) */
+static const long double zero = 0.0L;
+
+long double
+log1pl(long double xm1)
+{
+  long double x, y, z, r, s;
+  ieee_quad_shape_type u;
+  int32_t hx;
+  int e;
+
+  /* Test for NaN or infinity input. */
+  u.value = xm1;
+  hx = u.parts32.mswhi;
+  if (hx >= 0x7fff0000)
+    return xm1;
+
+  /* log1p(+- 0) = +- 0.  */
+  if (((hx & 0x7fffffff) == 0)
+      && (u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0)
+    return xm1;
+
+  x = xm1 + 1.0L;
+
+  /* log1p(-1) = -inf */
+  if (x <= 0.0L)
+    {
+      if (x == 0.0L)
+       return (-1.0L / (x - x));
+      else
+       return (zero / (x - x));
+    }
+
+  /* Separate mantissa from exponent.  */
+
+  /* Use frexp used so that denormal numbers will be handled properly.  */
+  x = frexpl (x, &e);
+
+  /* Logarithm using log(x) = z + z^3 P(z^2)/Q(z^2),
+     where z = 2(x-1)/x+1).  */
+  if ((e > 2) || (e < -2))
+    {
+      if (x < sqrth)
+       {                       /* 2( 2x-1 )/( 2x+1 ) */
+         e -= 1;
+         z = x - 0.5L;
+         y = 0.5L * z + 0.5L;
+       }
+      else
+       {                       /*  2 (x-1)/(x+1)   */
+         z = x - 0.5L;
+         z -= 0.5L;
+         y = 0.5L * x + 0.5L;
+       }
+      x = z / y;
+      z = x * x;
+      r = ((((R5 * z
+             + R4) * z
+            + R3) * z
+           + R2) * z
+          + R1) * z
+       + R0;
+      s = (((((z
+              + S5) * z
+             + S4) * z
+            + S3) * z
+           + S2) * z
+          + S1) * z
+       + S0;
+      z = x * (z * r / s);
+      z = z + e * C2;
+      z = z + x;
+      z = z + e * C1;
+      return (z);
+    }
+
+
+  /* Logarithm using log(1+x) = x - .5x^2 + x^3 P(x)/Q(x). */
+
+  if (x < sqrth)
+    {
+      e -= 1;
+      if (e != 0)
+       x = 2.0L * x - 1.0L;    /*  2x - 1  */
+      else
+       x = xm1;
+    }
+  else
+    {
+      if (e != 0)
+       x = x - 1.0L;
+      else
+       x = xm1;
+    }
+  z = x * x;
+  r = (((((((((((P12 * x
+                + P11) * x
+               + P10) * x
+              + P9) * x
+             + P8) * x
+            + P7) * x
+           + P6) * x
+          + P5) * x
+         + P4) * x
+        + P3) * x
+       + P2) * x
+       + P1) * x
+    + P0;
+  s = (((((((((((x
+                + Q11) * x
+               + Q10) * x
+              + Q9) * x
+             + Q8) * x
+            + Q7) * x
+           + Q6) * x
+          + Q5) * x
+         + Q4) * x
+        + Q3) * x
+       + Q2) * x
+       + Q1) * x
+    + Q0;
+  y = x * (z * r / s);
+  y = y + e * C2;
+  z = y - 0.5L * z;
+  z = z + x;
+  z = z + e * C1;
+  return (z);
+}
diff --git a/ld128/s_modfl.c b/ld128/s_modfl.c
new file mode 100644 (file)
index 0000000..bd18cba
--- /dev/null
@@ -0,0 +1,73 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modfl(long double x, long double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *     Bit twiddling.
+ *
+ * Exception:
+ *     No exception.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0;
+
+long double
+modfl(long double x, long double *iptr)
+{
+       int64_t i0,i1,jj0;
+       u_int64_t i;
+       GET_LDOUBLE_WORDS64(i0,i1,x);
+       jj0 = ((i0>>48)&0x7fff)-0x3fff; /* exponent of x */
+       if(jj0<48) {                    /* integer part in high x */
+           if(jj0<0) {                 /* |x|<1 */
+               /* *iptr = +-0 */
+               SET_LDOUBLE_WORDS64(*iptr,i0&0x8000000000000000ULL,0);
+               return x;
+           } else {
+               i = (0x0000ffffffffffffLL)>>jj0;
+               if(((i0&i)|i1)==0) {            /* x is integral */
+                   *iptr = x;
+                   /* return +-0 */
+                   SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0);
+                   return x;
+               } else {
+                   SET_LDOUBLE_WORDS64(*iptr,i0&(~i),0);
+                   return x - *iptr;
+               }
+           }
+       } else if (jj0>111) {           /* no fraction part */
+           *iptr = x*one;
+           /* We must handle NaNs separately.  */
+           if (jj0 == 0x4000 && ((i0 & 0x0000ffffffffffffLL) | i1))
+             return x*one;
+           /* return +-0 */
+           SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0);
+           return x;
+       } else {                        /* fraction part in low x */
+           i = -1ULL>>(jj0-48);
+           if((i1&i)==0) {             /* x is integral */
+               *iptr = x;
+               /* return +-0 */
+               SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0);
+               return x;
+           } else {
+               SET_LDOUBLE_WORDS64(*iptr,i0,i1&(~i));
+               return x - *iptr;
+           }
+       }
+}
diff --git a/ld128/s_nanl.c b/ld128/s_nanl.c
new file mode 100644 (file)
index 0000000..4dcdb4e
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2007 David Schultz
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/ld128/s_nanl.c,v 1.3 2008/03/02 20:16:55 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+nanl(const char *s)
+{
+       union {
+               union IEEEl2bits ieee;
+               uint32_t bits[4];
+       } u;
+
+       __scan_nan(u.bits, 4, s);
+       u.ieee.bits.exp = 0x7fff;
+       u.ieee.bits.manh |= 1ULL << 47; /* make it a quiet NaN */
+       return (u.ieee.e);
+}
diff --git a/ld128/s_nextafterl.c b/ld128/s_nextafterl.c
new file mode 100644 (file)
index 0000000..af667a0
--- /dev/null
@@ -0,0 +1,72 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *     nextafterl(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+long double
+nextafterl(long double x, long double y)
+{
+       int64_t hx,hy,ix,iy;
+       u_int64_t lx,ly;
+
+       GET_LDOUBLE_WORDS64(hx,lx,x);
+       GET_LDOUBLE_WORDS64(hy,ly,y);
+       ix = hx&0x7fffffffffffffffLL;           /* |x| */
+       iy = hy&0x7fffffffffffffffLL;           /* |y| */
+
+       if(((ix>=0x7fff000000000000LL)&&((ix-0x7fff000000000000LL)|lx)!=0) ||   /* x is nan */
+          ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0))     /* y is nan */
+          return x+y;
+       if(x==y) return y;              /* x=y, return y */
+       if((ix|lx)==0) {                        /* x == 0 */
+           volatile long double u;
+           SET_LDOUBLE_WORDS64(x,hy&0x8000000000000000ULL,1);/* return +-minsubnormal */
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(hx>=0) {                     /* x > 0 */
+           if(hx>hy||((hx==hy)&&(lx>ly))) {    /* x > y, x -= ulp */
+               if(lx==0) hx--;
+               lx--;
+           } else {                            /* x < y, x += ulp */
+               lx++;
+               if(lx==0) hx++;
+           }
+       } else {                                /* x < 0 */
+           if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+               if(lx==0) hx--;
+               lx--;
+           } else {                            /* x > y, x += ulp */
+               lx++;
+               if(lx==0) hx++;
+           }
+       }
+       hy = hx&0x7fff000000000000LL;
+       if(hy==0x7fff000000000000LL) return x+x;/* overflow  */
+       if(hy==0) {
+           volatile long double u = x*x;       /* underflow */
+       }
+       SET_LDOUBLE_WORDS64(x,hx,lx);
+       return x;
+}
+
+__strong_alias(nexttowardl, nextafterl);
diff --git a/ld128/s_nexttoward.c b/ld128/s_nexttoward.c
new file mode 100644 (file)
index 0000000..a9ff797
--- /dev/null
@@ -0,0 +1,85 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *     nexttoward(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+double
+nexttoward(double x, long double y)
+{
+       int32_t hx,ix;
+       int64_t hy,iy;
+       u_int32_t lx;
+       u_int64_t ly;
+
+       EXTRACT_WORDS(hx,lx,x);
+       GET_LDOUBLE_WORDS64(hy,ly,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = hy&0x7fffffffffffffffLL;   /* |y| */
+
+       if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+          ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0))
+                                                           /* y is nan */
+          return x+y;
+       if((long double) x==y) return y;        /* x=y, return y */
+       if((ix|lx)==0) {                        /* x == 0 */
+           volatile double u;
+           INSERT_WORDS(x,(u_int32_t)((hy>>32)&0x80000000),1);/* return +-minsub */
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if (hy<0||(ix>>20)>(iy>>48)-0x3c00
+               || ((ix>>20)==(iy>>48)-0x3c00
+                   && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL)
+                       || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL)
+                           && (lx&0xf)>(ly>>60))))) {  /* x > y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x < y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if (hy>=0||(ix>>20)>(iy>>48)-0x3c00
+               || ((ix>>20)==(iy>>48)-0x3c00
+                   && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL)
+                       || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL)
+                           && (lx&0xf)>(ly>>60))))) {  /* x < y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x > y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       }
+       hy = hx&0x7ff00000;
+       if(hy>=0x7ff00000) {
+         x = x+x;      /* overflow  */
+         return x;
+       }
+       if(hy<0x00100000) {
+           volatile double u = x*x;            /* underflow */
+       }
+       INSERT_WORDS(x,hx,lx);
+       return x;
+}
diff --git a/ld128/s_nexttowardf.c b/ld128/s_nexttowardf.c
new file mode 100644 (file)
index 0000000..61387ac
--- /dev/null
@@ -0,0 +1,65 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+float
+nexttowardf(float x, long double y)
+{
+       int32_t hx,ix;
+       int64_t hy,iy;
+       u_int64_t ly;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_LDOUBLE_WORDS64(hy,ly,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = hy&0x7fffffffffffffffLL;   /* |y| */
+
+       if((ix>0x7f800000) ||   /* x is nan */
+          ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0))
+                               /* y is nan */
+          return x+y;
+       if((long double) x==y) return y;        /* x=y, return y */
+       if(ix==0) {                             /* x == 0 */
+           volatile float u;
+           SET_FLOAT_WORD(x,(u_int32_t)((hy>>32)&0x80000000)|1);/* return +-minsub*/
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if(hy<0||(ix>>23)>(iy>>48)-0x3f80
+              || ((ix>>23)==(iy>>48)-0x3f80
+                  && (ix&0x7fffff)>((hy>>25)&0x7fffff))) {/* x > y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x < y, x += ulp */
+               hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if(hy>=0||(ix>>23)>(iy>>48)-0x3f80
+              || ((ix>>23)==(iy>>48)-0x3f80
+                  && (ix&0x7fffff)>((hy>>25)&0x7fffff))) {/* x < y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x > y, x += ulp */
+               hx += 1;
+           }
+       }
+       hy = hx&0x7f800000;
+       if(hy>=0x7f800000) return x+x;  /* overflow  */
+       if(hy<0x00800000) {
+           volatile float u = x*x;     /* underflow */
+       }
+       SET_FLOAT_WORD(x,hx);
+       return x;
+}
diff --git a/ld128/s_remquol.c b/ld128/s_remquol.c
new file mode 100644 (file)
index 0000000..f56ce4f
--- /dev/null
@@ -0,0 +1,168 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+#define        BIAS (LDBL_MAX_EXP - 1)
+
+/*
+ * These macros add and remove an explicit integer bit in front of the
+ * fractional mantissa, if the architecture doesn't have such a bit by
+ * default already.
+ */
+#ifdef LDBL_IMPLICIT_NBIT
+#define        LDBL_NBIT       0
+#define        SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
+#define        HFRAC_BITS      (EXT_FRACHBITS + EXT_FRACHMBITS)
+#else
+#define        LDBL_NBIT       0x80000000
+#define        SET_NBIT(hx)    (hx)
+#define        HFRAC_BITS      (EXT_FRACHBITS + EXT_FRACHMBITS - 1)
+#endif
+
+#define        MANL_SHIFT      (EXT_FRACLMBITS + EXT_FRACLBITS - 1)
+
+static const long double Zero[] = {0.0L, -0.0L};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ *
+ * Assumptions:
+ * - The low part of the mantissa fits in a manl_t exactly.
+ * - The high part of the mantissa fits in an int64_t with enough room
+ *   for an explicit integer bit in front of the fractional bits.
+ */
+long double
+remquol(long double x, long double y, int *quo)
+{
+       int64_t hx,hz,hy,_hx;
+       uint64_t lx,ly,lz;
+       uint64_t sx,sxy;
+       int ix,iy,n,q;
+
+       GET_LDOUBLE_WORDS64(hx,lx,x);
+       GET_LDOUBLE_WORDS64(hy,ly,y);
+       sx = (hx>>48)&0x8000;
+       sxy = sx ^ ((hy>>48)&0x8000);
+       hx &= 0x7fffffffffffffffLL;     /* |x| */
+       hy &= 0x7fffffffffffffffLL;     /* |y| */
+       SET_LDOUBLE_WORDS64(x,hx,lx);
+       SET_LDOUBLE_WORDS64(y,hy,ly);
+
+    /* purge off exception values */
+       if((hy|ly)==0 || /* y=0 */
+          ((hx>>48) == BIAS + LDBL_MAX_EXP) ||  /* or x not finite */
+          ((hy>>48) == BIAS + LDBL_MAX_EXP &&
+           (((hy&0x0000ffffffffffffLL)&~LDBL_NBIT)|ly)!=0)) /* or y is NaN */
+           return (x*y)/(x*y);
+       if((hx>>48)<=(hy>>48)) {
+           if(((hx>>48)<(hy>>48)) ||
+              ((hx&0x0000ffffffffffffLL)<=(hy&0x0000ffffffffffffLL) &&
+               ((hx&0x0000ffffffffffffLL)<(hy&0x0000ffffffffffffLL) ||
+                lx<ly))) {
+               q = 0;
+               goto fixup;     /* |x|<|y| return x or x-y */
+           }
+           if((hx&0x0000ffffffffffffLL)==(hy&0x0000ffffffffffffLL) &&
+               lx==ly) {
+               *quo = 1;
+               return Zero[sx!=0];     /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if((hx>>48) == 0) {     /* subnormal x */
+           x *= 0x1.0p512;
+           GET_LDOUBLE_WORDS64(hx,lx,x);
+           ix = (hx>>48) - (BIAS + 512);
+       } else {
+           ix = (hx>>48) - BIAS;
+       }
+
+    /* determine iy = ilogb(y) */
+       if((hy>>48) == 0) {     /* subnormal y */
+           y *= 0x1.0p512;
+           GET_LDOUBLE_WORDS64(hy,ly,y);
+           iy = (hy>>48) - (BIAS + 512);
+       } else {
+           iy = (hy>>48) - BIAS;
+       }
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       _hx = SET_NBIT(hx) & 0x0000ffffffffffffLL;
+       hy = SET_NBIT(hy);
+
+    /* fix point fmod */
+       n = ix - iy;
+       q = 0;
+
+       while(n--) {
+           hz=_hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){_hx = _hx+_hx+(lx>>MANL_SHIFT); lx = lx+lx;}
+           else {_hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;}
+           q <<= 1;
+       }
+       hz=_hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {_hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+       if((_hx|lx)==0) {                       /* return sign(x)*0 */
+           *quo = (sxy ? -q : q);
+           return Zero[sx!=0];
+       }
+       while(_hx<(1ULL<<HFRAC_BITS)) { /* normalize x */
+           _hx = _hx+_hx+(lx>>MANL_SHIFT); lx = lx+lx;
+           iy -= 1;
+       }
+       hx = (hx&0xffff000000000000LL) | (_hx&0x0000ffffffffffffLL);
+       if (iy < LDBL_MIN_EXP) {
+           hx = (hx&0x0000ffffffffffffLL) | (uint64_t)(iy + BIAS + 512)<<48;
+           SET_LDOUBLE_WORDS64(x,hx,lx);
+           x *= 0x1p-512;
+           GET_LDOUBLE_WORDS64(hx,lx,x);
+       } else {
+           hx = (hx&0x0000ffffffffffffLL) | (uint64_t)(iy + BIAS)<<48;
+       }
+       hx &= 0x7fffffffffffffffLL;
+       SET_LDOUBLE_WORDS64(x,hx,lx);
+fixup:
+       y = fabsl(y);
+       if (y < LDBL_MIN * 2) {
+           if (x+x>y || (x+x==y && (q & 1))) {
+               q++;
+               x-=y;
+           }
+       } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+           q++;
+           x-=y;
+       }
+
+       GET_LDOUBLE_MSW64(hx,x);
+       hx ^= sx;
+       SET_LDOUBLE_MSW64(x,hx);
+
+       q &= 0x7fffffff;
+       *quo = (sxy ? -q : q);
+       return x;
+}
diff --git a/ld128/s_tanhl.c b/ld128/s_tanhl.c
new file mode 100644 (file)
index 0000000..f8e6291
--- /dev/null
@@ -0,0 +1,105 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* tanhl(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *                                      x    -x
+ *                                     e  - e
+ *      0. tanhl(x) is defined to be -----------
+ *                                      x    -x
+ *                                     e  + e
+ *      1. reduce x to non-negative by tanhl(-x) = -tanhl(x).
+ *      2.  0      <= x <= 2**-57 : tanhl(x) := x*(one+x)
+ *                                               -t
+ *          2**-57 <  x <=  1     : tanhl(x) := -----; t = expm1l(-2x)
+ *                                              t + 2
+ *                                                    2
+ *          1      <= x <=  40.0  : tanhl(x) := 1-  ----- ; t=expm1l(2x)
+ *                                                  t + 2
+ *          40.0   <  x <= INF    : tanhl(x) := 1.
+ *
+ * Special cases:
+ *      tanhl(NaN) is NaN;
+ *      only tanhl(0)=0 is exact for finite argument.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, two = 2.0, tiny = 1.0e-4900L;
+
+long double
+tanhl(long double x)
+{
+  long double t, z;
+  u_int32_t jx, ix;
+  ieee_quad_shape_type u;
+
+  /* Words of |x|. */
+  u.value = x;
+  jx = u.parts32.mswhi;
+  ix = jx & 0x7fffffff;
+  /* x is INF or NaN */
+  if (ix >= 0x7fff0000)
+    {
+      /* for NaN it's not important which branch: tanhl(NaN) = NaN */
+      if (jx & 0x80000000)
+       return one / x - one;   /* tanhl(-inf)= -1; */
+      else
+       return one / x + one;   /* tanhl(+inf)=+1 */
+    }
+
+  /* |x| < 40 */
+  if (ix < 0x40044000)
+    {
+      if (u.value == 0)
+       return x;               /* x == +- 0 */
+      if (ix < 0x3fc60000)     /* |x| < 2^-57 */
+       return x * (one + tiny); /* tanh(small) = small */
+      u.parts32.mswhi = ix;    /* Absolute value of x.  */
+      if (ix >= 0x3fff0000)
+       {                       /* |x| >= 1  */
+         t = expm1l (two * u.value);
+         z = one - two / (t + two);
+       }
+      else
+       {
+         t = expm1l (-two * u.value);
+         z = -t / (t + two);
+       }
+      /* |x| > 40, return +-1 */
+    }
+  else
+    {
+      z = one - tiny;          /* raised inexact flag */
+    }
+  return (jx & 0x80000000) ? -z : z;
+}
diff --git a/ld128/s_truncl.c b/ld128/s_truncl.c
new file mode 100644 (file)
index 0000000..a0d8bd5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+/*
+ * truncl(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to truncl(x).
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define        MANH_SIZE       (EXT_FRACHBITS + EXT_FRACHMBITS + 1)
+#else
+#define        MANH_SIZE       (EXT_FRACHBITS + EXT_FRACHMBITS)
+#endif
+
+static const long double huge = 1.0e300;
+static const float zero[] = { 0.0, -0.0 };
+
+long double
+truncl(long double x)
+{
+       int e;
+       int64_t ix0, ix1;
+
+       GET_LDOUBLE_WORDS64(ix0,ix1,x);
+       e = ((ix0>>48)&0x7fff) - LDBL_MAX_EXP + 1;
+
+       if (e < MANH_SIZE - 1) {
+               if (e < 0) {                    /* raise inexact if x != 0 */
+                       if (huge + x > 0.0)
+                               return (zero[((ix0>>48)&0x8000)!=0]);
+               } else {
+                       uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+                       if (((ix0 & m) | ix1) == 0)
+                               return (x);     /* x is integral */
+                       if (huge + x > 0.0) {   /* raise inexact flag */
+                               ix0 &= ~m;
+                               ix1 = 0;
+                       }
+               }
+       } else if (e < LDBL_MANT_DIG - 1) {
+               uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+               if ((ix1 & m) == 0)
+                       return (x);     /* x is integral */
+               if (huge + x > 0.0)             /* raise inexact flag */
+                       ix1 &= ~m;
+       }
+       SET_LDOUBLE_WORDS64(x,ix0,ix1);
+       return (x);
+}
diff --git a/ld80/Make.files b/ld80/Make.files
new file mode 100644 (file)
index 0000000..1198cfb
--- /dev/null
@@ -0,0 +1,13 @@
+$(CUR_SRCS) +=         invtrig.c \
+            e_acoshl.c     e_powl.c       k_tanl.c       s_exp2l.c \
+            e_atanhl.c     e_lgammal_r.c  e_sinhl.c      s_asinhl.c     s_expm1l.c \
+            e_coshl.c      e_log10l.c     e_tgammal.c \
+            e_expl.c       e_log2l.c      k_cosl.c       s_log1pl.c     s_tanhl.c \
+            e_logl.c       k_sinl.c       s_erfl.c
+
+#           s_remquol.c    e_fmodl.c      s_truncl.c
+#           e_hypotl.c     s_floorl.c     s_nextafterl.c s_ceill.c      s_modfl.c
+
+ifneq ($(OS), WINNT)
+$(CUR_SRCS) += s_nanl.c
+endif
diff --git a/ld80/e_acoshl.c b/ld80/e_acoshl.c
new file mode 100644 (file)
index 0000000..35758bb
--- /dev/null
@@ -0,0 +1,57 @@
+/* @(#)e_acosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* acoshl(x)
+ * Method :
+ *     Based on
+ *             acoshl(x) = logl [ x + sqrtl(x*x-1) ]
+ *     we have
+ *             acoshl(x) := logl(x)+ln2,       if x is large; else
+ *             acoshl(x) := logl(2x-1/(sqrtl(x*x-1)+x)) if x>2; else
+ *             acoshl(x) := log1pl(t+sqrtl(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *     acoshl(x) is NaN with signal if x<1.
+ *     acoshl(NaN) is NaN without signal.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+one    = 1.0,
+ln2    = 6.931471805599453094287e-01L; /* 0x3FFE, 0xB17217F7, 0xD1CF79AC */
+
+long double
+acoshl(long double x)
+{
+       long double t;
+       u_int32_t se,i0,i1;
+       GET_LDOUBLE_WORDS(se,i0,i1,x);
+       if(se<0x3fff || se & 0x8000) {  /* x < 1 */
+           return (x-x)/(x-x);
+       } else if(se >=0x401d) {        /* x > 2**30 */
+           if(se >=0x7fff) {           /* x is inf of NaN */
+               return x+x;
+           } else
+               return logl(x)+ln2;     /* acoshl(huge)=logl(2x) */
+       } else if(((se-0x3fff)|i0|i1)==0) {
+           return 0.0;                 /* acosh(1) = 0 */
+       } else if (se > 0x4000) {       /* 2**28 > x > 2 */
+           t=x*x;
+           return logl(2.0*x-one/(x+sqrtl(t-one)));
+       } else {                        /* 1<x<2 */
+           t = x-one;
+           return log1pl(t+sqrtl(2.0*t+t*t));
+       }
+}
diff --git a/ld80/e_atanhl.c b/ld80/e_atanhl.c
new file mode 100644 (file)
index 0000000..6d13a5c
--- /dev/null
@@ -0,0 +1,60 @@
+/* @(#)e_atanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* atanhl(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                   1              2x                          x
+ *     atanhl(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                   2             1 - x                      1 - x
+ *
+ *     For x<0.5
+ *     atanhl(x) = 0.5*log1pl(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *     atanhl(x) is NaN if |x| > 1 with signal;
+ *     atanhl(NaN) is that NaN with no signal;
+ *     atanhl(+-1) is +-INF with signal.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, huge = 1e4900L;
+
+static const long double zero = 0.0;
+
+long double
+atanhl(long double x)
+{
+       long double t;
+       int32_t ix;
+       u_int32_t se,i0,i1;
+       GET_LDOUBLE_WORDS(se,i0,i1,x);
+       ix = se&0x7fff;
+       if ((ix+((((i0&0x7fffffff)|i1)|(-((i0&0x7fffffff)|i1)))>>31))>0x3fff)
+         /* |x|>1 */
+           return (x-x)/(x-x);
+       if(ix==0x3fff)
+           return x/zero;
+       if(ix<0x3fe3&&(huge+x)>zero) return x;  /* x<2**-28 */
+       SET_LDOUBLE_EXP(x,ix);
+       if(ix<0x3ffe) {         /* x < 0.5 */
+           t = x+x;
+           t = 0.5*log1pl(t+t*x/(one-x));
+       } else
+           t = 0.5*log1pl((x+x)/(one-x));
+       if(se<=0x7fff) return t; else return -t;
+}
diff --git a/ld80/e_coshl.c b/ld80/e_coshl.c
new file mode 100644 (file)
index 0000000..a0fb9b5
--- /dev/null
@@ -0,0 +1,83 @@
+/* @(#)e_cosh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* coshl(x)
+ * Method :
+ * mathematically coshl(x) if defined to be (exp(x)+exp(-x))/2
+ *     1. Replace x by |x| (coshl(x) = coshl(-x)).
+ *     2.
+ *                                                     [ exp(x) - 1 ]^2
+ *         0        <= x <= ln2/2  :  coshl(x) := 1 + -------------------
+ *                                                        2*exp(x)
+ *
+ *                                                exp(x) +  1/exp(x)
+ *         ln2/2    <= x <= 22     :  coshl(x) := -------------------
+ *                                                        2
+ *         22       <= x <= lnovft :  coshl(x) := expl(x)/2
+ *         lnovft   <= x <= ln2ovft:  coshl(x) := expl(x/2)/2 * expl(x/2)
+ *         ln2ovft  <  x           :  coshl(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ *     coshl(x) is |x| if x is +INF, -INF, or NaN.
+ *     only coshl(0)=1 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, half=0.5, huge = 1.0e4900L;
+
+long double
+coshl(long double x)
+{
+       long double t,w;
+       int32_t ex;
+       u_int32_t mx,lx;
+
+    /* High word of |x|. */
+       GET_LDOUBLE_WORDS(ex,mx,lx,x);
+       ex &= 0x7fff;
+
+    /* x is INF or NaN */
+       if(ex==0x7fff) return x*x;
+
+    /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */
+       if(ex < 0x3ffd || (ex == 0x3ffd && mx < 0xb17217f7u)) {
+           t = expm1l(fabsl(x));
+           w = one+t;
+           if (ex<0x3fbc) return w;    /* cosh(tiny) = 1 */
+           return one+(t*t)/(w+w);
+       }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+       if (ex < 0x4003 || (ex == 0x4003 && mx < 0xb0000000u)) {
+               t = expl(fabsl(x));
+               return half*t+half/t;
+       }
+
+    /* |x| in [22, ln(maxdouble)] return half*exp(|x|) */
+       if (ex < 0x400c || (ex == 0x400c && mx < 0xb1700000u))
+               return half*expl(fabsl(x));
+
+    /* |x| in [log(maxdouble), log(2*maxdouble)) */
+       if (ex == 0x400c && (mx < 0xb174ddc0u
+                            || (mx == 0xb174ddc0u && lx < 0x31aec0ebu)))
+       {
+           w = expl(half*fabsl(x));
+           t = half*w;
+           return t*w;
+       }
+
+    /* |x| >= log(2*maxdouble), cosh(x) overflow */
+       return huge*huge;
+}
diff --git a/ld80/e_expl.c b/ld80/e_expl.c
new file mode 100644 (file)
index 0000000..db0d1ca
--- /dev/null
@@ -0,0 +1,131 @@
+/*     $OpenBSD: e_expl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $     */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     expl.c
+ *
+ *     Exponential function, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, expl();
+ *
+ * y = expl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns e (2.71828...) raised to the x power.
+ *
+ * Range reduction is accomplished by separating the argument
+ * into an integer k and fraction f such that
+ *
+ *     x    k  f
+ *    e  = 2  e.
+ *
+ * A Pade' form of degree 2/3 is used to approximate exp(f) - 1
+ * in the basic range [-0.5 ln 2, 0.5 ln 2].
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      +-10000     50000       1.12e-19    2.81e-20
+ *
+ *
+ * Error amplification in the exponential function can be
+ * a serious matter.  The error propagation involves
+ * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ),
+ * which shows that a 1 lsb error in representing X produces
+ * a relative error of X times 1 lsb in the function.
+ * While the routine gives an accurate result for arguments
+ * that are exactly represented by a long double precision
+ * computer number, the result contains amplified roundoff
+ * error for large arguments not exactly represented.
+ *
+ *
+ * ERROR MESSAGES:
+ *
+ *   message         condition      value returned
+ * exp underflow    x < MINLOG         0.0
+ * exp overflow     x > MAXLOG         MAXNUM
+ *
+ */
+
+/*     Exponential function    */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static long double P[3] = {
+ 1.2617719307481059087798E-4L,
+ 3.0299440770744196129956E-2L,
+ 9.9999999999999999991025E-1L,
+};
+static long double Q[4] = {
+ 3.0019850513866445504159E-6L,
+ 2.5244834034968410419224E-3L,
+ 2.2726554820815502876593E-1L,
+ 2.0000000000000000000897E0L,
+};
+static const long double C1 = 6.9314575195312500000000E-1L;
+static const long double C2 = 1.4286068203094172321215E-6L;
+static const long double MAXLOGL = 1.1356523406294143949492E4L;
+static const long double MINLOGL = -1.13994985314888605586758E4L;
+static const long double LOG2EL = 1.4426950408889634073599E0L;
+
+long double
+expl(long double x)
+{
+long double px, xx;
+int n;
+
+if( isnan(x) )
+       return(x);
+if( x > MAXLOGL)
+       return( INFINITY );
+
+if( x < MINLOGL )
+       return(0.0L);
+
+/* Express e**x = e**g 2**n
+ *   = e**g e**( n loge(2) )
+ *   = e**( g + n loge(2) )
+ */
+px = floorl( LOG2EL * x + 0.5L ); /* floor() truncates toward -infinity. */
+n = px;
+x -= px * C1;
+x -= px * C2;
+
+
+/* rational approximation for exponential
+ * of the fractional part:
+ * e**x =  1 + 2x P(x**2)/( Q(x**2) - P(x**2) )
+ */
+xx = x * x;
+px = x * __polevll( xx, P, 2 );
+x =  px/( __polevll( xx, Q, 3 ) - px );
+x = 1.0L + ldexpl( x, 1 );
+
+x = ldexpl( x, n );
+return(x);
+}
diff --git a/ld80/e_fmodl.c b/ld80/e_fmodl.c
new file mode 100644 (file)
index 0000000..ec792e3
--- /dev/null
@@ -0,0 +1,142 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/types.h>
+//#include <machine/ieee.h>
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+#define        BIAS (LDBL_MAX_EXP - 1)
+
+/*
+ * These macros add and remove an explicit integer bit in front of the
+ * fractional mantissa, if the architecture doesn't have such a bit by
+ * default already.
+ */
+#ifdef LDBL_IMPLICIT_NBIT
+#define        LDBL_NBIT       0
+#define        SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
+#define        HFRAC_BITS      EXT_FRACHBITS
+#else
+#define        LDBL_NBIT       0x80000000
+#define        SET_NBIT(hx)    (hx)
+#define        HFRAC_BITS      (EXT_FRACHBITS - 1)
+#endif
+
+#define        MANL_SHIFT      (EXT_FRACLBITS - 1)
+
+static const long double one = 1.0, Zero[] = {0.0, -0.0,};
+
+/*
+ * fmodl(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ *
+ * Assumptions:
+ * - The low part of the mantissa fits in a manl_t exactly.
+ * - The high part of the mantissa fits in an int64_t with enough room
+ *   for an explicit integer bit in front of the fractional bits.
+ */
+long double
+fmodl(long double x, long double y)
+{
+       union {
+               long double e;
+               struct ieee_ext bits;
+       } ux, uy;
+       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
+       uint32_t hy;
+       uint32_t lx,ly,lz;
+       int ix,iy,n,sx;
+
+       ux.e = x;
+       uy.e = y;
+       sx = ux.bits.ext_sign;
+
+    /* purge off exception values */
+       if((uy.bits.ext_exp|uy.bits.ext_frach|uy.bits.ext_fracl)==0 || /* y=0 */
+          (ux.bits.ext_exp == BIAS + LDBL_MAX_EXP) ||   /* or x not finite */
+          (uy.bits.ext_exp == BIAS + LDBL_MAX_EXP &&
+           ((uy.bits.ext_frach&~LDBL_NBIT)|uy.bits.ext_fracl)!=0)) /* or y is NaN */
+           return (x*y)/(x*y);
+       if(ux.bits.ext_exp<=uy.bits.ext_exp) {
+           if((ux.bits.ext_exp<uy.bits.ext_exp) ||
+              (ux.bits.ext_frach<=uy.bits.ext_frach &&
+               (ux.bits.ext_frach<uy.bits.ext_frach ||
+                ux.bits.ext_fracl<uy.bits.ext_fracl))) {
+               return x;               /* |x|<|y| return x or x-y */
+           }
+           if(ux.bits.ext_frach==uy.bits.ext_frach &&
+               ux.bits.ext_fracl==uy.bits.ext_fracl) {
+               return Zero[sx];        /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if(ux.bits.ext_exp == 0) {      /* subnormal x */
+           ux.e *= 0x1.0p512;
+           ix = ux.bits.ext_exp - (BIAS + 512);
+       } else {
+           ix = ux.bits.ext_exp - BIAS;
+       }
+
+    /* determine iy = ilogb(y) */
+       if(uy.bits.ext_exp == 0) {      /* subnormal y */
+           uy.e *= 0x1.0p512;
+           iy = uy.bits.ext_exp - (BIAS + 512);
+       } else {
+           iy = uy.bits.ext_exp - BIAS;
+       }
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       hx = SET_NBIT(ux.bits.ext_frach);
+       hy = SET_NBIT(uy.bits.ext_frach);
+       lx = ux.bits.ext_fracl;
+       ly = uy.bits.ext_fracl;
+
+    /* fix point fmod */
+       n = ix - iy;
+
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;}
+           else {
+               if ((hz|lz)==0)         /* return sign(x)*0 */
+                   return Zero[sx];
+               hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz;
+           }
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0)                  /* return sign(x)*0 */
+           return Zero[sx];
+       while(hx<(1ULL<<HFRAC_BITS)) {  /* normalize x */
+           hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;
+           iy -= 1;
+       }
+       ux.bits.ext_frach = hx; /* The mantissa is truncated here if needed. */
+       ux.bits.ext_fracl = lx;
+       if (iy < LDBL_MIN_EXP) {
+           ux.bits.ext_exp = iy + (BIAS + 512);
+           ux.e *= 0x1p-512;
+       } else {
+           ux.bits.ext_exp = iy + BIAS;
+       }
+       x = ux.e * one;         /* create necessary signal */
+       return x;               /* exact output */
+}
diff --git a/ld80/e_hypotl.c b/ld80/e_hypotl.c
new file mode 100644 (file)
index 0000000..e6faa22
--- /dev/null
@@ -0,0 +1,122 @@
+/* @(#)e_hypot.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* hypotl(x,y)
+ *
+ * Method :
+ *     If (assume round-to-nearest) z=x*x+y*y
+ *     has error less than sqrt(2)/2 ulp, than
+ *     sqrt(z) has error less than 1 ulp (exercise).
+ *
+ *     So, compute sqrt(x*x+y*y) with some care as
+ *     follows to get the error below 1 ulp:
+ *
+ *     Assume x>y>0;
+ *     (if possible, set rounding to round-to-nearest)
+ *     1. if x > 2y  use
+ *             x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *     where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ *     2. if x <= 2y use
+ *             t1*yy1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *     where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ *     yy1= y with lower 32 bits chopped, y2 = y-yy1.
+ *
+ *     NOTE: scaling may be necessary if some argument is too
+ *           large or too tiny
+ *
+ * Special cases:
+ *     hypot(x,y) is INF if x or y is +INF or -INF; else
+ *     hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ *     hypot(x,y) returns sqrt(x^2+y^2) with error less
+ *     than 1 ulps (units in the last place)
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+long double
+hypotl(long double x, long double y)
+{
+       long double a,b,t1,t2,yy1,y2,w;
+       u_int32_t j,k,ea,eb;
+
+       GET_LDOUBLE_EXP(ea,x);
+       ea &= 0x7fff;
+       GET_LDOUBLE_EXP(eb,y);
+       eb &= 0x7fff;
+       if(eb > ea) {a=y;b=x;j=ea; ea=eb;eb=j;} else {a=x;b=y;}
+       SET_LDOUBLE_EXP(a,ea);  /* a <- |a| */
+       SET_LDOUBLE_EXP(b,eb);  /* b <- |b| */
+       if((ea-eb)>0x46) {return a+b;} /* x/y > 2**70 */
+       k=0;
+       if(ea > 0x5f3f) {       /* a>2**8000 */
+          if(ea == 0x7fff) {   /* Inf or NaN */
+              u_int32_t es,high,low;
+              w = a+b;                 /* for sNaN */
+              GET_LDOUBLE_WORDS(es,high,low,a);
+              if(((high&0x7fffffff)|low)==0) w = a;
+              GET_LDOUBLE_WORDS(es,high,low,b);
+              if(((eb^0x7fff)|(high&0x7fffffff)|low)==0) w = b;
+              return w;
+          }
+          /* scale a and b by 2**-9600 */
+          ea -= 0x2580; eb -= 0x2580;  k += 9600;
+          SET_LDOUBLE_EXP(a,ea);
+          SET_LDOUBLE_EXP(b,eb);
+       }
+       if(eb < 0x20bf) {       /* b < 2**-8000 */
+           if(eb == 0) {       /* subnormal b or 0 */
+               u_int32_t es,high,low;
+               GET_LDOUBLE_WORDS(es,high,low,b);
+               if((high|low)==0) return a;
+               SET_LDOUBLE_WORDS(t1, 0x7ffd, 0, 0);    /* t1=2^16382 */
+               b *= t1;
+               a *= t1;
+               k -= 16382;
+           } else {            /* scale a and b by 2^9600 */
+               ea += 0x2580;   /* a *= 2^9600 */
+               eb += 0x2580;   /* b *= 2^9600 */
+               k -= 9600;
+               SET_LDOUBLE_EXP(a,ea);
+               SET_LDOUBLE_EXP(b,eb);
+           }
+       }
+    /* medium size a and b */
+       w = a-b;
+       if (w>b) {
+           u_int32_t high;
+           GET_LDOUBLE_MSW(high,a);
+           SET_LDOUBLE_WORDS(t1,ea,high,0);
+           t2 = a-t1;
+           w  = sqrtl(t1*t1-(b*(-b)-t2*(a+t1)));
+       } else {
+           u_int32_t high;
+           GET_LDOUBLE_MSW(high,b);
+           a  = a+a;
+           SET_LDOUBLE_WORDS(yy1,eb,high,0);
+           y2 = b - yy1;
+           GET_LDOUBLE_MSW(high,a);
+           SET_LDOUBLE_WORDS(t1,ea+1,high,0);
+           t2 = a - t1;
+           w  = sqrtl(t1*yy1-(w*(-w)-(t1*y2+t2*b)));
+       }
+       if(k!=0) {
+           u_int32_t es;
+           t1 = 1.0;
+           GET_LDOUBLE_EXP(es,t1);
+           SET_LDOUBLE_EXP(t1,es+k);
+           return t1*w;
+       } else return w;
+}
diff --git a/ld80/e_lgammal_r.c b/ld80/e_lgammal_r.c
new file mode 100644 (file)
index 0000000..0af5420
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* lgammal_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ *   1. Argument Reduction for 0 < x <= 8
+ *     Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ *     reduce x to a number in [1.5,2.5] by
+ *             lgamma(1+s) = log(s) + lgamma(s)
+ *     for example,
+ *             lgamma(7.3) = log(6.3) + lgamma(6.3)
+ *                         = log(6.3*5.3) + lgamma(5.3)
+ *                         = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ *   2. Polynomial approximation of lgamma around its
+ *     minimun ymin=1.461632144968362245 to maintain monotonicity.
+ *     On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ *             Let z = x-ymin;
+ *             lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ *   2. Rational approximation in the primary interval [2,3]
+ *     We use the following approximation:
+ *             s = x-2.0;
+ *             lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ *     Our algorithms are based on the following observation
+ *
+ *                             zeta(2)-1    2    zeta(3)-1    3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s  -  --------- * s  + ...
+ *                                 2                 3
+ *
+ *     where Euler = 0.5771... is the Euler constant, which is very
+ *     close to 0.5.
+ *
+ *   3. For x>=8, we have
+ *     lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ *     (better formula:
+ *        lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ *     Let z = 1/x, then we approximation
+ *             f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ *     by
+ *                                 3       5             11
+ *             w = w0 + w1*z + w2*z  + w3*z  + ... + w6*z
+ *
+ *   4. For negative x, since (G is gamma function)
+ *             -x*G(-x)*G(x) = pi/sin(pi*x),
+ *     we have
+ *             G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ *     since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ *     Hence, for x<0, signgam = sign(sin(pi*x)) and
+ *             lgamma(x) = log(|Gamma(x)|)
+ *                       = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ *     Note: one should avoid compute pi*(-x) directly in the
+ *           computation of sin(pi*(-x)).
+ *
+ *   5. Special Cases
+ *             lgamma(2+s) ~ s*(1-Euler) for tiny s
+ *             lgamma(1)=lgamma(2)=0
+ *             lgamma(x) ~ -log(x) for tiny x
+ *             lgamma(0) = lgamma(inf) = inf
+ *             lgamma(-integer) = +-inf
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+  half = 0.5L,
+  one = 1.0L,
+  pi = 3.14159265358979323846264L,
+  two63 = 9.223372036854775808e18L,
+
+  /* lgam(1+x) = 0.5 x + x a(x)/b(x)
+     -0.268402099609375 <= x <= 0
+     peak relative error 6.6e-22 */
+  a0 = -6.343246574721079391729402781192128239938E2L,
+  a1 =  1.856560238672465796768677717168371401378E3L,
+  a2 =  2.404733102163746263689288466865843408429E3L,
+  a3 =  8.804188795790383497379532868917517596322E2L,
+  a4 =  1.135361354097447729740103745999661157426E2L,
+  a5 =  3.766956539107615557608581581190400021285E0L,
+
+  b0 =  8.214973713960928795704317259806842490498E3L,
+  b1 =  1.026343508841367384879065363925870888012E4L,
+  b2 =  4.553337477045763320522762343132210919277E3L,
+  b3 =  8.506975785032585797446253359230031874803E2L,
+  b4 =  6.042447899703295436820744186992189445813E1L,
+  /* b5 =  1.000000000000000000000000000000000000000E0 */
+
+
+  tc =  1.4616321449683623412626595423257213284682E0L,
+  tf = -1.2148629053584961146050602565082954242826E-1,/* double precision */
+/* tt = (tail of tf), i.e. tf + tt has extended precision. */
+  tt = 3.3649914684731379602768989080467587736363E-18L,
+  /* lgam ( 1.4616321449683623412626595423257213284682E0 ) =
+-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */
+
+  /* lgam (x + tc) = tf + tt + x g(x)/h(x)
+     - 0.230003726999612341262659542325721328468 <= x
+     <= 0.2699962730003876587373404576742786715318
+     peak relative error 2.1e-21 */
+  g0 = 3.645529916721223331888305293534095553827E-18L,
+  g1 = 5.126654642791082497002594216163574795690E3L,
+  g2 = 8.828603575854624811911631336122070070327E3L,
+  g3 = 5.464186426932117031234820886525701595203E3L,
+  g4 = 1.455427403530884193180776558102868592293E3L,
+  g5 = 1.541735456969245924860307497029155838446E2L,
+  g6 = 4.335498275274822298341872707453445815118E0L,
+
+  h0 = 1.059584930106085509696730443974495979641E4L,
+  h1 =  2.147921653490043010629481226937850618860E4L,
+  h2 = 1.643014770044524804175197151958100656728E4L,
+  h3 =  5.869021995186925517228323497501767586078E3L,
+  h4 =  9.764244777714344488787381271643502742293E2L,
+  h5 =  6.442485441570592541741092969581997002349E1L,
+  /* h6 = 1.000000000000000000000000000000000000000E0 */
+
+
+  /* lgam (x+1) = -0.5 x + x u(x)/v(x)
+     -0.100006103515625 <= x <= 0.231639862060546875
+     peak relative error 1.3e-21 */
+  u0 = -8.886217500092090678492242071879342025627E1L,
+  u1 =  6.840109978129177639438792958320783599310E2L,
+  u2 =  2.042626104514127267855588786511809932433E3L,
+  u3 =  1.911723903442667422201651063009856064275E3L,
+  u4 =  7.447065275665887457628865263491667767695E2L,
+  u5 =  1.132256494121790736268471016493103952637E2L,
+  u6 =  4.484398885516614191003094714505960972894E0L,
+
+  v0 =  1.150830924194461522996462401210374632929E3L,
+  v1 =  3.399692260848747447377972081399737098610E3L,
+  v2 =  3.786631705644460255229513563657226008015E3L,
+  v3 =  1.966450123004478374557778781564114347876E3L,
+  v4 =  4.741359068914069299837355438370682773122E2L,
+  v5 =  4.508989649747184050907206782117647852364E1L,
+  /* v6 =  1.000000000000000000000000000000000000000E0 */
+
+
+  /* lgam (x+2) = .5 x + x s(x)/r(x)
+     0 <= x <= 1
+     peak relative error 7.2e-22 */
+  s0 =  1.454726263410661942989109455292824853344E6L,
+  s1 = -3.901428390086348447890408306153378922752E6L,
+  s2 = -6.573568698209374121847873064292963089438E6L,
+  s3 = -3.319055881485044417245964508099095984643E6L,
+  s4 = -7.094891568758439227560184618114707107977E5L,
+  s5 = -6.263426646464505837422314539808112478303E4L,
+  s6 = -1.684926520999477529949915657519454051529E3L,
+
+  r0 = -1.883978160734303518163008696712983134698E7L,
+  r1 = -2.815206082812062064902202753264922306830E7L,
+  r2 = -1.600245495251915899081846093343626358398E7L,
+  r3 = -4.310526301881305003489257052083370058799E6L,
+  r4 = -5.563807682263923279438235987186184968542E5L,
+  r5 = -3.027734654434169996032905158145259713083E4L,
+  r6 = -4.501995652861105629217250715790764371267E2L,
+  /* r6 =  1.000000000000000000000000000000000000000E0 */
+
+
+/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2)
+   x >= 8
+   Peak relative error 1.51e-21
+   w0 = LS2PI - 0.5 */
+  w0 =  4.189385332046727417803e-1L,
+  w1 =  8.333333333333331447505E-2L,
+  w2 = -2.777777777750349603440E-3L,
+  w3 =  7.936507795855070755671E-4L,
+  w4 = -5.952345851765688514613E-4L,
+  w5 =  8.412723297322498080632E-4L,
+  w6 = -1.880801938119376907179E-3L,
+  w7 =  4.885026142432270781165E-3L;
+
+static const long double zero = 0.0L;
+
+static long double
+sin_pi(long double x)
+{
+  long double y, z;
+  int n, ix;
+  u_int32_t se, i0, i1;
+
+  GET_LDOUBLE_WORDS (se, i0, i1, x);
+  ix = se & 0x7fff;
+  ix = (ix << 16) | (i0 >> 16);
+  if (ix < 0x3ffd8000) /* 0.25 */
+    return sinl (pi * x);
+  y = -x;                      /* x is assume negative */
+
+  /*
+   * argument reduction, make sure inexact flag not raised if input
+   * is an integer
+   */
+  z = floorl (y);
+  if (z != y)
+    {                          /* inexact anyway */
+      y  *= 0.5;
+      y = 2.0*(y - floorl(y));         /* y = |x| mod 2.0 */
+      n = (int) (y*4.0);
+    }
+  else
+    {
+      if (ix >= 0x403f8000)  /* 2^64 */
+       {
+         y = zero; n = 0;              /* y must be even */
+       }
+      else
+       {
+       if (ix < 0x403e8000)  /* 2^63 */
+         z = y + two63;        /* exact */
+       GET_LDOUBLE_WORDS (se, i0, i1, z);
+       n = i1 & 1;
+       y  = n;
+       n <<= 2;
+      }
+    }
+
+  switch (n)
+    {
+    case 0:
+      y = sinl (pi * y);
+      break;
+    case 1:
+    case 2:
+      y = cosl (pi * (half - y));
+      break;
+    case 3:
+    case 4:
+      y = sinl (pi * (one - y));
+      break;
+    case 5:
+    case 6:
+      y = -cosl (pi * (y - 1.5));
+      break;
+    default:
+      y = sinl (pi * (y - 2.0));
+      break;
+    }
+  return -y;
+}
+
+
+long double
+lgammal_r(long double x, int *signgamp)
+{
+  long double t, y, z, nadj, p, p1, p2, q, r, w;
+  int i, ix;
+  u_int32_t se, i0, i1;
+
+  *signgamp = 1;
+  GET_LDOUBLE_WORDS (se, i0, i1, x);
+  ix = se & 0x7fff;
+
+  if ((ix | i0 | i1) == 0)
+    {
+      if (se & 0x8000)
+       *signgamp = -1;
+      return one / fabsl (x);
+    }
+
+  ix = (ix << 16) | (i0 >> 16);
+
+  /* purge off +-inf, NaN, +-0, and negative arguments */
+  if (ix >= 0x7fff0000)
+    return x * x;
+
+  if (ix < 0x3fc08000) /* 2^-63 */
+    {                          /* |x|<2**-63, return -log(|x|) */
+      if (se & 0x8000)
+       {
+         *signgamp = -1;
+         return -logl (-x);
+       }
+      else
+       return -logl (x);
+    }
+  if (se & 0x8000)
+    {
+      t = sin_pi (x);
+      if (t == zero)
+       return one / fabsl (t); /* -integer */
+      nadj = logl (pi / fabsl (t * x));
+      if (t < zero)
+       *signgamp = -1;
+      x = -x;
+    }
+
+  /* purge off 1 and 2 */
+  if ((((ix - 0x3fff8000) | i0 | i1) == 0)
+      || (((ix - 0x40008000) | i0 | i1) == 0))
+    r = 0;
+  else if (ix < 0x40008000) /* 2.0 */
+    {
+      /* x < 2.0 */
+      if (ix <= 0x3ffee666) /* 8.99993896484375e-1 */
+       {
+         /* lgamma(x) = lgamma(x+1) - log(x) */
+         r = -logl (x);
+         if (ix >= 0x3ffebb4a) /* 7.31597900390625e-1 */
+           {
+             y = x - one;
+             i = 0;
+           }
+         else if (ix >= 0x3ffced33)/* 2.31639862060546875e-1 */
+           {
+             y = x - (tc - one);
+             i = 1;
+           }
+         else
+           {
+             /* x < 0.23 */
+             y = x;
+             i = 2;
+           }
+       }
+      else
+       {
+         r = zero;
+         if (ix >= 0x3fffdda6) /* 1.73162841796875 */
+           {
+             /* [1.7316,2] */
+             y = x - 2.0;
+             i = 0;
+           }
+         else if (ix >= 0x3fff9da6)/* 1.23162841796875 */
+           {
+             /* [1.23,1.73] */
+             y = x - tc;
+             i = 1;
+           }
+         else
+           {
+             /* [0.9, 1.23] */
+             y = x - one;
+             i = 2;
+           }
+       }
+      switch (i)
+       {
+       case 0:
+         p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5))));
+         p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y))));
+         r += half * y + y * p1/p2;
+         break;
+       case 1:
+    p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6)))));
+    p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y)))));
+    p = tt + y * p1/p2;
+         r += (tf + p);
+         break;
+       case 2:
+ p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6))))));
+      p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y)))));
+         r += (-half * y + p1 / p2);
+       }
+    }
+  else if (ix < 0x40028000) /* 8.0 */
+    {
+      /* x < 8.0 */
+      i = (int) x;
+      t = zero;
+      y = x - (double) i;
+  p = y *
+     (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))))));
+  q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y))))));
+      r = half * y + p / q;
+      z = one;                 /* lgamma(1+s) = log(s) + lgamma(s) */
+      switch (i)
+       {
+       case 7:
+         z *= (y + 6.0);       /* FALLTHRU */
+       case 6:
+         z *= (y + 5.0);       /* FALLTHRU */
+       case 5:
+         z *= (y + 4.0);       /* FALLTHRU */
+       case 4:
+         z *= (y + 3.0);       /* FALLTHRU */
+       case 3:
+         z *= (y + 2.0);       /* FALLTHRU */
+         r += logl (z);
+         break;
+       }
+    }
+  else if (ix < 0x40418000) /* 2^66 */
+    {
+      /* 8.0 <= x < 2**66 */
+      t = logl (x);
+      z = one / x;
+      y = z * z;
+      w = w0 + z * (w1
+         + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7))))));
+      r = (x - half) * (t - one) + w;
+    }
+  else
+    /* 2**66 <= x <= inf */
+    r = x * (logl (x) - one);
+  if (se & 0x8000)
+    r = nadj - r;
+  return r;
+}
diff --git a/ld80/e_log10l.c b/ld80/e_log10l.c
new file mode 100644 (file)
index 0000000..bb6cd7d
--- /dev/null
@@ -0,0 +1,205 @@
+/*     $OpenBSD: e_log10l.c,v 1.2 2013/11/12 20:35:19 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     log10l.c
+ *
+ *     Common logarithm, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log10l();
+ *
+ * y = log10l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base 10 logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the logarithm
+ * of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z**3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      0.5, 2.0     30000      9.0e-20     2.6e-20
+ *    IEEE     exp(+-10000)  30000      6.0e-20     2.3e-20
+ *
+ * In the tests over the interval exp(+-10000), the logarithms
+ * of the random arguments were uniformly distributed over
+ * [-10000, +10000].
+ *
+ * ERROR MESSAGES:
+ *
+ * log singularity:  x = 0; returns MINLOG
+ * log domain:       x < 0; returns MINLOG
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.2e-22
+ */
+static long double P[] = {
+ 4.9962495940332550844739E-1L,
+ 1.0767376367209449010438E1L,
+ 7.7671073698359539859595E1L,
+ 2.5620629828144409632571E2L,
+ 4.2401812743503691187826E2L,
+ 3.4258224542413922935104E2L,
+ 1.0747524399916215149070E2L,
+};
+static long double Q[] = {
+/* 1.0000000000000000000000E0,*/
+ 2.3479774160285863271658E1L,
+ 1.9444210022760132894510E2L,
+ 7.7952888181207260646090E2L,
+ 1.6911722418503949084863E3L,
+ 2.0307734695595183428202E3L,
+ 1.2695660352705325274404E3L,
+ 3.2242573199748645407652E2L,
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.16e-22
+ */
+
+static long double R[4] = {
+ 1.9757429581415468984296E-3L,
+-7.1990767473014147232598E-1L,
+ 1.0777257190312272158094E1L,
+-3.5717684488096787370998E1L,
+};
+static long double S[4] = {
+/* 1.00000000000000000000E0L,*/
+-2.6201045551331104417768E1L,
+ 1.9361891836232102174846E2L,
+-4.2861221385716144629696E2L,
+};
+/* log10(2) */
+#define L102A 0.3125L
+#define L102B -1.1470004336018804786261e-2L
+/* log10(e) */
+#define L10EA 0.5L
+#define L10EB -6.5705518096748172348871e-2L
+
+#define SQRTH 0.70710678118654752440L
+
+long double
+log10l(long double x)
+{
+long double y;
+volatile long double z;
+int e;
+
+if( isnan(x) )
+       return(x);
+/* Test for domain */
+if( x <= 0.0L )
+       {
+       if( x == 0.0L )
+               return (-1.0L / (x - x));
+       else
+               return (x - x) / (x - x);
+       }
+if( x == INFINITY )
+       return(INFINITY);
+/* separate mantissa from exponent */
+
+/* Note, frexp is used so that denormal numbers
+ * will be handled properly.
+ */
+x = frexpl( x, &e );
+
+
+/* logarithm using log(x) = z + z**3 P(z)/Q(z),
+ * where z = 2(x-1)/x+1)
+ */
+if( (e > 2) || (e < -2) )
+{
+if( x < SQRTH )
+       { /* 2( 2x-1 )/( 2x+1 ) */
+       e -= 1;
+       z = x - 0.5L;
+       y = 0.5L * z + 0.5L;
+       }       
+else
+       { /*  2 (x-1)/(x+1)   */
+       z = x - 0.5L;
+       z -= 0.5L;
+       y = 0.5L * x  + 0.5L;
+       }
+x = z / y;
+z = x*x;
+y = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) );
+goto done;
+}
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+if( x < SQRTH )
+       {
+       e -= 1;
+       x = ldexpl( x, 1 ) - 1.0L; /*  2x - 1  */
+       }       
+else
+       {
+       x = x - 1.0L;
+       }
+z = x*x;
+y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 7 ) );
+y = y - ldexpl( z, -1 );   /* -0.5x^2 + ... */
+
+done:
+
+/* Multiply log of fraction by log10(e)
+ * and base 2 exponent by log10(2).
+ *
+ * ***CAUTION***
+ *
+ * This sequence of operations is critical and it may
+ * be horribly defeated by some compiler optimizers.
+ */
+z = y * (L10EB);
+z += x * (L10EB);
+z += e * (L102B);
+z += y * (L10EA);
+z += x * (L10EA);
+z += e * (L102A);
+
+return( z );
+}
diff --git a/ld80/e_log2l.c b/ld80/e_log2l.c
new file mode 100644 (file)
index 0000000..6ff6fe9
--- /dev/null
@@ -0,0 +1,199 @@
+/*     $OpenBSD: e_log2l.c,v 1.2 2013/11/12 20:35:19 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     log2l.c
+ *
+ *     Base 2 logarithm, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log2l();
+ *
+ * y = log2l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base 2 logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the (natural)
+ * logarithm of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z**3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      0.5, 2.0     30000      9.8e-20     2.7e-20
+ *    IEEE     exp(+-10000)  70000      5.4e-20     2.3e-20
+ *
+ * In the tests over the interval exp(+-10000), the logarithms
+ * of the random arguments were uniformly distributed over
+ * [-10000, +10000].
+ *
+ * ERROR MESSAGES:
+ *
+ * log singularity:  x = 0; returns -INFINITY
+ * log domain:       x < 0; returns NAN
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.2e-22
+ */
+static long double P[] = {
+ 4.9962495940332550844739E-1L,
+ 1.0767376367209449010438E1L,
+ 7.7671073698359539859595E1L,
+ 2.5620629828144409632571E2L,
+ 4.2401812743503691187826E2L,
+ 3.4258224542413922935104E2L,
+ 1.0747524399916215149070E2L,
+};
+static long double Q[] = {
+/* 1.0000000000000000000000E0,*/
+ 2.3479774160285863271658E1L,
+ 1.9444210022760132894510E2L,
+ 7.7952888181207260646090E2L,
+ 1.6911722418503949084863E3L,
+ 2.0307734695595183428202E3L,
+ 1.2695660352705325274404E3L,
+ 3.2242573199748645407652E2L,
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.16e-22
+ */
+static long double R[4] = {
+ 1.9757429581415468984296E-3L,
+-7.1990767473014147232598E-1L,
+ 1.0777257190312272158094E1L,
+-3.5717684488096787370998E1L,
+};
+static long double S[4] = {
+/* 1.00000000000000000000E0L,*/
+-2.6201045551331104417768E1L,
+ 1.9361891836232102174846E2L,
+-4.2861221385716144629696E2L,
+};
+/* log2(e) - 1 */
+#define LOG2EA 4.4269504088896340735992e-1L
+
+#define SQRTH 0.70710678118654752440L
+
+long double
+log2l(long double x)
+{
+volatile long double z;
+long double y;
+int e;
+
+if( isnan(x) )
+       return(x);
+if( x == INFINITY )
+       return(x);
+/* Test for domain */
+if( x <= 0.0L )
+       {
+       if( x == 0.0L )
+               return( -INFINITY );
+       else
+               return( NAN );
+       }
+
+/* separate mantissa from exponent */
+
+/* Note, frexp is used so that denormal numbers
+ * will be handled properly.
+ */
+x = frexpl( x, &e );
+
+
+/* logarithm using log(x) = z + z**3 P(z)/Q(z),
+ * where z = 2(x-1)/x+1)
+ */
+if( (e > 2) || (e < -2) )
+{
+if( x < SQRTH )
+       { /* 2( 2x-1 )/( 2x+1 ) */
+       e -= 1;
+       z = x - 0.5L;
+       y = 0.5L * z + 0.5L;
+       }       
+else
+       { /*  2 (x-1)/(x+1)   */
+       z = x - 0.5L;
+       z -= 0.5L;
+       y = 0.5L * x  + 0.5L;
+       }
+x = z / y;
+z = x*x;
+y = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) );
+goto done;
+}
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+if( x < SQRTH )
+       {
+       e -= 1;
+       x = ldexpl( x, 1 ) - 1.0L; /*  2x - 1  */
+       }       
+else
+       {
+       x = x - 1.0L;
+       }
+z = x*x;
+y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 7 ) );
+y = y - ldexpl( z, -1 );   /* -0.5x^2 + ... */
+
+done:
+
+/* Multiply log of fraction by log2(e)
+ * and base 2 exponent by 1
+ *
+ * ***CAUTION***
+ *
+ * This sequence of operations is critical and it may
+ * be horribly defeated by some compiler optimizers.
+ */
+z = y * LOG2EA;
+z += x * LOG2EA;
+z += y;
+z += x;
+z += e;
+return( z );
+}
diff --git a/ld80/e_logl.c b/ld80/e_logl.c
new file mode 100644 (file)
index 0000000..4722014
--- /dev/null
@@ -0,0 +1,190 @@
+/*     $OpenBSD: e_logl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $     */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     logl.c
+ *
+ *     Natural logarithm, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, logl();
+ *
+ * y = logl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base e (2.718...) logarithm of x.
+ *
+ * The argument is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the logarithm
+ * of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z**3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      0.5, 2.0    150000      8.71e-20    2.75e-20
+ *    IEEE     exp(+-10000) 100000      5.39e-20    2.34e-20
+ *
+ * In the tests over the interval exp(+-10000), the logarithms
+ * of the random arguments were uniformly distributed over
+ * [-10000, +10000].
+ *
+ * ERROR MESSAGES:
+ *
+ * log singularity:  x = 0; returns -INFINITY
+ * log domain:       x < 0; returns NAN
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 2.32e-20
+ */
+static long double P[] = {
+ 4.5270000862445199635215E-5L,
+ 4.9854102823193375972212E-1L,
+ 6.5787325942061044846969E0L,
+ 2.9911919328553073277375E1L,
+ 6.0949667980987787057556E1L,
+ 5.7112963590585538103336E1L,
+ 2.0039553499201281259648E1L,
+};
+static long double Q[] = {
+/* 1.0000000000000000000000E0,*/
+ 1.5062909083469192043167E1L,
+ 8.3047565967967209469434E1L,
+ 2.2176239823732856465394E2L,
+ 3.0909872225312059774938E2L,
+ 2.1642788614495947685003E2L,
+ 6.0118660497603843919306E1L,
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.16e-22
+ */
+
+static long double R[4] = {
+ 1.9757429581415468984296E-3L,
+-7.1990767473014147232598E-1L,
+ 1.0777257190312272158094E1L,
+-3.5717684488096787370998E1L,
+};
+static long double S[4] = {
+/* 1.00000000000000000000E0L,*/
+-2.6201045551331104417768E1L,
+ 1.9361891836232102174846E2L,
+-4.2861221385716144629696E2L,
+};
+static const long double C1 = 6.9314575195312500000000E-1L;
+static const long double C2 = 1.4286068203094172321215E-6L;
+
+#define SQRTH 0.70710678118654752440L
+
+long double
+logl(long double x)
+{
+long double y, z;
+int e;
+
+if( isnan(x) )
+       return(x);
+if( x == INFINITY )
+       return(x);
+/* Test for domain */
+if( x <= 0.0L )
+       {
+       if( x == 0.0L )
+               return( -INFINITY );
+       else
+               return( NAN );
+       }
+
+/* separate mantissa from exponent */
+
+/* Note, frexp is used so that denormal numbers
+ * will be handled properly.
+ */
+x = frexpl( x, &e );
+
+/* logarithm using log(x) = z + z**3 P(z)/Q(z),
+ * where z = 2(x-1)/x+1)
+ */
+if( (e > 2) || (e < -2) )
+{
+if( x < SQRTH )
+       { /* 2( 2x-1 )/( 2x+1 ) */
+       e -= 1;
+       z = x - 0.5L;
+       y = 0.5L * z + 0.5L;
+       }       
+else
+       { /*  2 (x-1)/(x+1)   */
+       z = x - 0.5L;
+       z -= 0.5L;
+       y = 0.5L * x  + 0.5L;
+       }
+x = z / y;
+z = x*x;
+z = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) );
+z = z + e * C2;
+z = z + x;
+z = z + e * C1;
+return( z );
+}
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+if( x < SQRTH )
+       {
+       e -= 1;
+       x = ldexpl( x, 1 ) - 1.0L; /*  2x - 1  */
+       }       
+else
+       {
+       x = x - 1.0L;
+       }
+z = x*x;
+y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 6 ) );
+y = y + e * C2;
+z = y - ldexpl( z, -1 );   /*  y - 0.5 * z  */
+/* Note, the sum of above terms does not exceed x/4,
+ * so it contributes at most about 1/4 lsb to the error.
+ */
+z = z + x;
+z = z + e * C1; /* This sum has an error of 1/2 lsb. */
+return( z );
+}
diff --git a/ld80/e_powl.c b/ld80/e_powl.c
new file mode 100644 (file)
index 0000000..dcb2b45
--- /dev/null
@@ -0,0 +1,615 @@
+/*     $OpenBSD: e_powl.c,v 1.5 2013/11/12 20:35:19 martynas Exp $     */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     powl.c
+ *
+ *     Power function, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, z, powl();
+ *
+ * z = powl( x, y );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Computes x raised to the yth power.  Analytically,
+ *
+ *      x**y  =  exp( y log(x) ).
+ *
+ * Following Cody and Waite, this program uses a lookup table
+ * of 2**-i/32 and pseudo extended precision arithmetic to
+ * obtain several extra bits of accuracy in both the logarithm
+ * and the exponential.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ * The relative error of pow(x,y) can be estimated
+ * by   y dl ln(2),   where dl is the absolute error of
+ * the internally computed base 2 logarithm.  At the ends
+ * of the approximation interval the logarithm equal 1/32
+ * and its relative error is about 1 lsb = 1.1e-19.  Hence
+ * the predicted relative error in the result is 2.3e-21 y .
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *
+ *    IEEE     +-1000       40000      2.8e-18      3.7e-19
+ * .001 < x < 1000, with log(x) uniformly distributed.
+ * -1000 < y < 1000, y uniformly distributed.
+ *
+ *    IEEE     0,8700       60000      6.5e-18      1.0e-18
+ * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed.
+ *
+ *
+ * ERROR MESSAGES:
+ *
+ *   message         condition      value returned
+ * pow overflow     x**y > MAXNUM      INFINITY
+ * pow underflow   x**y < 1/MAXNUM       0.0
+ * pow domain      x<0 and y noninteger  0.0
+ *
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Table size */
+#define NXT 32
+/* log2(Table size) */
+#define LNXT 5
+
+/* log(1+x) =  x - .5x^2 + x^3 *  P(z)/Q(z)
+ * on the domain  2^(-1/32) - 1  <=  x  <=  2^(1/32) - 1
+ */
+static long double P[] = {
+ 8.3319510773868690346226E-4L,
+ 4.9000050881978028599627E-1L,
+ 1.7500123722550302671919E0L,
+ 1.4000100839971580279335E0L,
+};
+static long double Q[] = {
+/* 1.0000000000000000000000E0L,*/
+ 5.2500282295834889175431E0L,
+ 8.4000598057587009834666E0L,
+ 4.2000302519914740834728E0L,
+};
+/* A[i] = 2^(-i/32), rounded to IEEE long double precision.
+ * If i is even, A[i] + B[i/2] gives additional accuracy.
+ */
+static long double A[33] = {
+ 1.0000000000000000000000E0L,
+ 9.7857206208770013448287E-1L,
+ 9.5760328069857364691013E-1L,
+ 9.3708381705514995065011E-1L,
+ 9.1700404320467123175367E-1L,
+ 8.9735453750155359320742E-1L,
+ 8.7812608018664974155474E-1L,
+ 8.5930964906123895780165E-1L,
+ 8.4089641525371454301892E-1L,
+ 8.2287773907698242225554E-1L,
+ 8.0524516597462715409607E-1L,
+ 7.8799042255394324325455E-1L,
+ 7.7110541270397041179298E-1L,
+ 7.5458221379671136985669E-1L,
+ 7.3841307296974965571198E-1L,
+ 7.2259040348852331001267E-1L,
+ 7.0710678118654752438189E-1L,
+ 6.9195494098191597746178E-1L,
+ 6.7712777346844636413344E-1L,
+ 6.6261832157987064729696E-1L,
+ 6.4841977732550483296079E-1L,
+ 6.3452547859586661129850E-1L,
+ 6.2092890603674202431705E-1L,
+ 6.0762367999023443907803E-1L,
+ 5.9460355750136053334378E-1L,
+ 5.8186242938878875689693E-1L,
+ 5.6939431737834582684856E-1L,
+ 5.5719337129794626814472E-1L,
+ 5.4525386633262882960438E-1L,
+ 5.3357020033841180906486E-1L,
+ 5.2213689121370692017331E-1L,
+ 5.1094857432705833910408E-1L,
+ 5.0000000000000000000000E-1L,
+};
+static long double B[17] = {
+ 0.0000000000000000000000E0L,
+ 2.6176170809902549338711E-20L,
+-1.0126791927256478897086E-20L,
+ 1.3438228172316276937655E-21L,
+ 1.2207982955417546912101E-20L,
+-6.3084814358060867200133E-21L,
+ 1.3164426894366316434230E-20L,
+-1.8527916071632873716786E-20L,
+ 1.8950325588932570796551E-20L,
+ 1.5564775779538780478155E-20L,
+ 6.0859793637556860974380E-21L,
+-2.0208749253662532228949E-20L,
+ 1.4966292219224761844552E-20L,
+ 3.3540909728056476875639E-21L,
+-8.6987564101742849540743E-22L,
+-1.2327176863327626135542E-20L,
+ 0.0000000000000000000000E0L,
+};
+
+/* 2^x = 1 + x P(x),
+ * on the interval -1/32 <= x <= 0
+ */
+static long double R[] = {
+ 1.5089970579127659901157E-5L,
+ 1.5402715328927013076125E-4L,
+ 1.3333556028915671091390E-3L,
+ 9.6181291046036762031786E-3L,
+ 5.5504108664798463044015E-2L,
+ 2.4022650695910062854352E-1L,
+ 6.9314718055994530931447E-1L,
+};
+
+#define douba(k) A[k]
+#define doubb(k) B[k]
+#define MEXP (NXT*16384.0L)
+/* The following if denormal numbers are supported, else -MEXP: */
+#define MNEXP (-NXT*(16384.0L+64.0L))
+/* log2(e) - 1 */
+#define LOG2EA 0.44269504088896340735992L
+
+#define F W
+#define Fa Wa
+#define Fb Wb
+#define G W
+#define Ga Wa
+#define Gb u
+#define H W
+#define Ha Wb
+#define Hb Wb
+
+static const long double MAXLOGL = 1.1356523406294143949492E4L;
+static const long double MINLOGL = -1.13994985314888605586758E4L;
+static const long double LOGE2L = 6.9314718055994530941723E-1L;
+static volatile long double z;
+static long double w, W, Wa, Wb, ya, yb, u;
+static const long double huge = 0x1p10000L;
+#if 0 /* XXX Prevent gcc from erroneously constant folding this. */
+static const long double twom10000 = 0x1p-10000L;
+#else
+static volatile long double twom10000 = 0x1p-10000L;
+#endif
+
+static long double reducl( long double );
+static long double powil ( long double, int );
+
+long double
+powl(long double x, long double y)
+{
+/* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */
+int i, nflg, iyflg, yoddint;
+long e;
+
+if( y == 0.0L )
+       return( 1.0L );
+
+if( x == 1.0L )
+       return( 1.0L );
+
+if( isnan(x) )
+       return( x );
+if( isnan(y) )
+       return( y );
+
+if( y == 1.0L )
+       return( x );
+
+if( !isfinite(y) && x == -1.0L )
+       return( 1.0L );
+
+if( y >= LDBL_MAX )
+       {
+       if( x > 1.0L )
+               return( INFINITY );
+       if( x > 0.0L && x < 1.0L )
+               return( 0.0L );
+       if( x < -1.0L )
+               return( INFINITY );
+       if( x > -1.0L && x < 0.0L )
+               return( 0.0L );
+       }
+if( y <= -LDBL_MAX )
+       {
+       if( x > 1.0L )
+               return( 0.0L );
+       if( x > 0.0L && x < 1.0L )
+               return( INFINITY );
+       if( x < -1.0L )
+               return( 0.0L );
+       if( x > -1.0L && x < 0.0L )
+               return( INFINITY );
+       }
+if( x >= LDBL_MAX )
+       {
+       if( y > 0.0L )
+               return( INFINITY );
+       return( 0.0L );
+       }
+
+w = floorl(y);
+/* Set iyflg to 1 if y is an integer.  */
+iyflg = 0;
+if( w == y )
+       iyflg = 1;
+
+/* Test for odd integer y.  */
+yoddint = 0;
+if( iyflg )
+       {
+       ya = fabsl(y);
+       ya = floorl(0.5L * ya);
+       yb = 0.5L * fabsl(w);
+       if( ya != yb )
+               yoddint = 1;
+       }
+
+if( x <= -LDBL_MAX )
+       {
+       if( y > 0.0L )
+               {
+               if( yoddint )
+                       return( -INFINITY );
+               return( INFINITY );
+               }
+       if( y < 0.0L )
+               {
+               if( yoddint )
+                       return( -0.0L );
+               return( 0.0 );
+               }
+       }
+
+
+nflg = 0;      /* flag = 1 if x<0 raised to integer power */
+if( x <= 0.0L )
+       {
+       if( x == 0.0L )
+               {
+               if( y < 0.0 )
+                       {
+                       if( signbit(x) && yoddint )
+                               return( -INFINITY );
+                       return( INFINITY );
+                       }
+               if( y > 0.0 )
+                       {
+                       if( signbit(x) && yoddint )
+                               return( -0.0L );
+                       return( 0.0 );
+                       }
+               if( y == 0.0L )
+                       return( 1.0L );  /*   0**0   */
+               else
+                       return( 0.0L );  /*   0**y   */
+               }
+       else
+               {
+               if( iyflg == 0 )
+                       return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */
+               nflg = 1;
+               }
+       }
+
+/* Integer power of an integer.  */
+
+if( iyflg )
+       {
+       i = w;
+       w = floorl(x);
+       if( (w == x) && (fabsl(y) < 32768.0) )
+               {
+               w = powil( x, (int) y );
+               return( w );
+               }
+       }
+
+
+if( nflg )
+       x = fabsl(x);
+
+/* separate significand from exponent */
+x = frexpl( x, &i );
+e = i;
+
+/* find significand in antilog table A[] */
+i = 1;
+if( x <= douba(17) )
+       i = 17;
+if( x <= douba(i+8) )
+       i += 8;
+if( x <= douba(i+4) )
+       i += 4;
+if( x <= douba(i+2) )
+       i += 2;
+if( x >= douba(1) )
+       i = -1;
+i += 1;
+
+
+/* Find (x - A[i])/A[i]
+ * in order to compute log(x/A[i]):
+ *
+ * log(x) = log( a x/a ) = log(a) + log(x/a)
+ *
+ * log(x/a) = log(1+v),  v = x/a - 1 = (x-a)/a
+ */
+x -= douba(i);
+x -= doubb(i/2);
+x /= douba(i);
+
+
+/* rational approximation for log(1+v):
+ *
+ * log(1+v)  =  v  -  v**2/2  +  v**3 P(v) / Q(v)
+ */
+z = x*x;
+w = x * ( z * __polevll( x, P, 3 ) / __p1evll( x, Q, 3 ) );
+w = w - ldexpl( z, -1 );   /*  w - 0.5 * z  */
+
+/* Convert to base 2 logarithm:
+ * multiply by log2(e) = 1 + LOG2EA
+ */
+z = LOG2EA * w;
+z += w;
+z += LOG2EA * x;
+z += x;
+
+/* Compute exponent term of the base 2 logarithm. */
+w = -i;
+w = ldexpl( w, -LNXT );        /* divide by NXT */
+w += e;
+/* Now base 2 log of x is w + z. */
+
+/* Multiply base 2 log by y, in extended precision. */
+
+/* separate y into large part ya
+ * and small part yb less than 1/NXT
+ */
+ya = reducl(y);
+yb = y - ya;
+
+/* (w+z)(ya+yb)
+ * = w*ya + w*yb + z*y
+ */
+F = z * y  +  w * yb;
+Fa = reducl(F);
+Fb = F - Fa;
+
+G = Fa + w * ya;
+Ga = reducl(G);
+Gb = G - Ga;
+
+H = Fb + Gb;
+Ha = reducl(H);
+w = ldexpl( Ga+Ha, LNXT );
+
+/* Test the power of 2 for overflow */
+if( w > MEXP )
+       return (huge * huge);           /* overflow */
+
+if( w < MNEXP )
+       return (twom10000 * twom10000); /* underflow */
+
+e = w;
+Hb = H - Ha;
+
+if( Hb > 0.0L )
+       {
+       e += 1;
+       Hb -= (1.0L/NXT);  /*0.0625L;*/
+       }
+
+/* Now the product y * log2(x)  =  Hb + e/NXT.
+ *
+ * Compute base 2 exponential of Hb,
+ * where -0.0625 <= Hb <= 0.
+ */
+z = Hb * __polevll( Hb, R, 6 );  /*    z  =  2**Hb - 1    */
+
+/* Express e/NXT as an integer plus a negative number of (1/NXT)ths.
+ * Find lookup table entry for the fractional power of 2.
+ */
+if( e < 0 )
+       i = 0;
+else
+       i = 1;
+i = e/NXT + i;
+e = NXT*i - e;
+w = douba( e );
+z = w * z;      /*    2**-e * ( 1 + (2**Hb-1) )    */
+z = z + w;
+z = ldexpl( z, i );  /* multiply by integer power of 2 */
+
+if( nflg )
+       {
+/* For negative x,
+ * find out if the integer exponent
+ * is odd or even.
+ */
+       w = ldexpl( y, -1 );
+       w = floorl(w);
+       w = ldexpl( w, 1 );
+       if( w != y )
+               z = -z; /* odd exponent */
+       }
+
+return( z );
+}
+
+
+/* Find a multiple of 1/NXT that is within 1/NXT of x. */
+static long double
+reducl(long double x)
+{
+long double t;
+
+t = ldexpl( x, LNXT );
+t = floorl( t );
+t = ldexpl( t, -LNXT );
+return(t);
+}
+
+/*                                                     powil.c
+ *
+ *     Real raised to integer power, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, powil();
+ * int n;
+ *
+ * y = powil( x, n );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns argument x raised to the nth power.
+ * The routine efficiently decomposes n as a sum of powers of
+ * two. The desired power is a product of two-to-the-kth
+ * powers of x.  Thus to compute the 32767 power of x requires
+ * 28 multiplications instead of 32767 multiplications.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *
+ *                      Relative error:
+ * arithmetic   x domain   n domain  # trials      peak         rms
+ *    IEEE     .001,1000  -1022,1023  50000       4.3e-17     7.8e-18
+ *    IEEE        1,2     -1022,1023  20000       3.9e-17     7.6e-18
+ *    IEEE     .99,1.01     0,8700    10000       3.6e-16     7.2e-17
+ *
+ * Returns MAXNUM on overflow, zero on underflow.
+ *
+ */
+
+static long double
+powil(long double x, int nn)
+{
+long double ww, y;
+long double s;
+int n, e, sign, asign, lx;
+
+if( x == 0.0L )
+       {
+       if( nn == 0 )
+               return( 1.0L );
+       else if( nn < 0 )
+               return( LDBL_MAX );
+       else
+               return( 0.0L );
+       }
+
+if( nn == 0 )
+       return( 1.0L );
+
+
+if( x < 0.0L )
+       {
+       asign = -1;
+       x = -x;
+       }
+else
+       asign = 0;
+
+
+if( nn < 0 )
+       {
+       sign = -1;
+       n = -nn;
+       }
+else
+       {
+       sign = 1;
+       n = nn;
+       }
+
+/* Overflow detection */
+
+/* Calculate approximate logarithm of answer */
+s = x;
+s = frexpl( s, &lx );
+e = (lx - 1)*n;
+if( (e == 0) || (e > 64) || (e < -64) )
+       {
+       s = (s - 7.0710678118654752e-1L) / (s +  7.0710678118654752e-1L);
+       s = (2.9142135623730950L * s - 0.5L + lx) * nn * LOGE2L;
+       }
+else
+       {
+       s = LOGE2L * e;
+       }
+
+if( s > MAXLOGL )
+       return (huge * huge);           /* overflow */
+
+if( s < MINLOGL )
+       return (twom10000 * twom10000); /* underflow */
+/* Handle tiny denormal answer, but with less accuracy
+ * since roundoff error in 1.0/x will be amplified.
+ * The precise demarcation should be the gradual underflow threshold.
+ */
+if( s < (-MAXLOGL+2.0L) )
+       {
+       x = 1.0L/x;
+       sign = -sign;
+       }
+
+/* First bit of the power */
+if( n & 1 )
+       y = x;
+               
+else
+       {
+       y = 1.0L;
+       asign = 0;
+       }
+
+ww = x;
+n >>= 1;
+while( n )
+       {
+       ww = ww * ww;   /* arg to the 2-to-the-kth power */
+       if( n & 1 )     /* if that bit is set, then include in product */
+               y *= ww;
+       n >>= 1;
+       }
+
+if( asign )
+       y = -y; /* odd power of negative number */
+if( sign < 0 )
+       y = 1.0L/y;
+return(y);
+}
diff --git a/ld80/e_rem_pio2l.h b/ld80/e_rem_pio2l.h
new file mode 100644 (file)
index 0000000..c44ad48
--- /dev/null
@@ -0,0 +1,152 @@
+/* From: @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * Optimized by Bruce D. Evans.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/e_rem_pio2l.h,v 1.3 2011/06/18 13:56:33 benl Exp $");
+
+/* ld80 version of __ieee754_rem_pio2l(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+
+/*
+ * invpio2:  64 bits of 2/pi
+ * pio2_1:   first  39 bits of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 39 bits of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  39 bits of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+pio2_1  =  1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */
+pio2_2  = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */
+pio2_3  =  6.36831716351370313614e-25; /*  0x18a2e037074000.0p-133 */
+
+#if defined(__amd64__) || defined(__i386__)
+/* Long double constants are slow on these arches, and broken on i386. */
+static const volatile double
+invpio2hi =  6.3661977236758138e-01,   /*  0x145f306dc9c883.0p-53 */
+invpio2lo = -3.9356538861223811e-17,   /* -0x16b00000000000.0p-107 */
+pio2_1thi = -1.0746346554971943e-12,   /* -0x12e7b9676733af.0p-92 */
+pio2_1tlo =  8.8451028997905949e-29,   /*  0x1c080000000000.0p-146 */
+pio2_2thi =  6.3683171635109499e-25,   /*  0x18a2e03707344a.0p-133 */
+pio2_2tlo =  2.3183081793789774e-41,   /*  0x10280000000000.0p-187 */
+pio2_3thi = -2.7529965190440717e-37,   /* -0x176b7ed8fbbacc.0p-174 */
+pio2_3tlo = -4.2006647512740502e-54;   /* -0x19c00000000000.0p-230 */
+#define        invpio2 ((long double)invpio2hi + invpio2lo)
+#define        pio2_1t ((long double)pio2_1thi + pio2_1tlo)
+#define        pio2_2t ((long double)pio2_2thi + pio2_2tlo)
+#define        pio2_3t ((long double)pio2_3thi + pio2_3tlo)
+#else
+static const long double
+invpio2 =  6.36619772367581343076e-01L,        /*  0xa2f9836e4e44152a.0p-64 */
+pio2_1t = -1.07463465549719416346e-12L,        /* -0x973dcb3b399d747f.0p-103 */
+pio2_2t =  6.36831716351095013979e-25L,        /*  0xc51701b839a25205.0p-144 */
+pio2_3t = -2.75299651904407171810e-37L;        /* -0xbb5bf6c7ddd660ce.0p-185 */
+#endif
+
+//VBS
+//static inline __always_inline int
+//__ieee754_rem_pio2l(long double x, long double *y)
+
+static inline int
+__ieee754_rem_pio2l(long double x, long double *y)
+{
+       union IEEEl2bits u,u1;
+       long double z,w,t,r,fn;
+       double tx[3],ty[2];
+       int e0,ex,i,j,nx,n;
+       int16_t expsign;
+
+       u.e = x;
+       expsign = u.xbits.expsign;
+       ex = expsign & 0x7fff;
+       if (ex < BIAS + 25 || (ex == BIAS + 25 && u.bits.manh < 0xc90fdaa2)) {
+           /* |x| ~< 2^25*(pi/2), medium size */
+           /* Use a specialized rint() to get fn.  Assume round-to-nearest. */
+           fn = x*invpio2+0x1.8p63;
+           fn = fn-0x1.8p63;
+#ifdef HAVE_EFFICIENT_IRINT
+           n  = irint(fn);
+#else
+           n  = fn;
+#endif
+           r  = x-fn*pio2_1;
+           w  = fn*pio2_1t;    /* 1st round good to 102 bit */
+           {
+               union IEEEl2bits u2;
+               int ex1;
+               j  = ex;
+               y[0] = r-w;
+               u2.e = y[0];
+               ex1 = u2.xbits.expsign & 0x7fff;
+               i = j-ex1;
+               if(i>22) {  /* 2nd iteration needed, good to 141 */
+                   t  = r;
+                   w  = fn*pio2_2;
+                   r  = t-w;
+                   w  = fn*pio2_2t-((t-r)-w);
+                   y[0] = r-w;
+                   u2.e = y[0];
+                   ex1 = u2.xbits.expsign & 0x7fff;
+                   i = j-ex1;
+                   if(i>61) {  /* 3rd iteration need, 180 bits acc */
+                       t  = r; /* will cover all possible cases */
+                       w  = fn*pio2_3;
+                       r  = t-w;
+                       w  = fn*pio2_3t-((t-r)-w);
+                       y[0] = r-w;
+                   }
+               }
+           }
+           y[1] = (r-y[0])-w;
+           return n;
+       }
+    /*
+     * all other (large) arguments
+     */
+       if(ex==0x7fff) {                /* x is inf or NaN */
+           y[0]=y[1]=x-x; return 0;
+       }
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+       u1.e = x;
+       e0 = ex - BIAS - 23;            /* e0 = ilogb(|x|)-23; */
+       u1.xbits.expsign = ex - e0;
+       z = u1.e;
+       for(i=0;i<2;i++) {
+               tx[i] = (double)((int32_t)(z));
+               z     = (z-tx[i])*two24;
+       }
+       tx[2] = z;
+       nx = 3;
+       while(tx[nx-1]==zero) nx--;     /* skip zero term */
+       n  =  __kernel_rem_pio2(tx,ty,e0,nx,2);
+       r = (long double)ty[0] + ty[1];
+       w = ty[1] - (r - ty[0]);
+       if(expsign<0) {y[0] = -r; y[1] = -w; return -n;}
+       y[0] = r; y[1] = w; return n;
+}
diff --git a/ld80/e_sinhl.c b/ld80/e_sinhl.c
new file mode 100644 (file)
index 0000000..cb45204
--- /dev/null
@@ -0,0 +1,76 @@
+/* @(#)e_sinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* sinhl(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *     1. Replace x by |x| (sinhl(-x) = -sinhl(x)).
+ *     2.
+ *                                                  E + E/(E+1)
+ *         0        <= x <= 25     :  sinhl(x) := --------------, E=expm1l(x)
+ *                                                      2
+ *
+ *         25       <= x <= lnovft :  sinhl(x) := expl(x)/2
+ *         lnovft   <= x <= ln2ovft:  sinhl(x) := expl(x/2)/2 * expl(x/2)
+ *         ln2ovft  <  x           :  sinhl(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ *     sinhl(x) is |x| if x is +INF, -INF, or NaN.
+ *     only sinhl(0)=0 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0, shuge = 1.0e4931L;
+
+long double
+sinhl(long double x)
+{
+       long double t,w,h;
+       u_int32_t jx,ix,i0,i1;
+
+    /* Words of |x|. */
+       GET_LDOUBLE_WORDS(jx,i0,i1,x);
+       ix = jx&0x7fff;
+
+    /* x is INF or NaN */
+       if(ix==0x7fff) return x+x;
+
+       h = 0.5;
+       if (jx & 0x8000) h = -h;
+    /* |x| in [0,25], return sign(x)*0.5*(E+E/(E+1))) */
+       if (ix < 0x4003 || (ix == 0x4003 && i0 <= 0xc8000000)) { /* |x|<25 */
+           if (ix<0x3fdf)               /* |x|<2**-32 */
+               if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+           t = expm1l(fabsl(x));
+           if(ix<0x3fff) return h*(2.0*t-t*t/(t+one));
+           return h*(t+t/(t+one));
+       }
+
+    /* |x| in [25, log(maxdouble)] return 0.5*exp(|x|) */
+       if (ix < 0x400c || (ix == 0x400c && i0 < 0xb17217f7))
+               return h*expl(fabsl(x));
+
+    /* |x| in [log(maxdouble), overflowthreshold] */
+       if (ix<0x400c || (ix == 0x400c && (i0 < 0xb174ddc0
+                                          || (i0 == 0xb174ddc0
+                                              && i1 <= 0x31aec0ea)))) {
+           w = expl(0.5*fabsl(x));
+           t = h*w;
+           return t*w;
+       }
+
+    /* |x| > overflowthreshold, sinhl(x) overflow */
+       return x*shuge;
+}
diff --git a/ld80/e_tgammal.c b/ld80/e_tgammal.c
new file mode 100644 (file)
index 0000000..036061c
--- /dev/null
@@ -0,0 +1,313 @@
+/*     $OpenBSD: e_tgammal.c,v 1.4 2013/11/12 20:35:19 martynas Exp $  */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     tgammal.c
+ *
+ *     Gamma function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, tgammal();
+ *
+ * y = tgammal( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns gamma function of the argument.  The result is correctly
+ * signed.  This variable is also filled in by the logarithmic gamma
+ * function lgamma().
+ *
+ * Arguments |x| <= 13 are reduced by recurrence and the function
+ * approximated by a rational function of degree 7/8 in the
+ * interval (2,3).  Large arguments are handled by Stirling's
+ * formula. Large negative arguments are made positive using
+ * a reflection formula.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE     -40,+40      10000       3.6e-19     7.9e-20
+ *    IEEE    -1755,+1755   10000       4.8e-18     6.5e-19
+ *
+ * Accuracy for large arguments is dominated by error in powl().
+ *
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+tgamma(x+2)  = tgamma(x+2) P(x)/Q(x)
+0 <= x <= 1
+Relative error
+n=7, d=8
+Peak error =  1.83e-20
+Relative error spread =  8.4e-23
+*/
+
+static long double P[8] = {
+ 4.212760487471622013093E-5L,
+ 4.542931960608009155600E-4L,
+ 4.092666828394035500949E-3L,
+ 2.385363243461108252554E-2L,
+ 1.113062816019361559013E-1L,
+ 3.629515436640239168939E-1L,
+ 8.378004301573126728826E-1L,
+ 1.000000000000000000009E0L,
+};
+static long double Q[9] = {
+-1.397148517476170440917E-5L,
+ 2.346584059160635244282E-4L,
+-1.237799246653152231188E-3L,
+-7.955933682494738320586E-4L,
+ 2.773706565840072979165E-2L,
+-4.633887671244534213831E-2L,
+-2.243510905670329164562E-1L,
+ 4.150160950588455434583E-1L,
+ 9.999999999999999999908E-1L,
+};
+
+/*
+static long double P[] = {
+-3.01525602666895735709e0L,
+-3.25157411956062339893e1L,
+-2.92929976820724030353e2L,
+-1.70730828800510297666e3L,
+-7.96667499622741999770e3L,
+-2.59780216007146401957e4L,
+-5.99650230220855581642e4L,
+-7.15743521530849602425e4L
+};
+static long double Q[] = {
+ 1.00000000000000000000e0L,
+-1.67955233807178858919e1L,
+ 8.85946791747759881659e1L,
+ 5.69440799097468430177e1L,
+-1.98526250512761318471e3L,
+ 3.31667508019495079814e3L,
+ 1.60577839621734713377e4L,
+-2.97045081369399940529e4L,
+-7.15743521530849602412e4L
+};
+*/
+#define MAXGAML 1755.455L
+/*static const long double LOGPI = 1.14472988584940017414L;*/
+
+/* Stirling's formula for the gamma function
+tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x))
+z(x) = x
+13 <= x <= 1024
+Relative error
+n=8, d=0
+Peak error =  9.44e-21
+Relative error spread =  8.8e-4
+*/
+
+static long double STIR[9] = {
+ 7.147391378143610789273E-4L,
+-2.363848809501759061727E-5L,
+-5.950237554056330156018E-4L,
+ 6.989332260623193171870E-5L,
+ 7.840334842744753003862E-4L,
+-2.294719747873185405699E-4L,
+-2.681327161876304418288E-3L,
+ 3.472222222230075327854E-3L,
+ 8.333333333333331800504E-2L,
+};
+
+#define MAXSTIR 1024.0L
+static const long double SQTPI = 2.50662827463100050242E0L;
+
+/* 1/tgamma(x) = z P(z)
+ * z(x) = 1/x
+ * 0 < x < 0.03125
+ * Peak relative error 4.2e-23
+ */
+
+static long double S[9] = {
+-1.193945051381510095614E-3L,
+ 7.220599478036909672331E-3L,
+-9.622023360406271645744E-3L,
+-4.219773360705915470089E-2L,
+ 1.665386113720805206758E-1L,
+-4.200263503403344054473E-2L,
+-6.558780715202540684668E-1L,
+ 5.772156649015328608253E-1L,
+ 1.000000000000000000000E0L,
+};
+
+/* 1/tgamma(-x) = z P(z)
+ * z(x) = 1/x
+ * 0 < x < 0.03125
+ * Peak relative error 5.16e-23
+ * Relative error spread =  2.5e-24
+ */
+
+static long double SN[9] = {
+ 1.133374167243894382010E-3L,
+ 7.220837261893170325704E-3L,
+ 9.621911155035976733706E-3L,
+-4.219773343731191721664E-2L,
+-1.665386113944413519335E-1L,
+-4.200263503402112910504E-2L,
+ 6.558780715202536547116E-1L,
+ 5.772156649015328608727E-1L,
+-1.000000000000000000000E0L,
+};
+
+static const long double PIL = 3.1415926535897932384626L;
+
+static long double stirf ( long double );
+
+/* Gamma function computed by Stirling's formula.
+ */
+static long double stirf(long double x)
+{
+long double y, w, v;
+
+w = 1.0L/x;
+/* For large x, use rational coefficients from the analytical expansion.  */
+if( x > 1024.0L )
+       w = (((((6.97281375836585777429E-5L * w
+               + 7.84039221720066627474E-4L) * w
+               - 2.29472093621399176955E-4L) * w
+               - 2.68132716049382716049E-3L) * w
+               + 3.47222222222222222222E-3L) * w
+               + 8.33333333333333333333E-2L) * w
+               + 1.0L;
+else
+       w = 1.0L + w * __polevll( w, STIR, 8 );
+y = expl(x);
+if( x > MAXSTIR )
+       { /* Avoid overflow in pow() */
+       v = powl( x, 0.5L * x - 0.25L );
+       y = v * (v / y);
+       }
+else
+       {
+       y = powl( x, x - 0.5L ) / y;
+       }
+y = SQTPI * y * w;
+return( y );
+}
+
+long double
+tgammal(long double x)
+{
+long double p, q, z;
+int i;
+
+if( isnan(x) )
+       return(NAN);
+if(x == INFINITY)
+       return(INFINITY);
+if(x == -INFINITY)
+       return(x - x);
+if( x == 0.0L )
+       return( 1.0L / x );
+q = fabsl(x);
+
+if( q > 13.0L )
+       {
+       int sign = 1;
+       if( q > MAXGAML )
+               goto goverf;
+       if( x < 0.0L )
+               {
+               p = floorl(q);
+               if( p == q )
+                       return (x - x) / (x - x);
+               i = p;
+               if( (i & 1) == 0 )
+                       sign = -1;
+               z = q - p;
+               if( z > 0.5L )
+                       {
+                       p += 1.0L;
+                       z = q - p;
+                       }
+               z = q * sinl( PIL * z );
+               z = fabsl(z) * stirf(q);
+               if( z <= PIL/LDBL_MAX )
+                       {
+goverf:
+                       return( sign * INFINITY);
+                       }
+               z = PIL/z;
+               }
+       else
+               {
+               z = stirf(x);
+               }
+       return( sign * z );
+       }
+
+z = 1.0L;
+while( x >= 3.0L )
+       {
+       x -= 1.0L;
+       z *= x;
+       }
+
+while( x < -0.03125L )
+       {
+       z /= x;
+       x += 1.0L;
+       }
+
+if( x <= 0.03125L )
+       goto small;
+
+while( x < 2.0L )
+       {
+       z /= x;
+       x += 1.0L;
+       }
+
+if( x == 2.0L )
+       return(z);
+
+x -= 2.0L;
+p = __polevll( x, P, 7 );
+q = __polevll( x, Q, 8 );
+z = z * p / q;
+return z;
+
+small:
+if( x == 0.0L )
+       return (x - x) / (x - x);
+else
+       {
+       if( x < 0.0L )
+               {
+               x = -x;
+               q = z / (x * __polevll( x, SN, 8 ));
+               }
+       else
+               q = z / (x * __polevll( x, S, 8 ));
+       }
+return q;
+}
diff --git a/ld80/invtrig.c b/ld80/invtrig.c
new file mode 100644 (file)
index 0000000..15692ad
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/invtrig.c,v 1.1 2008/07/31 22:41:26 das Exp $");
+
+#include "ld80/invtrig.h"
+
+/*
+ * asinl() and acosl()
+ */
+const long double
+pS0 =  1.66666666666666666631e-01L,
+pS1 = -4.16313987993683104320e-01L,
+pS2 =  3.69068046323246813704e-01L,
+pS3 = -1.36213932016738603108e-01L,
+pS4 =  1.78324189708471965733e-02L,
+pS5 = -2.19216428382605211588e-04L,
+pS6 = -7.10526623669075243183e-06L,
+qS1 = -2.94788392796209867269e+00L,
+qS2 =  3.27309890266528636716e+00L,
+qS3 = -1.68285799854822427013e+00L,
+qS4 =  3.90699412641738801874e-01L,
+qS5 = -3.14365703596053263322e-02L;
+
+/*
+ * atanl()
+ */
+const long double atanhi[] = {
+        4.63647609000806116202e-01L,
+        7.85398163397448309628e-01L,
+        9.82793723247329067960e-01L,
+        1.57079632679489661926e+00L,
+};
+
+const long double atanlo[] = {
+        1.18469937025062860669e-20L,
+       -1.25413940316708300586e-20L,
+        2.55232234165405176172e-20L,
+       -2.50827880633416601173e-20L,
+};
+
+const long double aT[] = {
+        3.33333333333333333017e-01L,
+       -1.99999999999999632011e-01L,
+        1.42857142857046531280e-01L,
+       -1.11111111100562372733e-01L,
+        9.09090902935647302252e-02L,
+       -7.69230552476207730353e-02L,
+        6.66661718042406260546e-02L,
+       -5.88158892835030888692e-02L,
+        5.25499891539726639379e-02L,
+       -4.70119845393155721494e-02L,
+        4.03539201366454414072e-02L,
+       -2.91303858419364158725e-02L,
+        1.24822046299269234080e-02L,
+};
+
+const long double pi_lo = -5.01655761266833202345e-20L;
diff --git a/ld80/invtrig.h b/ld80/invtrig.h
new file mode 100644 (file)
index 0000000..3d543e9
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2008 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.
+ *
+ * $FreeBSD: src/lib/msun/ld80/invtrig.h,v 1.2 2008/08/02 03:56:22 das Exp $
+ */
+
+#include <float.h>
+
+#include <openlibm_math.h>
+
+#define        BIAS            (LDBL_MAX_EXP - 1)
+#define        MANH_SIZE       LDBL_MANH_SIZE
+
+/* Approximation thresholds. */
+#define        ASIN_LINEAR     (BIAS - 32)     /* 2**-32 */
+#define        ACOS_CONST      (BIAS - 65)     /* 2**-65 */
+#define        ATAN_CONST      (BIAS + 65)     /* 2**65 */
+#define        ATAN_LINEAR     (BIAS - 32)     /* 2**-32 */
+
+/* 0.95 */
+#define        THRESH  ((0xe666666666666666ULL>>(64-(MANH_SIZE-1)))|LDBL_NBIT)
+
+/* Constants shared by the long double inverse trig functions. */
+#define        pS0     _ItL_pS0
+#define        pS1     _ItL_pS1
+#define        pS2     _ItL_pS2
+#define        pS3     _ItL_pS3
+#define        pS4     _ItL_pS4
+#define        pS5     _ItL_pS5
+#define        pS6     _ItL_pS6
+#define        qS1     _ItL_qS1
+#define        qS2     _ItL_qS2
+#define        qS3     _ItL_qS3
+#define        qS4     _ItL_qS4
+#define        qS5     _ItL_qS5
+#define        atanhi  _ItL_atanhi
+#define        atanlo  _ItL_atanlo
+#define        aT      _ItL_aT
+#define        pi_lo   _ItL_pi_lo
+
+#define        pio2_hi atanhi[3]
+#define        pio2_lo atanlo[3]
+#define        pio4_hi atanhi[1]
+
+#ifdef STRUCT_DECLS
+typedef struct longdouble {
+       uint64_t mant;
+       uint16_t expsign;
+} LONGDOUBLE;
+#else
+typedef long double LONGDOUBLE;
+#endif
+
+extern const LONGDOUBLE pS0, pS1, pS2, pS3, pS4, pS5, pS6;
+extern const LONGDOUBLE qS1, qS2, qS3, qS4, qS5;
+extern const LONGDOUBLE atanhi[], atanlo[], aT[];
+extern const LONGDOUBLE pi_lo;
+
+#ifndef STRUCT_DECLS
+
+static inline long double
+P(long double x)
+{
+
+       return (x * (pS0 + x * (pS1 + x * (pS2 + x * (pS3 + x * \
+               (pS4 + x * (pS5 + x * pS6)))))));
+}
+
+static inline long double
+Q(long double x)
+{
+
+       return (1.0 + x * (qS1 + x * (qS2 + x * (qS3 + x * (qS4 + x * qS5)))));
+}
+
+static inline long double
+T_even(long double x)
+{
+
+       return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * \
+               (aT[8] + x * (aT[10] + x * aT[12]))))));
+}
+
+static inline long double
+T_odd(long double x)
+{
+
+       return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * \
+               (aT[9] + x * aT[11])))));
+}
+
+#endif
diff --git a/ld80/k_cosl.c b/ld80/k_cosl.c
new file mode 100644 (file)
index 0000000..403da9d
--- /dev/null
@@ -0,0 +1,78 @@
+/* From: @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_cosl.c,v 1.1 2008/02/17 07:32:14 das Exp $");
+
+/*
+ * ld80 version of k_cos.c.  See ../src/k_cos.c for most comments.
+ */
+
+#include "math_private.h"
+
+/*
+ * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]:
+ * |cos(x) - c(x)| < 2**-75.1
+ *
+ * The coefficients of c(x) were generated by a pari-gp script using
+ * a Remez algorithm that searches for the best higher coefficients
+ * after rounding leading coefficients to a specified precision.
+ *
+ * Simpler methods like Chebyshev or basic Remez barely suffice for
+ * cos() in 64-bit precision, because we want the coefficient of x^2
+ * to be precisely -0.5 so that multiplying by it is exact, and plain
+ * rounding of the coefficients of a good polynomial approximation only
+ * gives this up to about 64-bit precision.  Plain rounding also gives
+ * a mediocre approximation for the coefficient of x^4, but a rounding
+ * error of 0.5 ulps for this coefficient would only contribute ~0.01
+ * ulps to the final error, so this is unimportant.  Rounding errors in
+ * higher coefficients are even less important.
+ *
+ * In fact, coefficients above the x^4 one only need to have 53-bit
+ * precision, and this is more efficient.  We get this optimization
+ * almost for free from the complications needed to search for the best
+ * higher coefficients.
+ */
+static const double
+one = 1.0;
+
+#if defined(__amd64__) || defined(__i386__)
+/* Long double constants are slow on these arches, and broken on i386. */
+static const volatile double
+C1hi = 0.041666666666666664,           /*  0x15555555555555.0p-57 */
+C1lo = 2.2598839032744733e-18;         /*  0x14d80000000000.0p-111 */
+#define        C1      ((long double)C1hi + C1lo)
+#else
+static const long double
+C1 =  0.0416666666666666666136L;       /*  0xaaaaaaaaaaaaaa9b.0p-68 */
+#endif
+
+static const double
+C2 = -0.0013888888888888874,           /* -0x16c16c16c16c10.0p-62 */
+C3 =  0.000024801587301571716,         /*  0x1a01a01a018e22.0p-68 */
+C4 = -0.00000027557319215507120,       /* -0x127e4fb7602f22.0p-74 */
+C5 =  0.0000000020876754400407278,     /*  0x11eed8caaeccf1.0p-81 */
+C6 = -1.1470297442401303e-11,          /* -0x19393412bd1529.0p-89 */
+C7 =  4.7383039476436467e-14;          /*  0x1aac9d9af5c43e.0p-97 */
+
+long double
+__kernel_cosl(long double x, long double y)
+{
+       long double hz,z,r,w;
+
+       z  = x*x;
+       r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*C7))))));
+       hz = 0.5*z;
+       w  = one-hz;
+       return w + (((one-w)-hz) + (z*r-x*y));
+}
diff --git a/ld80/k_sinl.c b/ld80/k_sinl.c
new file mode 100644 (file)
index 0000000..792baf6
--- /dev/null
@@ -0,0 +1,62 @@
+/* From: @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_sinl.c,v 1.1 2008/02/17 07:32:14 das Exp $");
+
+/*
+ * ld80 version of k_sin.c.  See ../src/k_sin.c for most comments.
+ */
+
+#include "math_private.h"
+
+static const double
+half =  0.5;
+
+/*
+ * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22]
+ * |sin(x)/x - s(x)| < 2**-72.1
+ *
+ * See ../ld80/k_cosl.c for more details about the polynomial.
+ */
+#if defined(__amd64__) || defined(__i386__)
+/* Long double constants are slow on these arches, and broken on i386. */
+static const volatile double
+S1hi = -0.16666666666666666,           /* -0x15555555555555.0p-55 */
+S1lo = -9.2563760475949941e-18;                /* -0x15580000000000.0p-109 */
+#define        S1      ((long double)S1hi + S1lo)
+#else
+static const long double
+S1 = -0.166666666666666666671L;                /* -0xaaaaaaaaaaaaaaab.0p-66 */
+#endif
+
+static const double
+S2 =  0.0083333333333333332,           /*  0x11111111111111.0p-59 */
+S3 = -0.00019841269841269427,          /* -0x1a01a01a019f81.0p-65 */
+S4 =  0.0000027557319223597490,                /*  0x171de3a55560f7.0p-71 */
+S5 = -0.000000025052108218074604,      /* -0x1ae64564f16cad.0p-78 */
+S6 =  1.6059006598854211e-10,          /*  0x161242b90243b5.0p-85 */
+S7 = -7.6429779983024564e-13,          /* -0x1ae42ebd1b2e00.0p-93 */
+S8 =  2.6174587166648325e-15;          /*  0x179372ea0b3f64.0p-101 */
+
+long double
+__kernel_sinl(long double x, long double y, int iy)
+{
+       long double z,r,v;
+
+       z       =  x*x;
+       v       =  z*x;
+       r       =  S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*S8)))));
+       if(iy==0) return x+v*(S1+z*r);
+       else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/ld80/k_tanl.c b/ld80/k_tanl.c
new file mode 100644 (file)
index 0000000..691c952
--- /dev/null
@@ -0,0 +1,125 @@
+/* From: @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_tanl.c,v 1.3 2008/02/18 15:39:52 bde Exp $");
+
+/*
+ * ld80 version of k_tan.c.  See ../src/k_tan.c for most comments.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22]
+ * |tan(x)/x - t(x)| < 2**-71.9
+ *
+ * See k_cosl.c for more details about the polynomial.
+ */
+#if defined(__amd64__) || defined(__i386__)
+/* Long double constants are slow on these arches, and broken on i386. */
+static const volatile double
+T3hi =  0.33333333333333331,           /*  0x15555555555555.0p-54 */
+T3lo =  1.8350121769317163e-17,                /*  0x15280000000000.0p-108 */
+T5hi =  0.13333333333333336,           /*  0x11111111111112.0p-55 */
+T5lo =  1.3051083651294260e-17,                /*  0x1e180000000000.0p-109 */
+T7hi =  0.053968253968250494,          /*  0x1ba1ba1ba1b827.0p-57 */
+T7lo =  3.1509625637859973e-18,                /*  0x1d100000000000.0p-111 */
+pio4_hi =  0.78539816339744828,                /*  0x1921fb54442d18.0p-53 */
+pio4_lo =  3.0628711372715500e-17,     /*  0x11a80000000000.0p-107 */
+pio4lo_hi = -1.2541394031670831e-20,   /* -0x1d9cceba3f91f2.0p-119 */
+pio4lo_lo =  6.1493048227390915e-37;   /*  0x1a280000000000.0p-173 */
+#define        T3      ((long double)T3hi + T3lo)
+#define        T5      ((long double)T5hi + T5lo)
+#define        T7      ((long double)T7hi + T7lo)
+#define        pio4    ((long double)pio4_hi + pio4_lo)
+#define        pio4lo  ((long double)pio4lo_hi + pio4lo_lo)
+#else
+static const long double
+T3 =   0.333333333333333333180L,       /*  0xaaaaaaaaaaaaaaa5.0p-65 */
+T5 =   0.133333333333333372290L,       /*  0x88888888888893c3.0p-66 */
+T7 =   0.0539682539682504975744L,      /*  0xdd0dd0dd0dc13ba2.0p-68 */
+pio4 = 0.785398163397448309628L,       /*  0xc90fdaa22168c235.0p-64 */
+pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */
+#endif
+
+static const double
+T9  =  0.021869488536312216,           /*  0x1664f4882cc1c2.0p-58 */
+T11 =  0.0088632355256619590,          /*  0x1226e355c17612.0p-59 */
+T13 =  0.0035921281113786528,          /*  0x1d6d3d185d7ff8.0p-61 */
+T15 =  0.0014558334756312418,          /*  0x17da354aa3f96b.0p-62 */
+T17 =  0.00059003538700862256,         /*  0x13559358685b83.0p-63 */
+T19 =  0.00023907843576635544,         /*  0x1f56242026b5be.0p-65 */
+T21 =  0.000097154625656538905,                /*  0x1977efc26806f4.0p-66 */
+T23 =  0.000038440165747303162,                /*  0x14275a09b3ceac.0p-67 */
+T25 =  0.000018082171885432524,                /*  0x12f5e563e5487e.0p-68 */
+T27 =  0.0000024196006108814377,       /*  0x144c0d80cc6896.0p-71 */
+T29 =  0.0000078293456938132840,       /*  0x106b59141a6cb3.0p-69 */
+T31 = -0.0000032609076735050182,       /* -0x1b5abef3ba4b59.0p-71 */
+T33 =  0.0000023261313142559411;       /*  0x13835436c0c87f.0p-71 */
+
+long double
+__kernel_tanl(long double x, long double y, int iy) {
+       long double z, r, v, w, s;
+       long double osign;
+       int i;
+
+       iy = (iy == 1 ? -1 : 1);        /* XXX recover original interface */
+       osign = (x >= 0 ? 1.0 : -1.0);  /* XXX slow, probably wrong for -0 */
+       if (fabsl(x) >= 0.67434) {
+               if (x < 0) {
+                       x = -x;
+                       y = -y;
+               }
+               z = pio4 - x;
+               w = pio4lo - y;
+               x = z + w;
+               y = 0.0;
+               i = 1;
+       } else
+               i = 0;
+       z = x * x;
+       w = z * z;
+       r = T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 +
+           w * (T25 + w * (T29 + w * T33))))));
+       v = z * (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 +
+           w * (T27 + w * T31))))));
+       s = z * x;
+       r = y + z * (s * (r + v) + y);
+       r += T3 * s;
+       w = x + r;
+       if (i == 1) {
+               v = (long double) iy;
+               return osign *
+                       (v - 2.0 * (x - (w * w / (w + v) - r)));
+       }
+       if (iy == 1)
+               return w;
+       else {
+               /*
+                * if allow error up to 2 ulp, simply return
+                * -1.0 / (x+r) here
+                */
+               /* compute -1.0 / (x+r) accurately */
+               long double a, t;
+               z = w;
+               z = z + 0x1p32 - 0x1p32;
+               v = r - (z - x);        /* z+v = r+x */
+               t = a = -1.0 / w;       /* a = -1.0/w */
+               t = t + 0x1p32 - 0x1p32;
+               s = 1.0 + t * z;
+               return t + a * (s + t * v);
+       }
+}
diff --git a/ld80/s_asinhl.c b/ld80/s_asinhl.c
new file mode 100644 (file)
index 0000000..0453a9c
--- /dev/null
@@ -0,0 +1,54 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinhl(x)
+ * Method :
+ *     Based on
+ *             asinhl(x) = signl(x) * logl [ |x| + sqrtl(x*x+1) ]
+ *     we have
+ *     asinhl(x) := x  if  1+x*x=1,
+ *               := signl(x)*(logl(x)+ln2)) for large |x|, else
+ *               := signl(x)*logl(2|x|+1/(|x|+sqrtl(x*x+1))) if|x|>2, else
+ *               := signl(x)*log1pl(|x| + x^2/(1 + sqrtl(1+x^2)))
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+one =  1.000000000000000000000e+00L, /* 0x3FFF, 0x00000000, 0x00000000 */
+ln2 =  6.931471805599453094287e-01L, /* 0x3FFE, 0xB17217F7, 0xD1CF79AC */
+huge=  1.000000000000000000e+4900L;
+
+long double
+asinhl(long double x)
+{
+       long double t,w;
+       int32_t hx,ix;
+       GET_LDOUBLE_EXP(hx,x);
+       ix = hx&0x7fff;
+       if(ix==0x7fff) return x+x;      /* x is inf or NaN */
+       if(ix< 0x3fde) {        /* |x|<2**-34 */
+           if(huge+x>one) return x;    /* return x inexact except 0 */
+       }
+       if(ix>0x4020) {         /* |x| > 2**34 */
+           w = logl(fabsl(x))+ln2;
+       } else if (ix>0x4000) { /* 2**34 > |x| > 2.0 */
+           t = fabsl(x);
+           w = logl(2.0*t+one/(sqrtl(x*x+one)+t));
+       } else {                /* 2.0 > |x| > 2**-28 */
+           t = x*x;
+           w =log1pl(fabsl(x)+t/(one+sqrtl(one+t)));
+       }
+       if(hx&0x8000) return -w; else return w;
+}
diff --git a/ld80/s_ceill.c b/ld80/s_ceill.c
new file mode 100644 (file)
index 0000000..9a3e805
--- /dev/null
@@ -0,0 +1,78 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceill(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double huge = 1.0e4930L;
+
+long double
+ceill(long double x)
+{
+       int32_t i1,jj0;
+       u_int32_t i,j,se,i0,sx;
+       GET_LDOUBLE_WORDS(se,i0,i1,x);
+       sx = (se>>15)&1;
+       jj0 = (se&0x7fff)-0x3fff;
+       if(jj0<31) {
+           if(jj0<0) { /* raise inexact if x != 0 */
+               if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(sx) {se=0x8000;i0=0;i1=0;}
+                   else if((i0|i1)!=0) { se=0x3fff;i0=0;i1=0;}
+               }
+           } else {
+               i = (0x7fffffff)>>jj0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(sx==0) {
+                       if (jj0>0 && (i0+(0x80000000>>jj0))>i0)
+                         i0+=0x80000000>>jj0;
+                       else
+                         {
+                           i = 0x7fffffff;
+                           ++se;
+                         }
+                   }
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (jj0>62) {
+           if(jj0==0x4000) return x+x; /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(jj0-31);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(sx==0) {
+                   if(jj0==31) i0+=1;
+                   else {
+                       j = i1 + (1<<(63-jj0));
+                       if(j<i1) i0+=1; /* got a carry */
+                       i1 = j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       SET_LDOUBLE_WORDS(x,se,i0,i1);
+       return x;
+}
diff --git a/ld80/s_erfl.c b/ld80/s_erfl.c
new file mode 100644 (file)
index 0000000..d352716
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ *                          x
+ *                   2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *                sqrt(pi) \|
+ *                          0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that
+ *             erf(-x) = -erf(x)
+ *             erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *     1. For |x| in [0, 0.84375]
+ *         erf(x)  = x + x*R(x^2)
+ *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+ *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+ *        Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *        and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *        is close to one. The interval is chosen because the fix
+ *        point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ *        near 0.6174), and by some experiment, 0.84375 is chosen to
+ *        guarantee the error is less than one ulp for erf.
+ *
+ *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *     erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+ *     erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+ *                       1+(c+P1(s)/Q1(s))    if x < 0
+ *        Remark: here we use the taylor series expansion at x=1.
+ *             erf(1+s) = erf(1) + s*Poly(s)
+ *                      = 0.845.. + P1(s)/Q1(s)
+ *        Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *
+ *      3. For x in [1.25,1/0.35(~2.857143)],
+ *     erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z))
+ *              z=1/x^2
+ *     erf(x)  = 1 - erfc(x)
+ *
+ *      4. For x in [1/0.35,107]
+ *     erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ *                     = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z))
+ *                             if -6.666<x<0
+ *                     = 2.0 - tiny            (if x <= -6.666)
+ *              z=1/x^2
+ *     erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6.666, else
+ *     erf(x)  = sign(x)*(1.0 - tiny)
+ *      Note1:
+ *        To compute exp(-x*x-0.5625+R/S), let s be a single
+ *        precision number and s := x; then
+ *             -x*x = -s*s + (s-x)*(s+x)
+ *             exp(-x*x-0.5626+R/S) =
+ *                     exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *        Here 4 and 5 make use of the asymptotic series
+ *                       exp(-x*x)
+ *             erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *                       x*sqrt(pi)
+ *
+ *      5. For inf > x >= 107
+ *     erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *     erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *                     = 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *     erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *     erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ *             erfc/erf(NaN) is NaN
+ */
+
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double
+tiny = 1e-4931L,
+  half = 0.5L,
+  one = 1.0L,
+  two = 2.0L,
+       /* c = (float)0.84506291151 */
+  erx = 0.845062911510467529296875L,
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+  /* 2/sqrt(pi) - 1 */
+  efx = 1.2837916709551257389615890312154517168810E-1L,
+  /* 8 * (2/sqrt(pi) - 1) */
+  efx8 = 1.0270333367641005911692712249723613735048E0L,
+
+  pp[6] = {
+    1.122751350964552113068262337278335028553E6L,
+    -2.808533301997696164408397079650699163276E6L,
+    -3.314325479115357458197119660818768924100E5L,
+    -6.848684465326256109712135497895525446398E4L,
+    -2.657817695110739185591505062971929859314E3L,
+    -1.655310302737837556654146291646499062882E2L,
+  },
+
+  qq[6] = {
+    8.745588372054466262548908189000448124232E6L,
+    3.746038264792471129367533128637019611485E6L,
+    7.066358783162407559861156173539693900031E5L,
+    7.448928604824620999413120955705448117056E4L,
+    4.511583986730994111992253980546131408924E3L,
+    1.368902937933296323345610240009071254014E2L,
+    /* 1.000000000000000000000000000000000000000E0 */
+  },
+
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+/* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x)
+   -0.15625 <= x <= +.25
+   Peak relative error 8.5e-22  */
+
+  pa[8] = {
+    -1.076952146179812072156734957705102256059E0L,
+     1.884814957770385593365179835059971587220E2L,
+    -5.339153975012804282890066622962070115606E1L,
+     4.435910679869176625928504532109635632618E1L,
+     1.683219516032328828278557309642929135179E1L,
+    -2.360236618396952560064259585299045804293E0L,
+     1.852230047861891953244413872297940938041E0L,
+     9.394994446747752308256773044667843200719E-2L,
+  },
+
+  qa[7] =  {
+    4.559263722294508998149925774781887811255E2L,
+    3.289248982200800575749795055149780689738E2L,
+    2.846070965875643009598627918383314457912E2L,
+    1.398715859064535039433275722017479994465E2L,
+    6.060190733759793706299079050985358190726E1L,
+    2.078695677795422351040502569964299664233E1L,
+    4.641271134150895940966798357442234498546E0L,
+    /* 1.000000000000000000000000000000000000000E0 */
+  },
+
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2))
+   1/2.85711669921875 < 1/x < 1/1.25
+   Peak relative error 3.1e-21  */
+
+    ra[] = {
+      1.363566591833846324191000679620738857234E-1L,
+      1.018203167219873573808450274314658434507E1L,
+      1.862359362334248675526472871224778045594E2L,
+      1.411622588180721285284945138667933330348E3L,
+      5.088538459741511988784440103218342840478E3L,
+      8.928251553922176506858267311750789273656E3L,
+      7.264436000148052545243018622742770549982E3L,
+      2.387492459664548651671894725748959751119E3L,
+      2.220916652813908085449221282808458466556E2L,
+    },
+
+    sa[] = {
+      -1.382234625202480685182526402169222331847E1L,
+      -3.315638835627950255832519203687435946482E2L,
+      -2.949124863912936259747237164260785326692E3L,
+      -1.246622099070875940506391433635999693661E4L,
+      -2.673079795851665428695842853070996219632E4L,
+      -2.880269786660559337358397106518918220991E4L,
+      -1.450600228493968044773354186390390823713E4L,
+      -2.874539731125893533960680525192064277816E3L,
+      -1.402241261419067750237395034116942296027E2L,
+      /* 1.000000000000000000000000000000000000000E0 */
+    },
+/*
+ * Coefficients for approximation to  erfc in [1/.35,107]
+ */
+/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2))
+   1/6.6666259765625 < 1/x < 1/2.85711669921875
+   Peak relative error 4.2e-22  */
+    rb[] = {
+      -4.869587348270494309550558460786501252369E-5L,
+      -4.030199390527997378549161722412466959403E-3L,
+      -9.434425866377037610206443566288917589122E-2L,
+      -9.319032754357658601200655161585539404155E-1L,
+      -4.273788174307459947350256581445442062291E0L,
+      -8.842289940696150508373541814064198259278E0L,
+      -7.069215249419887403187988144752613025255E0L,
+      -1.401228723639514787920274427443330704764E0L,
+    },
+
+    sb[] = {
+      4.936254964107175160157544545879293019085E-3L,
+      1.583457624037795744377163924895349412015E-1L,
+      1.850647991850328356622940552450636420484E0L,
+      9.927611557279019463768050710008450625415E0L,
+      2.531667257649436709617165336779212114570E1L,
+      2.869752886406743386458304052862814690045E1L,
+      1.182059497870819562441683560749192539345E1L,
+      /* 1.000000000000000000000000000000000000000E0 */
+    },
+/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2))
+   1/107 <= 1/x <= 1/6.6666259765625
+   Peak relative error 1.1e-21  */
+    rc[] = {
+      -8.299617545269701963973537248996670806850E-5L,
+      -6.243845685115818513578933902532056244108E-3L,
+      -1.141667210620380223113693474478394397230E-1L,
+      -7.521343797212024245375240432734425789409E-1L,
+      -1.765321928311155824664963633786967602934E0L,
+      -1.029403473103215800456761180695263439188E0L,
+    },
+
+    sc[] = {
+      8.413244363014929493035952542677768808601E-3L,
+      2.065114333816877479753334599639158060979E-1L,
+      1.639064941530797583766364412782135680148E0L,
+      4.936788463787115555582319302981666347450E0L,
+      5.005177727208955487404729933261347679090E0L,
+      /* 1.000000000000000000000000000000000000000E0 */
+    };
+
+long double
+erfl(long double x)
+{
+  long double R, S, P, Q, s, y, z, r;
+  int32_t ix, i;
+  u_int32_t se, i0, i1;
+
+  GET_LDOUBLE_WORDS (se, i0, i1, x);
+  ix = se & 0x7fff;
+
+  if (ix >= 0x7fff)
+    {                          /* erf(nan)=nan */
+      i = ((se & 0xffff) >> 15) << 1;
+      return (long double) (1 - i) + one / x;  /* erf(+-inf)=+-1 */
+    }
+
+  ix = (ix << 16) | (i0 >> 16);
+  if (ix < 0x3ffed800) /* |x|<0.84375 */
+    {
+      if (ix < 0x3fde8000) /* |x|<2**-33 */
+       {
+         if (ix < 0x00080000)
+           return 0.125 * (8.0 * x + efx8 * x);        /*avoid underflow */
+         return x + efx * x;
+       }
+      z = x * x;
+      r = pp[0] + z * (pp[1]
+       + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5]))));
+      s = qq[0] + z * (qq[1]
+       + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z)))));
+      y = r / s;
+      return x + x * y;
+    }
+  if (ix < 0x3fffa000) /* 1.25 */
+    {                          /* 0.84375 <= |x| < 1.25 */
+      s = fabsl (x) - one;
+      P = pa[0] + s * (pa[1] + s * (pa[2]
+       + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7]))))));
+      Q = qa[0] + s * (qa[1] + s * (qa[2]
+       + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s))))));
+      if ((se & 0x8000) == 0)
+       return erx + P / Q;
+      else
+       return -erx - P / Q;
+    }
+  if (ix >= 0x4001d555) /* 6.6666259765625 */
+    {                          /* inf>|x|>=6.666 */
+      if ((se & 0x8000) == 0)
+       return one - tiny;
+      else
+       return tiny - one;
+    }
+  x = fabsl (x);
+  s = one / (x * x);
+  if (ix < 0x4000b6db) /* 2.85711669921875 */
+    {
+      R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] +
+       s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8])))))));
+      S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] +
+       s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s))))))));
+    }
+  else
+    {                          /* |x| >= 1/0.35 */
+      R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] +
+       s * (rb[5] + s * (rb[6] + s * rb[7]))))));
+      S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] +
+       s * (sb[5] + s * (sb[6] + s))))));
+    }
+  z = x;
+  GET_LDOUBLE_WORDS (i, i0, i1, z);
+  i1 = 0;
+  SET_LDOUBLE_WORDS (z, i, i0, i1);
+  r =
+    expl (-z * z - 0.5625) * expl ((z - x) * (z + x) + R / S);
+  if ((se & 0x8000) == 0)
+    return one - r / x;
+  else
+    return r / x - one;
+}
+
+long double
+erfcl(long double x)
+{
+  int32_t hx, ix;
+  long double R, S, P, Q, s, y, z, r;
+  u_int32_t se, i0, i1;
+
+  GET_LDOUBLE_WORDS (se, i0, i1, x);
+  ix = se & 0x7fff;
+  if (ix >= 0x7fff)
+    {                          /* erfc(nan)=nan */
+      /* erfc(+-inf)=0,2 */
+      return (long double) (((se & 0xffff) >> 15) << 1) + one / x;
+    }
+
+  ix = (ix << 16) | (i0 >> 16);
+  if (ix < 0x3ffed800) /* |x|<0.84375 */
+    {
+      if (ix < 0x3fbe0000) /* |x|<2**-65 */
+       return one - x;
+      z = x * x;
+      r = pp[0] + z * (pp[1]
+       + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5]))));
+      s = qq[0] + z * (qq[1]
+       + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z)))));
+      y = r / s;
+      if (ix < 0x3ffd8000) /* x<1/4 */
+       {
+         return one - (x + x * y);
+       }
+      else
+       {
+         r = x * y;
+         r += (x - half);
+         return half - r;
+       }
+    }
+  if (ix < 0x3fffa000) /* 1.25 */
+    {                          /* 0.84375 <= |x| < 1.25 */
+      s = fabsl (x) - one;
+      P = pa[0] + s * (pa[1] + s * (pa[2]
+       + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7]))))));
+      Q = qa[0] + s * (qa[1] + s * (qa[2]
+       + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s))))));
+      if ((se & 0x8000) == 0)
+       {
+         z = one - erx;
+         return z - P / Q;
+       }
+      else
+       {
+         z = erx + P / Q;
+         return one + z;
+       }
+    }
+  if (ix < 0x4005d600) /* 107 */
+    {                          /* |x|<107 */
+      x = fabsl (x);
+      s = one / (x * x);
+      if (ix < 0x4000b6db) /* 2.85711669921875 */
+       {                       /* |x| < 1/.35 ~ 2.857143 */
+         R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] +
+           s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8])))))));
+         S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] +
+           s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s))))))));
+       }
+      else if (ix < 0x4001d555) /* 6.6666259765625 */
+       {                       /* 6.666 > |x| >= 1/.35 ~ 2.857143 */
+         R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] +
+           s * (rb[5] + s * (rb[6] + s * rb[7]))))));
+         S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] +
+           s * (sb[5] + s * (sb[6] + s))))));
+       }
+      else
+       {                       /* |x| >= 6.666 */
+         if (se & 0x8000)
+           return two - tiny;  /* x < -6.666 */
+
+         R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] +
+                                                   s * (rc[4] + s * rc[5]))));
+         S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] +
+                                                   s * (sc[4] + s))));
+       }
+      z = x;
+      GET_LDOUBLE_WORDS (hx, i0, i1, z);
+      i1 = 0;
+      i0 &= 0xffffff00;
+      SET_LDOUBLE_WORDS (z, hx, i0, i1);
+      r = expl (-z * z - 0.5625) *
+       expl ((z - x) * (z + x) + R / S);
+      if ((se & 0x8000) == 0)
+       return r / x;
+      else
+       return two - r / x;
+    }
+  else
+    {
+      if ((se & 0x8000) == 0)
+       return tiny * tiny;
+      else
+       return two - tiny;
+    }
+}
diff --git a/ld80/s_exp2l.c b/ld80/s_exp2l.c
new file mode 100644 (file)
index 0000000..0cf5259
--- /dev/null
@@ -0,0 +1,295 @@
+/*-
+ * Copyright (c) 2005-2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/ld80/s_exp2l.c,v 1.3 2008/02/13 10:44:44 bde Exp $");
+
+#include <float.h>
+#include <stdint.h>
+
+#include "bsd_cdefs.h"
+#include "amd64/bsd_ieeefp.h"
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#define        TBLBITS 7
+#define        TBLSIZE (1 << TBLBITS)
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+#define        EXPMASK (BIAS + LDBL_MAX_EXP)
+
+static const long double huge = 0x1p10000L;
+#if 0 /* XXX Prevent gcc from erroneously constant folding this. */
+static const long double twom10000 = 0x1p-10000L;
+#else
+static volatile long double twom10000 = 0x1p-10000L;
+#endif
+
+static const double
+    redux     = 0x1.8p63 / TBLSIZE,
+    P1        = 0x1.62e42fefa39efp-1,
+    P2        = 0x1.ebfbdff82c58fp-3,
+    P3        = 0x1.c6b08d7049fap-5,
+    P4        = 0x1.3b2ab6fba4da5p-7,
+    P5        = 0x1.5d8804780a736p-10,
+    P6        = 0x1.430918835e33dp-13;
+
+static const double tbl[TBLSIZE * 2] = {
+       0x1.6a09e667f3bcdp-1,   -0x1.bdd3413b2648p-55,
+       0x1.6c012750bdabfp-1,   -0x1.2895667ff0cp-57,
+       0x1.6dfb23c651a2fp-1,   -0x1.bbe3a683c88p-58,
+       0x1.6ff7df9519484p-1,   -0x1.83c0f25860fp-56,
+       0x1.71f75e8ec5f74p-1,   -0x1.16e4786887bp-56,
+       0x1.73f9a48a58174p-1,   -0x1.0a8d96c65d5p-55,
+       0x1.75feb564267c9p-1,   -0x1.0245957316ep-55,
+       0x1.780694fde5d3fp-1,    0x1.866b80a0216p-55,
+       0x1.7a11473eb0187p-1,   -0x1.41577ee0499p-56,
+       0x1.7c1ed0130c132p-1,    0x1.f124cd1164ep-55,
+       0x1.7e2f336cf4e62p-1,    0x1.05d02ba157ap-57,
+       0x1.80427543e1a12p-1,   -0x1.27c86626d97p-55,
+       0x1.82589994cce13p-1,   -0x1.d4c1dd41533p-55,
+       0x1.8471a4623c7adp-1,   -0x1.8d684a341cep-56,
+       0x1.868d99b4492edp-1,   -0x1.fc6f89bd4f68p-55,
+       0x1.88ac7d98a6699p-1,    0x1.994c2f37cb5p-55,
+       0x1.8ace5422aa0dbp-1,    0x1.6e9f156864bp-55,
+       0x1.8cf3216b5448cp-1,   -0x1.0d55e32e9e4p-57,
+       0x1.8f1ae99157736p-1,    0x1.5cc13a2e397p-56,
+       0x1.9145b0b91ffc6p-1,   -0x1.dd6792e5825p-55,
+       0x1.93737b0cdc5e5p-1,   -0x1.75fc781b58p-58,
+       0x1.95a44cbc8520fp-1,   -0x1.64b7c96a5fp-57,
+       0x1.97d829fde4e5p-1,    -0x1.d185b7c1b86p-55,
+       0x1.9a0f170ca07bap-1,   -0x1.173bd91cee6p-55,
+       0x1.9c49182a3f09p-1,     0x1.c7c46b071f2p-57,
+       0x1.9e86319e32323p-1,    0x1.824ca78e64cp-57,
+       0x1.a0c667b5de565p-1,   -0x1.359495d1cd5p-55,
+       0x1.a309bec4a2d33p-1,    0x1.6305c7ddc368p-55,
+       0x1.a5503b23e255dp-1,   -0x1.d2f6edb8d42p-55,
+       0x1.a799e1330b358p-1,    0x1.bcb7ecac564p-55,
+       0x1.a9e6b5579fdbfp-1,    0x1.0fac90ef7fdp-55,
+       0x1.ac36bbfd3f37ap-1,   -0x1.f9234cae76dp-56,
+       0x1.ae89f995ad3adp-1,    0x1.7a1cd345dcc8p-55,
+       0x1.b0e07298db666p-1,   -0x1.bdef54c80e4p-55,
+       0x1.b33a2b84f15fbp-1,   -0x1.2805e3084d8p-58,
+       0x1.b59728de5593ap-1,   -0x1.c71dfbbba6ep-55,
+       0x1.b7f76f2fb5e47p-1,   -0x1.5584f7e54acp-57,
+       0x1.ba5b030a1064ap-1,   -0x1.efcd30e5429p-55,
+       0x1.bcc1e904bc1d2p-1,    0x1.23dd07a2d9fp-56,
+       0x1.bf2c25bd71e09p-1,   -0x1.efdca3f6b9c8p-55,
+       0x1.c199bdd85529cp-1,    0x1.11065895049p-56,
+       0x1.c40ab5fffd07ap-1,    0x1.b4537e083c6p-55,
+       0x1.c67f12e57d14bp-1,    0x1.2884dff483c8p-55,
+       0x1.c8f6d9406e7b5p-1,    0x1.1acbc48805cp-57,
+       0x1.cb720dcef9069p-1,    0x1.503cbd1e94ap-57,
+       0x1.cdf0b555dc3fap-1,   -0x1.dd83b53829dp-56,
+       0x1.d072d4a07897cp-1,   -0x1.cbc3743797a8p-55,
+       0x1.d2f87080d89f2p-1,   -0x1.d487b719d858p-55,
+       0x1.d5818dcfba487p-1,    0x1.2ed02d75b37p-56,
+       0x1.d80e316c98398p-1,   -0x1.11ec18bedep-55,
+       0x1.da9e603db3285p-1,    0x1.c2300696db5p-55,
+       0x1.dd321f301b46p-1,     0x1.2da5778f019p-55,
+       0x1.dfc97337b9b5fp-1,   -0x1.1a5cd4f184b8p-55,
+       0x1.e264614f5a129p-1,   -0x1.7b627817a148p-55,
+       0x1.e502ee78b3ff6p-1,    0x1.39e8980a9cdp-56,
+       0x1.e7a51fbc74c83p-1,    0x1.2d522ca0c8ep-55,
+       0x1.ea4afa2a490dap-1,   -0x1.e9c23179c288p-55,
+       0x1.ecf482d8e67f1p-1,   -0x1.c93f3b411ad8p-55,
+       0x1.efa1bee615a27p-1,    0x1.dc7f486a4b68p-55,
+       0x1.f252b376bba97p-1,    0x1.3a1a5bf0d8e8p-55,
+       0x1.f50765b6e454p-1,     0x1.9d3e12dd8a18p-55,
+       0x1.f7bfdad9cbe14p-1,   -0x1.dbb12d00635p-55,
+       0x1.fa7c1819e90d8p-1,    0x1.74853f3a593p-56,
+       0x1.fd3c22b8f71f1p-1,    0x1.2eb74966578p-58,
+       0x1p+0,  0x0p+0,
+       0x1.0163da9fb3335p+0,    0x1.b61299ab8cd8p-54,
+       0x1.02c9a3e778061p+0,   -0x1.19083535b08p-56,
+       0x1.04315e86e7f85p+0,   -0x1.0a31c1977c98p-54,
+       0x1.059b0d3158574p+0,    0x1.d73e2a475b4p-55,
+       0x1.0706b29ddf6dep+0,   -0x1.c91dfe2b13cp-55,
+       0x1.0874518759bc8p+0,    0x1.186be4bb284p-57,
+       0x1.09e3ecac6f383p+0,    0x1.14878183161p-54,
+       0x1.0b5586cf9890fp+0,    0x1.8a62e4adc61p-54,
+       0x1.0cc922b7247f7p+0,    0x1.01edc16e24f8p-54,
+       0x1.0e3ec32d3d1a2p+0,    0x1.03a1727c58p-59,
+       0x1.0fb66affed31bp+0,   -0x1.b9bedc44ebcp-57,
+       0x1.11301d0125b51p+0,   -0x1.6c51039449bp-54,
+       0x1.12abdc06c31ccp+0,   -0x1.1b514b36ca8p-58,
+       0x1.1429aaea92dep+0,    -0x1.32fbf9af1368p-54,
+       0x1.15a98c8a58e51p+0,    0x1.2406ab9eeabp-55,
+       0x1.172b83c7d517bp+0,   -0x1.19041b9d78ap-55,
+       0x1.18af9388c8deap+0,   -0x1.11023d1970f8p-54,
+       0x1.1a35beb6fcb75p+0,    0x1.e5b4c7b4969p-55,
+       0x1.1bbe084045cd4p+0,   -0x1.95386352ef6p-54,
+       0x1.1d4873168b9aap+0,    0x1.e016e00a264p-54,
+       0x1.1ed5022fcd91dp+0,   -0x1.1df98027bb78p-54,
+       0x1.2063b88628cd6p+0,    0x1.dc775814a85p-55,
+       0x1.21f49917ddc96p+0,    0x1.2a97e9494a6p-55,
+       0x1.2387a6e756238p+0,    0x1.9b07eb6c7058p-54,
+       0x1.251ce4fb2a63fp+0,    0x1.ac155bef4f5p-55,
+       0x1.26b4565e27cddp+0,    0x1.2bd339940eap-55,
+       0x1.284dfe1f56381p+0,   -0x1.a4c3a8c3f0d8p-54,
+       0x1.29e9df51fdee1p+0,    0x1.612e8afad12p-55,
+       0x1.2b87fd0dad99p+0,    -0x1.10adcd6382p-59,
+       0x1.2d285a6e4030bp+0,    0x1.0024754db42p-54,
+       0x1.2ecafa93e2f56p+0,    0x1.1ca0f45d524p-56,
+       0x1.306fe0a31b715p+0,    0x1.6f46ad23183p-55,
+       0x1.32170fc4cd831p+0,    0x1.a9ce78e1804p-55,
+       0x1.33c08b26416ffp+0,    0x1.327218436598p-54,
+       0x1.356c55f929ff1p+0,   -0x1.b5cee5c4e46p-55,
+       0x1.371a7373aa9cbp+0,   -0x1.63aeabf42ebp-54,
+       0x1.38cae6d05d866p+0,   -0x1.e958d3c99048p-54,
+       0x1.3a7db34e59ff7p+0,   -0x1.5e436d661f6p-56,
+       0x1.3c32dc313a8e5p+0,   -0x1.efff8375d2ap-54,
+       0x1.3dea64c123422p+0,    0x1.ada0911f09fp-55,
+       0x1.3fa4504ac801cp+0,   -0x1.7d023f956fap-54,
+       0x1.4160a21f72e2ap+0,   -0x1.ef3691c309p-58,
+       0x1.431f5d950a897p+0,   -0x1.1c7dde35f7ap-55,
+       0x1.44e086061892dp+0,    0x1.89b7a04ef8p-59,
+       0x1.46a41ed1d0057p+0,    0x1.c944bd1648a8p-54,
+       0x1.486a2b5c13cdp+0,     0x1.3c1a3b69062p-56,
+       0x1.4a32af0d7d3dep+0,    0x1.9cb62f3d1be8p-54,
+       0x1.4bfdad5362a27p+0,    0x1.d4397afec42p-56,
+       0x1.4dcb299fddd0dp+0,    0x1.8ecdbbc6a78p-54,
+       0x1.4f9b2769d2ca7p+0,   -0x1.4b309d25958p-54,
+       0x1.516daa2cf6642p+0,   -0x1.f768569bd94p-55,
+       0x1.5342b569d4f82p+0,   -0x1.07abe1db13dp-55,
+       0x1.551a4ca5d920fp+0,   -0x1.d689cefede6p-55,
+       0x1.56f4736b527dap+0,    0x1.9bb2c011d938p-54,
+       0x1.58d12d497c7fdp+0,    0x1.295e15b9a1ep-55,
+       0x1.5ab07dd485429p+0,    0x1.6324c0546478p-54,
+       0x1.5c9268a5946b7p+0,    0x1.c4b1b81698p-60,
+       0x1.5e76f15ad2148p+0,    0x1.ba6f93080e68p-54,
+       0x1.605e1b976dc09p+0,   -0x1.3e2429b56de8p-54,
+       0x1.6247eb03a5585p+0,   -0x1.383c17e40b48p-54,
+       0x1.6434634ccc32p+0,    -0x1.c483c759d89p-55,
+       0x1.6623882552225p+0,   -0x1.bb60987591cp-54,
+       0x1.68155d44ca973p+0,    0x1.038ae44f74p-57,
+};
+
+/*
+ * exp2l(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.511 ulp.
+ *
+ * Method: (equally-spaced tables)
+ *
+ *   Reduce x:
+ *     x = 2**k + y, for integer k and |y| <= 1/2.
+ *     Thus we have exp2l(x) = 2**k * exp2(y).
+ *
+ *   Reduce y:
+ *     y = i/TBLSIZE + z for integer i near y * TBLSIZE.
+ *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
+ *     with |z| <= 2**-(TBLBITS+1).
+ *
+ *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
+ *   degree-6 minimax polynomial with maximum error under 2**-69.
+ *   The table entries each have 104 bits of accuracy, encoded as
+ *   a pair of double precision values.
+ */
+OLM_DLLEXPORT long double
+exp2l(long double x)
+{
+       union IEEEl2bits u, v;
+       long double r, twopk, twopkp10000, z;
+       uint32_t hx, ix, i0;
+       int k;
+
+       /* Filter out exceptional cases. */
+       u.e = x;
+       hx = u.xbits.expsign;
+       ix = hx & EXPMASK;
+       if (ix >= BIAS + 14) {          /* |x| >= 16384 or x is NaN */
+               if (ix == BIAS + LDBL_MAX_EXP) {
+                       if (u.xbits.man != 1ULL << 63 || (hx & 0x8000) == 0)
+                               return (x + x); /* x is +Inf or NaN */
+                       else
+                               return (0.0);   /* x is -Inf */
+               }
+               if (x >= 16384)
+                       return (huge * huge);   /* overflow */
+               if (x <= -16446)
+                       return (twom10000 * twom10000); /* underflow */
+       } else if (ix <= BIAS - 66) {           /* |x| < 0x1p-66 */
+               return (1.0 + x);
+       }
+
+#ifdef __i386__
+       /*
+        * The default precision on i386 is 53 bits, so long doubles are
+        * broken. Call exp2() to get an accurate (double precision) result.
+        */
+       if (__fpgetprec() != FP_PE)
+               return (exp2(x));
+#endif
+
+
+       /*
+        * Reduce x, computing z, i0, and k. The low bits of x + redux
+        * contain the 16-bit integer part of the exponent (k) followed by
+        * TBLBITS fractional bits (i0). We use bit tricks to extract these
+        * as integers, then set z to the remainder.
+        *
+        * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8.
+        * Then the low-order word of x + redux is 0x000abc12,
+        * We split this into k = 0xabc and i0 = 0x12 (adjusted to
+        * index into the table), then we compute z = 0x0.003456p0.
+        *
+        * XXX If the exponent is negative, the computation of k depends on
+        *     '>>' doing sign extension.
+        */
+       u.e = x + redux;
+       i0 = u.bits.manl + TBLSIZE / 2;
+       k = (int)i0 >> TBLBITS;
+       i0 = (i0 & (TBLSIZE - 1)) << 1;
+       u.e -= redux;
+       z = x - u.e;
+       v.xbits.man = 1ULL << 63;
+       if (k >= LDBL_MIN_EXP) {
+               v.xbits.expsign = LDBL_MAX_EXP - 1 + k;
+               twopk = v.e;
+       } else {
+               v.xbits.expsign = LDBL_MAX_EXP - 1 + k + 10000;
+               twopkp10000 = v.e;
+       }
+
+       /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */
+       long double t_hi = tbl[i0];
+       long double t_lo = tbl[i0 + 1];
+       /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */
+       r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4
+           + z * (P5 + z * P6))))) + t_hi;
+
+       /* Scale by 2**k. */
+       if (k >= LDBL_MIN_EXP) {
+               if (k == LDBL_MAX_EXP)
+                       return (r * 2.0 * 0x1p16383L);
+               return (r * twopk);
+       } else {
+               return (r * twopkp10000 * twom10000);
+       }
+}
diff --git a/ld80/s_expm1l.c b/ld80/s_expm1l.c
new file mode 100644 (file)
index 0000000..6ad23fa
--- /dev/null
@@ -0,0 +1,138 @@
+/*     $OpenBSD: s_expm1l.c,v 1.2 2011/07/20 21:02:51 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     expm1l.c
+ *
+ *     Exponential function, minus 1
+ *      Long double precision
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, expm1l();
+ *
+ * y = expm1l( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns e (2.71828...) raised to the x power, minus 1.
+ *
+ * Range reduction is accomplished by separating the argument
+ * into an integer k and fraction f such that
+ *
+ *     x    k  f
+ *    e  = 2  e.
+ *
+ * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1
+ * in the basic range [-0.5 ln 2, 0.5 ln 2].
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE    -45,+MAXLOG   200,000     1.2e-19     2.5e-20
+ *
+ * ERROR MESSAGES:
+ *
+ *   message         condition      value returned
+ * expm1l overflow   x > MAXLOG         MAXNUM
+ *
+ */
+
+#include <openlibm_math.h>
+
+static const long double MAXLOGL = 1.1356523406294143949492E4L;
+
+/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x)
+   -.5 ln 2  <  x  <  .5 ln 2
+   Theoretical peak relative error = 3.4e-22  */
+
+static const long double
+  P0 = -1.586135578666346600772998894928250240826E4L,
+  P1 =  2.642771505685952966904660652518429479531E3L,
+  P2 = -3.423199068835684263987132888286791620673E2L,
+  P3 =  1.800826371455042224581246202420972737840E1L,
+  P4 = -5.238523121205561042771939008061958820811E-1L,
+
+  Q0 = -9.516813471998079611319047060563358064497E4L,
+  Q1 =  3.964866271411091674556850458227710004570E4L,
+  Q2 = -7.207678383830091850230366618190187434796E3L,
+  Q3 =  7.206038318724600171970199625081491823079E2L,
+  Q4 = -4.002027679107076077238836622982900945173E1L,
+  /* Q5 = 1.000000000000000000000000000000000000000E0 */
+
+/* C1 + C2 = ln 2 */
+C1 = 6.93145751953125E-1L,
+C2 = 1.428606820309417232121458176568075500134E-6L,
+/* ln 2^-65 */
+minarg = -4.5054566736396445112120088E1L;
+static const long double huge = 0x1p10000L;
+
+long double
+expm1l(long double x)
+{
+long double px, qx, xx;
+int k;
+
+/* Overflow.  */
+if (x > MAXLOGL)
+  return (huge*huge);  /* overflow */
+
+if (x == 0.0)
+  return x;
+
+/* Minimum value.  */
+if (x < minarg)
+  return -1.0L;
+
+xx = C1 + C2;
+
+/* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */
+px = floorl (0.5 + x / xx);
+k = px;
+/* remainder times ln 2 */
+x -= px * C1;
+x -= px * C2;
+
+/* Approximate exp(remainder ln 2).  */
+px = (((( P4 * x
+        + P3) * x
+       + P2) * x
+       + P1) * x
+      + P0) * x;
+
+qx = (((( x
+        + Q4) * x
+       + Q3) * x
+       + Q2) * x
+      + Q1) * x
+     + Q0;
+
+xx = x * x;
+qx = x + (0.5 * xx + xx * px / qx);
+
+/* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2).
+   We have qx = exp(remainder ln 2) - 1, so
+   exp(x) - 1  =  2^k (qx + 1) - 1  =  2^k qx + 2^k - 1.  */
+px = ldexpl(1.0L, k);
+x = px * qx + (px - 1.0);
+return x;
+}
diff --git a/ld80/s_floorl.c b/ld80/s_floorl.c
new file mode 100644 (file)
index 0000000..7d42bd6
--- /dev/null
@@ -0,0 +1,80 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floorl(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floor(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double huge = 1.0e4930L;
+
+long double
+floorl(long double x)
+{
+       int32_t i1,jj0;
+       u_int32_t i,j,se,i0,sx;
+       GET_LDOUBLE_WORDS(se,i0,i1,x);
+       sx = (se>>15)&1;
+       jj0 = (se&0x7fff)-0x3fff;
+       if(jj0<31) {
+           if(jj0<0) { /* raise inexact if x != 0 */
+               if(huge+x>0.0) {
+                   if(sx==0)
+                       return 0.0L;
+                   else if(((se&0x7fff)|i0|i1)!=0)
+                       return -1.0L;
+               }
+           } else {
+               i = (0x7fffffff)>>jj0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(sx) {
+                       if (jj0>0 && (i0+(0x80000000>>jj0))>i0)
+                         i0 += (0x80000000)>>jj0;
+                       else
+                         {
+                           i = 0x7fffffff;
+                           ++se;
+                         }
+                   }
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (jj0>62) {
+           if(jj0==0x4000) return x+x; /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(jj0-31);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(sx) {
+                   if(jj0==31) i0+=1;
+                   else {
+                       j = i1+(1<<(63-jj0));
+                       if(j<i1) i0 +=1 ;       /* got a carry */
+                       i1=j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       SET_LDOUBLE_WORDS(x,se,i0,i1);
+       return x;
+}
diff --git a/ld80/s_log1pl.c b/ld80/s_log1pl.c
new file mode 100644 (file)
index 0000000..d340b37
--- /dev/null
@@ -0,0 +1,191 @@
+/*     $OpenBSD: s_log1pl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     log1pl.c
+ *
+ *      Relative error logarithm
+ *     Natural logarithm of 1+x, long double precision
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, log1pl();
+ *
+ * y = log1pl( x );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the base e (2.718...) logarithm of 1+x.
+ *
+ * The argument 1+x is separated into its exponent and fractional
+ * parts.  If the exponent is between -1 and +1, the logarithm
+ * of the fraction is approximated by
+ *
+ *     log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
+ *
+ * Otherwise, setting  z = 2(x-1)/x+1),
+ *
+ *     log(x) = z + z^3 P(z)/Q(z).
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE     -1.0, 9.0    100000      8.2e-20    2.5e-20
+ *
+ * ERROR MESSAGES:
+ *
+ * log singularity:  x-1 = 0; returns -INFINITY
+ * log domain:       x-1 < 0; returns NAN
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 2.32e-20
+ */
+
+static long double P[] = {
+ 4.5270000862445199635215E-5L,
+ 4.9854102823193375972212E-1L,
+ 6.5787325942061044846969E0L,
+ 2.9911919328553073277375E1L,
+ 6.0949667980987787057556E1L,
+ 5.7112963590585538103336E1L,
+ 2.0039553499201281259648E1L,
+};
+static long double Q[] = {
+/* 1.0000000000000000000000E0,*/
+ 1.5062909083469192043167E1L,
+ 8.3047565967967209469434E1L,
+ 2.2176239823732856465394E2L,
+ 3.0909872225312059774938E2L,
+ 2.1642788614495947685003E2L,
+ 6.0118660497603843919306E1L,
+};
+
+/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
+ * where z = 2(x-1)/(x+1)
+ * 1/sqrt(2) <= x < sqrt(2)
+ * Theoretical peak relative error = 6.16e-22
+ */
+
+static long double R[4] = {
+ 1.9757429581415468984296E-3L,
+-7.1990767473014147232598E-1L,
+ 1.0777257190312272158094E1L,
+-3.5717684488096787370998E1L,
+};
+static long double S[4] = {
+/* 1.00000000000000000000E0L,*/
+-2.6201045551331104417768E1L,
+ 1.9361891836232102174846E2L,
+-4.2861221385716144629696E2L,
+};
+static const long double C1 = 6.9314575195312500000000E-1L;
+static const long double C2 = 1.4286068203094172321215E-6L;
+
+#define SQRTH 0.70710678118654752440L
+
+long double
+log1pl(long double xm1)
+{
+long double x, y, z;
+int e;
+
+if( isnan(xm1) )
+       return(xm1);
+if( xm1 == INFINITY )
+       return(xm1);
+if(xm1 == 0.0)
+       return(xm1);
+
+x = xm1 + 1.0L;
+
+/* Test for domain errors.  */
+if( x <= 0.0L )
+       {
+       if( x == 0.0L )
+               return( -INFINITY );
+       else
+               return( NAN );
+       }
+
+/* Separate mantissa from exponent.
+   Use frexp so that denormal numbers will be handled properly.  */
+x = frexpl( x, &e );
+
+/* logarithm using log(x) = z + z^3 P(z)/Q(z),
+   where z = 2(x-1)/x+1)  */
+if( (e > 2) || (e < -2) )
+{
+if( x < SQRTH )
+       { /* 2( 2x-1 )/( 2x+1 ) */
+       e -= 1;
+       z = x - 0.5L;
+       y = 0.5L * z + 0.5L;
+       }       
+else
+       { /*  2 (x-1)/(x+1)   */
+       z = x - 0.5L;
+       z -= 0.5L;
+       y = 0.5L * x  + 0.5L;
+       }
+x = z / y;
+z = x*x;
+z = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) );
+z = z + e * C2;
+z = z + x;
+z = z + e * C1;
+return( z );
+}
+
+
+/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
+
+if( x < SQRTH )
+       {
+       e -= 1;
+       if (e != 0)
+         x = 2.0 * x - 1.0L;
+       else
+         x = xm1;
+       }       
+else
+       {
+         if (e != 0)
+           x = x - 1.0L;
+         else
+           x = xm1;
+       }
+z = x*x;
+y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 6 ) );
+y = y + e * C2;
+z = y - 0.5 * z;
+z = z + x;
+z = z + e * C1;
+return( z );
+}
diff --git a/ld80/s_modfl.c b/ld80/s_modfl.c
new file mode 100644 (file)
index 0000000..f9884af
--- /dev/null
@@ -0,0 +1,69 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modfl(long double x, long double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *     Bit twiddling.
+ *
+ * Exception:
+ *     No exception.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one = 1.0;
+
+long double
+modfl(long double x, long double *iptr)
+{
+       int32_t i0,i1,jj0;
+       u_int32_t i,se;
+       GET_LDOUBLE_WORDS(se,i0,i1,x);
+       jj0 = (se&0x7fff)-0x3fff;       /* exponent of x */
+       if(jj0<32) {                    /* integer part in high x */
+           if(jj0<0) {                 /* |x|<1 */
+               SET_LDOUBLE_WORDS(*iptr,se&0x8000,0,0); /* *iptr = +-0 */
+               return x;
+           } else {
+               i = (0x7fffffff)>>jj0;
+               if(((i0&i)|i1)==0) {            /* x is integral */
+                   *iptr = x;
+                   SET_LDOUBLE_WORDS(x,se&0x8000,0,0); /* return +-0 */
+                   return x;
+               } else {
+                   SET_LDOUBLE_WORDS(*iptr,se,i0&(~i),0);
+                   return x - *iptr;
+               }
+           }
+       } else if (jj0>63) {            /* no fraction part */
+           *iptr = x*one;
+           /* We must handle NaNs separately.  */
+           if (jj0 == 0x4000 && ((i0 & 0x7fffffff) | i1))
+             return x*one;
+           SET_LDOUBLE_WORDS(x,se&0x8000,0,0); /* return +-0 */
+           return x;
+       } else {                        /* fraction part in low x */
+           i = ((u_int32_t)(0x7fffffff))>>(jj0-32);
+           if((i1&i)==0) {             /* x is integral */
+               *iptr = x;
+               SET_LDOUBLE_WORDS(x,se&0x8000,0,0);     /* return +-0 */
+               return x;
+           } else {
+               SET_LDOUBLE_WORDS(*iptr,se,i0,i1&(~i));
+               return x - *iptr;
+           }
+       }
+}
diff --git a/ld80/s_nanl.c b/ld80/s_nanl.c
new file mode 100644 (file)
index 0000000..ca77048
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2007 David Schultz
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/ld80/s_nanl.c,v 1.2 2007/12/18 23:46:31 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+nanl(const char *s)
+{
+       union {
+               union IEEEl2bits ieee;
+               uint32_t bits[3];
+       } u;
+
+       __scan_nan(u.bits, 3, s);
+       u.ieee.bits.exp = 0x7fff;
+       u.ieee.bits.manh |= 0xc0000000; /* make it a quiet NaN */
+       return (u.ieee.e);
+}
diff --git a/ld80/s_nextafterl.c b/ld80/s_nextafterl.c
new file mode 100644 (file)
index 0000000..1e0764b
--- /dev/null
@@ -0,0 +1,90 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *     nextafterl(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+long double
+nextafterl(long double x, long double y)
+{
+       int32_t hx,hy,ix,iy;
+       u_int32_t lx,ly,esx,esy;
+
+       GET_LDOUBLE_WORDS(esx,hx,lx,x);
+       GET_LDOUBLE_WORDS(esy,hy,ly,y);
+       ix = esx&0x7fff;                /* |x| */
+       iy = esy&0x7fff;                /* |y| */
+
+       if (((ix==0x7fff)&&((hx&0x7fffffff|lx)!=0)) ||   /* x is nan */
+           ((iy==0x7fff)&&((hy&0x7fffffff|ly)!=0)))     /* y is nan */
+          return x+y;
+       if(x==y) return y;              /* x=y, return y */
+       if((ix|hx|lx)==0) {                     /* x == 0 */
+           volatile long double u;
+           SET_LDOUBLE_WORDS(x,esy&0x8000,0,1);/* return +-minsubnormal */
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(esx<0x8000) {                        /* x > 0 */
+           if(ix>iy||((ix==iy) && (hx>hy||((hx==hy)&&(lx>ly))))) {
+             /* x > y, x -= ulp */
+               if(lx==0) {
+                   if ((hx&0x7fffffff)==0) esx -= 1;
+                   hx = (hx - 1) | (hx & 0x80000000);
+               }
+               lx -= 1;
+           } else {                            /* x < y, x += ulp */
+               lx += 1;
+               if(lx==0) {
+                   hx = (hx + 1) | (hx & 0x80000000);
+                   if ((hx&0x7fffffff)==0) esx += 1;
+               }
+           }
+       } else {                                /* x < 0 */
+           if(esy>=0||(ix>iy||((ix==iy)&&(hx>hy||((hx==hy)&&(lx>ly)))))){
+             /* x < y, x -= ulp */
+               if(lx==0) {
+                   if ((hx&0x7fffffff)==0) esx -= 1;
+                   hx = (hx - 1) | (hx & 0x80000000);
+               }
+               lx -= 1;
+           } else {                            /* x > y, x += ulp */
+               lx += 1;
+               if(lx==0) {
+                   hx = (hx + 1) | (hx & 0x80000000);
+                   if ((hx&0x7fffffff)==0) esx += 1;
+               }
+           }
+       }
+       esy = esx&0x7fff;
+       if(esy==0x7fff) return x+x;             /* overflow  */
+       if(esy==0) {
+           volatile long double u = x*x;       /* underflow */
+           if(u==x) {
+               SET_LDOUBLE_WORDS(x,esx,hx,lx);
+               return x;
+           }
+       }
+       SET_LDOUBLE_WORDS(x,esx,hx,lx);
+       return x;
+}
+
+//__strong_alias(nexttowardl, nextafterl);
diff --git a/ld80/s_nexttoward.c b/ld80/s_nexttoward.c
new file mode 100644 (file)
index 0000000..b017668
--- /dev/null
@@ -0,0 +1,86 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *     nexttoward(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+double
+nexttoward(double x, long double y)
+{
+       int32_t hx,ix,iy;
+       u_int32_t lx,hy,ly,esy;
+
+       EXTRACT_WORDS(hx,lx,x);
+       GET_LDOUBLE_WORDS(esy,hy,ly,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = esy&0x7fff;                /* |y| */
+
+       if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+          ((iy>=0x7fff)&&(hy|ly)!=0))          /* y is nan */
+          return x+y;
+       if((long double) x==y) return y;        /* x=y, return y */
+       if((ix|lx)==0) {                        /* x == 0 */
+           volatile double u;
+           INSERT_WORDS(x,(esy&0x8000)<<16,1); /* return +-minsub */
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if (esy>=0x8000||((ix>>20)&0x7ff)>iy-0x3c00
+               || (((ix>>20)&0x7ff)==iy-0x3c00
+                   && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
+                       || (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
+                           && (lx<<11)>ly)))) {        /* x > y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x < y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if (esy<0x8000||((ix>>20)&0x7ff)>iy-0x3c00
+               || (((ix>>20)&0x7ff)==iy-0x3c00
+                   && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
+                       || (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
+                           && (lx<<11)>ly))))  {/* x < y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x > y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       }
+       hy = hx&0x7ff00000;
+       if(hy>=0x7ff00000) {
+         x = x+x;      /* overflow  */
+         return x;
+       }
+       if(hy<0x00100000) {
+           volatile double u = x*x;            /* underflow */
+           if(u==x) {
+               INSERT_WORDS(x,hx,lx);
+               return x;
+           }
+       }
+       INSERT_WORDS(x,hx,lx);
+       return x;
+}
diff --git a/ld80/s_nexttowardf.c b/ld80/s_nexttowardf.c
new file mode 100644 (file)
index 0000000..f2ac10d
--- /dev/null
@@ -0,0 +1,67 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+float
+nexttowardf(float x, long double y)
+{
+       int32_t hx,ix,iy;
+       u_int32_t hy,ly,esy;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_LDOUBLE_WORDS(esy,hy,ly,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = esy&0x7fff;                /* |y| */
+
+       if((ix>0x7f800000) ||                   /* x is nan */
+          (iy>=0x7fff&&((hy|ly)!=0)))          /* y is nan */
+          return x+y;
+       if((long double) x==y) return y;        /* x=y, return y */
+       if(ix==0) {                             /* x == 0 */
+           volatile float u;
+           SET_FLOAT_WORD(x,((esy&0x8000)<<16)|1);/* return +-minsub*/
+           u = x;
+           u = u * u;                          /* raise underflow flag */
+           return x;
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if(esy>=0x8000||((ix>>23)&0xff)>iy-0x3f80
+              || (((ix>>23)&0xff)==iy-0x3f80
+                  && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x > y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x < y, x += ulp */
+               hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if(esy<0x8000||((ix>>23)&0xff)>iy-0x3f80
+              || (((ix>>23)&0xff)==iy-0x3f80
+                  && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x < y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x > y, x += ulp */
+               hx += 1;
+           }
+       }
+       hy = hx&0x7f800000;
+       if(hy>=0x7f800000) {
+         x = x+x;      /* overflow  */
+         return x;
+       }
+       if(hy<0x00800000) {
+           volatile float u = x*x;             /* underflow */
+       }
+       SET_FLOAT_WORD(x,hx);
+       return x;
+}
diff --git a/ld80/s_remquol.c b/ld80/s_remquol.c
new file mode 100644 (file)
index 0000000..f649dca
--- /dev/null
@@ -0,0 +1,166 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+#define        BIAS (LDBL_MAX_EXP - 1)
+
+/*
+ * These macros add and remove an explicit integer bit in front of the
+ * fractional mantissa, if the architecture doesn't have such a bit by
+ * default already.
+ */
+#ifdef LDBL_IMPLICIT_NBIT
+#define        LDBL_NBIT       0
+#define        SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
+#define        HFRAC_BITS      EXT_FRACHBITS
+#else
+#define        LDBL_NBIT       0x80000000
+#define        SET_NBIT(hx)    (hx)
+#define        HFRAC_BITS      (EXT_FRACHBITS - 1)
+#endif
+
+#define        MANL_SHIFT      (EXT_FRACLBITS - 1)
+
+static const long double Zero[] = {0.0L, -0.0L};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ *
+ * Assumptions:
+ * - The low part of the mantissa fits in a manl_t exactly.
+ * - The high part of the mantissa fits in an int64_t with enough room
+ *   for an explicit integer bit in front of the fractional bits.
+ */
+long double
+remquol(long double x, long double y, int *quo)
+{
+       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
+       uint32_t hy;
+       uint32_t lx,ly,lz;
+       uint32_t esx, esy;
+       int ix,iy,n,q,sx,sxy;
+
+       GET_LDOUBLE_WORDS(esx,hx,lx,x);
+       GET_LDOUBLE_WORDS(esy,hy,ly,y);
+       sx = esx & 0x8000;
+       sxy = sx ^ (esy & 0x8000);
+       esx &= 0x7fff;                          /* |x| */
+       esy &= 0x7fff;                          /* |y| */
+       SET_LDOUBLE_EXP(x,esx);
+       SET_LDOUBLE_EXP(y,esy);
+
+    /* purge off exception values */
+       if((esy|hy|ly)==0 ||                    /* y=0 */
+          (esx == BIAS + LDBL_MAX_EXP) ||      /* or x not finite */
+          (esy == BIAS + LDBL_MAX_EXP &&
+           ((hy&~LDBL_NBIT)|ly)!=0))           /* or y is NaN */
+           return (x*y)/(x*y);
+       if(esx<=esy) {
+           if((esx<esy) ||
+              (hx<=hy &&
+               (hx<hy ||
+                lx<ly))) {
+               q = 0;
+               goto fixup;                     /* |x|<|y| return x or x-y */
+           }
+           if(hx==hy && lx==ly) {
+               *quo = 1;
+               return Zero[sx!=0];             /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if(esx == 0) {                          /* subnormal x */
+           x *= 0x1.0p512;
+           GET_LDOUBLE_WORDS(esx,hx,lx,x);
+           ix = esx - (BIAS + 512);
+       } else {
+           ix = esx - BIAS;
+       }
+
+    /* determine iy = ilogb(y) */
+       if(esy == 0) {                          /* subnormal y */
+           y *= 0x1.0p512;
+           GET_LDOUBLE_WORDS(esy,hy,ly,y);
+           iy = esy - (BIAS + 512);
+       } else {
+           iy = esy - BIAS;
+       }
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       hx = SET_NBIT(hx);
+       lx = SET_NBIT(lx);
+
+    /* fix point fmod */
+       n = ix - iy;
+       q = 0;
+
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;}
+           else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;}
+           q <<= 1;
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0) {                        /* return sign(x)*0 */
+           *quo = (sxy ? -q : q);
+           return Zero[sx!=0];
+       }
+       while(hx<(1ULL<<HFRAC_BITS)) {  /* normalize x */
+           hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;
+           iy -= 1;
+       }
+       if (iy < LDBL_MIN_EXP) {
+           esx = (iy + BIAS + 512) & 0x7fff;
+           SET_LDOUBLE_WORDS(x,esx,hx,lx);
+           x *= 0x1p-512;
+           GET_LDOUBLE_WORDS(esx,hx,lx,x);
+       } else {
+           esx = (iy + BIAS) & 0x7fff;
+       }
+       SET_LDOUBLE_WORDS(x,esx,hx,lx);
+fixup:
+       y = fabsl(y);
+       if (y < LDBL_MIN * 2) {
+           if (x+x>y || (x+x==y && (q & 1))) {
+               q++;
+               x-=y;
+           }
+       } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+           q++;
+           x-=y;
+       }
+
+       GET_LDOUBLE_EXP(esx,x);
+       esx ^= sx;
+       SET_LDOUBLE_EXP(x,esx);
+
+       q &= 0x7fffffff;
+       *quo = (sxy ? -q : q);
+       return x;
+}
diff --git a/ld80/s_tanhl.c b/ld80/s_tanhl.c
new file mode 100644 (file)
index 0000000..1a46583
--- /dev/null
@@ -0,0 +1,79 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* tanhl(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *                                     x    -x
+ *                                    e  - e
+ *     0. tanhl(x) is defined to be -----------
+ *                                     x    -x
+ *                                    e  + e
+ *     1. reduce x to non-negative by tanhl(-x) = -tanhl(x).
+ *     2.  0      <= x <= 2**-55 : tanhl(x) := x*(one+x)
+ *                                              -t
+ *         2**-55 <  x <=  1     : tanhl(x) := -----; t = expm1l(-2x)
+ *                                             t + 2
+ *                                                   2
+ *         1      <= x <=  23.0  : tanhl(x) := 1-  ----- ; t=expm1l(2x)
+ *                                                 t + 2
+ *         23.0   <  x <= INF    : tanhl(x) := 1.
+ *
+ * Special cases:
+ *     tanhl(NaN) is NaN;
+ *     only tanhl(0)=0 is exact for finite argument.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const long double one=1.0, two=2.0, tiny = 1.0e-4900L;
+
+long double
+tanhl(long double x)
+{
+       long double t,z;
+       int32_t se;
+       u_int32_t jj0,jj1,ix;
+
+    /* High word of |x|. */
+       GET_LDOUBLE_WORDS(se,jj0,jj1,x);
+       ix = se&0x7fff;
+
+    /* x is INF or NaN */
+       if(ix==0x7fff) {
+           /* for NaN it's not important which branch: tanhl(NaN) = NaN */
+           if (se&0x8000) return one/x-one;    /* tanhl(-inf)= -1; */
+           else           return one/x+one;    /* tanhl(+inf)=+1 */
+       }
+
+    /* |x| < 23 */
+       if (ix < 0x4003 || (ix == 0x4003 && jj0 < 0xb8000000u)) {/* |x|<23 */
+           if ((ix|jj0|jj1) == 0)
+               return x;               /* x == +- 0 */
+           if (ix<0x3fc8)              /* |x|<2**-55 */
+               return x*(one+tiny);    /* tanh(small) = small */
+           if (ix>=0x3fff) {   /* |x|>=1  */
+               t = expm1l(two*fabsl(x));
+               z = one - two/(t+two);
+           } else {
+               t = expm1l(-two*fabsl(x));
+               z= -t/(t+two);
+           }
+    /* |x| > 23, return +-1 */
+       } else {
+           z = one - tiny;             /* raised inexact flag */
+       }
+       return (se&0x8000)? -z: z;
+}
diff --git a/ld80/s_truncl.c b/ld80/s_truncl.c
new file mode 100644 (file)
index 0000000..8a261d8
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+/*
+ * truncl(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to truncl(x).
+ */
+
+#include <sys/types.h>
+//#include <machine/ieee.h>
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define        MANH_SIZE       (EXT_FRACHBITS + 1)
+#else
+#define        MANH_SIZE       EXT_FRACHBITS
+#endif
+
+static const long double huge = 1.0e300;
+static const float zero[] = { 0.0, -0.0 };
+
+long double
+truncl(long double x)
+{
+       int e, es;
+       uint32_t ix0, ix1;
+
+       GET_LDOUBLE_WORDS(es,ix0,ix1,x);
+       e = (es&0x7fff) - LDBL_MAX_EXP + 1;
+
+       if (e < MANH_SIZE - 1) {
+               if (e < 0) {                    /* raise inexact if x != 0 */
+                       if (huge + x > 0.0)
+                               return (zero[(es&0x8000)!=0]);
+               } else {
+                       uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+                       if (((ix0 & m) | ix1) == 0)
+                               return (x);     /* x is integral */
+                       if (huge + x > 0.0) {   /* raise inexact flag */
+                               ix0 &= ~m;
+                               ix1 = 0;
+                       }
+               }
+       } else if (e < LDBL_MANT_DIG - 1) {
+               uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+               if ((ix1 & m) == 0)
+                       return (x);     /* x is integral */
+               if (huge + x > 0.0)             /* raise inexact flag */
+                       ix1 &= ~m;
+       }
+       SET_LDOUBLE_WORDS(x,es,ix0,ix1);
+       return (x);
+}
diff --git a/mips/Make.files b/mips/Make.files
new file mode 100644 (file)
index 0000000..483a7cc
--- /dev/null
@@ -0,0 +1 @@
+$(CUR_SRCS) = fenv.c
diff --git a/mips/fenv-softfloat.h b/mips/fenv-softfloat.h
new file mode 100644 (file)
index 0000000..0511335
--- /dev/null
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2004-2011 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _FENV_H_
+#error "This file is meant to be included only by <fenv.h>."
+#endif
+
+/*
+ * This file implements the functionality of <fenv.h> on platforms that
+ * lack an FPU and use softfloat in libc for floating point.  To use it,
+ * you must write an <fenv.h> that provides the following:
+ *
+ *   - a typedef for fenv_t, which may be an integer or struct type
+ *   - a typedef for fexcept_t (XXX This file assumes fexcept_t is a
+ *     simple integer type containing the exception mask.)
+ *   - definitions of FE_* constants for the five exceptions and four
+ *     rounding modes in IEEE 754, as described in fenv(3)
+ *   - a definition, and the corresponding external symbol, for FE_DFL_ENV
+ *   - a macro __set_env(env, flags, mask, rnd), which sets the given fenv_t
+ *     from the exception flags, mask, and rounding mode
+ *   - macros __env_flags(env), __env_mask(env), and __env_round(env), which
+ *     extract fields from an fenv_t
+ *   - a definition of __fenv_static
+ *
+ * If the architecture supports an optional FPU, it's recommended that you
+ * define fenv_t and fexcept_t to match the hardware ABI.  Otherwise, it
+ * doesn't matter how you define them.
+ */
+
+extern int __softfloat_float_exception_flags;
+extern int __softfloat_float_exception_mask;
+extern int __softfloat_float_rounding_mode;
+void __softfloat_float_raise(int);
+
+__fenv_static inline int
+feclearexcept(int __excepts)
+{
+
+       __softfloat_float_exception_flags &= ~__excepts;
+       return (0);
+}
+
+__fenv_static inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+
+       *__flagp = __softfloat_float_exception_flags & __excepts;
+       return (0);
+}
+
+__fenv_static inline int
+fesetexceptflag(const fexcept_t *__flagp, int __excepts)
+{
+
+       __softfloat_float_exception_flags &= ~__excepts;
+       __softfloat_float_exception_flags |= *__flagp & __excepts;
+       return (0);
+}
+
+__fenv_static inline int
+feraiseexcept(int __excepts)
+{
+
+       __softfloat_float_raise(__excepts);
+       return (0);
+}
+
+__fenv_static inline int
+fetestexcept(int __excepts)
+{
+
+       return (__softfloat_float_exception_flags & __excepts);
+}
+
+__fenv_static inline int
+fegetround(void)
+{
+
+       return (__softfloat_float_rounding_mode);
+}
+
+__fenv_static inline int
+fesetround(int __round)
+{
+
+       __softfloat_float_rounding_mode = __round;
+       return (0);
+}
+
+__fenv_static inline int
+fegetenv(fenv_t *__envp)
+{
+
+       __set_env(*__envp, __softfloat_float_exception_flags,
+           __softfloat_float_exception_mask, __softfloat_float_rounding_mode);
+       return (0);
+}
+
+__fenv_static inline int
+feholdexcept(fenv_t *__envp)
+{
+       fenv_t __env;
+
+       fegetenv(__envp);
+       __softfloat_float_exception_flags = 0;
+       __softfloat_float_exception_mask = 0;
+       return (0);
+}
+
+__fenv_static inline int
+fesetenv(const fenv_t *__envp)
+{
+
+       __softfloat_float_exception_flags = __env_flags(*__envp);
+       __softfloat_float_exception_mask = __env_mask(*__envp);
+       __softfloat_float_rounding_mode = __env_round(*__envp);
+       return (0);
+}
+
+__fenv_static inline int
+feupdateenv(const fenv_t *__envp)
+{
+       int __oflags = __softfloat_float_exception_flags;
+
+       fesetenv(__envp);
+       feraiseexcept(__oflags);
+       return (0);
+}
+
+#if __BSD_VISIBLE
+
+/* We currently provide no external definitions of the functions below. */
+
+__fenv_static inline int
+feenableexcept(int __mask)
+{
+       int __omask = __softfloat_float_exception_mask;
+
+       __softfloat_float_exception_mask |= __mask;
+       return (__omask);
+}
+
+__fenv_static inline int
+fedisableexcept(int __mask)
+{
+       int __omask = __softfloat_float_exception_mask;
+
+       __softfloat_float_exception_mask &= ~__mask;
+       return (__omask);
+}
+
+__fenv_static inline int
+fegetexcept(void)
+{
+
+       return (__softfloat_float_exception_mask);
+}
+
+#endif /* __BSD_VISIBLE */
\ No newline at end of file
diff --git a/mips/fenv.c b/mips/fenv.c
new file mode 100644 (file)
index 0000000..4a7ed80
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD$
+ */
+
+#define        __fenv_static
+#include "openlibm_fenv.h"
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+/*
+ * Hopefully the system ID byte is immutable, so it's valid to use
+ * this as a default environment.
+ */
+const fenv_t __fe_dfl_env = 0;
+
+#ifdef __mips_soft_float
+#define __set_env(env, flags, mask, rnd) env = ((flags)                 \
+                                                | (mask)<<_FPUSW_SHIFT  \
+                                                | (rnd) << 24)
+#define __env_flags(env)                ((env) & FE_ALL_EXCEPT)
+#define __env_mask(env)                 (((env) >> _FPUSW_SHIFT)        \
+                                                & FE_ALL_EXCEPT)
+#define __env_round(env)                (((env) >> 24) & _ROUND_MASK)
+#include "fenv-softfloat.h"
+#endif
+
+extern inline int feclearexcept(int __excepts);
+extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+extern inline int feraiseexcept(int __excepts);
+extern inline int fetestexcept(int __excepts);
+extern inline int fegetround(void);
+extern inline int fesetround(int __round);
+extern inline int fegetenv(fenv_t *__envp);
+extern inline int feholdexcept(fenv_t *__envp);
+extern inline int fesetenv(const fenv_t *__envp);
+extern inline int feupdateenv(const fenv_t *__envp);
+extern inline int feenableexcept(int __mask);
+extern inline int fedisableexcept(int __mask);
+extern inline int fegetexcept(void);
+
diff --git a/openlibm.pc.in b/openlibm.pc.in
new file mode 100644 (file)
index 0000000..242d447
--- /dev/null
@@ -0,0 +1,10 @@
+exec_prefix=${prefix}
+includedir=${prefix}/include
+libdir=${exec_prefix}/lib
+
+Name: openlibm
+Version: ${version}
+URL: https://github.com/JuliaLang/openlibm
+Description: High quality system independent, open source libm.
+Cflags: -I${includedir}
+Libs: -L${libdir} -lopenlibm
diff --git a/powerpc/Make.files b/powerpc/Make.files
new file mode 100644 (file)
index 0000000..483a7cc
--- /dev/null
@@ -0,0 +1 @@
+$(CUR_SRCS) = fenv.c
diff --git a/powerpc/fenv.c b/powerpc/fenv.c
new file mode 100644 (file)
index 0000000..78e6015
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD$
+ */
+
+#define        __fenv_static
+#include <openlibm_fenv.h>
+
+#ifdef __GNUC_GNU_INLINE__
+#error "This file must be compiled with C99 'inline' semantics"
+#endif
+
+const fenv_t __fe_dfl_env = 0x00000000;
+
+extern inline int feclearexcept(int __excepts);
+extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+extern inline int feraiseexcept(int __excepts);
+extern inline int fetestexcept(int __excepts);
+extern inline int fegetround(void);
+extern inline int fesetround(int __round);
+extern inline int fegetenv(fenv_t *__envp);
+extern inline int feholdexcept(fenv_t *__envp);
+extern inline int fesetenv(const fenv_t *__envp);
+extern inline int feupdateenv(const fenv_t *__envp);
diff --git a/src/Make.files b/src/Make.files
new file mode 100644 (file)
index 0000000..5462ffc
--- /dev/null
@@ -0,0 +1,71 @@
+$(CUR_SRCS) = common.c \
+       e_acos.c e_acosf.c e_acosh.c e_acoshf.c e_asin.c e_asinf.c \
+       e_atan2.c e_atan2f.c e_atanh.c e_atanhf.c e_cosh.c e_coshf.c e_exp.c \
+       e_expf.c e_fmod.c e_fmodf.c \
+       e_hypot.c e_hypotf.c e_j0.c e_j0f.c e_j1.c e_j1f.c \
+       e_jn.c e_jnf.c e_lgamma.c e_lgamma_r.c e_lgammaf.c e_lgammaf_r.c \
+       e_log.c e_log10.c e_log10f.c e_log2.c e_log2f.c e_logf.c \
+       e_pow.c e_powf.c e_remainder.c e_remainderf.c \
+       e_rem_pio2.c e_rem_pio2f.c \
+       e_sinh.c e_sinhf.c e_sqrt.c e_sqrtf.c \
+       k_cos.c k_exp.c k_expf.c k_rem_pio2.c k_sin.c k_tan.c \
+       k_cosf.c k_sinf.c k_tanf.c \
+       s_asinh.c s_asinhf.c s_atan.c s_atanf.c s_carg.c s_cargf.c \
+       s_cbrt.c s_cbrtf.c s_ceil.c s_ceilf.c \
+       s_copysign.c s_copysignf.c s_cos.c s_cosf.c \
+       s_csqrt.c s_csqrtf.c s_erf.c s_erff.c \
+       s_exp2.c s_exp2f.c s_expm1.c s_expm1f.c s_fabs.c s_fabsf.c s_fdim.c \
+       s_floor.c s_floorf.c s_fma.c s_fmaf.c \
+       s_fmax.c s_fmaxf.c s_fmin.c \
+       s_fminf.c s_fpclassify.c \
+       s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
+       s_isinf.c s_isfinite.c s_isnormal.c s_isnan.c \
+       s_llrint.c s_llrintf.c s_llround.c s_llroundf.c  \
+       s_log1p.c s_log1pf.c s_logb.c s_logbf.c s_lrint.c s_lrintf.c \
+       s_lround.c s_lroundf.c s_modf.c s_modff.c \
+       s_nearbyint.c s_nextafter.c s_nextafterf.c \
+       s_nexttowardf.c s_remquo.c s_remquof.c \
+       s_rint.c s_rintf.c s_round.c s_roundf.c \
+       s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \
+       s_signgam.c s_sin.c s_sincos.c \
+       s_sinf.c s_sincosf.c s_tan.c s_tanf.c s_tanh.c s_tanhf.c s_tgammaf.c \
+       s_trunc.c s_truncf.c s_cpow.c  s_cpowf.c \
+       w_cabs.c w_cabsf.c
+
+ifneq ($(OS), WINNT)
+$(CUR_SRCS) += s_nan.c
+endif
+
+# Add in long double functions for x86, x64 and aarch64
+ifneq ($(filter $(ARCH),i387 amd64 aarch64),)
+# C99 long double functions
+$(CUR_SRCS) += s_copysignl.c s_fabsl.c s_llrintl.c s_lrintl.c s_modfl.c
+
+# If long double != double use these; otherwise, we alias the double versions.
+$(CUR_SRCS) += e_acosl.c e_asinl.c e_atan2l.c e_fmodl.c \
+       s_fmaxl.c s_fminl.c s_ilogbl.c \
+       e_hypotl.c e_lgammal.c e_remainderl.c e_sqrtl.c \
+       s_atanl.c s_ceill.c s_cosl.c s_cprojl.c \
+       s_csqrtl.c s_floorl.c s_fmal.c \
+       s_frexpl.c s_logbl.c s_nexttoward.c \
+       s_remquol.c s_roundl.c s_lroundl.c s_llroundl.c \
+       s_cpowl.c s_cargl.c \
+       s_sinl.c s_sincosl.c s_tanl.c s_truncl.c w_cabsl.c \
+       s_nextafterl.c s_rintl.c s_scalbnl.c polevll.c \
+       s_casinl.c s_ctanl.c \
+       s_cimagl.c s_conjl.c s_creall.c s_cacoshl.c s_catanhl.c s_casinhl.c \
+       s_catanl.c s_csinl.c s_cacosl.c s_cexpl.c s_csinhl.c s_ccoshl.c \
+       s_clogl.c s_ctanhl.c s_ccosl.c s_cbrtl.c
+endif
+
+# C99 complex functions
+$(CUR_SRCS) += s_ccosh.c s_ccoshf.c s_cexp.c s_cexpf.c \
+       s_cimag.c s_cimagf.c \
+       s_conj.c s_conjf.c \
+       s_cproj.c s_cprojf.c s_creal.c s_crealf.c \
+       s_csinh.c s_csinhf.c s_ctanh.c s_ctanhf.c \
+        s_cacos.c s_cacosf.c \
+        s_cacosh.c s_cacoshf.c \
+        s_casin.c s_casinf.c s_casinh.c s_casinhf.c \
+        s_catan.c s_catanf.c s_catanh.c s_catanhf.c \
+        s_clog.c s_clogf.c
diff --git a/src/aarch64_fpmath.h b/src/aarch64_fpmath.h
new file mode 100644 (file)
index 0000000..c4e407c
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * Copyright (2) 2014 The FreeBSD Foundation
+ * 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.
+ *
+ * $FreeBSD: head/lib/libc/aarch64/_fpmath.h 281197 2015-04-07 09:52:14Z andrew $
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+               unsigned long   manl    :64;
+               unsigned long   manh    :48;
+               unsigned int    exp     :15;
+               unsigned int    sign    :1;
+       } bits;
+       /* TODO andrew: Check the packing here */
+       struct {
+               unsigned long   manl    :64;
+               unsigned long   manh    :48;
+               unsigned int    expsign :16;
+       } xbits;
+};
+
+#define        LDBL_NBIT       0
+#define        LDBL_IMPLICIT_NBIT
+#define        mask_nbit_l(u)  ((void)0)
+
+#define        LDBL_MANH_SIZE  48
+#define        LDBL_MANL_SIZE  64
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)((u).bits.manl >> 32);       \
+       (a)[2] = (uint32_t)(u).bits.manh;               \
+       (a)[3] = (uint32_t)((u).bits.manh >> 32);       \
+} while(0)
diff --git a/src/amd64_fpmath.h b/src/amd64_fpmath.h
new file mode 100644 (file)
index 0000000..41b01c3
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002, 2003 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.
+ *
+ * $FreeBSD: src/lib/libc/amd64/_fpmath.h,v 1.7 2008/01/17 16:39:06 bde Exp $
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+               unsigned int    manl    :32;
+               unsigned int    manh    :32;
+               unsigned int    exp     :15;
+               unsigned int    sign    :1;
+               unsigned int    junkl   :16;
+               unsigned int    junkh   :32;
+       } bits;
+       struct {
+               unsigned long   man     :64;
+               unsigned int    expsign :16;
+               unsigned long   junk    :48;
+       } xbits;
+};
+
+#define        LDBL_NBIT       0x80000000
+#define        mask_nbit_l(u)  ((u).bits.manh &= ~LDBL_NBIT)
+
+#define        LDBL_MANH_SIZE  32
+#define        LDBL_MANL_SIZE  32
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)(u).bits.manh;               \
+} while (0)
diff --git a/src/bsd_cdefs.h b/src/bsd_cdefs.h
new file mode 100644 (file)
index 0000000..5799193
--- /dev/null
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Berkeley Software Design, Inc.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)cdefs.h     8.8 (Berkeley) 1/9/95
+ * $FreeBSD: src/sys/sys/cdefs.h,v 1.114 2011/02/18 21:44:53 nwhitehorn Exp $
+ */
+
+/* Do not redefine macros if the system provides them in sys/cdefs.h.
+ * The two macros correspond to different platforms. */
+#ifndef _BSD_CDEFS_H_
+#define _BSD_CDEFS_H_
+
+/*
+ * This code has been put in place to help reduce the addition of
+ * compiler specific defines in FreeBSD code.  It helps to aid in
+ * having a compiler-agnostic source tree.
+ */
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+
+#if __GNUC__ >= 3 || defined(__INTEL_COMPILER)
+#define __GNUCLIKE_ASM 3
+#else
+#define __GNUCLIKE_ASM 2
+#endif
+
+#define __CC_SUPPORTS___INLINE__ 1
+
+#endif /* __GNUC__ || __INTEL_COMPILER */
+
+#if defined(__STDC__) || defined(__cplusplus)
+
+#define        __volatile      volatile
+#if defined(__cplusplus)
+#define        __inline        inline          /* convert to C++ keyword */
+#else
+#if !defined(__CC_SUPPORTS___INLINE)
+#define        __inline                        /* delete GCC keyword */
+#endif /* ! __CC_SUPPORTS___INLINE */
+#endif /* !__cplusplus */
+
+#else  /* !(__STDC__ || __cplusplus) */
+
+#if !defined(__CC_SUPPORTS___INLINE)
+#define        __inline
+#define        __volatile
+#endif /* !__CC_SUPPORTS___INLINE */
+#endif /* !(__STDC__ || __cplusplus) */
+
+/*
+ * Macro to test if we're using a specific version of gcc or later.
+ */
+#ifndef __GNUC_PREREQ__
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+#define        __GNUC_PREREQ__(ma, mi) \
+       (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))
+#else
+#define        __GNUC_PREREQ__(ma, mi) 0
+#endif
+#endif /* __GNUC_PREREQ__ */
+
+/*
+ * Compiler-dependent macro to help declare pure (no side effects) functions.
+ * It is null except for versions of gcc that are known to support the features
+ * properly (old versions of gcc-2 supported the dead and pure features
+ * in a different (wrong) way), and for icc.  If we do not provide an implementation
+ * for a given compiler, let the compile fail if it is told to use
+ * a feature that we cannot live without.
+ */
+#if !defined(__pure2) && (__GNUC_PREREQ__(2, 7) || defined(__INTEL_COMPILER))
+#define        __pure2         __attribute__((__const__))
+#endif
+
+#endif /* !_BSD_CDEFS_H_ */
diff --git a/src/cdefs-compat.h b/src/cdefs-compat.h
new file mode 100644 (file)
index 0000000..fb31965
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _CDEFS_COMPAT_H_
+#define        _CDEFS_COMPAT_H_
+
+#if !defined(__BEGIN_DECLS)
+#if defined(__cplusplus)
+#define        __BEGIN_DECLS   extern "C" {
+#define        __END_DECLS     }
+#else
+#define        __BEGIN_DECLS
+#define        __END_DECLS
+#endif
+#endif /* !defined(__BEGIN_DECLS) */
+
+#ifdef __GNUC__
+#ifndef __strong_reference
+#ifdef __APPLE__
+#define __strong_reference(sym,aliassym) __weak_reference(sym,aliassym)
+#else
+#define __strong_reference(sym,aliassym)       \
+       OLM_DLLEXPORT extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)));
+#endif /* __APPLE__ */
+#endif /* __strong_reference */
+
+#ifndef __weak_reference
+#ifdef __ELF__
+#ifdef __STDC__
+#define        __weak_reference(sym,alias)     \
+       __asm__(".weak " #alias);       \
+       __asm__(".equ "  #alias ", " #sym)
+#ifndef __warn_references
+#define        __warn_references(sym,msg)      \
+       __asm__(".section .gnu.warning." #sym); \
+       __asm__(".asciz \"" msg "\"");  \
+       __asm__(".previous")
+#endif /* __warn_references */
+#else
+#define        __weak_reference(sym,alias)     \
+       __asm__(".weak alias");         \
+       __asm__(".equ alias, sym")
+#ifndef __warn_references
+#define        __warn_references(sym,msg)      \
+       __asm__(".section .gnu.warning.sym"); \
+       __asm__(".asciz \"msg\"");      \
+       __asm__(".previous")
+#endif /* __warn_references */
+#endif /* __STDC__ */
+#elif defined(__clang__) /* CLANG */
+#ifdef __STDC__
+#define __weak_reference(sym,alias)     \
+    __asm__(".weak_reference " #alias); \
+    __asm__(".set " #alias ", " #sym)
+#else
+#define __weak_reference(sym,alias)     \
+    __asm__(".weak_reference alias");\
+    __asm__(".set alias, sym")
+#endif
+#else  /* !__ELF__ */
+#ifdef __STDC__
+#define __weak_reference(sym,alias)    \
+       __asm__(".stabs \"_" #alias "\",11,0,0,0");     \
+       __asm__(".stabs \"_" #sym "\",1,0,0,0")
+#ifndef __warn_references
+#define __warn_references(sym,msg)     \
+       __asm__(".stabs \"" msg "\",30,0,0,0");         \
+       __asm__(".stabs \"_" #sym "\",1,0,0,0")
+#endif /* __warn_references */
+#else
+#define __weak_reference(sym,alias)    \
+       __asm__(".stabs \"_/**/alias\",11,0,0,0");      \
+       __asm__(".stabs \"_/**/sym\",1,0,0,0")
+#ifndef __warn_references
+#define __warn_references(sym,msg)     \
+       __asm__(".stabs msg,30,0,0,0");                 \
+       __asm__(".stabs \"_/**/sym\",1,0,0,0")
+#endif /* __warn_references */
+#endif /* __STDC__ */
+#endif /* __ELF__ */
+#endif  /* __weak_reference */
+#endif /* __GNUC__ */
+
+
+#endif /* _CDEFS_COMPAT_H_ */
diff --git a/src/common.c b/src/common.c
new file mode 100644 (file)
index 0000000..b02d697
--- /dev/null
@@ -0,0 +1,7 @@
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT int isopenlibm(void) {
+    return 1;
+}
diff --git a/src/e_acos.c b/src/e_acos.c
new file mode 100644 (file)
index 0000000..b7a74b9
--- /dev/null
@@ -0,0 +1,111 @@
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_acos.c,v 1.13 2008/07/31 22:41:26 das Exp $");
+
+/* __ieee754_acos(x)
+ * Method :                  
+ *     acos(x)  = pi/2 - asin(x)
+ *     acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ *     acos(x) = pi/2 - (x + x*x^2*R(x^2))     (see asin.c)
+ * For x>0.5
+ *     acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ *             = 2asin(sqrt((1-x)/2))  
+ *             = 2s + 2s*z*R(z)        ...z=(1-x)/2, s=sqrt(z)
+ *             = 2f + (2c + 2s*z*R(z))
+ *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ *     for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ *     acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ *             = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ *     if x is NaN, return x itself;
+ *     if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one=  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi =  1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
+static volatile double
+pio2_lo =  6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
+static const double
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+OLM_DLLEXPORT double
+__ieee754_acos(double x)
+{
+       double z,p,q,r,w,s,c,df;
+       int32_t hx,ix;
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x3ff00000) {    /* |x| >= 1 */
+           u_int32_t lx;
+           GET_LOW_WORD(lx,x);
+           if(((ix-0x3ff00000)|lx)==0) {       /* |x|==1 */
+               if(hx>0) return 0.0;            /* acos(1) = 0  */
+               else return pi+2.0*pio2_lo;     /* acos(-1)= pi */
+           }
+           return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+       }
+       if(ix<0x3fe00000) {     /* |x| < 0.5 */
+           if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+           z = x*x;
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           r = p/q;
+           return pio2_hi - (x - (pio2_lo-x*r));
+       } else  if (hx<0) {             /* x < -0.5 */
+           z = (one+x)*0.5;
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           s = sqrt(z);
+           r = p/q;
+           w = r*s-pio2_lo;
+           return pi - 2.0*(s+w);
+       } else {                        /* x > 0.5 */
+           z = (one-x)*0.5;
+           s = sqrt(z);
+           df = s;
+           SET_LOW_WORD(df,0);
+           c  = (z-df*df)/(s+df);
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           r = p/q;
+           w = r*s+c;
+           return 2.0*(df+w);
+       }
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(acos, acosl);
+#endif
diff --git a/src/e_acosf.c b/src/e_acosf.c
new file mode 100644 (file)
index 0000000..2beab5c
--- /dev/null
@@ -0,0 +1,78 @@
+/* e_acosf.c -- float version of e_acos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_acosf.c,v 1.11 2008/08/03 17:39:54 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+pi =  3.1415925026e+00, /* 0x40490fda */
+pio2_hi =  1.5707962513e+00; /* 0x3fc90fda */
+static volatile float
+pio2_lo =  7.5497894159e-08; /* 0x33a22168 */
+static const float
+pS0 =  1.6666586697e-01,
+pS1 = -4.2743422091e-02,
+pS2 = -8.6563630030e-03,
+qS1 = -7.0662963390e-01;
+
+OLM_DLLEXPORT float
+__ieee754_acosf(float x)
+{
+       float z,p,q,r,w,s,c,df;
+       int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x3f800000) {            /* |x| >= 1 */
+           if(ix==0x3f800000) {        /* |x| == 1 */
+               if(hx>0) return 0.0;    /* acos(1) = 0 */
+               else return pi+(float)2.0*pio2_lo;      /* acos(-1)= pi */
+           }
+           return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+       }
+       if(ix<0x3f000000) {     /* |x| < 0.5 */
+           if(ix<=0x32800000) return pio2_hi+pio2_lo;/*if|x|<2**-26*/
+           z = x*x;
+           p = z*(pS0+z*(pS1+z*pS2));
+           q = one+z*qS1;
+           r = p/q;
+           return pio2_hi - (x - (pio2_lo-x*r));
+       } else  if (hx<0) {             /* x < -0.5 */
+           z = (one+x)*(float)0.5;
+           p = z*(pS0+z*(pS1+z*pS2));
+           q = one+z*qS1;
+           s = sqrtf(z);
+           r = p/q;
+           w = r*s-pio2_lo;
+           return pi - (float)2.0*(s+w);
+       } else {                        /* x > 0.5 */
+           int32_t idf;
+           z = (one-x)*(float)0.5;
+           s = sqrtf(z);
+           df = s;
+           GET_FLOAT_WORD(idf,df);
+           SET_FLOAT_WORD(df,idf&0xfffff000);
+           c  = (z-df*df)/(s+df);
+           p = z*(pS0+z*(pS1+z*pS2));
+           q = one+z*qS1;
+           r = p/q;
+           w = r*s+c;
+           return (float)2.0*(df+w);
+       }
+}
diff --git a/src/e_acosh.c b/src/e_acosh.c
new file mode 100644 (file)
index 0000000..3f80d95
--- /dev/null
@@ -0,0 +1,63 @@
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_acosh.c,v 1.9 2008/02/22 02:30:34 das Exp $");
+
+/* __ieee754_acosh(x)
+ * Method :
+ *     Based on 
+ *             acosh(x) = log [ x + sqrt(x*x-1) ]
+ *     we have
+ *             acosh(x) := log(x)+ln2, if x is large; else
+ *             acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ *             acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *     acosh(x) is NaN with signal if x<1.
+ *     acosh(NaN) is NaN without signal.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one    = 1.0,
+ln2    = 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */
+
+OLM_DLLEXPORT double
+__ieee754_acosh(double x)
+{
+       double t;
+       int32_t hx;
+       u_int32_t lx;
+       EXTRACT_WORDS(hx,lx,x);
+       if(hx<0x3ff00000) {             /* x < 1 */
+           return (x-x)/(x-x);
+       } else if(hx >=0x41b00000) {    /* x > 2**28 */
+           if(hx >=0x7ff00000) {       /* x is inf of NaN */
+               return x+x;
+           } else 
+               return __ieee754_log(x)+ln2;    /* acosh(huge)=log(2x) */
+       } else if(((hx-0x3ff00000)|lx)==0) {
+           return 0.0;                 /* acosh(1) = 0 */
+       } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+           t=x*x;
+           return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+       } else {                        /* 1<x<2 */
+           t = x-one;
+           return log1p(t+sqrt(2.0*t+t*t));
+       }
+}
diff --git a/src/e_acoshf.c b/src/e_acoshf.c
new file mode 100644 (file)
index 0000000..729e593
--- /dev/null
@@ -0,0 +1,49 @@
+/* e_acoshf.c -- float version of e_acosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_acoshf.c,v 1.8 2008/02/22 02:30:34 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one    = 1.0,
+ln2    = 6.9314718246e-01;  /* 0x3f317218 */
+
+OLM_DLLEXPORT float
+__ieee754_acoshf(float x)
+{
+       float t;
+       int32_t hx;
+       GET_FLOAT_WORD(hx,x);
+       if(hx<0x3f800000) {             /* x < 1 */
+           return (x-x)/(x-x);
+       } else if(hx >=0x4d800000) {    /* x > 2**28 */
+           if(hx >=0x7f800000) {       /* x is inf of NaN */
+               return x+x;
+           } else
+               return __ieee754_logf(x)+ln2;   /* acosh(huge)=log(2x) */
+       } else if (hx==0x3f800000) {
+           return 0.0;                 /* acosh(1) = 0 */
+       } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+           t=x*x;
+           return __ieee754_logf((float)2.0*x-one/(x+__ieee754_sqrtf(t-one)));
+       } else {                        /* 1<x<2 */
+           t = x-one;
+           return log1pf(t+__ieee754_sqrtf((float)2.0*t+t*t));
+       }
+}
diff --git a/src/e_acosl.c b/src/e_acosl.c
new file mode 100644 (file)
index 0000000..ebe5a22
--- /dev/null
@@ -0,0 +1,87 @@
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/* FreeBSD: head/lib/msun/src/e_acos.c 176451 2008-02-22 02:30:36Z das */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_acosl.c,v 1.2 2008/08/02 03:56:22 das Exp $");
+
+/*
+ * See comments in e_acos.c.
+ * Converted to long double by David Schultz <das@FreeBSD.ORG>.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "invtrig.h"
+#include "math_private.h"
+
+static const long double
+one=  1.00000000000000000000e+00;
+
+#ifdef __i386__
+/* XXX Work around the fact that gcc truncates long double constants on i386 */
+static volatile double
+pi1 =  3.14159265358979311600e+00,     /*  0x1.921fb54442d18p+1  */
+pi2 =  1.22514845490862001043e-16;     /*  0x1.1a80000000000p-53 */
+#define        pi      ((long double)pi1 + pi2)
+#else
+static const long double
+pi =  3.14159265358979323846264338327950280e+00L;
+#endif
+
+OLM_DLLEXPORT long double
+acosl(long double x)
+{
+       union IEEEl2bits u;
+       long double z,p,q,r,w,s,c,df;
+       int16_t expsign, expt;
+       u.e = x;
+       expsign = u.xbits.expsign;
+       expt = expsign & 0x7fff;
+       if(expt >= BIAS) {      /* |x| >= 1 */
+           if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) {
+               if (expsign>0) return 0.0;      /* acos(1) = 0  */
+               else return pi+2.0*pio2_lo;     /* acos(-1)= pi */
+           }
+           return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+       }
+       if(expt<BIAS-1) {       /* |x| < 0.5 */
+           if(expt<ACOS_CONST) return pio2_hi+pio2_lo;/*x tiny: acosl=pi/2*/
+           z = x*x;
+           p = P(z);
+           q = Q(z);
+           r = p/q;
+           return pio2_hi - (x - (pio2_lo-x*r));
+       } else  if (expsign<0) {        /* x < -0.5 */
+           z = (one+x)*0.5;
+           p = P(z);
+           q = Q(z);
+           s = sqrtl(z);
+           r = p/q;
+           w = r*s-pio2_lo;
+           return pi - 2.0*(s+w);
+       } else {                        /* x > 0.5 */
+           z = (one-x)*0.5;
+           s = sqrtl(z);
+           u.e = s;
+           u.bits.manl = 0;
+           df = u.e;
+           c  = (z-df*df)/(s+df);
+           p = P(z);
+           q = Q(z);
+           r = p/q;
+           w = r*s+c;
+           return 2.0*(df+w);
+       }
+}
diff --git a/src/e_asin.c b/src/e_asin.c
new file mode 100644 (file)
index 0000000..2ec1764
--- /dev/null
@@ -0,0 +1,117 @@
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_asin.c,v 1.15 2011/02/10 07:37:50 das Exp $");
+
+/* __ieee754_asin(x)
+ * Method :                  
+ *     Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ *     we approximate asin(x) on [0,0.5] by
+ *             asin(x) = x + x*x^2*R(x^2)
+ *     where
+ *             R(x^2) is a rational approximation of (asin(x)-x)/x^3 
+ *     and its remez error is bounded by
+ *             |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ *     For x in [0.5,1]
+ *             asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ *     Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ *     then for x>0.98
+ *             asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                     = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ *     For x<=0.98, let pio4_hi = pio2_hi/2, then
+ *             f = hi part of s;
+ *             c = sqrt(z) - f = (z-f*f)/(s+f)         ...f+c=sqrt(z)
+ *     and
+ *             asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                     = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ *                     = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ *     if x is NaN, return x itself;
+ *     if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge =  1.000e+300,
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+       /* coefficient for R(x^2) */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+OLM_DLLEXPORT double
+__ieee754_asin(double x)
+{
+       double t=0.0,w,p,q,c,r,s;
+       int32_t hx,ix;
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>= 0x3ff00000) {           /* |x|>= 1 */
+           u_int32_t lx;
+           GET_LOW_WORD(lx,x);
+           if(((ix-0x3ff00000)|lx)==0)
+                   /* asin(1)=+-pi/2 with inexact */
+               return x*pio2_hi+x*pio2_lo;     
+           return (x-x)/(x-x);         /* asin(|x|>1) is NaN */   
+       } else if (ix<0x3fe00000) {     /* |x|<0.5 */
+           if(ix<0x3e500000) {         /* if |x| < 2**-26 */
+               if(huge+x>one) return x;/* return x with inexact if x!=0*/
+           }
+           t = x*x;
+           p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+           q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+           w = p/q;
+           return x+x*w;
+       }
+       /* 1> |x|>= 0.5 */
+       w = one-fabs(x);
+       t = w*0.5;
+       p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+       q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+       s = sqrt(t);
+       if(ix>=0x3FEF3333) {    /* if |x| > 0.975 */
+           w = p/q;
+           t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+       } else {
+           w  = s;
+           SET_LOW_WORD(w,0);
+           c  = (t-w*w)/(s+w);
+           r  = p/q;
+           p  = 2.0*s*r-(pio2_lo-2.0*c);
+           q  = pio4_hi-2.0*w;
+           t  = pio4_hi-(p-q);
+       }    
+       if(hx>0) return t; else return -t;    
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(asin, asinl);
+#endif
diff --git a/src/e_asinf.c b/src/e_asinf.c
new file mode 100644 (file)
index 0000000..1c1ab2c
--- /dev/null
@@ -0,0 +1,66 @@
+/* e_asinf.c -- float version of e_asin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_asinf.c,v 1.13 2008/08/08 00:21:27 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+huge =  1.000e+30,
+       /* coefficient for R(x^2) */
+pS0 =  1.6666586697e-01,
+pS1 = -4.2743422091e-02,
+pS2 = -8.6563630030e-03,
+qS1 = -7.0662963390e-01;
+
+static const double
+pio2 =  1.570796326794896558e+00;
+
+OLM_DLLEXPORT float
+__ieee754_asinf(float x)
+{
+       double s;
+       float t,w,p,q;
+       int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x3f800000) {            /* |x| >= 1 */
+           if(ix==0x3f800000)          /* |x| == 1 */
+               return x*pio2;          /* asin(+-1) = +-pi/2 with inexact */
+           return (x-x)/(x-x);         /* asin(|x|>1) is NaN */
+       } else if (ix<0x3f000000) {     /* |x|<0.5 */
+           if(ix<0x39800000) {         /* |x| < 2**-12 */
+               if(huge+x>one) return x;/* return x with inexact if x!=0*/
+           }
+           t = x*x;
+           p = t*(pS0+t*(pS1+t*pS2));
+           q = one+t*qS1;
+           w = p/q;
+           return x+x*w;
+       }
+       /* 1> |x|>= 0.5 */
+       w = one-fabsf(x);
+       t = w*(float)0.5;
+       p = t*(pS0+t*(pS1+t*pS2));
+       q = one+t*qS1;
+       s = sqrt(t);
+       w = p/q;
+       t = pio2-2.0*(s+s*w);
+       if(hx>0) return t; else return -t;
+}
diff --git a/src/e_asinl.c b/src/e_asinl.c
new file mode 100644 (file)
index 0000000..521913a
--- /dev/null
@@ -0,0 +1,77 @@
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/* FreeBSD: head/lib/msun/src/e_asin.c 176451 2008-02-22 02:30:36Z das */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_asinl.c,v 1.2 2008/08/03 17:49:05 das Exp $");
+
+/*
+ * See comments in e_asin.c.
+ * Converted to long double by David Schultz <das@FreeBSD.ORG>.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "invtrig.h"
+#include "math_private.h"
+
+static const long double
+one =  1.00000000000000000000e+00,
+huge = 1.000e+300;
+
+OLM_DLLEXPORT long double
+asinl(long double x)
+{
+       union IEEEl2bits u;
+       long double t=0.0,w,p,q,c,r,s;
+       int16_t expsign, expt;
+       u.e = x;
+       expsign = u.xbits.expsign;
+       expt = expsign & 0x7fff;
+       if(expt >= BIAS) {              /* |x|>= 1 */
+               if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0)
+                   /* asin(1)=+-pi/2 with inexact */
+                   return x*pio2_hi+x*pio2_lo; 
+           return (x-x)/(x-x);         /* asin(|x|>1) is NaN */   
+       } else if (expt<BIAS-1) {       /* |x|<0.5 */
+           if(expt<ASIN_LINEAR) {      /* if |x| is small, asinl(x)=x */
+               if(huge+x>one) return x;/* return x with inexact if x!=0*/
+           }
+           t = x*x;
+           p = P(t);
+           q = Q(t);
+           w = p/q;
+           return x+x*w;
+       }
+       /* 1> |x|>= 0.5 */
+       w = one-fabsl(x);
+       t = w*0.5;
+       p = P(t);
+       q = Q(t);
+       s = sqrtl(t);
+       if(u.bits.manh>=THRESH) {       /* if |x| is close to 1 */
+           w = p/q;
+           t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+       } else {
+           u.e = s;
+           u.bits.manl = 0;
+           w = u.e;
+           c  = (t-w*w)/(s+w);
+           r  = p/q;
+           p  = 2.0*s*r-(pio2_lo-2.0*c);
+           q  = pio4_hi-2.0*w;
+           t  = pio4_hi-(p-q);
+       }    
+       if(expsign>0) return t; else return -t;    
+}
diff --git a/src/e_atan2.c b/src/e_atan2.c
new file mode 100644 (file)
index 0000000..70384dc
--- /dev/null
@@ -0,0 +1,129 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2.c,v 1.14 2008/08/02 19:17:00 das Exp $");
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ *     1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ *     2. Reduce x to positive by (if x and y are unexceptional): 
+ *             ARG (x+iy) = arctan(y/x)           ... if x > 0,
+ *             ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0,
+ *
+ * Special cases:
+ *
+ *     ATAN2((anything), NaN ) is NaN;
+ *     ATAN2(NAN , (anything) ) is NaN;
+ *     ATAN2(+-0, +(anything but NaN)) is +-0  ;
+ *     ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ *     ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ *     ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ *     ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ *     ATAN2(+-INF,+INF ) is +-pi/4 ;
+ *     ATAN2(+-INF,-INF ) is +-3pi/4;
+ *     ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static volatile double
+tiny  = 1.0e-300;
+static const double
+zero  = 0.0,
+pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi      = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */
+static volatile double
+pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+OLM_DLLEXPORT double
+__ieee754_atan2(double y, double x)
+{
+       double z;
+       int32_t k,m,hx,hy,ix,iy;
+       u_int32_t lx,ly;
+
+       EXTRACT_WORDS(hx,lx,x);
+       ix = hx&0x7fffffff;
+       EXTRACT_WORDS(hy,ly,y);
+       iy = hy&0x7fffffff;
+       if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+          ((iy|((ly|-ly)>>31))>0x7ff00000))    /* x or y is NaN */
+          return x+y;
+       if(hx==0x3ff00000&&lx==0) return atan(y);   /* x=1.0 */
+       m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+       if((iy|ly)==0) {
+           switch(m) {
+               case 0: 
+               case 1: return y;       /* atan(+-0,+anything)=+-0 */
+               case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+               case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+           }
+       }
+    /* when x = 0 */
+       if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+           
+    /* when x is INF */
+       if(ix==0x7ff00000) {
+           if(iy==0x7ff00000) {
+               switch(m) {
+                   case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                   case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                   case 2: return  3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                   case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+               }
+           } else {
+               switch(m) {
+                   case 0: return  zero  ;     /* atan(+...,+INF) */
+                   case 1: return -zero  ;     /* atan(-...,+INF) */
+                   case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                   case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+               }
+           }
+       }
+    /* when y is INF */
+       if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+       k = (iy-ix)>>20;
+       if(k > 60) {                    /* |y/x| >  2**60 */
+           z=pi_o_2+0.5*pi_lo;
+           m&=1;
+       }
+       else if(hx<0&&k<-60) z=0.0;     /* 0 > |y|/x > -2**-60 */
+       else z=atan(fabs(y/x));         /* safe to do y/x */
+       switch (m) {
+           case 0: return       z  ;   /* atan(+,+) */
+           case 1: return      -z  ;   /* atan(-,+) */
+           case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+           default: /* case 3 */
+                   return  (z-pi_lo)-pi;/* atan(-,-) */
+       }
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(atan2, atan2l);
+#endif
diff --git a/src/e_atan2f.c b/src/e_atan2f.c
new file mode 100644 (file)
index 0000000..a52a581
--- /dev/null
@@ -0,0 +1,97 @@
+/* e_atan2f.c -- float version of e_atan2.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2f.c,v 1.12 2008/08/03 17:39:54 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static volatile float
+tiny  = 1.0e-30;
+static const float
+zero  = 0.0,
+pi_o_4  = 7.8539818525e-01, /* 0x3f490fdb */
+pi_o_2  = 1.5707963705e+00, /* 0x3fc90fdb */
+pi      = 3.1415927410e+00; /* 0x40490fdb */
+static volatile float
+pi_lo   = -8.7422776573e-08; /* 0xb3bbbd2e */
+
+OLM_DLLEXPORT float
+__ieee754_atan2f(float y, float x)
+{
+       float z;
+       int32_t k,m,hx,hy,ix,iy;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       GET_FLOAT_WORD(hy,y);
+       iy = hy&0x7fffffff;
+       if((ix>0x7f800000)||
+          (iy>0x7f800000))     /* x or y is NaN */
+          return x+y;
+       if(hx==0x3f800000) return atanf(y);   /* x=1.0 */
+       m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+       if(iy==0) {
+           switch(m) {
+               case 0:
+               case 1: return y;       /* atan(+-0,+anything)=+-0 */
+               case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+               case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+           }
+       }
+    /* when x = 0 */
+       if(ix==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* when x is INF */
+       if(ix==0x7f800000) {
+           if(iy==0x7f800000) {
+               switch(m) {
+                   case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                   case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                   case 2: return  (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                   case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+               }
+           } else {
+               switch(m) {
+                   case 0: return  zero  ;     /* atan(+...,+INF) */
+                   case 1: return -zero  ;     /* atan(-...,+INF) */
+                   case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                   case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+               }
+           }
+       }
+    /* when y is INF */
+       if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+       k = (iy-ix)>>23;
+       if(k > 26) {                    /* |y/x| >  2**26 */
+           z=pi_o_2+(float)0.5*pi_lo;
+           m&=1;
+       }
+       else if(k<-26&&hx<0) z=0.0;     /* 0 > |y|/x > -2**-26 */
+       else z=atanf(fabsf(y/x));       /* safe to do y/x */
+       switch (m) {
+           case 0: return       z  ;   /* atan(+,+) */
+           case 1: return      -z  ;   /* atan(-,+) */
+           case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+           default: /* case 3 */
+                   return  (z-pi_lo)-pi;/* atan(-,-) */
+       }
+}
diff --git a/src/e_atan2l.c b/src/e_atan2l.c
new file mode 100644 (file)
index 0000000..1c0a796
--- /dev/null
@@ -0,0 +1,120 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/* FreeBSD: head/lib/msun/src/e_atan2.c 176451 2008-02-22 02:30:36Z das */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2l.c,v 1.3 2008/08/02 19:17:00 das Exp $");
+
+/*
+ * See comments in e_atan2.c.
+ * Converted to long double by David Schultz <das@FreeBSD.ORG>.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "invtrig.h"
+#include "math_private.h"
+
+static volatile long double
+tiny  = 1.0e-300;
+static const long double
+zero  = 0.0;
+
+#ifdef __i386__
+/* XXX Work around the fact that gcc truncates long double constants on i386 */
+static volatile double
+pi1 =  3.14159265358979311600e+00,     /*  0x1.921fb54442d18p+1  */
+pi2 =  1.22514845490862001043e-16;     /*  0x1.1a80000000000p-53 */
+#define        pi      ((long double)pi1 + pi2)
+#else
+static const long double
+pi =  3.14159265358979323846264338327950280e+00L;
+#endif
+
+OLM_DLLEXPORT long double
+atan2l(long double y, long double x)
+{
+       union IEEEl2bits ux, uy;
+       long double z;
+       int32_t k,m;
+       int16_t exptx, expsignx, expty, expsigny;
+
+       uy.e = y;
+       expsigny = uy.xbits.expsign;
+       expty = expsigny & 0x7fff;
+       ux.e = x;
+       expsignx = ux.xbits.expsign;
+       exptx = expsignx & 0x7fff;
+
+       if ((exptx==BIAS+LDBL_MAX_EXP &&
+            ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)!=0) ||    /* x is NaN */
+           (expty==BIAS+LDBL_MAX_EXP &&
+            ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0))      /* y is NaN */
+           return x+y;
+       if (expsignx==BIAS && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0)
+           return atanl(y);                                    /* x=1.0 */
+       m = ((expsigny>>15)&1)|((expsignx>>14)&2);      /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+       if(expty==0 && ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)==0) {
+           switch(m) {
+               case 0: 
+               case 1: return y;       /* atan(+-0,+anything)=+-0 */
+               case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+               case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+           }
+       }
+    /* when x = 0 */
+       if(exptx==0 && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0)
+           return (expsigny<0)?  -pio2_hi-tiny: pio2_hi+tiny;
+
+    /* when x is INF */
+       if(exptx==BIAS+LDBL_MAX_EXP) {
+           if(expty==BIAS+LDBL_MAX_EXP) {
+               switch(m) {
+                   case 0: return  pio2_hi*0.5+tiny;/* atan(+INF,+INF) */
+                   case 1: return -pio2_hi*0.5-tiny;/* atan(-INF,+INF) */
+                   case 2: return  1.5*pio2_hi+tiny;/*atan(+INF,-INF)*/
+                   case 3: return -1.5*pio2_hi-tiny;/*atan(-INF,-INF)*/
+               }
+           } else {
+               switch(m) {
+                   case 0: return  zero  ;     /* atan(+...,+INF) */
+                   case 1: return -zero  ;     /* atan(-...,+INF) */
+                   case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                   case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+               }
+           }
+       }
+    /* when y is INF */
+       if(expty==BIAS+LDBL_MAX_EXP)
+           return (expsigny<0)? -pio2_hi-tiny: pio2_hi+tiny;
+
+    /* compute y/x */
+       k = expty-exptx;
+       if(k > LDBL_MANT_DIG+2) {                       /* |y/x| huge */
+           z=pio2_hi+pio2_lo;
+           m&=1;
+       }
+       else if(expsignx<0&&k<-LDBL_MANT_DIG-2) z=0.0;  /* |y/x| tiny, x<0 */
+       else z=atanl(fabsl(y/x));               /* safe to do y/x */
+       switch (m) {
+           case 0: return       z  ;   /* atan(+,+) */
+           case 1: return      -z  ;   /* atan(-,+) */
+           case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+           default: /* case 3 */
+                   return  (z-pi_lo)-pi;/* atan(-,-) */
+       }
+}
diff --git a/src/e_atanh.c b/src/e_atanh.c
new file mode 100644 (file)
index 0000000..b278af3
--- /dev/null
@@ -0,0 +1,63 @@
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_atanh.c,v 1.8 2008/02/22 02:30:34 das Exp $");
+
+/* __ieee754_atanh(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                  1              2x                          x
+ *     atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                  2             1 - x                      1 - x
+ *     
+ *     For x<0.5
+ *     atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *     atanh(x) is NaN if |x| > 1 with signal;
+ *     atanh(NaN) is that NaN with no signal;
+ *     atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0, huge = 1e300;
+static const double zero = 0.0;
+
+OLM_DLLEXPORT double
+__ieee754_atanh(double x)
+{
+       double t;
+       int32_t hx,ix;
+       u_int32_t lx;
+       EXTRACT_WORDS(hx,lx,x);
+       ix = hx&0x7fffffff;
+       if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+           return (x-x)/(x-x);
+       if(ix==0x3ff00000) 
+           return x/zero;
+       if(ix<0x3e300000&&(huge+x)>zero) return x;      /* x<2**-28 */
+       SET_HIGH_WORD(x,ix);
+       if(ix<0x3fe00000) {             /* x < 0.5 */
+           t = x+x;
+           t = 0.5*log1p(t+t*x/(one-x));
+       } else 
+           t = 0.5*log1p((x+x)/(one-x));
+       if(hx>=0) return t; else return -t;
+}
diff --git a/src/e_atanhf.c b/src/e_atanhf.c
new file mode 100644 (file)
index 0000000..1ce329c
--- /dev/null
@@ -0,0 +1,46 @@
+/* e_atanhf.c -- float version of e_atanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_atanhf.c,v 1.7 2008/02/22 02:30:34 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one = 1.0, huge = 1e30;
+
+static const float zero = 0.0;
+
+OLM_DLLEXPORT float
+__ieee754_atanhf(float x)
+{
+       float t;
+       int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if (ix>0x3f800000)              /* |x|>1 */
+           return (x-x)/(x-x);
+       if(ix==0x3f800000)
+           return x/zero;
+       if(ix<0x31800000&&(huge+x)>zero) return x;      /* x<2**-28 */
+       SET_FLOAT_WORD(x,ix);
+       if(ix<0x3f000000) {             /* x < 0.5 */
+           t = x+x;
+           t = (float)0.5*log1pf(t+t*x/(one-x));
+       } else
+           t = (float)0.5*log1pf((x+x)/(one-x));
+       if(hx>=0) return t; else return -t;
+}
diff --git a/src/e_cosh.c b/src/e_cosh.c
new file mode 100644 (file)
index 0000000..a4bfe0b
--- /dev/null
@@ -0,0 +1,80 @@
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_cosh.c,v 1.10 2011/10/21 06:28:47 das Exp $");
+
+/* __ieee754_cosh(x)
+ * Method : 
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ *     1. Replace x by |x| (cosh(x) = cosh(-x)). 
+ *     2. 
+ *                                                     [ exp(x) - 1 ]^2 
+ *         0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+ *                                                        2*exp(x)
+ *
+ *                                               exp(x) +  1/exp(x)
+ *         ln2/2    <= x <= 22     :  cosh(x) := -------------------
+ *                                                       2
+ *         22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+ *         lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+ *         ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ *     cosh(x) is |x| if x is +INF, -INF, or NaN.
+ *     only cosh(0)=1 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+
+OLM_DLLEXPORT double
+__ieee754_cosh(double x)
+{
+       double t,w;
+       int32_t ix;
+
+    /* High word of |x|. */
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7ff00000) return x*x;  
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+       if(ix<0x3fd62e43) {
+           t = expm1(fabs(x));
+           w = one+t;
+           if (ix<0x3c800000) return w;        /* cosh(tiny) = 1 */
+           return one+(t*t)/(w+w);
+       }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+       if (ix < 0x40360000) {
+               t = __ieee754_exp(fabs(x));
+               return half*t+half/t;
+       }
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+       if (ix < 0x40862E42)  return half*__ieee754_exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+       if (ix<=0x408633CE)
+           return __ldexp_exp(fabs(x), -1);
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+       return huge*huge;
+}
diff --git a/src/e_coshf.c b/src/e_coshf.c
new file mode 100644 (file)
index 0000000..e129659
--- /dev/null
@@ -0,0 +1,60 @@
+/* e_coshf.c -- float version of e_cosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_coshf.c,v 1.9 2011/10/21 06:28:47 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one = 1.0, half=0.5, huge = 1.0e30;
+
+OLM_DLLEXPORT float
+__ieee754_coshf(float x)
+{
+       float t,w;
+       int32_t ix;
+
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7f800000) return x*x;
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+       if(ix<0x3eb17218) {
+           t = expm1f(fabsf(x));
+           w = one+t;
+           if (ix<0x39800000) return one;      /* cosh(tiny) = 1 */
+           return one+(t*t)/(w+w);
+       }
+
+    /* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */
+       if (ix < 0x41100000) {
+               t = __ieee754_expf(fabsf(x));
+               return half*t+half/t;
+       }
+
+    /* |x| in [9, log(maxfloat)] return half*exp(|x|) */
+       if (ix < 0x42b17217)  return half*__ieee754_expf(fabsf(x));
+
+    /* |x| in [log(maxfloat), overflowthresold] */
+       if (ix<=0x42b2d4fc)
+           return __ldexp_expf(fabsf(x), -1);
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+       return huge*huge;
+}
diff --git a/src/e_exp.c b/src/e_exp.c
new file mode 100644 (file)
index 0000000..ed0e3fe
--- /dev/null
@@ -0,0 +1,167 @@
+
+/* @(#)e_exp.c 1.6 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_exp.c,v 1.14 2011/10/21 06:26:38 das Exp $");
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ *     Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2.  
+ *
+ *      Here r will be represented as r = hi-lo for better 
+ *     accuracy.
+ *
+ *   2. Approximation of exp(r) by a special rational function on
+ *     the interval [0,0.34658]:
+ *     Write
+ *         R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ *      We use a special Remes algorithm on [0,0.34658] to generate 
+ *     a polynomial of degree 5 to approximate R. The maximum error 
+ *     of this polynomial approximation is bounded by 2**-59. In
+ *     other words,
+ *         R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ *     (where z=r*r, and the values of P1 to P5 are listed below)
+ *     and
+ *         |                  5          |     -59
+ *         | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 
+ *         |                             |
+ *     The computation of exp(r) thus becomes
+ *                             2*r
+ *             exp(r) = 1 + -------
+ *                           R - r
+ *                                 r*R1(r)     
+ *                    = 1 + r + ----------- (for better accuracy)
+ *                               2 - R1(r)
+ *     where
+ *                              2       4             10
+ *             R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+ *     
+ *   3. Scale back to obtain exp(x):
+ *     From step 1, we have
+ *        exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ *     exp(INF) is INF, exp(NaN) is NaN;
+ *     exp(-INF) is 0, and
+ *     for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ *     according to an error analysis, the error is always less than
+ *     1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *     For IEEE double 
+ *         if x >  7.09782712893383973096e+02 then exp(x) overflow
+ *         if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one    = 1.0,
+halF[2]        = {0.5,-0.5,},
+huge   = 1.0e+300,
+o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */
+ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */
+            -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */
+            -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+static volatile double
+twom1000= 9.33263618503218878990e-302;     /* 2**-1000=0x01700000,0*/
+
+OLM_DLLEXPORT double
+__ieee754_exp(double x)        /* default IEEE double exp */
+{
+       double y,hi=0.0,lo=0.0,c,t,twopk;
+       int32_t k=0,xsb;
+       u_int32_t hx;
+
+       GET_HIGH_WORD(hx,x);
+       xsb = (hx>>31)&1;               /* sign bit of x */
+       hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+       if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */
+            if(hx>=0x7ff00000) {
+               u_int32_t lx;
+               GET_LOW_WORD(lx,x);
+               if(((hx&0xfffff)|lx)!=0)
+                    return x+x;                /* NaN */
+               else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */
+           }
+           if(x > o_threshold) return huge*huge; /* overflow */
+           if(x < u_threshold) return twom1000*twom1000; /* underflow */
+       }
+
+        /* this implementation gives 2.7182818284590455 for exp(1.0),
+           which is well within the allowable error. however,
+           2.718281828459045 is closer to the true value so we prefer that
+           answer, given that 1.0 is such an important argument value. */
+        if (x == 1.0)
+            return 2.718281828459045235360;
+
+    /* argument reduction */
+       if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */ 
+           if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+               hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+           } else {
+               k  = (int)(invln2*x+halF[xsb]);
+               t  = k;
+               hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+               lo = t*ln2LO[0];
+           }
+           STRICT_ASSIGN(double, x, hi - lo);
+       } 
+       else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */
+           if(huge+x>one) return one+x;/* trigger inexact */
+       }
+       else k = 0;
+
+    /* x is now in primary range */
+       t  = x*x;
+       if(k >= -1021)
+           INSERT_WORDS(twopk,0x3ff00000+(k<<20), 0);
+       else
+           INSERT_WORDS(twopk,0x3ff00000+((k+1000)<<20), 0);
+       c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+       if(k==0)        return one-((x*c)/(c-2.0)-x); 
+       else            y = one-((lo-(x*c)/(2.0-c))-hi);
+       if(k >= -1021) {
+           if (k==1024) return y*2.0*0x1p1023;
+           return y*twopk;
+       } else {
+           return y*twopk*twom1000;
+       }
+}
diff --git a/src/e_expf.c b/src/e_expf.c
new file mode 100644 (file)
index 0000000..a239413
--- /dev/null
@@ -0,0 +1,97 @@
+/* e_expf.c -- float version of e_exp.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_expf.c,v 1.16 2011/10/21 06:26:38 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one    = 1.0,
+halF[2]        = {0.5,-0.5,},
+huge   = 1.0e+30,
+o_threshold=  8.8721679688e+01,  /* 0x42b17180 */
+u_threshold= -1.0397208405e+02,  /* 0xc2cff1b5 */
+ln2HI[2]   ={ 6.9314575195e-01,                /* 0x3f317200 */
+            -6.9314575195e-01,},       /* 0xbf317200 */
+ln2LO[2]   ={ 1.4286067653e-06,        /* 0x35bfbe8e */
+            -1.4286067653e-06,},       /* 0xb5bfbe8e */
+invln2 =  1.4426950216e+00,            /* 0x3fb8aa3b */
+/*
+ * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
+ * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
+ */
+P1 =  1.6666625440e-1,         /*  0xaaaa8f.0p-26 */
+P2 = -2.7667332906e-3;         /* -0xb55215.0p-32 */
+
+static volatile float twom100 = 7.8886090522e-31;      /* 2**-100=0x0d800000 */
+
+OLM_DLLEXPORT float
+__ieee754_expf(float x)
+{
+       float y,hi=0.0,lo=0.0,c,t,twopk;
+       int32_t k=0,xsb;
+       u_int32_t hx;
+
+       GET_FLOAT_WORD(hx,x);
+       xsb = (hx>>31)&1;               /* sign bit of x */
+       hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+       if(hx >= 0x42b17218) {                  /* if |x|>=88.721... */
+           if(hx>0x7f800000)
+                return x+x;                    /* NaN */
+            if(hx==0x7f800000)
+               return (xsb==0)? x:0.0;         /* exp(+-inf)={inf,0} */
+           if(x > o_threshold) return huge*huge; /* overflow */
+           if(x < u_threshold) return twom100*twom100; /* underflow */
+       }
+
+    /* argument reduction */
+       if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+           if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+               hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+           } else {
+               k  = invln2*x+halF[xsb];
+               t  = k;
+               hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+               lo = t*ln2LO[0];
+           }
+           STRICT_ASSIGN(float, x, hi - lo);
+       }
+       else if(hx < 0x39000000)  {     /* when |x|<2**-14 */
+           if(huge+x>one) return one+x;/* trigger inexact */
+       }
+       else k = 0;
+
+    /* x is now in primary range */
+       t  = x*x;
+       if(k >= -125)
+           SET_FLOAT_WORD(twopk,0x3f800000+(k<<23));
+       else
+           SET_FLOAT_WORD(twopk,0x3f800000+((k+100)<<23));
+       c  = x - t*(P1+t*P2);
+       if(k==0)        return one-((x*c)/(c-(float)2.0)-x);
+       else            y = one-((lo-(x*c)/((float)2.0-c))-hi);
+       if(k >= -125) {
+           if(k==128) return y*2.0F*0x1p127F;
+           return y*twopk;
+       } else {
+           return y*twopk*twom100;
+       }
+}
diff --git a/src/e_fmod.c b/src/e_fmod.c
new file mode 100644 (file)
index 0000000..285da8d
--- /dev/null
@@ -0,0 +1,133 @@
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmod.c,v 1.10 2008/02/22 02:30:34 das Exp $");
+
+/* 
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+OLM_DLLEXPORT double
+__ieee754_fmod(double x, double y)
+{
+       int32_t n,hx,hy,hz,ix,iy,sx,i;
+       u_int32_t lx,ly,lz;
+
+       EXTRACT_WORDS(hx,lx,x);
+       EXTRACT_WORDS(hy,ly,y);
+       sx = hx&0x80000000;             /* sign of x */
+       hx ^=sx;                /* |x| */
+       hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+       if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+         ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+           return (x*y)/(x*y);
+       if(hx<=hy) {
+           if((hx<hy)||(lx<ly)) return x;      /* |x|<|y| return x */
+           if(lx==ly) 
+               return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+       }
+
+    /* determine ix = ilogb(x) */
+       if(hx<0x00100000) {     /* subnormal x */
+           if(hx==0) {
+               for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+           } else {
+               for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+           }
+       } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+       if(hy<0x00100000) {     /* subnormal y */
+           if(hy==0) {
+               for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+           } else {
+               for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+           }
+       } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       if(ix >= -1022) 
+           hx = 0x00100000|(0x000fffff&hx);
+       else {          /* subnormal x, shift x to normal */
+           n = -1022-ix;
+           if(n<=31) {
+               hx = (hx<<n)|(lx>>(32-n));
+               lx <<= n;
+           } else {
+               hx = lx<<(n-32);
+               lx = 0;
+           }
+       }
+       if(iy >= -1022) 
+           hy = 0x00100000|(0x000fffff&hy);
+       else {          /* subnormal y, shift y to normal */
+           n = -1022-iy;
+           if(n<=31) {
+               hy = (hy<<n)|(ly>>(32-n));
+               ly <<= n;
+           } else {
+               hy = ly<<(n-32);
+               ly = 0;
+           }
+       }
+
+    /* fix point fmod */
+       n = ix - iy;
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+           else {
+               if((hz|lz)==0)          /* return sign(x)*0 */
+                   return Zero[(u_int32_t)sx>>31];
+               hx = hz+hz+(lz>>31); lx = lz+lz;
+           }
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0)                  /* return sign(x)*0 */
+           return Zero[(u_int32_t)sx>>31];
+       while(hx<0x00100000) {          /* normalize x */
+           hx = hx+hx+(lx>>31); lx = lx+lx;
+           iy -= 1;
+       }
+       if(iy>= -1022) {        /* normalize output */
+           hx = ((hx-0x00100000)|((iy+1023)<<20));
+           INSERT_WORDS(x,hx|sx,lx);
+       } else {                /* subnormal output */
+           n = -1022 - iy;
+           if(n<=20) {
+               lx = (lx>>n)|((u_int32_t)hx<<(32-n));
+               hx >>= n;
+           } else if (n<=31) {
+               lx = (hx<<(32-n))|(lx>>n); hx = sx;
+           } else {
+               lx = hx>>(n-32); hx = sx;
+           }
+           INSERT_WORDS(x,hx|sx,lx);
+           x *= one;           /* create necessary signal */
+       }
+       return x;               /* exact output */
+}
diff --git a/src/e_fmodf.c b/src/e_fmodf.c
new file mode 100644 (file)
index 0000000..88fd8ae
--- /dev/null
@@ -0,0 +1,105 @@
+/* e_fmodf.c -- float version of e_fmod.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmodf.c,v 1.7 2008/02/22 02:30:34 das Exp $");
+
+/*
+ * __ieee754_fmodf(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one = 1.0, Zero[] = {0.0, -0.0,};
+
+OLM_DLLEXPORT float
+__ieee754_fmodf(float x, float y)
+{
+       int32_t n,hx,hy,hz,ix,iy,sx,i;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_FLOAT_WORD(hy,y);
+       sx = hx&0x80000000;             /* sign of x */
+       hx ^=sx;                /* |x| */
+       hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+       if(hy==0||(hx>=0x7f800000)||            /* y=0,or x not finite */
+          (hy>0x7f800000))                     /* or y is NaN */
+           return (x*y)/(x*y);
+       if(hx<hy) return x;                     /* |x|<|y| return x */
+       if(hx==hy)
+           return Zero[(u_int32_t)sx>>31];     /* |x|=|y| return x*0*/
+
+    /* determine ix = ilogb(x) */
+       if(hx<0x00800000) {     /* subnormal x */
+           for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+       } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+       if(hy<0x00800000) {     /* subnormal y */
+           for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1;
+       } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       if(ix >= -126)
+           hx = 0x00800000|(0x007fffff&hx);
+       else {          /* subnormal x, shift x to normal */
+           n = -126-ix;
+           hx = hx<<n;
+       }
+       if(iy >= -126)
+           hy = 0x00800000|(0x007fffff&hy);
+       else {          /* subnormal y, shift y to normal */
+           n = -126-iy;
+           hy = hy<<n;
+       }
+
+    /* fix point fmod */
+       n = ix - iy;
+       while(n--) {
+           hz=hx-hy;
+           if(hz<0){hx = hx+hx;}
+           else {
+               if(hz==0)               /* return sign(x)*0 */
+                   return Zero[(u_int32_t)sx>>31];
+               hx = hz+hz;
+           }
+       }
+       hz=hx-hy;
+       if(hz>=0) {hx=hz;}
+
+    /* convert back to floating value and restore the sign */
+       if(hx==0)                       /* return sign(x)*0 */
+           return Zero[(u_int32_t)sx>>31];
+       while(hx<0x00800000) {          /* normalize x */
+           hx = hx+hx;
+           iy -= 1;
+       }
+       if(iy>= -126) {         /* normalize output */
+           hx = ((hx-0x00800000)|((iy+127)<<23));
+           SET_FLOAT_WORD(x,hx|sx);
+       } else {                /* subnormal output */
+           n = -126 - iy;
+           hx >>= n;
+           SET_FLOAT_WORD(x,hx|sx);
+           x *= one;           /* create necessary signal */
+       }
+       return x;               /* exact output */
+}
diff --git a/src/e_fmodl.c b/src/e_fmodl.c
new file mode 100644 (file)
index 0000000..47d961b
--- /dev/null
@@ -0,0 +1,150 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmodl.c,v 1.2 2008/07/31 20:09:47 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+
+#include "math_private.h"
+
+#define        BIAS (LDBL_MAX_EXP - 1)
+
+#if LDBL_MANL_SIZE > 32
+typedef        u_int64_t manl_t;
+#else
+typedef        u_int32_t manl_t;
+#endif
+
+#if LDBL_MANH_SIZE > 32
+typedef        u_int64_t manh_t;
+#else
+typedef        u_int32_t manh_t;
+#endif
+
+/*
+ * These macros add and remove an explicit integer bit in front of the
+ * fractional mantissa, if the architecture doesn't have such a bit by
+ * default already.
+ */
+#ifdef LDBL_IMPLICIT_NBIT
+#define        SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
+#define        HFRAC_BITS      LDBL_MANH_SIZE
+#else
+#define        SET_NBIT(hx)    (hx)
+#define        HFRAC_BITS      (LDBL_MANH_SIZE - 1)
+#endif
+
+#define        MANL_SHIFT      (LDBL_MANL_SIZE - 1)
+
+static const long double one = 1.0, Zero[] = {0.0, -0.0,};
+
+/*
+ * fmodl(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ *
+ * Assumptions:
+ * - The low part of the mantissa fits in a manl_t exactly.
+ * - The high part of the mantissa fits in an int64_t with enough room
+ *   for an explicit integer bit in front of the fractional bits.
+ */
+OLM_DLLEXPORT long double
+fmodl(long double x, long double y)
+{
+       union IEEEl2bits ux, uy;
+       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
+       manh_t hy;
+       manl_t lx,ly,lz;
+       int ix,iy,n,sx;
+
+       ux.e = x;
+       uy.e = y;
+       sx = ux.bits.sign;
+
+    /* purge off exception values */
+       if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */
+          (ux.bits.exp == BIAS + LDBL_MAX_EXP) ||       /* or x not finite */
+          (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
+           ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */
+           return (x*y)/(x*y);
+       if(ux.bits.exp<=uy.bits.exp) {
+           if((ux.bits.exp<uy.bits.exp) ||
+              (ux.bits.manh<=uy.bits.manh &&
+               (ux.bits.manh<uy.bits.manh ||
+                ux.bits.manl<uy.bits.manl))) {
+               return x;               /* |x|<|y| return x or x-y */
+           }
+           if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) {
+               return Zero[sx];        /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if(ux.bits.exp == 0) {  /* subnormal x */
+           ux.e *= 0x1.0p512;
+           ix = ux.bits.exp - (BIAS + 512);
+       } else {
+           ix = ux.bits.exp - BIAS;
+       }
+
+    /* determine iy = ilogb(y) */
+       if(uy.bits.exp == 0) {  /* subnormal y */
+           uy.e *= 0x1.0p512;
+           iy = uy.bits.exp - (BIAS + 512);
+       } else {
+           iy = uy.bits.exp - BIAS;
+       }
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       hx = SET_NBIT(ux.bits.manh);
+       hy = SET_NBIT(uy.bits.manh);
+       lx = ux.bits.manl;
+       ly = uy.bits.manl;
+
+    /* fix point fmod */
+       n = ix - iy;
+
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;}
+           else {
+               if ((hz|lz)==0)         /* return sign(x)*0 */
+                   return Zero[sx];
+               hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz;
+           }
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0)                  /* return sign(x)*0 */
+           return Zero[sx];
+       while(hx<(1ULL<<HFRAC_BITS)) {  /* normalize x */
+           hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;
+           iy -= 1;
+       }
+       ux.bits.manh = hx; /* The mantissa is truncated here if needed. */
+       ux.bits.manl = lx;
+       if (iy < LDBL_MIN_EXP) {
+           ux.bits.exp = iy + (BIAS + 512);
+           ux.e *= 0x1p-512;
+       } else {
+           ux.bits.exp = iy + BIAS;
+       }
+       x = ux.e * one;         /* create necessary signal */
+       return x;               /* exact output */
+}
diff --git a/src/e_hypot.c b/src/e_hypot.c
new file mode 100644 (file)
index 0000000..23fdc95
--- /dev/null
@@ -0,0 +1,131 @@
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypot.c,v 1.14 2011/10/15 07:00:28 das Exp $");
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :                  
+ *     If (assume round-to-nearest) z=x*x+y*y 
+ *     has error less than sqrt(2)/2 ulp, than 
+ *     sqrt(z) has error less than 1 ulp (exercise).
+ *
+ *     So, compute sqrt(x*x+y*y) with some care as 
+ *     follows to get the error below 1 ulp:
+ *
+ *     Assume x>y>0;
+ *     (if possible, set rounding to round-to-nearest)
+ *     1. if x > 2y  use
+ *             x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *     where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ *     2. if x <= 2y use
+ *             t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *     where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, 
+ *     y1= y with lower 32 bits chopped, y2 = y-y1.
+ *             
+ *     NOTE: scaling may be necessary if some argument is too 
+ *           large or too tiny
+ *
+ * Special cases:
+ *     hypot(x,y) is INF if x or y is +INF or -INF; else
+ *     hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ *     hypot(x,y) returns sqrt(x^2+y^2) with error less 
+ *     than 1 ulps (units in the last place) 
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+__ieee754_hypot(double x, double y)
+{
+       double a,b,t1,t2,y1,y2,w;
+       int32_t j,k,ha,hb;
+
+       GET_HIGH_WORD(ha,x);
+       ha &= 0x7fffffff;
+       GET_HIGH_WORD(hb,y);
+       hb &= 0x7fffffff;
+       if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+       a = fabs(a);
+       b = fabs(b);
+       if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+       k=0;
+       if(ha > 0x5f300000) {   /* a>2**500 */
+          if(ha >= 0x7ff00000) {       /* Inf or NaN */
+              u_int32_t low;
+              /* Use original arg order iff result is NaN; quieten sNaNs. */
+              w = fabs(x+0.0)-fabs(y+0.0);
+              GET_LOW_WORD(low,a);
+              if(((ha&0xfffff)|low)==0) w = a;
+              GET_LOW_WORD(low,b);
+              if(((hb^0x7ff00000)|low)==0) w = b;
+              return w;
+          }
+          /* scale a and b by 2**-600 */
+          ha -= 0x25800000; hb -= 0x25800000;  k += 600;
+          SET_HIGH_WORD(a,ha);
+          SET_HIGH_WORD(b,hb);
+       }
+       if(hb < 0x20b00000) {   /* b < 2**-500 */
+           if(hb <= 0x000fffff) {      /* subnormal b or 0 */
+               u_int32_t low;
+               GET_LOW_WORD(low,b);
+               if((hb|low)==0) return a;
+               t1=0;
+               SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */
+               b *= t1;
+               a *= t1;
+               k -= 1022;
+           } else {            /* scale a and b by 2^600 */
+               ha += 0x25800000;       /* a *= 2^600 */
+               hb += 0x25800000;       /* b *= 2^600 */
+               k -= 600;
+               SET_HIGH_WORD(a,ha);
+               SET_HIGH_WORD(b,hb);
+           }
+       }
+    /* medium size a and b */
+       w = a-b;
+       if (w>b) {
+           t1 = 0;
+           SET_HIGH_WORD(t1,ha);
+           t2 = a-t1;
+           w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+       } else {
+           a  = a+a;
+           y1 = 0;
+           SET_HIGH_WORD(y1,hb);
+           y2 = b - y1;
+           t1 = 0;
+           SET_HIGH_WORD(t1,ha+0x00100000);
+           t2 = a - t1;
+           w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+       }
+       if(k!=0) {
+           u_int32_t high;
+           t1 = 1.0;
+           GET_HIGH_WORD(high,t1);
+           SET_HIGH_WORD(t1,high+(k<<20));
+           return t1*w;
+       } else return w;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(hypot, hypotl);
+#endif
diff --git a/src/e_hypotf.c b/src/e_hypotf.c
new file mode 100644 (file)
index 0000000..e90fb5d
--- /dev/null
@@ -0,0 +1,84 @@
+/* e_hypotf.c -- float version of e_hypot.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypotf.c,v 1.14 2011/10/15 07:00:28 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+__ieee754_hypotf(float x, float y)
+{
+       float a,b,t1,t2,y1,y2,w;
+       int32_t j,k,ha,hb;
+
+       GET_FLOAT_WORD(ha,x);
+       ha &= 0x7fffffff;
+       GET_FLOAT_WORD(hb,y);
+       hb &= 0x7fffffff;
+       if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+       a = fabsf(a);
+       b = fabsf(b);
+       if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */
+       k=0;
+       if(ha > 0x58800000) {   /* a>2**50 */
+          if(ha >= 0x7f800000) {       /* Inf or NaN */
+              /* Use original arg order iff result is NaN; quieten sNaNs. */
+              w = fabsf(x+0.0F)-fabsf(y+0.0F);
+              if(ha == 0x7f800000) w = a;
+              if(hb == 0x7f800000) w = b;
+              return w;
+          }
+          /* scale a and b by 2**-68 */
+          ha -= 0x22000000; hb -= 0x22000000;  k += 68;
+          SET_FLOAT_WORD(a,ha);
+          SET_FLOAT_WORD(b,hb);
+       }
+       if(hb < 0x26800000) {   /* b < 2**-50 */
+           if(hb <= 0x007fffff) {      /* subnormal b or 0 */
+               if(hb==0) return a;
+               SET_FLOAT_WORD(t1,0x7e800000);  /* t1=2^126 */
+               b *= t1;
+               a *= t1;
+               k -= 126;
+           } else {            /* scale a and b by 2^68 */
+               ha += 0x22000000;       /* a *= 2^68 */
+               hb += 0x22000000;       /* b *= 2^68 */
+               k -= 68;
+               SET_FLOAT_WORD(a,ha);
+               SET_FLOAT_WORD(b,hb);
+           }
+       }
+    /* medium size a and b */
+       w = a-b;
+       if (w>b) {
+           SET_FLOAT_WORD(t1,ha&0xfffff000);
+           t2 = a-t1;
+           w  = __ieee754_sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
+       } else {
+           a  = a+a;
+           SET_FLOAT_WORD(y1,hb&0xfffff000);
+           y2 = b - y1;
+           SET_FLOAT_WORD(t1,(ha+0x00800000)&0xfffff000);
+           t2 = a - t1;
+           w  = __ieee754_sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+       }
+       if(k!=0) {
+           SET_FLOAT_WORD(t1,0x3f800000+(k<<23));
+           return t1*w;
+       } else return w;
+}
diff --git a/src/e_hypotl.c b/src/e_hypotl.c
new file mode 100644 (file)
index 0000000..047484d
--- /dev/null
@@ -0,0 +1,124 @@
+/* From: @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypotl.c,v 1.3 2011/10/16 05:36:39 das Exp $");
+
+/* long double version of hypot().  See e_hypot.c for most comments. */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#define        GET_LDBL_MAN(h, l, v) do {      \
+       union IEEEl2bits uv;            \
+                                       \
+       uv.e = v;                       \
+       h = uv.bits.manh;               \
+       l = uv.bits.manl;               \
+} while (0)
+
+#undef GET_HIGH_WORD
+#define        GET_HIGH_WORD(i, v)     GET_LDBL_EXPSIGN(i, v)
+#undef SET_HIGH_WORD
+#define        SET_HIGH_WORD(v, i)     SET_LDBL_EXPSIGN(v, i)
+
+#define        DESW(exp)       (exp)           /* delta expsign word */
+#define        ESW(exp)        (MAX_EXP - 1 + (exp))   /* expsign word */
+#define        MANT_DIG        LDBL_MANT_DIG
+#define        MAX_EXP         LDBL_MAX_EXP
+
+#if LDBL_MANL_SIZE > 32
+typedef        u_int64_t man_t;
+#else
+typedef        u_int32_t man_t;
+#endif
+
+OLM_DLLEXPORT long double
+hypotl(long double x, long double y)
+{
+       long double a=x,b=y,t1,t2,y1,y2,w;
+       int32_t j,k,ha,hb;
+
+       GET_HIGH_WORD(ha,x);
+       ha &= 0x7fff;
+       GET_HIGH_WORD(hb,y);
+       hb &= 0x7fff;
+       if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+       a = fabsl(a);
+       b = fabsl(b);
+       if((ha-hb)>DESW(MANT_DIG+7)) {return a+b;} /* x/y > 2**(MANT_DIG+7) */
+       k=0;
+       if(ha > ESW(MAX_EXP/2-12)) {    /* a>2**(MAX_EXP/2-12) */
+          if(ha >= ESW(MAX_EXP)) {     /* Inf or NaN */
+              man_t manh, manl;
+              /* Use original arg order iff result is NaN; quieten sNaNs. */
+              w = fabsl(x+0.0)-fabsl(y+0.0);
+              GET_LDBL_MAN(manh,manl,a);
+              if (manh == LDBL_NBIT && manl == 0) w = a;
+              GET_LDBL_MAN(manh,manl,b);
+              if (hb >= ESW(MAX_EXP) && manh == LDBL_NBIT && manl == 0) w = b;
+              return w;
+          }
+          /* scale a and b by 2**-(MAX_EXP/2+88) */
+          ha -= DESW(MAX_EXP/2+88); hb -= DESW(MAX_EXP/2+88);
+          k += MAX_EXP/2+88;
+          SET_HIGH_WORD(a,ha);
+          SET_HIGH_WORD(b,hb);
+       }
+       if(hb < ESW(-(MAX_EXP/2-12))) { /* b < 2**-(MAX_EXP/2-12) */
+           if(hb <= 0) {               /* subnormal b or 0 */
+               man_t manh, manl;
+               GET_LDBL_MAN(manh,manl,b);
+               if((manh|manl)==0) return a;
+               t1=0;
+               SET_HIGH_WORD(t1,ESW(MAX_EXP-2));       /* t1=2^(MAX_EXP-2) */
+               b *= t1;
+               a *= t1;
+               k -= MAX_EXP-2;
+           } else {            /* scale a and b by 2^(MAX_EXP/2+88) */
+               ha += DESW(MAX_EXP/2+88);
+               hb += DESW(MAX_EXP/2+88);
+               k -= MAX_EXP/2+88;
+               SET_HIGH_WORD(a,ha);
+               SET_HIGH_WORD(b,hb);
+           }
+       }
+    /* medium size a and b */
+       w = a-b;
+       if (w>b) {
+           t1 = a;
+           union IEEEl2bits uv;
+           uv.e = t1; uv.bits.manl = 0; t1 = uv.e;
+           t2 = a-t1;
+           w  = sqrtl(t1*t1-(b*(-b)-t2*(a+t1)));
+       } else {
+           a  = a+a;
+           y1 = b;
+           union IEEEl2bits uv;
+           uv.e = y1; uv.bits.manl = 0; y1 = uv.e;
+           y2 = b - y1;
+           t1 = a;
+           uv.e = t1; uv.bits.manl = 0; t1 = uv.e;
+           t2 = a - t1;
+           w  = sqrtl(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+       }
+       if(k!=0) {
+           u_int32_t high;
+           t1 = 1.0;
+           GET_HIGH_WORD(high,t1);
+           SET_HIGH_WORD(t1,high+DESW(k));
+           return t1*w;
+       } else return w;
+}
diff --git a/src/e_j0.c b/src/e_j0.c
new file mode 100644 (file)
index 0000000..a2419d3
--- /dev/null
@@ -0,0 +1,388 @@
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <assert.h>
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_j0.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ *     1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ *     2. Reduce x to |x| since j0(x)=j0(-x),  and
+ *        for x in (0,2)
+ *             j0(x) = 1-z/4+ z^2*R0/S0,  where z = x*x;
+ *        (precision:  |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ *        for x in (2,inf)
+ *             j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ *        where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ *        as follow:
+ *             cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ *                     = 1/sqrt(2) * (cos(x) + sin(x))
+ *             sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ *                     = 1/sqrt(2) * (sin(x) - cos(x))
+ *        (To avoid cancellation, use
+ *             sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ *         to compute the worse one.)
+ *        
+ *     3 Special cases
+ *             j0(nan)= nan
+ *             j0(0) = 1
+ *             j0(inf) = 0
+ *             
+ * Method -- y0(x):
+ *     1. For x<2.
+ *        Since 
+ *             y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ *        therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ *        We use the following function to approximate y0,
+ *             y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ *        where 
+ *             U(z) = u00 + u01*z + ... + u06*z^6
+ *             V(z) = 1  + v01*z + ... + v04*z^4
+ *        with absolute approximation error bounded by 2**-72.
+ *        Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ *             y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ *     2. For x>=2.
+ *             y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ *        where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ *        by the method mentioned above.
+ *     3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static double pzero(double), qzero(double);
+
+static const double
+huge   = 1e300,
+one    = 1.0,
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi      =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+               /* R0/S0 on [0, 2.00] */
+R02  =  1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03  = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04  =  1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05  = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01  =  1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02  =  1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03  =  5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04  =  1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static const double zero = 0.0;
+
+OLM_DLLEXPORT double
+__ieee754_j0(double x)
+{
+       double z, s,c,ss,cc,r,u,v;
+       int32_t hx,ix;
+
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) return one/(x*x);
+       x = fabs(x);
+       if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+               s = sin(x);
+               c = cos(x);
+               ss = s-c;
+               cc = s+c;
+               if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+                   z = -cos(x+x);
+                   if ((s*c)<zero) cc = z/ss;
+                   else            ss = z/cc;
+               }
+       /*
+        * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+        * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+        */
+               if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+               else {
+                   u = pzero(x); v = qzero(x);
+                   z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+               }
+               return z;
+       }
+       if(ix<0x3f200000) {     /* |x| < 2**-13 */
+           if(huge+x>one) {    /* raise inexact if x != 0 */
+               if(ix<0x3e400000) return one;   /* |x|<2**-27 */
+               else          return one - 0.25*x*x;
+           }
+       }
+       z = x*x;
+       r =  z*(R02+z*(R03+z*(R04+z*R05)));
+       s =  one+z*(S01+z*(S02+z*(S03+z*S04)));
+       if(ix < 0x3FF00000) {   /* |x| < 1.00 */
+           return one + z*(-0.25+(r/s));
+       } else {
+           u = 0.5*x;
+           return((one+u)*(one-u)+z*(r/s));
+       }
+}
+
+static const double
+u00  = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01  =  1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02  = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03  =  3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04  = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05  =  1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06  = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01  =  1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02  =  7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03  =  2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04  =  4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+OLM_DLLEXPORT double
+__ieee754_y0(double x)
+{
+       double z, s,c,ss,cc,u,v;
+       int32_t hx,ix,lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+        ix = 0x7fffffff&hx;
+    /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0  */
+       if(ix>=0x7ff00000) return  one/(x+x*x); 
+        if((ix|lx)==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+        /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+         * where x0 = x-pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+         *                      =  1/sqrt(2) * (sin(x) + cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                s = sin(x);
+                c = cos(x);
+                ss = s-c;
+                cc = s+c;
+       /*
+        * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+        * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+        */
+                if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+                    z = -cos(x+x);
+                    if ((s*c)<zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+                if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+                else {
+                    u = pzero(x); v = qzero(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+                }
+                return z;
+       }
+       if(ix<=0x3e400000) {    /* x < 2**-27 */
+           return(u00 + tpi*__ieee754_log(x));
+       }
+       z = x*x;
+       u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+       v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+       return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ *     1 - 9/128 s^2 + 11025/98304 s^4 - ...,  where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ *     pzero(x) = 1 + (R/S)
+ * where  R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ *       S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ *     | pzero(x)-1-R/S | <= 2  ** ( -60.26)
+ */
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+static const double pS8[5] = {
+  1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+  3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+  4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+  1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+  4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+static const double pS5[5] = {
+  6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+  1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+  5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+  9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+  2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+static const double pS3[5] = {
+  3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+  3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+  1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+  1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+  1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+static const double pS2[5] = {
+  2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+  1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+  2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+  1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+  1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+       /* Note: This function is only called for ix>=0x40000000 (see above) */
+       static double pzero(double x)
+{
+       const double *p,*q;
+       double z,r,s;
+       int32_t ix;
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+        assert(ix>=0x40000000 && ix<=0x48000000);
+       if(ix>=0x40200000)     {p = pR8; q= pS8;}
+       else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+       else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+       else                   {p = pR2; q= pS2;}
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+       return one+ r/s;
+}
+               
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ *     -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ *     qzero(x) = s*(-1.25 + (R/S))
+ * where  R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ *       S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ *     | qzero(x)/s +1.25-R/S | <= 2  ** ( -61.22)
+ */
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+  7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+  1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+  5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+  8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+  3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+static const double qS8[6] = {
+  1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+  8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+  1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+  8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+  8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+  7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+  5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+  1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+  1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+  1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+static const double qS5[6] = {
+  8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+  2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+  1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+  5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+  3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+  4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+  7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+  3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+  4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+  1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+  1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+static const double qS3[6] = {
+  4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+  7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+  3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+  6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+  2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+  7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+  1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+  1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+  3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+  1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+static const double qS2[6] = {
+  3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+  2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+  8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+  8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+  2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+       /* Note: This function is only called for ix>=0x40000000 (see above) */
+       static double qzero(double x)
+{
+       const double *p,*q;
+       double s,r,z;
+       int32_t ix;
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+        assert(ix>=0x40000000 && ix<=0x48000000);
+       if(ix>=0x40200000)     {p = qR8; q= qS8;}
+       else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+       else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+       else                   {p = qR2; q= qS2;}
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+       return (-.125 + r/s)/x;
+}
diff --git a/src/e_j0f.c b/src/e_j0f.c
new file mode 100644 (file)
index 0000000..62258b1
--- /dev/null
@@ -0,0 +1,337 @@
+/* e_j0f.c -- float version of e_j0.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <assert.h>
+#include "cdefs-compat.h"
+
+#include <openlibm_math.h>
+#include "math_private.h"
+
+static float pzerof(float), qzerof(float);
+
+static const float
+huge   = 1e30,
+one    = 1.0,
+invsqrtpi=  5.6418961287e-01, /* 0x3f106ebb */
+tpi      =  6.3661974669e-01, /* 0x3f22f983 */
+               /* R0/S0 on [0, 2.00] */
+R02  =  1.5625000000e-02, /* 0x3c800000 */
+R03  = -1.8997929874e-04, /* 0xb947352e */
+R04  =  1.8295404516e-06, /* 0x35f58e88 */
+R05  = -4.6183270541e-09, /* 0xb19eaf3c */
+S01  =  1.5619102865e-02, /* 0x3c7fe744 */
+S02  =  1.1692678527e-04, /* 0x38f53697 */
+S03  =  5.1354652442e-07, /* 0x3509daa6 */
+S04  =  1.1661400734e-09; /* 0x30a045e8 */
+
+static const float zero = 0.0;
+
+OLM_DLLEXPORT float
+__ieee754_j0f(float x)
+{
+       float z, s,c,ss,cc,r,u,v;
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) return one/(x*x);
+       x = fabsf(x);
+       if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+               s = sinf(x);
+               c = cosf(x);
+               ss = s-c;
+               cc = s+c;
+               if(ix<0x7f000000) {  /* make sure x+x not overflow */
+                   z = -cosf(x+x);
+                   if ((s*c)<zero) cc = z/ss;
+                   else            ss = z/cc;
+               }
+       /*
+        * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+        * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+        */
+               if(ix>0x58000000) z = (invsqrtpi*cc)/sqrtf(x); /* |x|>2**49 */
+               else {
+                   u = pzerof(x); v = qzerof(x);
+                   z = invsqrtpi*(u*cc-v*ss)/sqrtf(x);
+               }
+               return z;
+       }
+       if(ix<0x3b000000) {     /* |x| < 2**-9 */
+           if(huge+x>one) {    /* raise inexact if x != 0 */
+               if(ix<0x39800000) return one;   /* |x|<2**-12 */
+               else          return one - x*x/4;
+           }
+       }
+       z = x*x;
+       r =  z*(R02+z*(R03+z*(R04+z*R05)));
+       s =  one+z*(S01+z*(S02+z*(S03+z*S04)));
+       if(ix < 0x3F800000) {   /* |x| < 1.00 */
+           return one + z*((float)-0.25+(r/s));
+       } else {
+           u = (float)0.5*x;
+           return((one+u)*(one-u)+z*(r/s));
+       }
+}
+
+static const float
+u00  = -7.3804296553e-02, /* 0xbd9726b5 */
+u01  =  1.7666645348e-01, /* 0x3e34e80d */
+u02  = -1.3818567619e-02, /* 0xbc626746 */
+u03  =  3.4745343146e-04, /* 0x39b62a69 */
+u04  = -3.8140706238e-06, /* 0xb67ff53c */
+u05  =  1.9559013964e-08, /* 0x32a802ba */
+u06  = -3.9820518410e-11, /* 0xae2f21eb */
+v01  =  1.2730483897e-02, /* 0x3c509385 */
+v02  =  7.6006865129e-05, /* 0x389f65e0 */
+v03  =  2.5915085189e-07, /* 0x348b216c */
+v04  =  4.4111031494e-10; /* 0x2ff280c2 */
+
+OLM_DLLEXPORT float
+__ieee754_y0f(float x)
+{
+       float z, s,c,ss,cc,u,v;
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+        ix = 0x7fffffff&hx;
+    /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0  */
+       if(ix>=0x7f800000) return  one/(x+x*x);
+        if(ix==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+        /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+         * where x0 = x-pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+         *                      =  1/sqrt(2) * (sin(x) + cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                s = sinf(x);
+                c = cosf(x);
+                ss = s-c;
+                cc = s+c;
+       /*
+        * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+        * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+        */
+                if(ix<0x7f000000) {  /* make sure x+x not overflow */
+                    z = -cosf(x+x);
+                    if ((s*c)<zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+                if(ix>0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */
+                else {
+                    u = pzerof(x); v = qzerof(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
+                }
+                return z;
+       }
+       if(ix<=0x39000000) {    /* x < 2**-13 */
+           return(u00 + tpi*__ieee754_logf(x));
+       }
+       z = x*x;
+       u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+       v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+       return(u/v + tpi*(__ieee754_j0f(x)*__ieee754_logf(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ *     1 - 9/128 s^2 + 11025/98304 s^4 - ...,  where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ *     pzero(x) = 1 + (R/S)
+ * where  R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ *       S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ *     | pzero(x)-1-R/S | <= 2  ** ( -60.26)
+ */
+static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.0000000000e+00, /* 0x00000000 */
+ -7.0312500000e-02, /* 0xbd900000 */
+ -8.0816707611e+00, /* 0xc1014e86 */
+ -2.5706311035e+02, /* 0xc3808814 */
+ -2.4852163086e+03, /* 0xc51b5376 */
+ -5.2530439453e+03, /* 0xc5a4285a */
+};
+static const float pS8[5] = {
+  1.1653436279e+02, /* 0x42e91198 */
+  3.8337448730e+03, /* 0x456f9beb */
+  4.0597855469e+04, /* 0x471e95db */
+  1.1675296875e+05, /* 0x47e4087c */
+  4.7627726562e+04, /* 0x473a0bba */
+};
+static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.1412546255e-11, /* 0xad48c58a */
+ -7.0312492549e-02, /* 0xbd8fffff */
+ -4.1596107483e+00, /* 0xc0851b88 */
+ -6.7674766541e+01, /* 0xc287597b */
+ -3.3123129272e+02, /* 0xc3a59d9b */
+ -3.4643338013e+02, /* 0xc3ad3779 */
+};
+static const float pS5[5] = {
+  6.0753936768e+01, /* 0x42730408 */
+  1.0512523193e+03, /* 0x44836813 */
+  5.9789707031e+03, /* 0x45bad7c4 */
+  9.6254453125e+03, /* 0x461665c8 */
+  2.4060581055e+03, /* 0x451660ee */
+};
+
+static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.5470459075e-09, /* 0xb12f081b */
+ -7.0311963558e-02, /* 0xbd8fffb8 */
+ -2.4090321064e+00, /* 0xc01a2d95 */
+ -2.1965976715e+01, /* 0xc1afba52 */
+ -5.8079170227e+01, /* 0xc2685112 */
+ -3.1447946548e+01, /* 0xc1fb9565 */
+};
+static const float pS3[5] = {
+  3.5856033325e+01, /* 0x420f6c94 */
+  3.6151397705e+02, /* 0x43b4c1ca */
+  1.1936077881e+03, /* 0x44953373 */
+  1.1279968262e+03, /* 0x448cffe6 */
+  1.7358093262e+02, /* 0x432d94b8 */
+};
+
+static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.8753431271e-08, /* 0xb3be98b7 */
+ -7.0303097367e-02, /* 0xbd8ffb12 */
+ -1.4507384300e+00, /* 0xbfb9b1cc */
+ -7.6356959343e+00, /* 0xc0f4579f */
+ -1.1193166733e+01, /* 0xc1331736 */
+ -3.2336456776e+00, /* 0xc04ef40d */
+};
+static const float pS2[5] = {
+  2.2220300674e+01, /* 0x41b1c32d */
+  1.3620678711e+02, /* 0x430834f0 */
+  2.7047027588e+02, /* 0x43873c32 */
+  1.5387539673e+02, /* 0x4319e01a */
+  1.4657617569e+01, /* 0x416a859a */
+};
+
+       static float pzerof(float x)
+{
+       const float *p,*q;
+       float z,r,s;
+       int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+       if(ix>=0x41000000)     {p = pR8; q= pS8;}
+       else if(ix>=0x409173eb){p = pR5; q= pS5;}
+       else if(ix>=0x4036d917){p = pR3; q= pS3;}
+       else                   {p = pR2; q= pS2;}       /* ix>=0x40000000 */
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+       return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ *     -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ *     qzero(x) = s*(-1.25 + (R/S))
+ * where  R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ *       S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ *     | qzero(x)/s +1.25-R/S | <= 2  ** ( -61.22)
+ */
+static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.0000000000e+00, /* 0x00000000 */
+  7.3242187500e-02, /* 0x3d960000 */
+  1.1768206596e+01, /* 0x413c4a93 */
+  5.5767340088e+02, /* 0x440b6b19 */
+  8.8591972656e+03, /* 0x460a6cca */
+  3.7014625000e+04, /* 0x471096a0 */
+};
+static const float qS8[6] = {
+  1.6377603149e+02, /* 0x4323c6aa */
+  8.0983447266e+03, /* 0x45fd12c2 */
+  1.4253829688e+05, /* 0x480b3293 */
+  8.0330925000e+05, /* 0x49441ed4 */
+  8.4050156250e+05, /* 0x494d3359 */
+ -3.4389928125e+05, /* 0xc8a7eb69 */
+};
+
+static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.8408595828e-11, /* 0x2da1ec79 */
+  7.3242180049e-02, /* 0x3d95ffff */
+  5.8356351852e+00, /* 0x40babd86 */
+  1.3511157227e+02, /* 0x43071c90 */
+  1.0272437744e+03, /* 0x448067cd */
+  1.9899779053e+03, /* 0x44f8bf4b */
+};
+static const float qS5[6] = {
+  8.2776611328e+01, /* 0x42a58da0 */
+  2.0778142090e+03, /* 0x4501dd07 */
+  1.8847289062e+04, /* 0x46933e94 */
+  5.6751113281e+04, /* 0x475daf1d */
+  3.5976753906e+04, /* 0x470c88c1 */
+ -5.3543427734e+03, /* 0xc5a752be */
+};
+
+static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+  4.3774099900e-09, /* 0x3196681b */
+  7.3241114616e-02, /* 0x3d95ff70 */
+  3.3442313671e+00, /* 0x405607e3 */
+  4.2621845245e+01, /* 0x422a7cc5 */
+  1.7080809021e+02, /* 0x432acedf */
+  1.6673394775e+02, /* 0x4326bbe4 */
+};
+static const float qS3[6] = {
+  4.8758872986e+01, /* 0x42430916 */
+  7.0968920898e+02, /* 0x44316c1c */
+  3.7041481934e+03, /* 0x4567825f */
+  6.4604252930e+03, /* 0x45c9e367 */
+  2.5163337402e+03, /* 0x451d4557 */
+ -1.4924745178e+02, /* 0xc3153f59 */
+};
+
+static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.5044444979e-07, /* 0x342189db */
+  7.3223426938e-02, /* 0x3d95f62a */
+  1.9981917143e+00, /* 0x3fffc4bf */
+  1.4495602608e+01, /* 0x4167edfd */
+  3.1666231155e+01, /* 0x41fd5471 */
+  1.6252708435e+01, /* 0x4182058c */
+};
+static const float qS2[6] = {
+  3.0365585327e+01, /* 0x41f2ecb8 */
+  2.6934811401e+02, /* 0x4386ac8f */
+  8.4478375244e+02, /* 0x44533229 */
+  8.8293585205e+02, /* 0x445cbbe5 */
+  2.1266638184e+02, /* 0x4354aa98 */
+ -5.3109550476e+00, /* 0xc0a9f358 */
+};
+
+       static float qzerof(float x)
+{
+       const float *p,*q;
+       float s,r,z;
+       int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+       if(ix>=0x41000000)     {p = qR8; q= qS8;}
+       else if(ix>=0x409173eb){p = qR5; q= qS5;}
+       else if(ix>=0x4036d917){p = qR3; q= qS3;}
+       else                   {p = qR2; q= qS2;}       /* ix>=0x40000000 */
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+       return (-(float).125 + r/s)/x;
+}
diff --git a/src/e_j1.c b/src/e_j1.c
new file mode 100644 (file)
index 0000000..4be57cd
--- /dev/null
@@ -0,0 +1,383 @@
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <assert.h>
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_j1.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ *     1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ *     2. Reduce x to |x| since j1(x)=-j1(-x),  and
+ *        for x in (0,2)
+ *             j1(x) = x/2 + x*z*R0/S0,  where z = x*x;
+ *        (precision:  |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ *        for x in (2,inf)
+ *             j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ *             y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ *        where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ *        as follow:
+ *             cos(x1) =  cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ *                     =  1/sqrt(2) * (sin(x) - cos(x))
+ *             sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ *                     = -1/sqrt(2) * (sin(x) + cos(x))
+ *        (To avoid cancellation, use
+ *             sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ *         to compute the worse one.)
+ *        
+ *     3 Special cases
+ *             j1(nan)= nan
+ *             j1(0) = 0
+ *             j1(inf) = 0
+ *             
+ * Method -- y1(x):
+ *     1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN 
+ *     2. For x<2.
+ *        Since 
+ *             y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ *        therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ *        We use the following function to approximate y1,
+ *             y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ *        where for x in [0,2] (abs err less than 2**-65.89)
+ *             U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ *             V(z) = 1  + v0[0]*z + ... + v0[4]*z^5
+ *        Note: For tiny x, 1/x dominate y1 and hence
+ *             y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ *     3. For x>=2.
+ *             y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ *        where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ *        by method mentioned above.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static double pone(double), qone(double);
+
+static const double
+huge    = 1e300,
+one    = 1.0,
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi      =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+       /* R0/S0 on [0,2] */
+r00  = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01  =  1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02  = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03  =  4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01  =  1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02  =  1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03  =  1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04  =  5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05  =  1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static const double zero    = 0.0;
+
+OLM_DLLEXPORT double
+__ieee754_j1(double x)
+{
+       double z, s,c,ss,cc,r,u,v,y;
+       int32_t hx,ix;
+
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) return one/x;
+       y = fabs(x);
+       if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+               s = sin(y);
+               c = cos(y);
+               ss = -s-c;
+               cc = s-c;
+               if(ix<0x7fe00000) {  /* make sure y+y not overflow */
+                   z = cos(y+y);
+                   if ((s*c)>zero) cc = z/ss;
+                   else            ss = z/cc;
+               }
+       /*
+        * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+        * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+        */
+               if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+               else {
+                   u = pone(y); v = qone(y);
+                   z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+               }
+               if(hx<0) return -z;
+               else     return  z;
+       }
+       if(ix<0x3e400000) {     /* |x|<2**-27 */
+           if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+       }
+       z = x*x;
+       r =  z*(r00+z*(r01+z*(r02+z*r03)));
+       s =  one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+       r *= x;
+       return(x*0.5+r/s);
+}
+
+static const double U0[5] = {
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+  5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+  2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+static const double V0[5] = {
+  1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+  2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+  1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+  6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+  1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+OLM_DLLEXPORT double
+__ieee754_y1(double x)
+{
+       double z, s,c,ss,cc,u,v;
+       int32_t hx,ix,lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+        ix = 0x7fffffff&hx;
+    /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+       if(ix>=0x7ff00000) return  one/(x+x*x); 
+        if((ix|lx)==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+                s = sin(x);
+                c = cos(x);
+                ss = -s-c;
+                cc = s-c;
+                if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+                    z = cos(x+x);
+                    if ((s*c)>zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+        /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+         * where x0 = x-3pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      = -1/sqrt(2) * (cos(x) + sin(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+                else {
+                    u = pone(x); v = qone(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+                }
+                return z;
+        } 
+        if(ix<=0x3c900000) {    /* x < 2**-54 */
+            return(-tpi/x);
+        } 
+        z = x*x;
+        u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+        v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+        return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ *     1 + 15/128 s^2 - 4725/2^15 s^4 - ...,   where s = 1/x.
+ * We approximate pone by
+ *     pone(x) = 1 + (R/S)
+ * where  R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ *       S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ *     | pone(x)-1-R/S | <= 2  ** ( -60.06)
+ */
+
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+  1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+  1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+  4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+  3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+  7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+static const double ps8[5] = {
+  1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+  3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+  3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+  9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+  3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+  1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+  6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+  1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+  5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+  5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+static const double ps5[5] = {
+  5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+  9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+  5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+  7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+  1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+static const double pr3[6] = {
+  3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+  1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+  3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+  3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+  9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+  4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+static const double ps3[5] = {
+  3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+  3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+  1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+  8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+  1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+  1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+  2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+  1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+  1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+  5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+static const double ps2[5] = {
+  2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+  1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+  2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+  1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+  8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+       /* Note: This function is only called for ix>=0x40000000 (see above) */
+       static double pone(double x)
+{
+       const double *p,*q;
+       double z,r,s;
+        int32_t ix;
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+        assert(ix>=0x40000000 && ix<=0x48000000);
+        if(ix>=0x40200000)     {p = pr8; q= ps8;}
+        else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+        else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+        else                   {p = pr2; q= ps2;}
+        z = one/(x*x);
+        r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+        s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+        return one+ r/s;
+}
+               
+
+/* For x >= 8, the asymptotic expansions of qone is
+ *     3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ *     qone(x) = s*(0.375 + (R/S))
+ * where  R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ *       S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ *     | qone(x)/s -0.375-R/S | <= 2  ** ( -61.13)
+ */
+
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+static const double qs8[6] = {
+  1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+  7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+  1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+  7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+  6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+static const double qs5[6] = {
+  8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+  1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+  1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+  4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+  2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+static const double qr3[6] = {
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+static const double qs3[6] = {
+  4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+  6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+  3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+  5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+  1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+static const double qs2[6] = {
+  2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+  2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+  7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+  7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+  1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+       /* Note: This function is only called for ix>=0x40000000 (see above) */
+       static double qone(double x)
+{
+       const double *p,*q;
+       double  s,r,z;
+       int32_t ix;
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+        assert(ix>=0x40000000 && ix<=0x48000000);
+       if(ix>=0x40200000)     {p = qr8; q= qs8;}
+       else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+       else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+       else                   {p = qr2; q= qs2;}
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+       return (.375 + r/s)/x;
+}
diff --git a/src/e_j1f.c b/src/e_j1f.c
new file mode 100644 (file)
index 0000000..ac32c6f
--- /dev/null
@@ -0,0 +1,332 @@
+/* e_j1f.c -- float version of e_j1.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <assert.h>
+#include "cdefs-compat.h"
+#include <openlibm_math.h>
+#include "math_private.h"
+
+static float ponef(float), qonef(float);
+
+static const float
+huge    = 1e30,
+one    = 1.0,
+invsqrtpi=  5.6418961287e-01, /* 0x3f106ebb */
+tpi      =  6.3661974669e-01, /* 0x3f22f983 */
+       /* R0/S0 on [0,2] */
+r00  = -6.2500000000e-02, /* 0xbd800000 */
+r01  =  1.4070566976e-03, /* 0x3ab86cfd */
+r02  = -1.5995563444e-05, /* 0xb7862e36 */
+r03  =  4.9672799207e-08, /* 0x335557d2 */
+s01  =  1.9153760746e-02, /* 0x3c9ce859 */
+s02  =  1.8594678841e-04, /* 0x3942fab6 */
+s03  =  1.1771846857e-06, /* 0x359dffc2 */
+s04  =  5.0463624390e-09, /* 0x31ad6446 */
+s05  =  1.2354227016e-11; /* 0x2d59567e */
+
+static const float zero    = 0.0;
+
+OLM_DLLEXPORT float
+__ieee754_j1f(float x)
+{
+       float z, s,c,ss,cc,r,u,v,y;
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) return one/x;
+       y = fabsf(x);
+       if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+               s = sinf(y);
+               c = cosf(y);
+               ss = -s-c;
+               cc = s-c;
+               if(ix<0x7f000000) {  /* make sure y+y not overflow */
+                   z = cosf(y+y);
+                   if ((s*c)>zero) cc = z/ss;
+                   else            ss = z/cc;
+               }
+       /*
+        * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+        * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+        */
+               if(ix>0x58000000) z = (invsqrtpi*cc)/sqrtf(y); /* |x|>2**49 */
+               else {
+                   u = ponef(y); v = qonef(y);
+                   z = invsqrtpi*(u*cc-v*ss)/sqrtf(y);
+               }
+               if(hx<0) return -z;
+               else     return  z;
+       }
+       if(ix<0x39000000) {     /* |x|<2**-13 */
+           if(huge+x>one) return (float)0.5*x;/* inexact if x!=0 necessary */
+       }
+       z = x*x;
+       r =  z*(r00+z*(r01+z*(r02+z*r03)));
+       s =  one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+       r *= x;
+       return(x*(float)0.5+r/s);
+}
+
+static const float U0[5] = {
+ -1.9605709612e-01, /* 0xbe48c331 */
+  5.0443872809e-02, /* 0x3d4e9e3c */
+ -1.9125689287e-03, /* 0xbafaaf2a */
+  2.3525259166e-05, /* 0x37c5581c */
+ -9.1909917899e-08, /* 0xb3c56003 */
+};
+static const float V0[5] = {
+  1.9916731864e-02, /* 0x3ca3286a */
+  2.0255257550e-04, /* 0x3954644b */
+  1.3560879779e-06, /* 0x35b602d4 */
+  6.2274145840e-09, /* 0x31d5f8eb */
+  1.6655924903e-11, /* 0x2d9281cf */
+};
+
+OLM_DLLEXPORT float
+__ieee754_y1f(float x)
+{
+       float z, s,c,ss,cc,u,v;
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+        ix = 0x7fffffff&hx;
+    /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+       if(ix>=0x7f800000) return  one/(x+x*x);
+        if(ix==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+                s = sinf(x);
+                c = cosf(x);
+                ss = -s-c;
+                cc = s-c;
+                if(ix<0x7f000000) {  /* make sure x+x not overflow */
+                    z = cosf(x+x);
+                    if ((s*c)>zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+        /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+         * where x0 = x-3pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      = -1/sqrt(2) * (cos(x) + sin(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                if(ix>0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */
+                else {
+                    u = ponef(x); v = qonef(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrtf(x);
+                }
+                return z;
+        }
+        if(ix<=0x33000000) {    /* x < 2**-25 */
+            return(-tpi/x);
+        }
+        z = x*x;
+        u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+        v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+        return(x*(u/v) + tpi*(__ieee754_j1f(x)*__ieee754_logf(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ *     1 + 15/128 s^2 - 4725/2^15 s^4 - ...,   where s = 1/x.
+ * We approximate pone by
+ *     pone(x) = 1 + (R/S)
+ * where  R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ *       S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ *     | pone(x)-1-R/S | <= 2  ** ( -60.06)
+ */
+
+static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.0000000000e+00, /* 0x00000000 */
+  1.1718750000e-01, /* 0x3df00000 */
+  1.3239480972e+01, /* 0x4153d4ea */
+  4.1205184937e+02, /* 0x43ce06a3 */
+  3.8747453613e+03, /* 0x45722bed */
+  7.9144794922e+03, /* 0x45f753d6 */
+};
+static const float ps8[5] = {
+  1.1420736694e+02, /* 0x42e46a2c */
+  3.6509309082e+03, /* 0x45642ee5 */
+  3.6956207031e+04, /* 0x47105c35 */
+  9.7602796875e+04, /* 0x47bea166 */
+  3.0804271484e+04, /* 0x46f0a88b */
+};
+
+static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.3199052094e-11, /* 0x2d68333f */
+  1.1718749255e-01, /* 0x3defffff */
+  6.8027510643e+00, /* 0x40d9b023 */
+  1.0830818176e+02, /* 0x42d89dca */
+  5.1763616943e+02, /* 0x440168b7 */
+  5.2871520996e+02, /* 0x44042dc6 */
+};
+static const float ps5[5] = {
+  5.9280597687e+01, /* 0x426d1f55 */
+  9.9140142822e+02, /* 0x4477d9b1 */
+  5.3532670898e+03, /* 0x45a74a23 */
+  7.8446904297e+03, /* 0x45f52586 */
+  1.5040468750e+03, /* 0x44bc0180 */
+};
+
+static const float pr3[6] = {
+  3.0250391081e-09, /* 0x314fe10d */
+  1.1718686670e-01, /* 0x3defffab */
+  3.9329774380e+00, /* 0x407bb5e7 */
+  3.5119403839e+01, /* 0x420c7a45 */
+  9.1055007935e+01, /* 0x42b61c2a */
+  4.8559066772e+01, /* 0x42423c7c */
+};
+static const float ps3[5] = {
+  3.4791309357e+01, /* 0x420b2a4d */
+  3.3676245117e+02, /* 0x43a86198 */
+  1.0468714600e+03, /* 0x4482dbe3 */
+  8.9081134033e+02, /* 0x445eb3ed */
+  1.0378793335e+02, /* 0x42cf936c */
+};
+
+static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.0771083225e-07, /* 0x33e74ea8 */
+  1.1717621982e-01, /* 0x3deffa16 */
+  2.3685150146e+00, /* 0x401795c0 */
+  1.2242610931e+01, /* 0x4143e1bc */
+  1.7693971634e+01, /* 0x418d8d41 */
+  5.0735230446e+00, /* 0x40a25a4d */
+};
+static const float ps2[5] = {
+  2.1436485291e+01, /* 0x41ab7dec */
+  1.2529022980e+02, /* 0x42fa9499 */
+  2.3227647400e+02, /* 0x436846c7 */
+  1.1767937469e+02, /* 0x42eb5bd7 */
+  8.3646392822e+00, /* 0x4105d590 */
+};
+
+       static float ponef(float x)
+{
+       const float *p,*q;
+       float z,r,s;
+        int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+        if(ix>=0x41000000)     {p = pr8; q= ps8;}
+        else if(ix>=0x409173eb){p = pr5; q= ps5;}
+        else if(ix>=0x4036d917){p = pr3; q= ps3;}
+       else                   {p = pr2; q= ps2;}       /* ix>=0x40000000 */
+        z = one/(x*x);
+        r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+        s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+        return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ *     3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ *     qone(x) = s*(0.375 + (R/S))
+ * where  R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ *       S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ *     | qone(x)/s -0.375-R/S | <= 2  ** ( -61.13)
+ */
+
+static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.0000000000e+00, /* 0x00000000 */
+ -1.0253906250e-01, /* 0xbdd20000 */
+ -1.6271753311e+01, /* 0xc1822c8d */
+ -7.5960174561e+02, /* 0xc43de683 */
+ -1.1849806641e+04, /* 0xc639273a */
+ -4.8438511719e+04, /* 0xc73d3683 */
+};
+static const float qs8[6] = {
+  1.6139537048e+02, /* 0x43216537 */
+  7.8253862305e+03, /* 0x45f48b17 */
+  1.3387534375e+05, /* 0x4802bcd6 */
+  7.1965775000e+05, /* 0x492fb29c */
+  6.6660125000e+05, /* 0x4922be94 */
+ -2.9449025000e+05, /* 0xc88fcb48 */
+};
+
+static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.0897993405e-11, /* 0xadb7d219 */
+ -1.0253904760e-01, /* 0xbdd1fffe */
+ -8.0564479828e+00, /* 0xc100e736 */
+ -1.8366960144e+02, /* 0xc337ab6b */
+ -1.3731937256e+03, /* 0xc4aba633 */
+ -2.6124443359e+03, /* 0xc523471c */
+};
+static const float qs5[6] = {
+  8.1276550293e+01, /* 0x42a28d98 */
+  1.9917987061e+03, /* 0x44f8f98f */
+  1.7468484375e+04, /* 0x468878f8 */
+  4.9851425781e+04, /* 0x4742bb6d */
+  2.7948074219e+04, /* 0x46da5826 */
+ -4.7191835938e+03, /* 0xc5937978 */
+};
+
+static const float qr3[6] = {
+ -5.0783124372e-09, /* 0xb1ae7d4f */
+ -1.0253783315e-01, /* 0xbdd1ff5b */
+ -4.6101160049e+00, /* 0xc0938612 */
+ -5.7847221375e+01, /* 0xc267638e */
+ -2.2824453735e+02, /* 0xc3643e9a */
+ -2.1921012878e+02, /* 0xc35b35cb */
+};
+static const float qs3[6] = {
+  4.7665153503e+01, /* 0x423ea91e */
+  6.7386511230e+02, /* 0x4428775e */
+  3.3801528320e+03, /* 0x45534272 */
+  5.5477290039e+03, /* 0x45ad5dd5 */
+  1.9031191406e+03, /* 0x44ede3d0 */
+ -1.3520118713e+02, /* 0xc3073381 */
+};
+
+static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.7838172539e-07, /* 0xb43f8932 */
+ -1.0251704603e-01, /* 0xbdd1f475 */
+ -2.7522056103e+00, /* 0xc0302423 */
+ -1.9663616180e+01, /* 0xc19d4f16 */
+ -4.2325313568e+01, /* 0xc2294d1f */
+ -2.1371921539e+01, /* 0xc1aaf9b2 */
+};
+static const float qs2[6] = {
+  2.9533363342e+01, /* 0x41ec4454 */
+  2.5298155212e+02, /* 0x437cfb47 */
+  7.5750280762e+02, /* 0x443d602e */
+  7.3939318848e+02, /* 0x4438d92a */
+  1.5594900513e+02, /* 0x431bf2f2 */
+ -4.9594988823e+00, /* 0xc09eb437 */
+};
+
+       static float qonef(float x)
+{
+       const float *p,*q;
+       float  s,r,z;
+       int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+       if(ix>=0x41000000)     {p = qr8; q= qs8;}
+       else if(ix>=0x409173eb){p = qr5; q= qs5;}
+       else if(ix>=0x4036d917){p = qr3; q= qs3;}
+       else                   {p = qr2; q= qs2;}       /* ix>=0x40000000 */
+       z = one/(x*x);
+       r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+       s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+       return ((float).375 + r/s)/x;
+}
diff --git a/src/e_jn.c b/src/e_jn.c
new file mode 100644 (file)
index 0000000..1a53965
--- /dev/null
@@ -0,0 +1,271 @@
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_jn.c,v 1.11 2010/11/13 10:54:10 uqs Exp $");
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *          
+ * Special cases:
+ *     y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ *     y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ *     For n=0, j0(x) is called,
+ *     for n=1, j1(x) is called,
+ *     for n<x, forward recursion us used starting
+ *     from values of j0(x) and j1(x).
+ *     for n>x, a continued fraction approximation to
+ *     j(n,x)/j(n-1,x) is evaluated and then backward
+ *     recursion is used starting from a supposed value
+ *     for j(n,x). The resulting value of j(0,x) is
+ *     compared with the actual value to correct the
+ *     supposed value of j(n,x).
+ *
+ *     yn(n,x) is similar in all respects, except
+ *     that forward recursion is used for all
+ *     values of n>1.
+ *     
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two   =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one   =  1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static const double zero  =  0.00000000000000000000e+00;
+
+OLM_DLLEXPORT double
+__ieee754_jn(int n, double x)
+{
+       int32_t i,hx,ix,lx, sgn;
+       double a, b, temp, di;
+       double z, w;
+
+    /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+     * Thus, J(-n,x) = J(n,-x)
+     */
+       EXTRACT_WORDS(hx,lx,x);
+       ix = 0x7fffffff&hx;
+    /* if J(n,NaN) is NaN */
+       if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
+       if(n<0){                
+               n = -n;
+               x = -x;
+               hx ^= 0x80000000;
+       }
+       if(n==0) return(__ieee754_j0(x));
+       if(n==1) return(__ieee754_j1(x));
+       sgn = (n&1)&(hx>>31);   /* even n -- 0, odd n -- sign(x) */
+       x = fabs(x);
+       if((ix|lx)==0||ix>=0x7ff00000)  /* if x is 0 or inf */
+           b = zero;
+       else if((double)n<=x) {   
+               /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+           if(ix>=0x52D00000) { /* x > 2**302 */
+    /* (x >> n**2) 
+     *     Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *     Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *     Let s=sin(x), c=cos(x), 
+     *         xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+     *
+     *            n    sin(xn)*sqt2    cos(xn)*sqt2
+     *         ----------------------------------
+     *            0     s-c             c+s
+     *            1    -s-c            -c+s
+     *            2    -s+c            -c-s
+     *            3     s+c             c-s
+     */
+               switch(n&3) {
+                   case 0: temp =  cos(x)+sin(x); break;
+                   case 1: temp = -cos(x)+sin(x); break;
+                   case 2: temp = -cos(x)-sin(x); break;
+                   case 3: temp =  cos(x)-sin(x); break;
+               }
+               b = invsqrtpi*temp/sqrt(x);
+           } else {    
+               a = __ieee754_j0(x);
+               b = __ieee754_j1(x);
+               for(i=1;i<n;i++){
+                   temp = b;
+                   b = b*((double)(i+i)/x) - a; /* avoid underflow */
+                   a = temp;
+               }
+           }
+       } else {
+           if(ix<0x3e100000) { /* x < 2**-29 */
+    /* x is tiny, return the first Taylor expansion of J(n,x) 
+     * J(n,x) = 1/n!*(x/2)^n  - ...
+     */
+               if(n>33)        /* underflow */
+                   b = zero;
+               else {
+                   temp = x*0.5; b = temp;
+                   for (a=one,i=2;i<=n;i++) {
+                       a *= (double)i;         /* a = n! */
+                       b *= temp;              /* b = (x/2)^n */
+                   }
+                   b = b/a;
+               }
+           } else {
+               /* use backward recurrence */
+               /*                      x      x^2      x^2       
+                *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
+                *                      2n  - 2(n+1) - 2(n+2)
+                *
+                *                      1      1        1       
+                *  (for large x)   =  ----  ------   ------   .....
+                *                      2n   2(n+1)   2(n+2)
+                *                      -- - ------ - ------ - 
+                *                       x     x         x
+                *
+                * Let w = 2n/x and h=2/x, then the above quotient
+                * is equal to the continued fraction:
+                *                  1
+                *      = -----------------------
+                *                     1
+                *         w - -----------------
+                *                        1
+                *              w+h - ---------
+                *                     w+2h - ...
+                *
+                * To determine how many terms needed, let
+                * Q(0) = w, Q(1) = w(w+h) - 1,
+                * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+                * When Q(k) > 1e4      good for single 
+                * When Q(k) > 1e9      good for double 
+                * When Q(k) > 1e17     good for quadruple 
+                */
+           /* determine k */
+               double t,v;
+               double q0,q1,h,tmp; int32_t k,m;
+               w  = (n+n)/(double)x; h = 2.0/(double)x;
+               q0 = w;  z = w+h; q1 = w*z - 1.0; k=1;
+               while(q1<1.0e9) {
+                       k += 1; z += h;
+                       tmp = z*q1 - q0;
+                       q0 = q1;
+                       q1 = tmp;
+               }
+               m = n+n;
+               for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+               a = t;
+               b = one;
+               /*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+                *  Hence, if n*(log(2n/x)) > ...
+                *  single 8.8722839355e+01
+                *  double 7.09782712893383973096e+02
+                *  long double 1.1356523406294143949491931077970765006170e+04
+                *  then recurrent value may overflow and the result is
+                *  likely underflow to zero
+                */
+               tmp = n;
+               v = two/x;
+               tmp = tmp*__ieee754_log(fabs(v*tmp));
+               if(tmp<7.09782712893383973096e+02) {
+                   for(i=n-1,di=(double)(i+i);i>0;i--){
+                       temp = b;
+                       b *= di;
+                       b  = b/x - a;
+                       a = temp;
+                       di -= two;
+                   }
+               } else {
+                   for(i=n-1,di=(double)(i+i);i>0;i--){
+                       temp = b;
+                       b *= di;
+                       b  = b/x - a;
+                       a = temp;
+                       di -= two;
+                   /* scale b to avoid spurious overflow */
+                       if(b>1e100) {
+                           a /= b;
+                           t /= b;
+                           b  = one;
+                       }
+                   }
+               }
+               z = __ieee754_j0(x);
+               w = __ieee754_j1(x);
+               if (fabs(z) >= fabs(w))
+                   b = (t*z/b);
+               else
+                   b = (t*w/a);
+           }
+       }
+       if(sgn==1) return -b; else return b;
+}
+
+OLM_DLLEXPORT double
+__ieee754_yn(int n, double x)
+{
+       int32_t i,hx,ix,lx;
+       int32_t sign;
+       double a, b, temp;
+
+       EXTRACT_WORDS(hx,lx,x);
+       ix = 0x7fffffff&hx;
+    /* if Y(n,NaN) is NaN */
+       if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x;
+       if((ix|lx)==0) return -one/zero;
+       if(hx<0) return zero/zero;
+       sign = 1;
+       if(n<0){
+               n = -n;
+               sign = 1 - ((n&1)<<1);
+       }
+       if(n==0) return(__ieee754_y0(x));
+       if(n==1) return(sign*__ieee754_y1(x));
+       if(ix==0x7ff00000) return zero;
+       if(ix>=0x52D00000) { /* x > 2**302 */
+    /* (x >> n**2) 
+     *     Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *     Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *     Let s=sin(x), c=cos(x), 
+     *         xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+     *
+     *            n    sin(xn)*sqt2    cos(xn)*sqt2
+     *         ----------------------------------
+     *            0     s-c             c+s
+     *            1    -s-c            -c+s
+     *            2    -s+c            -c-s
+     *            3     s+c             c-s
+     */
+               switch(n&3) {
+                   case 0: temp =  sin(x)-cos(x); break;
+                   case 1: temp = -sin(x)-cos(x); break;
+                   case 2: temp = -sin(x)+cos(x); break;
+                   case 3: temp =  sin(x)+cos(x); break;
+               }
+               b = invsqrtpi*temp/sqrt(x);
+       } else {
+           u_int32_t high;
+           a = __ieee754_y0(x);
+           b = __ieee754_y1(x);
+       /* quit if b is -inf */
+           GET_HIGH_WORD(high,b);
+           for(i=1;i<n&&high!=0xfff00000;i++){
+               temp = b;
+               b = ((double)(i+i)/x)*b - a;
+               GET_HIGH_WORD(high,b);
+               a = temp;
+           }
+       }
+       if(sign>0) return b; else return -b;
+}
diff --git a/src/e_jnf.c b/src/e_jnf.c
new file mode 100644 (file)
index 0000000..cb73e86
--- /dev/null
@@ -0,0 +1,200 @@
+/* e_jnf.c -- float version of e_jn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_jnf.c,v 1.11 2010/11/13 10:54:10 uqs Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+two   =  2.0000000000e+00, /* 0x40000000 */
+one   =  1.0000000000e+00; /* 0x3F800000 */
+
+static const float zero  =  0.0000000000e+00;
+
+OLM_DLLEXPORT float
+__ieee754_jnf(int n, float x)
+{
+       int32_t i,hx,ix, sgn;
+       float a, b, temp, di;
+       float z, w;
+
+    /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+     * Thus, J(-n,x) = J(n,-x)
+     */
+       GET_FLOAT_WORD(hx,x);
+       ix = 0x7fffffff&hx;
+    /* if J(n,NaN) is NaN */
+       if(ix>0x7f800000) return x+x;
+       if(n<0){
+               n = -n;
+               x = -x;
+               hx ^= 0x80000000;
+       }
+       if(n==0) return(__ieee754_j0f(x));
+       if(n==1) return(__ieee754_j1f(x));
+       sgn = (n&1)&(hx>>31);   /* even n -- 0, odd n -- sign(x) */
+       x = fabsf(x);
+       if(ix==0||ix>=0x7f800000)       /* if x is 0 or inf */
+           b = zero;
+       else if((float)n<=x) {
+               /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+           a = __ieee754_j0f(x);
+           b = __ieee754_j1f(x);
+           for(i=1;i<n;i++){
+               temp = b;
+               b = b*((float)(i+i)/x) - a; /* avoid underflow */
+               a = temp;
+           }
+       } else {
+           if(ix<0x30800000) { /* x < 2**-29 */
+    /* x is tiny, return the first Taylor expansion of J(n,x)
+     * J(n,x) = 1/n!*(x/2)^n  - ...
+     */
+               if(n>33)        /* underflow */
+                   b = zero;
+               else {
+                   temp = x*(float)0.5; b = temp;
+                   for (a=one,i=2;i<=n;i++) {
+                       a *= (float)i;          /* a = n! */
+                       b *= temp;              /* b = (x/2)^n */
+                   }
+                   b = b/a;
+               }
+           } else {
+               /* use backward recurrence */
+               /*                      x      x^2      x^2
+                *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
+                *                      2n  - 2(n+1) - 2(n+2)
+                *
+                *                      1      1        1
+                *  (for large x)   =  ----  ------   ------   .....
+                *                      2n   2(n+1)   2(n+2)
+                *                      -- - ------ - ------ -
+                *                       x     x         x
+                *
+                * Let w = 2n/x and h=2/x, then the above quotient
+                * is equal to the continued fraction:
+                *                  1
+                *      = -----------------------
+                *                     1
+                *         w - -----------------
+                *                        1
+                *              w+h - ---------
+                *                     w+2h - ...
+                *
+                * To determine how many terms needed, let
+                * Q(0) = w, Q(1) = w(w+h) - 1,
+                * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+                * When Q(k) > 1e4      good for single
+                * When Q(k) > 1e9      good for double
+                * When Q(k) > 1e17     good for quadruple
+                */
+           /* determine k */
+               float t,v;
+               float q0,q1,h,tmp; int32_t k,m;
+               w  = (n+n)/(float)x; h = (float)2.0/(float)x;
+               q0 = w;  z = w+h; q1 = w*z - (float)1.0; k=1;
+               while(q1<(float)1.0e9) {
+                       k += 1; z += h;
+                       tmp = z*q1 - q0;
+                       q0 = q1;
+                       q1 = tmp;
+               }
+               m = n+n;
+               for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+               a = t;
+               b = one;
+               /*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+                *  Hence, if n*(log(2n/x)) > ...
+                *  single 8.8722839355e+01
+                *  double 7.09782712893383973096e+02
+                *  long double 1.1356523406294143949491931077970765006170e+04
+                *  then recurrent value may overflow and the result is
+                *  likely underflow to zero
+                */
+               tmp = n;
+               v = two/x;
+               tmp = tmp*__ieee754_logf(fabsf(v*tmp));
+               if(tmp<(float)8.8721679688e+01) {
+                   for(i=n-1,di=(float)(i+i);i>0;i--){
+                       temp = b;
+                       b *= di;
+                       b  = b/x - a;
+                       a = temp;
+                       di -= two;
+                   }
+               } else {
+                   for(i=n-1,di=(float)(i+i);i>0;i--){
+                       temp = b;
+                       b *= di;
+                       b  = b/x - a;
+                       a = temp;
+                       di -= two;
+                   /* scale b to avoid spurious overflow */
+                       if(b>(float)1e10) {
+                           a /= b;
+                           t /= b;
+                           b  = one;
+                       }
+                   }
+               }
+               z = __ieee754_j0f(x);
+               w = __ieee754_j1f(x);
+               if (fabsf(z) >= fabsf(w))
+                   b = (t*z/b);
+               else
+                   b = (t*w/a);
+           }
+       }
+       if(sgn==1) return -b; else return b;
+}
+
+OLM_DLLEXPORT float
+__ieee754_ynf(int n, float x)
+{
+       int32_t i,hx,ix,ib;
+       int32_t sign;
+       float a, b, temp;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = 0x7fffffff&hx;
+    /* if Y(n,NaN) is NaN */
+       if(ix>0x7f800000) return x+x;
+       if(ix==0) return -one/zero;
+       if(hx<0) return zero/zero;
+       sign = 1;
+       if(n<0){
+               n = -n;
+               sign = 1 - ((n&1)<<1);
+       }
+       if(n==0) return(__ieee754_y0f(x));
+       if(n==1) return(sign*__ieee754_y1f(x));
+       if(ix==0x7f800000) return zero;
+
+       a = __ieee754_y0f(x);
+       b = __ieee754_y1f(x);
+       /* quit if b is -inf */
+       GET_FLOAT_WORD(ib,b);
+       for(i=1;i<n&&ib!=0xff800000;i++){
+           temp = b;
+           b = ((float)(i+i)/x)*b - a;
+           GET_FLOAT_WORD(ib,b);
+           a = temp;
+       }
+       if(sign>0) return b; else return -b;
+}
diff --git a/src/e_lgamma.c b/src/e_lgamma.c
new file mode 100644 (file)
index 0000000..d316796
--- /dev/null
@@ -0,0 +1,36 @@
+
+/* @(#)e_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgamma.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+/* __ieee754_lgamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+__ieee754_lgamma(double x)
+{
+#ifdef OPENLIBM_ONLY_THREAD_SAFE
+       int signgam;
+#endif
+
+       return __ieee754_lgamma_r(x,&signgam);
+}
diff --git a/src/e_lgamma_r.c b/src/e_lgamma_r.c
new file mode 100644 (file)
index 0000000..df3ae23
--- /dev/null
@@ -0,0 +1,298 @@
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgamma_r.c,v 1.11 2011/10/15 07:00:28 das Exp $");
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function 
+ * with user provide pointer for the sign of Gamma(x). 
+ *
+ * Method:
+ *   1. Argument Reduction for 0 < x <= 8
+ *     Since gamma(1+s)=s*gamma(s), for x in [0,8], we may 
+ *     reduce x to a number in [1.5,2.5] by
+ *             lgamma(1+s) = log(s) + lgamma(s)
+ *     for example,
+ *             lgamma(7.3) = log(6.3) + lgamma(6.3)
+ *                         = log(6.3*5.3) + lgamma(5.3)
+ *                         = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ *   2. Polynomial approximation of lgamma around its
+ *     minimun ymin=1.461632144968362245 to maintain monotonicity.
+ *     On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ *             Let z = x-ymin;
+ *             lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ *     where
+ *             poly(z) is a 14 degree polynomial.
+ *   2. Rational approximation in the primary interval [2,3]
+ *     We use the following approximation:
+ *             s = x-2.0;
+ *             lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ *     with accuracy
+ *             |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ *     Our algorithms are based on the following observation
+ *
+ *                             zeta(2)-1    2    zeta(3)-1    3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s  -  --------- * s  + ...
+ *                                 2                 3
+ *
+ *     where Euler = 0.5771... is the Euler constant, which is very
+ *     close to 0.5.
+ *
+ *   3. For x>=8, we have
+ *     lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ *     (better formula:
+ *        lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ *     Let z = 1/x, then we approximation
+ *             f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ *     by
+ *                                 3       5             11
+ *             w = w0 + w1*z + w2*z  + w3*z  + ... + w6*z
+ *     where 
+ *             |w - f(z)| < 2**-58.74
+ *             
+ *   4. For negative x, since (G is gamma function)
+ *             -x*G(-x)*G(x) = pi/sin(pi*x),
+ *     we have
+ *             G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ *     since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ *     Hence, for x<0, signgam = sign(sin(pi*x)) and 
+ *             lgamma(x) = log(|Gamma(x)|)
+ *                       = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ *     Note: one should avoid compute pi*(-x) directly in the 
+ *           computation of sin(pi*(-x)).
+ *             
+ *   5. Special Cases
+ *             lgamma(2+s) ~ s*(1-Euler) for tiny s
+ *             lgamma(1) = lgamma(2) = 0
+ *             lgamma(x) ~ -log(|x|) for tiny x
+ *             lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero
+ *             lgamma(inf) = inf
+ *             lgamma(-inf) = inf (bug for bug compatible with C99!?)
+ *     
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+two52=  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi  =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0  =  7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1  =  3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2  =  6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3  =  2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4  =  7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5  =  2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6  =  1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7  =  5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8  =  2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9  =  1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 =  2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 =  4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc  =  1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf  = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt  = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0  =  4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1  = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2  =  6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3  = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4  =  1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5  = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6  =  6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7  = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8  =  2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9  = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 =  8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 =  3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 =  3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1  =  6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2  =  1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3  =  9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4  =  2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5  =  1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1  =  2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2  =  2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3  =  7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4  =  1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5  =  3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1  =  2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2  =  3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3  =  1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4  =  2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5  =  1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6  =  3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1  =  1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2  =  7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3  =  1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4  =  1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5  =  7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6  =  7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0  =  4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1  =  8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2  = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3  =  7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4  = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5  =  8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6  = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static const double zero=  0.00000000000000000000e+00;
+
+       static double sin_pi(double x)
+{
+       double y,z;
+       int n,ix;
+
+       GET_HIGH_WORD(ix,x);
+       ix &= 0x7fffffff;
+
+       if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+       y = -x;         /* x is assume negative */
+
+    /*
+     * argument reduction, make sure inexact flag not raised if input
+     * is an integer
+     */
+       z = floor(y);
+       if(z!=y) {                              /* inexact anyway */
+           y  *= 0.5;
+           y   = 2.0*(y - floor(y));           /* y = |x| mod 2.0 */
+           n   = (int) (y*4.0);
+       } else {
+            if(ix>=0x43400000) {
+                y = zero; n = 0;                 /* y must be even */
+            } else {
+                if(ix<0x43300000) z = y+two52; /* exact */
+               GET_LOW_WORD(n,z);
+               n &= 1;
+                y  = n;
+                n<<= 2;
+            }
+        }
+       switch (n) {
+           case 0:   y =  __kernel_sin(pi*y,zero,0); break;
+           case 1:   
+           case 2:   y =  __kernel_cos(pi*(0.5-y),zero); break;
+           case 3:  
+           case 4:   y =  __kernel_sin(pi*(one-y),zero,0); break;
+           case 5:
+           case 6:   y = -__kernel_cos(pi*(y-1.5),zero); break;
+           default:  y =  __kernel_sin(pi*(y-2.0),zero,0); break;
+           }
+       return -y;
+}
+
+
+OLM_DLLEXPORT double
+__ieee754_lgamma_r(double x, int *signgamp)
+{
+       double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+       int32_t hx;
+       int i,lx,ix;
+
+       EXTRACT_WORDS(hx,lx,x);
+
+    /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+       *signgamp = 1;
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) return x*x;
+       if((ix|lx)==0) return one/zero;
+       if(ix<0x3b900000) {     /* |x|<2**-70, return -log(|x|) */
+           if(hx<0) {
+               *signgamp = -1;
+               return -__ieee754_log(-x);
+           } else return -__ieee754_log(x);
+       }
+       if(hx<0) {
+           if(ix>=0x43300000)  /* |x|>=2**52, must be -integer */
+               return one/zero;
+           t = sin_pi(x);
+           if(t==zero) return one/zero; /* -integer */
+           nadj = __ieee754_log(pi/fabs(t*x));
+           if(t<zero) *signgamp = -1;
+           x = -x;
+       }
+
+    /* purge off 1 and 2 */
+       if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+    /* for x < 2.0 */
+       else if(ix<0x40000000) {
+           if(ix<=0x3feccccc) {        /* lgamma(x) = lgamma(x+1)-log(x) */
+               r = -__ieee754_log(x);
+               if(ix>=0x3FE76944) {y = one-x; i= 0;}
+               else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+               else {y = x; i=2;}
+           } else {
+               r = zero;
+               if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+               else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+               else {y=x-one;i=2;}
+           }
+           switch(i) {
+             case 0:
+               z = y*y;
+               p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+               p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+               p  = y*p1+p2;
+               r  += (p-0.5*y); break;
+             case 1:
+               z = y*y;
+               w = z*y;
+               p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12)));    /* parallel comp */
+               p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+               p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+               p  = z*p1-(tt-w*(p2+y*p3));
+               r += (tf + p); break;
+             case 2:   
+               p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+               p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+               r += (-0.5*y + p1/p2);
+           }
+       }
+       else if(ix<0x40200000) {                        /* x < 8.0 */
+           i = (int)x;
+           y = x-(double)i;
+           p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+           q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+           r = half*y+p/q;
+           z = one;    /* lgamma(1+s) = log(s) + lgamma(s) */
+           switch(i) {
+           case 7: z *= (y+6.0);       /* FALLTHRU */
+           case 6: z *= (y+5.0);       /* FALLTHRU */
+           case 5: z *= (y+4.0);       /* FALLTHRU */
+           case 4: z *= (y+3.0);       /* FALLTHRU */
+           case 3: z *= (y+2.0);       /* FALLTHRU */
+                   r += __ieee754_log(z); break;
+           }
+    /* 8.0 <= x < 2**58 */
+       } else if (ix < 0x43900000) {
+           t = __ieee754_log(x);
+           z = one/x;
+           y = z*z;
+           w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+           r = (x-half)*(t-one)+w;
+       } else 
+    /* 2**58 <= x <= inf */
+           r =  x*(__ieee754_log(x)-one);
+       if(hx<0) r = nadj - r;
+       return r;
+}
diff --git a/src/e_lgammaf.c b/src/e_lgammaf.c
new file mode 100644 (file)
index 0000000..5b95f02
--- /dev/null
@@ -0,0 +1,37 @@
+/* e_lgammaf.c -- float version of e_lgamma.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgammaf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+/* __ieee754_lgammaf(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgammaf_r
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+__ieee754_lgammaf(float x)
+{
+#ifdef OPENLIBM_ONLY_THREAD_SAFE
+       int signgam;
+#endif
+
+       return __ieee754_lgammaf_r(x,&signgam);
+}
diff --git a/src/e_lgammaf_r.c b/src/e_lgammaf_r.c
new file mode 100644 (file)
index 0000000..7446dfc
--- /dev/null
@@ -0,0 +1,231 @@
+/* e_lgammaf_r.c -- float version of e_lgamma_r.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgammaf_r.c,v 1.12 2011/10/15 07:00:28 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+two23=  8.3886080000e+06, /* 0x4b000000 */
+half=  5.0000000000e-01, /* 0x3f000000 */
+one =  1.0000000000e+00, /* 0x3f800000 */
+pi  =  3.1415927410e+00, /* 0x40490fdb */
+a0  =  7.7215664089e-02, /* 0x3d9e233f */
+a1  =  3.2246702909e-01, /* 0x3ea51a66 */
+a2  =  6.7352302372e-02, /* 0x3d89f001 */
+a3  =  2.0580807701e-02, /* 0x3ca89915 */
+a4  =  7.3855509982e-03, /* 0x3bf2027e */
+a5  =  2.8905137442e-03, /* 0x3b3d6ec6 */
+a6  =  1.1927076848e-03, /* 0x3a9c54a1 */
+a7  =  5.1006977446e-04, /* 0x3a05b634 */
+a8  =  2.2086278477e-04, /* 0x39679767 */
+a9  =  1.0801156895e-04, /* 0x38e28445 */
+a10 =  2.5214456400e-05, /* 0x37d383a2 */
+a11 =  4.4864096708e-05, /* 0x383c2c75 */
+tc  =  1.4616321325e+00, /* 0x3fbb16c3 */
+tf  = -1.2148628384e-01, /* 0xbdf8cdcd */
+/* tt = -(tail of tf) */
+tt  =  6.6971006518e-09, /* 0x31e61c52 */
+t0  =  4.8383611441e-01, /* 0x3ef7b95e */
+t1  = -1.4758771658e-01, /* 0xbe17213c */
+t2  =  6.4624942839e-02, /* 0x3d845a15 */
+t3  = -3.2788541168e-02, /* 0xbd064d47 */
+t4  =  1.7970675603e-02, /* 0x3c93373d */
+t5  = -1.0314224288e-02, /* 0xbc28fcfe */
+t6  =  6.1005386524e-03, /* 0x3bc7e707 */
+t7  = -3.6845202558e-03, /* 0xbb7177fe */
+t8  =  2.2596477065e-03, /* 0x3b141699 */
+t9  = -1.4034647029e-03, /* 0xbab7f476 */
+t10 =  8.8108185446e-04, /* 0x3a66f867 */
+t11 = -5.3859531181e-04, /* 0xba0d3085 */
+t12 =  3.1563205994e-04, /* 0x39a57b6b */
+t13 = -3.1275415677e-04, /* 0xb9a3f927 */
+t14 =  3.3552918467e-04, /* 0x39afe9f7 */
+u0  = -7.7215664089e-02, /* 0xbd9e233f */
+u1  =  6.3282704353e-01, /* 0x3f2200f4 */
+u2  =  1.4549225569e+00, /* 0x3fba3ae7 */
+u3  =  9.7771751881e-01, /* 0x3f7a4bb2 */
+u4  =  2.2896373272e-01, /* 0x3e6a7578 */
+u5  =  1.3381091878e-02, /* 0x3c5b3c5e */
+v1  =  2.4559779167e+00, /* 0x401d2ebe */
+v2  =  2.1284897327e+00, /* 0x4008392d */
+v3  =  7.6928514242e-01, /* 0x3f44efdf */
+v4  =  1.0422264785e-01, /* 0x3dd572af */
+v5  =  3.2170924824e-03, /* 0x3b52d5db */
+s0  = -7.7215664089e-02, /* 0xbd9e233f */
+s1  =  2.1498242021e-01, /* 0x3e5c245a */
+s2  =  3.2577878237e-01, /* 0x3ea6cc7a */
+s3  =  1.4635047317e-01, /* 0x3e15dce6 */
+s4  =  2.6642270386e-02, /* 0x3cda40e4 */
+s5  =  1.8402845599e-03, /* 0x3af135b4 */
+s6  =  3.1947532989e-05, /* 0x3805ff67 */
+r1  =  1.3920053244e+00, /* 0x3fb22d3b */
+r2  =  7.2193557024e-01, /* 0x3f38d0c5 */
+r3  =  1.7193385959e-01, /* 0x3e300f6e */
+r4  =  1.8645919859e-02, /* 0x3c98bf54 */
+r5  =  7.7794247773e-04, /* 0x3a4beed6 */
+r6  =  7.3266842264e-06, /* 0x36f5d7bd */
+w0  =  4.1893854737e-01, /* 0x3ed67f1d */
+w1  =  8.3333335817e-02, /* 0x3daaaaab */
+w2  = -2.7777778450e-03, /* 0xbb360b61 */
+w3  =  7.9365057172e-04, /* 0x3a500cfd */
+w4  = -5.9518753551e-04, /* 0xba1c065c */
+w5  =  8.3633989561e-04, /* 0x3a5b3dd2 */
+w6  = -1.6309292987e-03; /* 0xbad5c4e8 */
+
+static const float zero=  0.0000000000e+00;
+
+       static float sin_pif(float x)
+{
+       float y,z;
+       int n,ix;
+
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;
+
+       if(ix<0x3e800000) return __kernel_sindf(pi*x);
+       y = -x;         /* x is assume negative */
+
+    /*
+     * argument reduction, make sure inexact flag not raised if input
+     * is an integer
+     */
+       z = floorf(y);
+       if(z!=y) {                              /* inexact anyway */
+           y  *= (float)0.5;
+           y   = (float)2.0*(y - floorf(y));   /* y = |x| mod 2.0 */
+           n   = (int) (y*(float)4.0);
+       } else {
+            if(ix>=0x4b800000) {
+                y = zero; n = 0;                 /* y must be even */
+            } else {
+                if(ix<0x4b000000) z = y+two23; /* exact */
+               GET_FLOAT_WORD(n,z);
+               n &= 1;
+                y  = n;
+                n<<= 2;
+            }
+        }
+       switch (n) {
+           case 0:   y =  __kernel_sindf(pi*y); break;
+           case 1:
+           case 2:   y =  __kernel_cosdf(pi*((float)0.5-y)); break;
+           case 3:
+           case 4:   y =  __kernel_sindf(pi*(one-y)); break;
+           case 5:
+           case 6:   y = -__kernel_cosdf(pi*(y-(float)1.5)); break;
+           default:  y =  __kernel_sindf(pi*(y-(float)2.0)); break;
+           }
+       return -y;
+}
+
+
+OLM_DLLEXPORT float
+__ieee754_lgammaf_r(float x, int *signgamp)
+{
+       float t,y,z,nadj,p,p1,p2,p3,q,r,w;
+       int32_t hx;
+       int i,ix;
+
+       GET_FLOAT_WORD(hx,x);
+
+    /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+       *signgamp = 1;
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) return x*x;
+       if(ix==0) return one/zero;
+       if(ix<0x35000000) {     /* |x|<2**-21, return -log(|x|) */
+           if(hx<0) {
+               *signgamp = -1;
+               return -__ieee754_logf(-x);
+           } else return -__ieee754_logf(x);
+       }
+       if(hx<0) {
+           if(ix>=0x4b000000)  /* |x|>=2**23, must be -integer */
+               return one/zero;
+           t = sin_pif(x);
+           if(t==zero) return one/zero; /* -integer */
+           nadj = __ieee754_logf(pi/fabsf(t*x));
+           if(t<zero) *signgamp = -1;
+           x = -x;
+       }
+
+    /* purge off 1 and 2 */
+       if (ix==0x3f800000||ix==0x40000000) r = 0;
+    /* for x < 2.0 */
+       else if(ix<0x40000000) {
+           if(ix<=0x3f666666) {        /* lgamma(x) = lgamma(x+1)-log(x) */
+               r = -__ieee754_logf(x);
+               if(ix>=0x3f3b4a20) {y = one-x; i= 0;}
+               else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;}
+               else {y = x; i=2;}
+           } else {
+               r = zero;
+               if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */
+               else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */
+               else {y=x-one;i=2;}
+           }
+           switch(i) {
+             case 0:
+               z = y*y;
+               p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+               p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+               p  = y*p1+p2;
+               r  += (p-(float)0.5*y); break;
+             case 1:
+               z = y*y;
+               w = z*y;
+               p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12)));    /* parallel comp */
+               p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+               p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+               p  = z*p1-(tt-w*(p2+y*p3));
+               r += (tf + p); break;
+             case 2:
+               p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+               p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+               r += (-(float)0.5*y + p1/p2);
+           }
+       }
+       else if(ix<0x41000000) {                        /* x < 8.0 */
+           i = (int)x;
+           y = x-(float)i;
+           p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+           q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+           r = half*y+p/q;
+           z = one;    /* lgamma(1+s) = log(s) + lgamma(s) */
+           switch(i) {
+           case 7: z *= (y+(float)6.0);        /* FALLTHRU */
+           case 6: z *= (y+(float)5.0);        /* FALLTHRU */
+           case 5: z *= (y+(float)4.0);        /* FALLTHRU */
+           case 4: z *= (y+(float)3.0);        /* FALLTHRU */
+           case 3: z *= (y+(float)2.0);        /* FALLTHRU */
+                   r += __ieee754_logf(z); break;
+           }
+    /* 8.0 <= x < 2**58 */
+       } else if (ix < 0x5c800000) {
+           t = __ieee754_logf(x);
+           z = one/x;
+           y = z*z;
+           w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+           r = (x-half)*(t-one)+w;
+       } else
+    /* 2**58 <= x <= inf */
+           r =  x*(__ieee754_logf(x)-one);
+       if(hx<0) r = nadj - r;
+       return r;
+}
diff --git a/src/e_lgammal.c b/src/e_lgammal.c
new file mode 100644 (file)
index 0000000..c1bfb25
--- /dev/null
@@ -0,0 +1,15 @@
+#include "cdefs-compat.h"
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+lgammal(long double x)
+{
+#ifdef OPENLIBM_ONLY_THREAD_SAFE
+       int signgam;
+#endif
+
+       return (lgammal_r(x, &signgam));
+}
diff --git a/src/e_log.c b/src/e_log.c
new file mode 100644 (file)
index 0000000..4e0a0a9
--- /dev/null
@@ -0,0 +1,141 @@
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_log.c,v 1.15 2008/03/29 16:37:59 das Exp $");
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *                     x = 2^k * (1+f), 
+ *        where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *   2. Approximation of log(1+f).
+ *     Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *              = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *              = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ *     a polynomial of degree 14 to approximate R The maximum error 
+ *     of this polynomial approximation is bounded by 2**-58.45. In
+ *     other words,
+ *                     2      4      6      8      10      12      14
+ *         R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
+ *     (the values of Lg1 to Lg7 are listed in the program)
+ *     and
+ *         |      2          14          |     -58.45
+ *         | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
+ *         |                             |
+ *     Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *     In order to guarantee error in log below 1ulp, we compute log
+ *     by
+ *             log(1+f) = f - s*(f - R)        (if f is not too large)
+ *             log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
+ *     
+ *     3. Finally,  log(x) = k*ln2 + log(1+f).  
+ *                         = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *        Here ln2 is split into two floating point number: 
+ *                     ln2_hi + ln2_lo,
+ *        where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *     log(x) is NaN with signal if x < 0 (including -INF) ; 
+ *     log(+INF) is +INF; log(0) is -INF with signal;
+ *     log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *     according to an error analysis, the error is always less than
+ *     1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero   =  0.0;
+
+OLM_DLLEXPORT double
+__ieee754_log(double x)
+{
+       double hfsq,f,s,z,R,w,t1,t2,dk;
+       int32_t k,hx,i,j;
+       u_int32_t lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+
+       k=0;
+       if (hx < 0x00100000) {                  /* x < 2**-1022  */
+           if (((hx&0x7fffffff)|lx)==0) 
+               return -two54/zero;             /* log(+-0)=-inf */
+           if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 54; x *= two54; /* subnormal number, scale up x */
+           GET_HIGH_WORD(hx,x);
+       } 
+       if (hx >= 0x7ff00000) return x+x;
+       k += (hx>>20)-1023;
+       hx &= 0x000fffff;
+       i = (hx+0x95f64)&0x100000;
+       SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */
+       k += (i>>20);
+       f = x-1.0;
+       if((0x000fffff&(2+hx))<3) {     /* -2**-20 <= f < 2**-20 */
+           if(f==zero) {
+               if(k==0) {
+                   return zero;
+               } else {
+                   dk=(double)k;
+                   return dk*ln2_hi+dk*ln2_lo;
+               }
+           }
+           R = f*f*(0.5-0.33333333333333333*f);
+           if(k==0) return f-R; else {dk=(double)k;
+                    return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+       }
+       s = f/(2.0+f); 
+       dk = (double)k;
+       z = s*s;
+       i = hx-0x6147a;
+       w = z*z;
+       j = 0x6b851-hx;
+       t1= w*(Lg2+w*(Lg4+w*Lg6)); 
+       t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); 
+       i |= j;
+       R = t2+t1;
+       if(i>0) {
+           hfsq=0.5*f*f;
+           if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                    return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+       } else {
+           if(k==0) return f-s*(f-R); else
+                    return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+       }
+}
diff --git a/src/e_log10.c b/src/e_log10.c
new file mode 100644 (file)
index 0000000..5d20746
--- /dev/null
@@ -0,0 +1,88 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_log10.c,v 1.15 2011/10/15 05:23:28 das Exp $");
+
+/*
+ * Return the base 10 logarithm of x.  See e_log.c and k_log.h for most
+ * comments.
+ *
+ *    log10(x) = (f - 0.5*f*f + k_log1p(f)) / ln10 + k * log10(2)
+ * in not-quite-routine extra precision.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#include "k_log.h"
+
+static const double
+two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10hi   =  4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */
+ivln10lo   =  2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */
+log10_2hi  =  3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo  =  3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static const double zero   =  0.0;
+
+OLM_DLLEXPORT double
+__ieee754_log10(double x)
+{
+       double f,hfsq,hi,lo,r,val_hi,val_lo,w,y,y2;
+       int32_t i,k,hx;
+       u_int32_t lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+
+       k=0;
+       if (hx < 0x00100000) {                  /* x < 2**-1022  */
+           if (((hx&0x7fffffff)|lx)==0)
+               return -two54/zero;             /* log(+-0)=-inf */
+           if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 54; x *= two54; /* subnormal number, scale up x */
+           GET_HIGH_WORD(hx,x);
+       }
+       if (hx >= 0x7ff00000) return x+x;
+       if (hx == 0x3ff00000 && lx == 0)
+           return zero;                        /* log(1) = +0 */
+       k += (hx>>20)-1023;
+       hx &= 0x000fffff;
+       i = (hx+0x95f64)&0x100000;
+       SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */
+       k += (i>>20);
+       y = (double)k;
+       f = x - 1.0;
+       hfsq = 0.5*f*f;
+       r = k_log1p(f);
+
+       /* See e_log2.c for most details. */
+       hi = f - hfsq;
+       SET_LOW_WORD(hi,0);
+       lo = (f - hi) - hfsq + r;
+       val_hi = hi*ivln10hi;
+       y2 = y*log10_2hi;
+       val_lo = y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi;
+
+       /*
+        * Extra precision in for adding y*log10_2hi is not strictly needed
+        * since there is no very large cancellation near x = sqrt(2) or
+        * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
+        * with some parallelism and it reduces the error for many args.
+        */
+       w = y2 + val_hi;
+       val_lo += (y2 - w) + val_hi;
+       val_hi = w;
+
+       return val_lo + val_hi;
+}
diff --git a/src/e_log10f.c b/src/e_log10f.c
new file mode 100644 (file)
index 0000000..1f6e31a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_log10f.c,v 1.13 2011/10/16 05:36:23 das Exp $");
+
+/*
+ * Float version of e_log10.c.  See the latter for most comments.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#include "k_logf.h"
+
+// VBS
+#define float_t float
+
+static const float
+two25      =  3.3554432000e+07, /* 0x4c000000 */
+ivln10hi   =  4.3432617188e-01, /* 0x3ede6000 */
+ivln10lo   = -3.1689971365e-05, /* 0xb804ead9 */
+log10_2hi  =  3.0102920532e-01, /* 0x3e9a2080 */
+log10_2lo  =  7.9034151668e-07; /* 0x355427db */
+
+static const float zero   =  0.0;
+
+OLM_DLLEXPORT float
+__ieee754_log10f(float x)
+{
+       float f,hfsq,hi,lo,r,y;
+       int32_t i,k,hx;
+
+       GET_FLOAT_WORD(hx,x);
+
+       k=0;
+       if (hx < 0x00800000) {                  /* x < 2**-126  */
+           if ((hx&0x7fffffff)==0)
+               return -two25/zero;             /* log(+-0)=-inf */
+           if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 25; x *= two25; /* subnormal number, scale up x */
+           GET_FLOAT_WORD(hx,x);
+       }
+       if (hx >= 0x7f800000) return x+x;
+       if (hx == 0x3f800000)
+           return zero;                        /* log(1) = +0 */
+       k += (hx>>23)-127;
+       hx &= 0x007fffff;
+       i = (hx+(0x4afb0d))&0x800000;
+       SET_FLOAT_WORD(x,hx|(i^0x3f800000));    /* normalize x or x/2 */
+       k += (i>>23);
+       y = (float)k;
+       f = x - (float)1.0;
+       hfsq = (float)0.5*f*f;
+       r = k_log1pf(f);
+
+       /* See e_log2f.c and e_log2.c for details. */
+       if (sizeof(float_t) > sizeof(float))
+               return (r - hfsq + f) * ((float_t)ivln10lo + ivln10hi) +
+                   y * ((float_t)log10_2lo + log10_2hi);
+       hi = f - hfsq;
+       GET_FLOAT_WORD(hx,hi);
+       SET_FLOAT_WORD(hi,hx&0xfffff000);
+       lo = (f - hi) - hfsq + r;
+       return y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi +
+           y*log10_2hi;
+}
diff --git a/src/e_log2.c b/src/e_log2.c
new file mode 100644 (file)
index 0000000..9fb21a1
--- /dev/null
@@ -0,0 +1,111 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_log2.c,v 1.4 2011/10/15 05:23:28 das Exp $");
+
+/*
+ * Return the base 2 logarithm of x.  See e_log.c and k_log.h for most
+ * comments.
+ *
+ * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel,
+ * then does the combining and scaling steps
+ *    log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k
+ * in not-quite-routine extra precision.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#include "k_log.h"
+
+static const double
+two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln2hi    =  1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */
+ivln2lo    =  1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */
+
+static const double zero   =  0.0;
+
+OLM_DLLEXPORT double
+__ieee754_log2(double x)
+{
+       double f,hfsq,hi,lo,r,val_hi,val_lo,w,y;
+       int32_t i,k,hx;
+       u_int32_t lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+
+       k=0;
+       if (hx < 0x00100000) {                  /* x < 2**-1022  */
+           if (((hx&0x7fffffff)|lx)==0)
+               return -two54/zero;             /* log(+-0)=-inf */
+           if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 54; x *= two54; /* subnormal number, scale up x */
+           GET_HIGH_WORD(hx,x);
+       }
+       if (hx >= 0x7ff00000) return x+x;
+       if (hx == 0x3ff00000 && lx == 0)
+           return zero;                        /* log(1) = +0 */
+       k += (hx>>20)-1023;
+       hx &= 0x000fffff;
+       i = (hx+0x95f64)&0x100000;
+       SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */
+       k += (i>>20);
+       y = (double)k;
+       f = x - 1.0;
+       hfsq = 0.5*f*f;
+       r = k_log1p(f);
+
+       /*
+        * f-hfsq must (for args near 1) be evaluated in extra precision
+        * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2).
+        * This is fairly efficient since f-hfsq only depends on f, so can
+        * be evaluated in parallel with R.  Not combining hfsq with R also
+        * keeps R small (though not as small as a true `lo' term would be),
+        * so that extra precision is not needed for terms involving R.
+        *
+        * Compiler bugs involving extra precision used to break Dekker's
+        * theorem for spitting f-hfsq as hi+lo, unless double_t was used
+        * or the multi-precision calculations were avoided when double_t
+        * has extra precision.  These problems are now automatically
+        * avoided as a side effect of the optimization of combining the
+        * Dekker splitting step with the clear-low-bits step.
+        *
+        * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra
+        * precision to avoid a very large cancellation when x is very near
+        * these values.  Unlike the above cancellations, this problem is
+        * specific to base 2.  It is strange that adding +-1 is so much
+        * harder than adding +-ln2 or +-log10_2.
+        *
+        * This uses Dekker's theorem to normalize y+val_hi, so the
+        * compiler bugs are back in some configurations, sigh.  And I
+        * don't want to used double_t to avoid them, since that gives a
+        * pessimization and the support for avoiding the pessimization
+        * is not yet available.
+        *
+        * The multi-precision calculations for the multiplications are
+        * routine.
+        */
+       hi = f - hfsq;
+       SET_LOW_WORD(hi,0);
+       lo = (f - hi) - hfsq + r;
+       val_hi = hi*ivln2hi;
+       val_lo = (lo+hi)*ivln2lo + lo*ivln2hi;
+
+       /* spadd(val_hi, val_lo, y), except for not using double_t: */
+       w = y + val_hi;
+       val_lo += (y - w) + val_hi;
+       val_hi = w;
+
+       return val_lo + val_hi;
+}
diff --git a/src/e_log2f.c b/src/e_log2f.c
new file mode 100644 (file)
index 0000000..58977ac
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_log2f.c,v 1.5 2011/10/15 05:23:28 das Exp $");
+
+/*
+ * Float version of e_log2.c.  See the latter for most comments.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#include "k_logf.h"
+
+// VBS
+#define float_t float
+
+static const float
+two25      =  3.3554432000e+07, /* 0x4c000000 */
+ivln2hi    =  1.4428710938e+00, /* 0x3fb8b000 */
+ivln2lo    = -1.7605285393e-04; /* 0xb9389ad4 */
+
+static const float zero   =  0.0;
+
+OLM_DLLEXPORT float
+__ieee754_log2f(float x)
+{
+       float f,hfsq,hi,lo,r,y;
+       int32_t i,k,hx;
+
+       GET_FLOAT_WORD(hx,x);
+
+       k=0;
+       if (hx < 0x00800000) {                  /* x < 2**-126  */
+           if ((hx&0x7fffffff)==0)
+               return -two25/zero;             /* log(+-0)=-inf */
+           if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 25; x *= two25; /* subnormal number, scale up x */
+           GET_FLOAT_WORD(hx,x);
+       }
+       if (hx >= 0x7f800000) return x+x;
+       if (hx == 0x3f800000)
+           return zero;                        /* log(1) = +0 */
+       k += (hx>>23)-127;
+       hx &= 0x007fffff;
+       i = (hx+(0x4afb0d))&0x800000;
+       SET_FLOAT_WORD(x,hx|(i^0x3f800000));    /* normalize x or x/2 */
+       k += (i>>23);
+       y = (float)k;
+       f = x - (float)1.0;
+       hfsq = (float)0.5*f*f;
+       r = k_log1pf(f);
+
+       /*
+        * We no longer need to avoid falling into the multi-precision
+        * calculations due to compiler bugs breaking Dekker's theorem.
+        * Keep avoiding this as an optimization.  See e_log2.c for more
+        * details (some details are here only because the optimization
+        * is not yet available in double precision).
+        *
+        * Another compiler bug turned up.  With gcc on i386,
+        * (ivln2lo + ivln2hi) would be evaluated in float precision
+        * despite runtime evaluations using double precision.  So we
+        * must cast one of its terms to float_t.  This makes the whole
+        * expression have type float_t, so return is forced to waste
+        * time clobbering its extra precision.
+        */
+       if (sizeof(float_t) > sizeof(float))
+               return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y;
+
+       hi = f - hfsq;
+       GET_FLOAT_WORD(hx,hi);
+       SET_FLOAT_WORD(hi,hx&0xfffff000);
+       lo = (f - hi) - hfsq + r;
+       return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y;
+}
diff --git a/src/e_logf.c b/src/e_logf.c
new file mode 100644 (file)
index 0000000..dc5e151
--- /dev/null
@@ -0,0 +1,89 @@
+/* e_logf.c -- float version of e_log.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_logf.c,v 1.11 2008/03/29 16:37:59 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,   /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,   /* 0x3717f7d1 */
+two25 =    3.355443200e+07,    /* 0x4c000000 */
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 =      0xaaaaaa.0p-24,     /* 0.66666662693 */
+Lg2 =      0xccce13.0p-25,     /* 0.40000972152 */
+Lg3 =      0x91e9ee.0p-25,     /* 0.28498786688 */
+Lg4 =      0xf89e26.0p-26;     /* 0.24279078841 */
+
+static const float zero   =  0.0;
+
+OLM_DLLEXPORT float
+__ieee754_logf(float x)
+{
+       float hfsq,f,s,z,R,w,t1,t2,dk;
+       int32_t k,ix,i,j;
+
+       GET_FLOAT_WORD(ix,x);
+
+       k=0;
+       if (ix < 0x00800000) {                  /* x < 2**-126  */
+           if ((ix&0x7fffffff)==0)
+               return -two25/zero;             /* log(+-0)=-inf */
+           if (ix<0) return (x-x)/zero;        /* log(-#) = NaN */
+           k -= 25; x *= two25; /* subnormal number, scale up x */
+           GET_FLOAT_WORD(ix,x);
+       }
+       if (ix >= 0x7f800000) return x+x;
+       k += (ix>>23)-127;
+       ix &= 0x007fffff;
+       i = (ix+(0x95f64<<3))&0x800000;
+       SET_FLOAT_WORD(x,ix|(i^0x3f800000));    /* normalize x or x/2 */
+       k += (i>>23);
+       f = x-(float)1.0;
+       if((0x007fffff&(0x8000+ix))<0xc000) {   /* -2**-9 <= f < 2**-9 */
+           if(f==zero) {
+               if(k==0) {
+                   return zero;
+               } else {
+                   dk=(float)k;
+                   return dk*ln2_hi+dk*ln2_lo;
+               }
+           }
+           R = f*f*((float)0.5-(float)0.33333333333333333*f);
+           if(k==0) return f-R; else {dk=(float)k;
+                    return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+       }
+       s = f/((float)2.0+f);
+       dk = (float)k;
+       z = s*s;
+       i = ix-(0x6147a<<3);
+       w = z*z;
+       j = (0x6b851<<3)-ix;
+       t1= w*(Lg2+w*Lg4);
+       t2= z*(Lg1+w*Lg3);
+       i |= j;
+       R = t2+t1;
+       if(i>0) {
+           hfsq=(float)0.5*f*f;
+           if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                    return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+       } else {
+           if(k==0) return f-s*(f-R); else
+                    return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+       }
+}
diff --git a/src/e_pow.c b/src/e_pow.c
new file mode 100644 (file)
index 0000000..e407983
--- /dev/null
@@ -0,0 +1,312 @@
+/* @(#)e_pow.c 1.5 04/04/22 SMI */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_pow.c,v 1.14 2011/10/21 06:26:07 das Exp $");
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ *                   n
+ * Method:  Let x =  2   * (1+f)
+ *     1. Compute and return log2(x) in two pieces:
+ *             log2(x) = w1 + w2,
+ *        where w1 has 53-24 = 29 bit trailing zeros.
+ *     2. Perform y*log2(x) = n+y' by simulating muti-precision 
+ *        arithmetic, where |y'|<=0.5.
+ *     3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *     1.  (anything) ** 0  is 1
+ *     2.  (anything) ** 1  is itself
+ *     3.  (anything) ** NAN is NAN
+ *     4.  NAN ** (anything except 0) is NAN
+ *     5.  +-(|x| > 1) **  +INF is +INF
+ *     6.  +-(|x| > 1) **  -INF is +0
+ *     7.  +-(|x| < 1) **  +INF is +0
+ *     8.  +-(|x| < 1) **  -INF is +INF
+ *     9.  +-1         ** +-INF is NAN
+ *     10. +0 ** (+anything except 0, NAN)               is +0
+ *     11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *     12. +0 ** (-anything except 0, NAN)               is +INF
+ *     13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *     14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *     15. +INF ** (+anything except 0,NAN) is +INF
+ *     16. +INF ** (-anything except 0,NAN) is +0
+ *     17. -INF ** (anything)  = -0 ** (-anything)
+ *     18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *     19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ *     pow(x,y) returns x**y nearly rounded. In particular
+ *                     pow(integer,integer)
+ *     always returns the correct integer provided it is 
+ *     representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero    =  0.0,
+one    =  1.0,
+two    =  2.0,
+two53  =  9007199254740992.0,  /* 0x43400000, 0x00000000 */
+huge   =  1.0e300,
+tiny    =  1.0e-300,
+       /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+OLM_DLLEXPORT double
+__ieee754_pow(double x, double y)
+{
+       double z,ax,z_h,z_l,p_h,p_l;
+       double y1,t1,t2,r,s,t,u,v,w;
+       int32_t i,j,k,yisint,n;
+       int32_t hx,hy,ix,iy;
+       u_int32_t lx,ly;
+
+       EXTRACT_WORDS(hx,lx,x);
+       EXTRACT_WORDS(hy,ly,y);
+       ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+       if((iy|ly)==0) return one;      
+
+    /* x==1: 1**y = 1, even if y is NaN */
+       if (hx==0x3ff00000 && lx == 0) return one;
+
+    /* y!=zero: result is NaN if either arg is NaN */
+       if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+          iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
+               return (x+0.0)+(y+0.0);
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0      ... y is not an integer
+     * yisint = 1      ... y is an odd int
+     * yisint = 2      ... y is an even int
+     */
+       yisint  = 0;
+       if(hx<0) {      
+           if(iy>=0x43400000) yisint = 2; /* even integer y */
+           else if(iy>=0x3ff00000) {
+               k = (iy>>20)-0x3ff;        /* exponent */
+               if(k>20) {
+                   j = ly>>(52-k);
+                   if((j<<(52-k))==ly) yisint = 2-(j&1);
+               } else if(ly==0) {
+                   j = iy>>(20-k);
+                   if((j<<(20-k))==iy) yisint = 2-(j&1);
+               }
+           }           
+       } 
+
+    /* special value of y */
+       if(ly==0) {     
+           if (iy==0x7ff00000) {       /* y is +-inf */
+               if(((ix-0x3ff00000)|lx)==0)
+                   return  one;        /* (-1)**+-inf is NaN */
+               else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+                   return (hy>=0)? y: zero;
+               else                    /* (|x|<1)**-,+inf = inf,0 */
+                   return (hy<0)?-y: zero;
+           } 
+           if(iy==0x3ff00000) {        /* y is  +-1 */
+               if(hy<0) return one/x; else return x;
+           }
+            if(hy==0x40000000) return x*x;   /* y is  2 */
+            if(hy==0x40080000) return x*x*x; /* y is  3 */
+            if(hy==0x40100000) {             /* y is  4 */
+                u = x*x;
+                return u*u;
+            }
+           if(hy==0x3fe00000) {             /* y is  0.5 */
+               if(hx>=0)       /* x >= +0 */
+                    return sqrt(x);
+           }
+       }
+
+       ax   = fabs(x);
+    /* special value of x */
+       if(lx==0) {
+           if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+               z = ax;                 /*x is +-0,+-inf,+-1*/
+               if(hy<0) z = one/z;     /* z = (1/|x|) */
+               if(hx<0) {
+                   if(((ix-0x3ff00000)|yisint)==0) {
+                       z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+                   } else if(yisint==1) 
+                       z = -z;         /* (x<0)**odd = -(|x|**odd) */
+               }
+               return z;
+           }
+       }
+    
+    /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be
+       n = (hx>>31)+1;
+       but ANSI C says a right shift of a signed negative quantity is
+       implementation defined.  */
+       n = ((u_int32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+       if((n|yisint)==0) return (x-x)/(x-x);
+
+       s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+       if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+       if(iy>0x41e00000) { /* if |y| > 2**31 */
+           if(iy>0x43f00000){  /* if |y| > 2**64, must o/uflow */
+               if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+               if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+           }
+       /* over/underflow if x is not close to one */
+           if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+           if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+       /* now |1-x| is tiny <= 2**-20, suffice to compute 
+          log(x) by x-x^2/2+x^3/3-x^4/4 */
+           t = ax-one;         /* t has 20 trailing zeros */
+           w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+           u = ivln2_h*t;      /* ivln2_h has 21 sig. bits */
+           v = t*ivln2_l-w*ivln2;
+           t1 = u+v;
+           SET_LOW_WORD(t1,0);
+           t2 = v-(t1-u);
+       } else {
+           double ss,s2,s_h,s_l,t_h,t_l;
+           n = 0;
+       /* take care subnormal number */
+           if(ix<0x00100000)
+               {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); }
+           n  += ((ix)>>20)-0x3ff;
+           j  = ix&0x000fffff;
+       /* determine interval */
+           ix = j|0x3ff00000;          /* normalize ix */
+           if(j<=0x3988E) k=0;         /* |x|<sqrt(3/2) */
+           else if(j<0xBB67A) k=1;     /* |x|<sqrt(3)   */
+           else {k=0;n+=1;ix -= 0x00100000;}
+           SET_HIGH_WORD(ax,ix);
+
+       /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+           u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+           v = one/(ax+bp[k]);
+           ss = u*v;
+           s_h = ss;
+           SET_LOW_WORD(s_h,0);
+       /* t_h=ax+bp[k] High */
+           t_h = zero;
+           SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18));
+           t_l = ax - (t_h-bp[k]);
+           s_l = v*((u-s_h*t_h)-s_h*t_l);
+       /* compute log(ax) */
+           s2 = ss*ss;
+           r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+           r += s_l*(s_h+ss);
+           s2  = s_h*s_h;
+           t_h = 3.0+s2+r;
+           SET_LOW_WORD(t_h,0);
+           t_l = r-((t_h-3.0)-s2);
+       /* u+v = ss*(1+...) */
+           u = s_h*t_h;
+           v = s_l*t_h+t_l*ss;
+       /* 2/(3log2)*(ss+...) */
+           p_h = u+v;
+           SET_LOW_WORD(p_h,0);
+           p_l = v-(p_h-u);
+           z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+           z_l = cp_l*p_h+p_l*cp+dp_l[k];
+       /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+           t = (double)n;
+           t1 = (((z_h+z_l)+dp_h[k])+t);
+           SET_LOW_WORD(t1,0);
+           t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+       }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+       y1  = y;
+       SET_LOW_WORD(y1,0);
+       p_l = (y-y1)*t1+y*t2;
+       p_h = y1*t1;
+       z = p_l+p_h;
+       EXTRACT_WORDS(j,i,z);
+       if (j>=0x40900000) {                            /* z >= 1024 */
+           if(((j-0x40900000)|i)!=0)                   /* if z > 1024 */
+               return s*huge*huge;                     /* overflow */
+           else {
+               if(p_l+ovt>z-p_h) return s*huge*huge;   /* overflow */
+           }
+       } else if((j&0x7fffffff)>=0x4090cc00 ) {        /* z <= -1075 */
+           if(((j-0xc090cc00)|i)!=0)           /* z < -1075 */
+               return s*tiny*tiny;             /* underflow */
+           else {
+               if(p_l<=z-p_h) return s*tiny*tiny;      /* underflow */
+           }
+       }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+       i = j&0x7fffffff;
+       k = (i>>20)-0x3ff;
+       n = 0;
+       if(i>0x3fe00000) {              /* if |z| > 0.5, set n = [z+0.5] */
+           n = j+(0x00100000>>(k+1));
+           k = ((n&0x7fffffff)>>20)-0x3ff;     /* new k for n */
+           t = zero;
+           SET_HIGH_WORD(t,n&~(0x000fffff>>k));
+           n = ((n&0x000fffff)|0x00100000)>>(20-k);
+           if(j<0) n = -n;
+           p_h -= t;
+       } 
+       t = p_l+p_h;
+       SET_LOW_WORD(t,0);
+       u = t*lg2_h;
+       v = (p_l-(t-p_h))*lg2+t*lg2_l;
+       z = u+v;
+       w = v-(z-u);
+       t  = z*z;
+       t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+       r  = (z*t1)/(t1-two)-(w+z*w);
+       z  = one-(r-z);
+       GET_HIGH_WORD(j,z);
+       j += (n<<20);
+       if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+       else SET_HIGH_WORD(z,j);
+       return s*z;
+}
diff --git a/src/e_powf.c b/src/e_powf.c
new file mode 100644 (file)
index 0000000..84b5692
--- /dev/null
@@ -0,0 +1,255 @@
+/* e_powf.c -- float version of e_pow.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_powf.c,v 1.16 2011/10/21 06:26:07 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
+dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
+zero    =  0.0,
+one    =  1.0,
+two    =  2.0,
+two24  =  16777216.0,  /* 0x4b800000 */
+huge   =  1.0e30,
+tiny    =  1.0e-30,
+       /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  6.0000002384e-01, /* 0x3f19999a */
+L2  =  4.2857143283e-01, /* 0x3edb6db7 */
+L3  =  3.3333334327e-01, /* 0x3eaaaaab */
+L4  =  2.7272811532e-01, /* 0x3e8ba305 */
+L5  =  2.3066075146e-01, /* 0x3e6c3255 */
+L6  =  2.0697501302e-01, /* 0x3e53f142 */
+P1   =  1.6666667163e-01, /* 0x3e2aaaab */
+P2   = -2.7777778450e-03, /* 0xbb360b61 */
+P3   =  6.6137559770e-05, /* 0x388ab355 */
+P4   = -1.6533901999e-06, /* 0xb5ddea0e */
+P5   =  4.1381369442e-08, /* 0x3331bb4c */
+lg2  =  6.9314718246e-01, /* 0x3f317218 */
+lg2_h  =  6.93145752e-01, /* 0x3f317200 */
+lg2_l  =  1.42860654e-06, /* 0x35bfbe8c */
+ovt =  4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
+cp    =  9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
+cp_h  =  9.6191406250e-01, /* 0x3f764000 =12b cp */
+cp_l  = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */
+ivln2    =  1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
+ivln2_h  =  1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
+ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
+
+OLM_DLLEXPORT float
+__ieee754_powf(float x, float y)
+{
+       float z,ax,z_h,z_l,p_h,p_l;
+       float y1,t1,t2,r,s,sn,t,u,v,w;
+       int32_t i,j,k,yisint,n;
+       int32_t hx,hy,ix,iy,is;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_FLOAT_WORD(hy,y);
+       ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+       if(iy==0) return one;
+
+    /* x==1: 1**y = 1, even if y is NaN */
+       if (hx==0x3f800000) return one;
+
+    /* y!=zero: result is NaN if either arg is NaN */
+       if(ix > 0x7f800000 ||
+          iy > 0x7f800000)
+               return (x+0.0F)+(y+0.0F);
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0      ... y is not an integer
+     * yisint = 1      ... y is an odd int
+     * yisint = 2      ... y is an even int
+     */
+       yisint  = 0;
+       if(hx<0) {
+           if(iy>=0x4b800000) yisint = 2; /* even integer y */
+           else if(iy>=0x3f800000) {
+               k = (iy>>23)-0x7f;         /* exponent */
+               j = iy>>(23-k);
+               if((j<<(23-k))==iy) yisint = 2-(j&1);
+           }
+       }
+
+    /* special value of y */
+       if (iy==0x7f800000) {   /* y is +-inf */
+           if (ix==0x3f800000)
+               return  one;    /* (-1)**+-inf is NaN */
+           else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */
+               return (hy>=0)? y: zero;
+           else                        /* (|x|<1)**-,+inf = inf,0 */
+               return (hy<0)?-y: zero;
+       }
+       if(iy==0x3f800000) {    /* y is  +-1 */
+           if(hy<0) return one/x; else return x;
+       }
+        if(hy==0x40000000) return x*x;   /* y is  2 */
+        if(hy==0x40400000) return x*x*x; /* y is  3 */
+        if(hy==0x40800000) {             /* y is  4 */
+            u = x*x;
+            return u*u;
+        }
+        if(hy==0x3f000000) {             /* y is  0.5 */
+           if(hx>=0)   /* x >= +0 */
+                return __ieee754_sqrtf(x);
+       }
+
+       ax   = fabsf(x);
+    /* special value of x */
+       if(ix==0x7f800000||ix==0||ix==0x3f800000){
+           z = ax;                     /*x is +-0,+-inf,+-1*/
+           if(hy<0) z = one/z; /* z = (1/|x|) */
+           if(hx<0) {
+               if(((ix-0x3f800000)|yisint)==0) {
+                   z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+               } else if(yisint==1)
+                   z = -z;             /* (x<0)**odd = -(|x|**odd) */
+           }
+           return z;
+       }
+
+       n = ((u_int32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+       if((n|yisint)==0) return (x-x)/(x-x);
+
+       sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+       if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+       if(iy>0x4d000000) { /* if |y| > 2**27 */
+       /* over/underflow if x is not close to one */
+           if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny;
+           if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny;
+       /* now |1-x| is tiny <= 2**-20, suffice to compute
+          log(x) by x-x^2/2+x^3/3-x^4/4 */
+           t = ax-1;           /* t has 20 trailing zeros */
+           w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25));
+           u = ivln2_h*t;      /* ivln2_h has 16 sig. bits */
+           v = t*ivln2_l-w*ivln2;
+           t1 = u+v;
+           GET_FLOAT_WORD(is,t1);
+           SET_FLOAT_WORD(t1,is&0xfffff000);
+           t2 = v-(t1-u);
+       } else {
+           float s2,s_h,s_l,t_h,t_l;
+           n = 0;
+       /* take care subnormal number */
+           if(ix<0x00800000)
+               {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); }
+           n  += ((ix)>>23)-0x7f;
+           j  = ix&0x007fffff;
+       /* determine interval */
+           ix = j|0x3f800000;          /* normalize ix */
+           if(j<=0x1cc471) k=0;        /* |x|<sqrt(3/2) */
+           else if(j<0x5db3d7) k=1;    /* |x|<sqrt(3)   */
+           else {k=0;n+=1;ix -= 0x00800000;}
+           SET_FLOAT_WORD(ax,ix);
+
+       /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+           u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+           v = one/(ax+bp[k]);
+           s = u*v;
+           s_h = s;
+           GET_FLOAT_WORD(is,s_h);
+           SET_FLOAT_WORD(s_h,is&0xfffff000);
+       /* t_h=ax+bp[k] High */
+           is = ((ix>>1)&0xfffff000)|0x20000000;
+           SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21));
+           t_l = ax - (t_h-bp[k]);
+           s_l = v*((u-s_h*t_h)-s_h*t_l);
+       /* compute log(ax) */
+           s2 = s*s;
+           r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+           r += s_l*(s_h+s);
+           s2  = s_h*s_h;
+           t_h = (float)3.0+s2+r;
+           GET_FLOAT_WORD(is,t_h);
+           SET_FLOAT_WORD(t_h,is&0xfffff000);
+           t_l = r-((t_h-(float)3.0)-s2);
+       /* u+v = s*(1+...) */
+           u = s_h*t_h;
+           v = s_l*t_h+t_l*s;
+       /* 2/(3log2)*(s+...) */
+           p_h = u+v;
+           GET_FLOAT_WORD(is,p_h);
+           SET_FLOAT_WORD(p_h,is&0xfffff000);
+           p_l = v-(p_h-u);
+           z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+           z_l = cp_l*p_h+p_l*cp+dp_l[k];
+       /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+           t = (float)n;
+           t1 = (((z_h+z_l)+dp_h[k])+t);
+           GET_FLOAT_WORD(is,t1);
+           SET_FLOAT_WORD(t1,is&0xfffff000);
+           t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+       }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+       GET_FLOAT_WORD(is,y);
+       SET_FLOAT_WORD(y1,is&0xfffff000);
+       p_l = (y-y1)*t1+y*t2;
+       p_h = y1*t1;
+       z = p_l+p_h;
+       GET_FLOAT_WORD(j,z);
+       if (j>0x43000000)                               /* if z > 128 */
+           return sn*huge*huge;                        /* overflow */
+       else if (j==0x43000000) {                       /* if z == 128 */
+           if(p_l+ovt>z-p_h) return sn*huge*huge;      /* overflow */
+       }
+       else if ((j&0x7fffffff)>0x43160000)             /* z <= -150 */
+           return sn*tiny*tiny;                        /* underflow */
+       else if (j==0xc3160000){                        /* z == -150 */
+           if(p_l<=z-p_h) return sn*tiny*tiny;         /* underflow */
+       }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+       i = j&0x7fffffff;
+       k = (i>>23)-0x7f;
+       n = 0;
+       if(i>0x3f000000) {              /* if |z| > 0.5, set n = [z+0.5] */
+           n = j+(0x00800000>>(k+1));
+           k = ((n&0x7fffffff)>>23)-0x7f;      /* new k for n */
+           SET_FLOAT_WORD(t,n&~(0x007fffff>>k));
+           n = ((n&0x007fffff)|0x00800000)>>(23-k);
+           if(j<0) n = -n;
+           p_h -= t;
+       }
+       t = p_l+p_h;
+       GET_FLOAT_WORD(is,t);
+       SET_FLOAT_WORD(t,is&0xffff8000);
+       u = t*lg2_h;
+       v = (p_l-(t-p_h))*lg2+t*lg2_l;
+       z = u+v;
+       w = v-(z-u);
+       t  = z*z;
+       t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+       r  = (z*t1)/(t1-two)-(w+z*w);
+       z  = one-(r-z);
+       GET_FLOAT_WORD(j,z);
+       j += (n<<23);
+       if((j>>23)<=0) z = scalbnf(z,n);        /* subnormal output */
+       else SET_FLOAT_WORD(z,j);
+       return sn*z;
+}
diff --git a/src/e_rem_pio2.c b/src/e_rem_pio2.c
new file mode 100644 (file)
index 0000000..c09e38a
--- /dev/null
@@ -0,0 +1,183 @@
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ * Optimized by Bruce D. Evans.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_rem_pio2.c,v 1.22 2011/06/19 17:07:58 kargl Exp $");
+
+/* __ieee754_rem_pio2(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2()
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * invpio2:  53 bits of 2/pi
+ * pio2_1:   first  33 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 33 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  33 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+__inline int
+__ieee754_rem_pio2(double x, double *y)
+{
+       double z,w,t,r,fn;
+       double tx[3],ty[2];
+       int32_t e0,i,j,nx,n,ix,hx;
+       u_int32_t low;
+
+       GET_HIGH_WORD(hx,x);            /* high word of x */
+       ix = hx&0x7fffffff;
+#if 0 /* Must be handled in caller. */
+       if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */
+           {y[0] = x; y[1] = 0; return 0;}
+#endif
+       if (ix <= 0x400f6a7a) {         /* |x| ~<= 5pi/4 */
+           if ((ix & 0xfffff) == 0x921fb)  /* |x| ~= pi/2 or 2pi/2 */
+               goto medium;            /* cancellation -- use medium case */
+           if (ix <= 0x4002d97c) {     /* |x| ~<= 3pi/4 */
+               if (hx > 0) {
+                   z = x - pio2_1;     /* one round good to 85 bits */
+                   y[0] = z - pio2_1t;
+                   y[1] = (z-y[0])-pio2_1t;
+                   return 1;
+               } else {
+                   z = x + pio2_1;
+                   y[0] = z + pio2_1t;
+                   y[1] = (z-y[0])+pio2_1t;
+                   return -1;
+               }
+           } else {
+               if (hx > 0) {
+                   z = x - 2*pio2_1;
+                   y[0] = z - 2*pio2_1t;
+                   y[1] = (z-y[0])-2*pio2_1t;
+                   return 2;
+               } else {
+                   z = x + 2*pio2_1;
+                   y[0] = z + 2*pio2_1t;
+                   y[1] = (z-y[0])+2*pio2_1t;
+                   return -2;
+               }
+           }
+       }
+       if (ix <= 0x401c463b) {         /* |x| ~<= 9pi/4 */
+           if (ix <= 0x4015fdbc) {     /* |x| ~<= 7pi/4 */
+               if (ix == 0x4012d97c)   /* |x| ~= 3pi/2 */
+                   goto medium;
+               if (hx > 0) {
+                   z = x - 3*pio2_1;
+                   y[0] = z - 3*pio2_1t;
+                   y[1] = (z-y[0])-3*pio2_1t;
+                   return 3;
+               } else {
+                   z = x + 3*pio2_1;
+                   y[0] = z + 3*pio2_1t;
+                   y[1] = (z-y[0])+3*pio2_1t;
+                   return -3;
+               }
+           } else {
+               if (ix == 0x401921fb)   /* |x| ~= 4pi/2 */
+                   goto medium;
+               if (hx > 0) {
+                   z = x - 4*pio2_1;
+                   y[0] = z - 4*pio2_1t;
+                   y[1] = (z-y[0])-4*pio2_1t;
+                   return 4;
+               } else {
+                   z = x + 4*pio2_1;
+                   y[0] = z + 4*pio2_1t;
+                   y[1] = (z-y[0])+4*pio2_1t;
+                   return -4;
+               }
+           }
+       }
+       if(ix<0x413921fb) {     /* |x| ~< 2^20*(pi/2), medium size */
+medium:
+           /* Use a specialized rint() to get fn.  Assume round-to-nearest. */
+           STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52);
+           fn = fn-0x1.8p52;
+#ifdef HAVE_EFFICIENT_IRINT
+           n  = irint(fn);
+#else
+           n  = (int32_t)fn;
+#endif
+           r  = x-fn*pio2_1;
+           w  = fn*pio2_1t;    /* 1st round good to 85 bit */
+           {
+               u_int32_t high;
+               j  = ix>>20;
+               y[0] = r-w; 
+               GET_HIGH_WORD(high,y[0]);
+               i = j-((high>>20)&0x7ff);
+               if(i>16) {  /* 2nd iteration needed, good to 118 */
+                   t  = r;
+                   w  = fn*pio2_2;     
+                   r  = t-w;
+                   w  = fn*pio2_2t-((t-r)-w);  
+                   y[0] = r-w;
+                   GET_HIGH_WORD(high,y[0]);
+                   i = j-((high>>20)&0x7ff);
+                   if(i>49)  { /* 3rd iteration need, 151 bits acc */
+                       t  = r; /* will cover all possible cases */
+                       w  = fn*pio2_3; 
+                       r  = t-w;
+                       w  = fn*pio2_3t-((t-r)-w);      
+                       y[0] = r-w;
+                   }
+               }
+           }
+           y[1] = (r-y[0])-w;
+           return n;
+       }
+    /* 
+     * all other (large) arguments
+     */
+       if(ix>=0x7ff00000) {            /* x is inf or NaN */
+           y[0]=y[1]=x-x; return 0;
+       }
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+       GET_LOW_WORD(low,x);
+       e0      = (ix>>20)-1046;        /* e0 = ilogb(z)-23; */
+       INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low);
+       for(i=0;i<2;i++) {
+               tx[i] = (double)((int32_t)(z));
+               z     = (z-tx[i])*two24;
+       }
+       tx[2] = z;
+       nx = 3;
+       while(tx[nx-1]==zero) nx--;     /* skip zero term */
+       n  =  __kernel_rem_pio2(tx,ty,e0,nx,1);
+       if(hx<0) {y[0] = -ty[0]; y[1] = -ty[1]; return -n;}
+       y[0] = ty[0]; y[1] = ty[1]; return n;
+}
diff --git a/src/e_rem_pio2f.c b/src/e_rem_pio2f.c
new file mode 100644 (file)
index 0000000..9861bb9
--- /dev/null
@@ -0,0 +1,81 @@
+/* e_rem_pio2f.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_rem_pio2f.c,v 1.32 2009/06/03 08:16:34 ed Exp $");
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in *y
+ * use double precision for everything except passing x
+ * use __kernel_rem_pio2() for large x
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * invpio2:  53 bits of 2/pi
+ * pio2_1:   first  33 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ */
+
+static const double
+invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1  =  1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */
+pio2_1t =  1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */
+
+__inline int
+__ieee754_rem_pio2f(float x, double *y)
+{
+       double w,r,fn;
+       double tx[1],ty[1];
+       float z;
+       int32_t e0,n,ix,hx;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+    /* 33+53 bit pi is good enough for medium size */
+       if(ix<0x4dc90fdb) {             /* |x| ~< 2^28*(pi/2), medium size */
+           /* Use a specialized rint() to get fn.  Assume round-to-nearest. */
+           STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52);
+           fn = fn-0x1.8p52;
+#ifdef HAVE_EFFICIENT_IRINT
+           n  = irint(fn);
+#else
+           n  = (int32_t)fn;
+#endif
+           r  = x-fn*pio2_1;
+           w  = fn*pio2_1t;
+           *y = r-w;
+           return n;
+       }
+    /*
+     * all other (large) arguments
+     */
+       if(ix>=0x7f800000) {            /* x is inf or NaN */
+           *y=x-x; return 0;
+       }
+    /* set z = scalbn(|x|,ilogb(|x|)-23) */
+       e0 = (ix>>23)-150;              /* e0 = ilogb(|x|)-23; */
+       SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23)));
+       tx[0] = z;
+       n  =  __kernel_rem_pio2(tx,ty,e0,1,0);
+       if(hx<0) {*y = -ty[0]; return -n;}
+       *y = ty[0]; return n;
+}
diff --git a/src/e_remainder.c b/src/e_remainder.c
new file mode 100644 (file)
index 0000000..bc9d9bf
--- /dev/null
@@ -0,0 +1,79 @@
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainder.c,v 1.12 2008/03/30 20:47:42 das Exp $");
+
+/* __ieee754_remainder(x,p)
+ * Return :                  
+ *     returns  x REM p  =  x - [x/p]*p as if in infinite 
+ *     precise arithmetic, where [x/p] is the (infinite bit) 
+ *     integer nearest x/p (in half way case choose the even one).
+ * Method : 
+ *     Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double zero = 0.0;
+
+
+OLM_DLLEXPORT double
+__ieee754_remainder(double x, double p)
+{
+       int32_t hx,hp;
+       u_int32_t sx,lx,lp;
+       double p_half;
+
+       EXTRACT_WORDS(hx,lx,x);
+       EXTRACT_WORDS(hp,lp,p);
+       sx = hx&0x80000000;
+       hp &= 0x7fffffff;
+       hx &= 0x7fffffff;
+
+    /* purge off exception values */
+       if((hp|lp)==0) return (x*p)/(x*p);      /* p = 0 */
+       if((hx>=0x7ff00000)||                   /* x not finite */
+         ((hp>=0x7ff00000)&&                   /* p is NaN */
+         (((hp-0x7ff00000)|lp)!=0)))
+           return ((long double)x*p)/((long double)x*p);
+
+
+       if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p);  /* now x < 2p */
+       if (((hx-hp)|(lx-lp))==0) return zero*x;
+       x  = fabs(x);
+       p  = fabs(p);
+       if (hp<0x00200000) {
+           if(x+x>p) {
+               x-=p;
+               if(x+x>=p) x -= p;
+           }
+       } else {
+           p_half = 0.5*p;
+           if(x>p_half) {
+               x-=p;
+               if(x>=p_half) x -= p;
+           }
+       }
+       GET_HIGH_WORD(hx,x);
+       if ((hx&0x7fffffff)==0) hx = 0;
+       SET_HIGH_WORD(x,hx^sx);
+       return x;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(remainder, remainderl);
+#endif
diff --git a/src/e_remainderf.c b/src/e_remainderf.c
new file mode 100644 (file)
index 0000000..ac0d153
--- /dev/null
@@ -0,0 +1,66 @@
+/* e_remainderf.c -- float version of e_remainder.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainderf.c,v 1.8 2008/02/12 17:11:36 bde Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float zero = 0.0;
+
+
+OLM_DLLEXPORT float
+__ieee754_remainderf(float x, float p)
+{
+       int32_t hx,hp;
+       u_int32_t sx;
+       float p_half;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_FLOAT_WORD(hp,p);
+       sx = hx&0x80000000;
+       hp &= 0x7fffffff;
+       hx &= 0x7fffffff;
+
+    /* purge off exception values */
+       if(hp==0) return (x*p)/(x*p);           /* p = 0 */
+       if((hx>=0x7f800000)||                   /* x not finite */
+         ((hp>0x7f800000)))                    /* p is NaN */
+           return ((long double)x*p)/((long double)x*p);
+
+
+       if (hp<=0x7effffff) x = __ieee754_fmodf(x,p+p); /* now x < 2p */
+       if ((hx-hp)==0) return zero*x;
+       x  = fabsf(x);
+       p  = fabsf(p);
+       if (hp<0x01000000) {
+           if(x+x>p) {
+               x-=p;
+               if(x+x>=p) x -= p;
+           }
+       } else {
+           p_half = (float)0.5*p;
+           if(x>p_half) {
+               x-=p;
+               if(x>=p_half) x -= p;
+           }
+       }
+       GET_FLOAT_WORD(hx,x);
+       if ((hx&0x7fffffff)==0) hx = 0;
+       SET_FLOAT_WORD(x,hx^sx);
+       return x;
+}
diff --git a/src/e_remainderl.c b/src/e_remainderl.c
new file mode 100644 (file)
index 0000000..5f1ee61
--- /dev/null
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainderl.c,v 1.1 2008/03/30 20:47:42 das Exp $");
+
+#include <openlibm_math.h>
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+remainderl(long double x, long double y)
+{
+       int quo;
+
+       return (remquol(x, y, &quo));
+}
diff --git a/src/e_sinh.c b/src/e_sinh.c
new file mode 100644 (file)
index 0000000..e6ca6bc
--- /dev/null
@@ -0,0 +1,74 @@
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_sinh.c,v 1.11 2011/10/21 06:28:47 das Exp $");
+
+/* __ieee754_sinh(x)
+ * Method : 
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *     1. Replace x by |x| (sinh(-x) = -sinh(x)). 
+ *     2. 
+ *                                                 E + E/(E+1)
+ *         0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
+ *                                                     2
+ *
+ *         22       <= x <= lnovft :  sinh(x) := exp(x)/2 
+ *         lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
+ *         ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ *     sinh(x) is |x| if x is +INF, -INF, or NaN.
+ *     only sinh(0)=0 is exact for finite x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0, shuge = 1.0e307;
+
+OLM_DLLEXPORT double
+__ieee754_sinh(double x)
+{
+       double t,h;
+       int32_t ix,jx;
+
+    /* High word of |x|. */
+       GET_HIGH_WORD(jx,x);
+       ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7ff00000) return x+x;  
+
+       h = 0.5;
+       if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+       if (ix < 0x40360000) {          /* |x|<22 */
+           if (ix<0x3e300000)          /* |x|<2**-28 */
+               if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+           t = expm1(fabs(x));
+           if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+           return h*(t+t/(t+one));
+       }
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+       if (ix < 0x40862E42)  return h*__ieee754_exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+       if (ix<=0x408633CE)
+           return h*2.0*__ldexp_exp(fabs(x), -1);
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+       return x*shuge;
+}
diff --git a/src/e_sinhf.c b/src/e_sinhf.c
new file mode 100644 (file)
index 0000000..6e5e06d
--- /dev/null
@@ -0,0 +1,57 @@
+/* e_sinhf.c -- float version of e_sinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_sinhf.c,v 1.10 2011/10/21 06:28:47 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one = 1.0, shuge = 1.0e37;
+
+OLM_DLLEXPORT float
+__ieee754_sinhf(float x)
+{
+       float t,h;
+       int32_t ix,jx;
+
+       GET_FLOAT_WORD(jx,x);
+       ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7f800000) return x+x;
+
+       h = 0.5;
+       if (jx<0) h = -h;
+    /* |x| in [0,9], return sign(x)*0.5*(E+E/(E+1))) */
+       if (ix < 0x41100000) {          /* |x|<9 */
+           if (ix<0x39800000)          /* |x|<2**-12 */
+               if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+           t = expm1f(fabsf(x));
+           if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one));
+           return h*(t+t/(t+one));
+       }
+
+    /* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */
+       if (ix < 0x42b17217)  return h*__ieee754_expf(fabsf(x));
+
+    /* |x| in [logf(maxfloat), overflowthresold] */
+       if (ix<=0x42b2d4fc)
+           return h*2.0F*__ldexp_expf(fabsf(x), -1);
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+       return x*shuge;
+}
diff --git a/src/e_sqrt.c b/src/e_sqrt.c
new file mode 100644 (file)
index 0000000..01c7104
--- /dev/null
@@ -0,0 +1,451 @@
+
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_sqrt.c,v 1.11 2008/03/02 01:47:58 das Exp $");
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ *           ------------------------------------------
+ *          |  Use the hardware sqrt if you have one |
+ *           ------------------------------------------
+ * Method: 
+ *   Bit by bit method using integer arithmetic. (Slow, but portable) 
+ *   1. Normalization
+ *     Scale x to y in [1,4) with even powers of 2: 
+ *     find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
+ *             sqrt(x) = 2^k * sqrt(y)
+ *   2. Bit by bit computation
+ *     Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+ *          i                                                   0
+ *                                     i+1         2
+ *         s  = 2*q , and      y  =  2   * ( y - q  ).         (1)
+ *          i      i            i                 i
+ *                                                        
+ *     To compute q    from q , one checks whether 
+ *                 i+1       i                       
+ *
+ *                           -(i+1) 2
+ *                     (q + 2      ) <= y.                     (2)
+ *                               i
+ *                                                           -(i+1)
+ *     If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+ *                            i+1   i             i+1   i
+ *
+ *     With some algebric manipulation, it is not difficult to see
+ *     that (2) is equivalent to 
+ *                             -(i+1)
+ *                     s  +  2       <= y                      (3)
+ *                      i                i
+ *
+ *     The advantage of (3) is that s  and y  can be computed by 
+ *                                   i      i
+ *     the following recurrence formula:
+ *         if (3) is false
+ *
+ *         s     =  s  ,       y    = y   ;                    (4)
+ *          i+1      i          i+1    i
+ *
+ *         otherwise,
+ *                         -i                     -(i+1)
+ *         s     =  s  + 2  ,  y    = y  -  s  - 2             (5)
+ *           i+1      i          i+1    i     i
+ *                             
+ *     One may easily use induction to prove (4) and (5). 
+ *     Note. Since the left hand side of (3) contain only i+2 bits,
+ *           it does not necessary to do a full (53-bit) comparison 
+ *           in (3).
+ *   3. Final rounding
+ *     After generating the 53 bits result, we compute one more bit.
+ *     Together with the remainder, we can decide whether the
+ *     result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ *     (it will never equal to 1/2ulp).
+ *     The rounding mode can be detected by checking whether
+ *     huge + tiny is equal to huge, and whether huge - tiny is
+ *     equal to huge for some floating point number "huge" and "tiny".
+ *             
+ * Special cases:
+ *     sqrt(+-0) = +-0         ... exact
+ *     sqrt(inf) = inf
+ *     sqrt(-ve) = NaN         ... with invalid signal
+ *     sqrt(NaN) = NaN         ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double    one     = 1.0, tiny=1.0e-300;
+
+OLM_DLLEXPORT double
+__ieee754_sqrt(double x)
+{
+       double z;
+       int32_t sign = (int)0x80000000;
+       int32_t ix0,s0,q,m,t,i;
+       u_int32_t r,t1,s1,ix1,q1;
+
+       EXTRACT_WORDS(ix0,ix1,x);
+
+    /* take care of Inf and NaN */
+       if((ix0&0x7ff00000)==0x7ff00000) {                      
+           return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                          sqrt(-inf)=sNaN */
+       } 
+    /* take care of zero */
+       if(ix0<=0) {
+           if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+           else if(ix0<0)
+               return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+       }
+    /* normalize x */
+       m = (ix0>>20);
+       if(m==0) {                              /* subnormal x */
+           while(ix0==0) {
+               m -= 21;
+               ix0 |= (ix1>>11); ix1 <<= 21;
+           }
+           for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+           m -= i-1;
+           ix0 |= (ix1>>(32-i));
+           ix1 <<= i;
+       }
+       m -= 1023;      /* unbias exponent */
+       ix0 = (ix0&0x000fffff)|0x00100000;
+       if(m&1){        /* odd m, double x to make it even */
+           ix0 += ix0 + ((ix1&sign)>>31);
+           ix1 += ix1;
+       }
+       m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+       ix0 += ix0 + ((ix1&sign)>>31);
+       ix1 += ix1;
+       q = q1 = s0 = s1 = 0;   /* [q,q1] = sqrt(x) */
+       r = 0x00200000;         /* r = moving bit from right to left */
+
+       while(r!=0) {
+           t = s0+r; 
+           if(t<=ix0) { 
+               s0   = t+r; 
+               ix0 -= t; 
+               q   += r; 
+           } 
+           ix0 += ix0 + ((ix1&sign)>>31);
+           ix1 += ix1;
+           r>>=1;
+       }
+
+       r = sign;
+       while(r!=0) {
+           t1 = s1+r; 
+           t  = s0;
+           if((t<ix0)||((t==ix0)&&(t1<=ix1))) { 
+               s1  = t1+r;
+               if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+               ix0 -= t;
+               if (ix1 < t1) ix0 -= 1;
+               ix1 -= t1;
+               q1  += r;
+           }
+           ix0 += ix0 + ((ix1&sign)>>31);
+           ix1 += ix1;
+           r>>=1;
+       }
+
+    /* use floating add to find out rounding direction */
+       if((ix0|ix1)!=0) {
+           z = one-tiny; /* trigger inexact flag */
+           if (z>=one) {
+               z = one+tiny;
+               if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;}
+               else if (z>one) {
+                   if (q1==(u_int32_t)0xfffffffe) q+=1;
+                   q1+=2; 
+               } else
+                   q1 += (q1&1);
+           }
+       }
+       ix0 = (q>>1)+0x3fe00000;
+       ix1 =  q1>>1;
+       if ((q&1)==1) ix1 |= sign;
+       ix0 += (m <<20);
+       INSERT_WORDS(z,ix0,ix1);
+       return z;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(sqrt, sqrtl);
+#endif
+
+/*
+Other methods  (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan 
+and K.C. Ng, written in May, 1986)
+
+       Two algorithms are given here to implement sqrt(x) 
+       (IEEE double precision arithmetic) in software.
+       Both supply sqrt(x) correctly rounded. The first algorithm (in
+       Section A) uses newton iterations and involves four divisions.
+       The second one uses reciproot iterations to avoid division, but
+       requires more multiplications. Both algorithms need the ability
+       to chop results of arithmetic operations instead of round them, 
+       and the INEXACT flag to indicate when an arithmetic operation
+       is executed exactly with no roundoff error, all part of the 
+       standard (IEEE 754-1985). The ability to perform shift, add,
+       subtract and logical AND operations upon 32-bit words is needed
+       too, though not part of the standard.
+
+A.  sqrt(x) by Newton Iteration
+
+   (1) Initial approximation
+
+       Let x0 and x1 be the leading and the trailing 32-bit words of
+       a floating point number x (in IEEE double format) respectively 
+
+           1    11                  52                           ...widths
+          ------------------------------------------------------
+       x: |s|    e     |             f                         |
+          ------------------------------------------------------
+             msb    lsb  msb                                 lsb ...order
+
+            ------------------------        ------------------------
+       x0:  |s|   e    |    f1     |    x1: |          f2           |
+            ------------------------        ------------------------
+
+       By performing shifts and subtracts on x0 and x1 (both regarded
+       as integers), we obtain an 8-bit approximation of sqrt(x) as
+       follows.
+
+               k  := (x0>>1) + 0x1ff80000;
+               y0 := k - T1[31&(k>>15)].       ... y ~ sqrt(x) to 8 bits
+       Here k is a 32-bit integer and T1[] is an integer array containing
+       correction terms. Now magically the floating value of y (y's
+       leading 32-bit word is y0, the value of its trailing word is 0)
+       approximates sqrt(x) to almost 8-bit.
+
+       Value of T1:
+       static int T1[32]= {
+       0,      1024,   3062,   5746,   9193,   13348,  18162,  23592,
+       29598,  36145,  43202,  50740,  58733,  67158,  75992,  85215,
+       83599,  71378,  60428,  50647,  41945,  34246,  27478,  21581,
+       16499,  12183,  8588,   5674,   3403,   1742,   661,    130,};
+
+    (2)        Iterative refinement
+
+       Apply Heron's rule three times to y, we have y approximates 
+       sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+               y := (y+x/y)/2          ... almost 17 sig. bits
+               y := (y+x/y)/2          ... almost 35 sig. bits
+               y := y-(y-x/y)/2        ... within 1 ulp
+
+
+       Remark 1.
+           Another way to improve y to within 1 ulp is:
+
+               y := (y+x/y)            ... almost 17 sig. bits to 2*sqrt(x)
+               y := y - 0x00100006     ... almost 18 sig. bits to sqrt(x)
+
+                               2
+                           (x-y )*y
+               y := y + 2* ----------  ...within 1 ulp
+                              2
+                            3y  + x
+
+
+       This formula has one division fewer than the one above; however,
+       it requires more multiplications and additions. Also x must be
+       scaled in advance to avoid spurious overflow in evaluating the
+       expression 3y*y+x. Hence it is not recommended uless division
+       is slow. If division is very slow, then one should use the 
+       reciproot algorithm given in section B.
+
+    (3) Final adjustment
+
+       By twiddling y's last bit it is possible to force y to be 
+       correctly rounded according to the prevailing rounding mode
+       as follows. Let r and i be copies of the rounding mode and
+       inexact flag before entering the square root program. Also we
+       use the expression y+-ulp for the next representable floating
+       numbers (up and down) of y. Note that y+-ulp = either fixed
+       point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+       mode.
+
+               I := FALSE;     ... reset INEXACT flag I
+               R := RZ;        ... set rounding mode to round-toward-zero
+               z := x/y;       ... chopped quotient, possibly inexact
+               If(not I) then {        ... if the quotient is exact
+                   if(z=y) {
+                       I := i;  ... restore inexact flag
+                       R := r;  ... restore rounded mode
+                       return sqrt(x):=y.
+                   } else {
+                       z := z - ulp;   ... special rounding
+                   }
+               }
+               i := TRUE;              ... sqrt(x) is inexact
+               If (r=RN) then z=z+ulp  ... rounded-to-nearest
+               If (r=RP) then {        ... round-toward-+inf
+                   y = y+ulp; z=z+ulp;
+               }
+               y := y+z;               ... chopped sum
+               y0:=y0-0x00100000;      ... y := y/2 is correctly rounded.
+               I := i;                 ... restore inexact flag
+               R := r;                 ... restore rounded mode
+               return sqrt(x):=y.
+                   
+    (4)        Special cases
+
+       Square root of +inf, +-0, or NaN is itself;
+       Square root of a negative number is NaN with invalid signal.
+
+
+B.  sqrt(x) by Reciproot Iteration
+
+   (1) Initial approximation
+
+       Let x0 and x1 be the leading and the trailing 32-bit words of
+       a floating point number x (in IEEE double format) respectively
+       (see section A). By performing shifs and subtracts on x0 and y0,
+       we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+           k := 0x5fe80000 - (x0>>1);
+           y0:= k - T2[63&(k>>14)].    ... y ~ 1/sqrt(x) to 7.8 bits
+
+       Here k is a 32-bit integer and T2[] is an integer array 
+       containing correction terms. Now magically the floating
+       value of y (y's leading 32-bit word is y0, the value of
+       its trailing word y1 is set to zero) approximates 1/sqrt(x)
+       to almost 7.8-bit.
+
+       Value of T2:
+       static int T2[64]= {
+       0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+       0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+       0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+       0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+       0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+       0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+       0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+       0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+    (2)        Iterative refinement
+
+       Apply Reciproot iteration three times to y and multiply the
+       result by x to get an approximation z that matches sqrt(x)
+       to about 1 ulp. To be exact, we will have 
+               -1ulp < sqrt(x)-z<1.0625ulp.
+       
+       ... set rounding mode to Round-to-nearest
+          y := y*(1.5-0.5*x*y*y)       ... almost 15 sig. bits to 1/sqrt(x)
+          y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+       ... special arrangement for better accuracy
+          z := x*y                     ... 29 bits to sqrt(x), with z*y<1
+          z := z + 0.5*z*(1-z*y)       ... about 1 ulp to sqrt(x)
+
+       Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+       (a) the term z*y in the final iteration is always less than 1; 
+       (b) the error in the final result is biased upward so that
+               -1 ulp < sqrt(x) - z < 1.0625 ulp
+           instead of |sqrt(x)-z|<1.03125ulp.
+
+    (3)        Final adjustment
+
+       By twiddling y's last bit it is possible to force y to be 
+       correctly rounded according to the prevailing rounding mode
+       as follows. Let r and i be copies of the rounding mode and
+       inexact flag before entering the square root program. Also we
+       use the expression y+-ulp for the next representable floating
+       numbers (up and down) of y. Note that y+-ulp = either fixed
+       point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+       mode.
+
+       R := RZ;                ... set rounding mode to round-toward-zero
+       switch(r) {
+           case RN:            ... round-to-nearest
+              if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+              if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+              break;
+           case RZ:case RM:    ... round-to-zero or round-to--inf
+              R:=RP;           ... reset rounding mod to round-to-+inf
+              if(x<z*z ... rounded up) z = z - ulp; else
+              if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+              break;
+           case RP:            ... round-to-+inf
+              if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+              if(x>z*z ...chopped) z = z+ulp;
+              break;
+       }
+
+       Remark 3. The above comparisons can be done in fixed point. For
+       example, to compare x and w=z*z chopped, it suffices to compare
+       x1 and w1 (the trailing parts of x and w), regarding them as
+       two's complement integers.
+
+       ...Is z an exact square root?
+       To determine whether z is an exact square root of x, let z1 be the
+       trailing part of z, and also let x0 and x1 be the leading and
+       trailing parts of x.
+
+       If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+           I := 1;             ... Raise Inexact flag: z is not exact
+       else {
+           j := 1 - [(x0>>20)&1]       ... j = logb(x) mod 2
+           k := z1 >> 26;              ... get z's 25-th and 26-th 
+                                           fraction bits
+           I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+       }
+       R:= r           ... restore rounded mode
+       return sqrt(x):=z.
+
+       If multiplication is cheaper then the foregoing red tape, the 
+       Inexact flag can be evaluated by
+
+           I := i;
+           I := (z*z!=x) or I.
+
+       Note that z*z can overwrite I; this value must be sensed if it is 
+       True.
+
+       Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+       zero.
+
+                   --------------------
+               z1: |        f2        | 
+                   --------------------
+               bit 31             bit 0
+
+       Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+       or even of logb(x) have the following relations:
+
+       -------------------------------------------------
+       bit 27,26 of z1         bit 1,0 of x1   logb(x)
+       -------------------------------------------------
+       00                      00              odd and even
+       01                      01              even
+       10                      10              odd
+       10                      00              even
+       11                      01              even
+       -------------------------------------------------
+
+    (4)        Special cases (see (4) of Section A).   
+ */
diff --git a/src/e_sqrtf.c b/src/e_sqrtf.c
new file mode 100644 (file)
index 0000000..2aeaa9f
--- /dev/null
@@ -0,0 +1,86 @@
+/* e_sqrtf.c -- float version of e_sqrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float     one     = 1.0, tiny=1.0e-30;
+
+OLM_DLLEXPORT float
+__ieee754_sqrtf(float x)
+{
+       float z;
+       int32_t sign = (int)0x80000000;
+       int32_t ix,s,q,m,t,i;
+       u_int32_t r;
+
+       GET_FLOAT_WORD(ix,x);
+
+    /* take care of Inf and NaN */
+       if((ix&0x7f800000)==0x7f800000) {
+           return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                          sqrt(-inf)=sNaN */
+       }
+    /* take care of zero */
+       if(ix<=0) {
+           if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
+           else if(ix<0)
+               return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+       }
+    /* normalize x */
+       m = (ix>>23);
+       if(m==0) {                              /* subnormal x */
+           for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
+           m -= i-1;
+       }
+       m -= 127;       /* unbias exponent */
+       ix = (ix&0x007fffff)|0x00800000;
+       if(m&1) /* odd m, double x to make it even */
+           ix += ix;
+       m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+       ix += ix;
+       q = s = 0;              /* q = sqrt(x) */
+       r = 0x01000000;         /* r = moving bit from right to left */
+
+       while(r!=0) {
+           t = s+r;
+           if(t<=ix) {
+               s    = t+r;
+               ix  -= t;
+               q   += r;
+           }
+           ix += ix;
+           r>>=1;
+       }
+
+    /* use floating add to find out rounding direction */
+       if(ix!=0) {
+           z = one-tiny; /* trigger inexact flag */
+           if (z>=one) {
+               z = one+tiny;
+               if (z>one)
+                   q += 2;
+               else
+                   q += (q&1);
+           }
+       }
+       ix = (q>>1)+0x3f000000;
+       ix += (m <<23);
+       SET_FLOAT_WORD(z,ix);
+       return z;
+}
diff --git a/src/e_sqrtl.c b/src/e_sqrtl.c
new file mode 100644 (file)
index 0000000..a073bf9
--- /dev/null
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2007 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/e_sqrtl.c,v 1.1 2008/03/02 01:47:58 das Exp $");
+
+#include <float.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+/* Return (x + ulp) for normal positive x. Assumes no overflow. */
+static inline long double
+inc(long double x)
+{
+       union IEEEl2bits u;
+
+       u.e = x;
+       if (++u.bits.manl == 0) {
+               if (++u.bits.manh == 0) {
+                       u.bits.exp++;
+                       u.bits.manh |= LDBL_NBIT;
+               }
+       }
+       return (u.e);
+}
+
+/* Return (x - ulp) for normal positive x. Assumes no underflow. */
+static inline long double
+dec(long double x)
+{
+       union IEEEl2bits u;
+
+       u.e = x;
+       if (u.bits.manl-- == 0) {
+               if (u.bits.manh-- == LDBL_NBIT) {
+                       u.bits.exp--;
+                       u.bits.manh |= LDBL_NBIT;
+               }
+       }
+       return (u.e);
+}
+
+#ifndef __GNUC__
+#pragma STDC FENV_ACCESS ON
+#endif
+
+/*
+ * This is slow, but simple and portable. You should use hardware sqrt
+ * if possible.
+ */
+
+OLM_DLLEXPORT long double
+sqrtl(long double x)
+{
+       union IEEEl2bits u;
+       int k, r;
+       long double lo, xn;
+       fenv_t env;
+
+       u.e = x;
+
+       /* If x = NaN, then sqrt(x) = NaN. */
+       /* If x = Inf, then sqrt(x) = Inf. */
+       /* If x = -Inf, then sqrt(x) = NaN. */
+       if (u.bits.exp == LDBL_MAX_EXP * 2 - 1)
+               return (x * x + x);
+
+       /* If x = +-0, then sqrt(x) = +-0. */
+       if ((u.bits.manh | u.bits.manl | u.bits.exp) == 0)
+               return (x);
+
+       /* If x < 0, then raise invalid and return NaN */
+       if (u.bits.sign)
+               return ((x - x) / (x - x));
+
+       feholdexcept(&env);
+
+       if (u.bits.exp == 0) {
+               /* Adjust subnormal numbers. */
+               u.e *= 0x1.0p514;
+               k = -514;
+       } else {
+               k = 0;
+       }
+       /*
+        * u.e is a normal number, so break it into u.e = e*2^n where
+        * u.e = (2*e)*2^2k for odd n and u.e = (4*e)*2^2k for even n.
+        */
+       if ((u.bits.exp - 0x3ffe) & 1) {        /* n is odd.     */
+               k += u.bits.exp - 0x3fff;       /* 2k = n - 1.   */
+               u.bits.exp = 0x3fff;            /* u.e in [1,2). */
+       } else {
+               k += u.bits.exp - 0x4000;       /* 2k = n - 2.   */
+               u.bits.exp = 0x4000;            /* u.e in [2,4). */
+       }
+
+       /*
+        * Newton's iteration.
+        * Split u.e into a high and low part to achieve additional precision.
+        */
+       xn = sqrt(u.e);                 /* 53-bit estimate of sqrtl(x). */
+#if LDBL_MANT_DIG > 100
+       xn = (xn + (u.e / xn)) * 0.5;   /* 106-bit estimate. */
+#endif
+       lo = u.e;
+       u.bits.manl = 0;                /* Zero out lower bits. */
+       lo = (lo - u.e) / xn;           /* Low bits divided by xn. */
+       xn = xn + (u.e / xn);           /* High portion of estimate. */
+       u.e = xn + lo;                  /* Combine everything. */
+       u.bits.exp += (k >> 1) - 1;
+
+       feclearexcept(FE_INEXACT);
+       r = fegetround();
+       fesetround(FE_TOWARDZERO);      /* Set to round-toward-zero. */
+       xn = x / u.e;                   /* Chopped quotient (inexact?). */
+
+       if (!fetestexcept(FE_INEXACT)) { /* Quotient is exact. */
+               if (xn == u.e) {
+                       fesetenv(&env);
+                       return (u.e);
+               }
+               /* Round correctly for inputs like x = y**2 - ulp. */
+               xn = dec(xn);           /* xn = xn - ulp. */
+       }
+
+       if (r == FE_TONEAREST) {
+               xn = inc(xn);           /* xn = xn + ulp. */
+       } else if (r == FE_UPWARD) {
+               u.e = inc(u.e);         /* u.e = u.e + ulp. */
+               xn = inc(xn);           /* xn  = xn + ulp. */
+       }
+       u.e = u.e + xn;                         /* Chopped sum. */
+       feupdateenv(&env);      /* Restore env and raise inexact */
+       u.bits.exp--;
+       return (u.e);
+}
diff --git a/src/fpmath.h b/src/fpmath.h
new file mode 100644 (file)
index 0000000..763def7
--- /dev/null
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+ * Copyright (c) 2002 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.
+ *
+ * $FreeBSD: src/lib/libc/include/fpmath.h,v 1.4 2008/12/23 22:20:59 marcel Exp $
+ */
+#ifndef _FPMATH_H_
+#define _FPMATH_H_
+
+#if defined(__aarch64__)
+#include "aarch64_fpmath.h"
+#elif defined(__i386__) || defined(__x86_64__)
+#ifdef __LP64__
+#include "amd64_fpmath.h"
+#else 
+#include "i386_fpmath.h"
+#endif
+#elif defined(__powerpc__)
+#include "powerpc_fpmath.h"
+#elif defined(__mips__)
+#include "mips_fpmath.h"
+#endif
+
+/* Definitions provided directly by GCC and Clang. */
+#if !(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__))
+
+#if defined(__GLIBC__)
+
+#include <features.h>
+#include <endian.h>
+#define __ORDER_LITTLE_ENDIAN__  __LITTLE_ENDIAN
+#define __ORDER_BIG_ENDIAN__     __BIG_ENDIAN
+#define __BYTE_ORDER__           __BYTE_ORDER
+
+#elif defined(__APPLE__)
+
+#include <machine/endian.h>
+#define __ORDER_LITTLE_ENDIAN__  LITTLE_ENDIAN
+#define __ORDER_BIG_ENDIAN__     BIG_ENDIAN
+#define __BYTE_ORDER__           BYTE_ORDER
+
+#elif defined(_WIN32)
+
+#define __ORDER_LITTLE_ENDIAN__  1234
+#define __ORDER_BIG_ENDIAN__     4321
+#define __BYTE_ORDER__           __ORDER_LITTLE_ENDIAN__
+
+#endif
+
+#endif /* __BYTE_ORDER__, __ORDER_LITTLE_ENDIAN__ and __ORDER_BIG_ENDIAN__ */
+
+#ifndef __FLOAT_WORD_ORDER__
+#define __FLOAT_WORD_ORDER__     __BYTE_ORDER__
+#endif
+
+union IEEEf2bits {
+       float   f;
+       struct {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+               unsigned int    man     :23;
+               unsigned int    exp     :8;
+               unsigned int    sign    :1;
+#else /* _BIG_ENDIAN */
+               unsigned int    sign    :1;
+               unsigned int    exp     :8;
+               unsigned int    man     :23;
+#endif
+       } bits;
+};
+
+#define        DBL_MANH_SIZE   20
+#define        DBL_MANL_SIZE   32
+
+union IEEEd2bits {
+       double  d;
+       struct {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
+               unsigned int    manl    :32;
+#endif
+               unsigned int    manh    :20;
+               unsigned int    exp     :11;
+               unsigned int    sign    :1;
+#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
+               unsigned int    manl    :32;
+#endif
+#else /* _BIG_ENDIAN */
+               unsigned int    sign    :1;
+               unsigned int    exp     :11;
+               unsigned int    manh    :20;
+               unsigned int    manl    :32;
+#endif
+       } bits;
+};
+
+#endif
diff --git a/src/i386_fpmath.h b/src/i386_fpmath.h
new file mode 100644 (file)
index 0000000..455631c
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2002, 2003 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.
+ *
+ * $FreeBSD: src/lib/libc/i386/_fpmath.h,v 1.6 2008/01/17 16:39:06 bde Exp $
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+               unsigned int    manl    :32;
+               unsigned int    manh    :32;
+               unsigned int    exp     :15;
+               unsigned int    sign    :1;
+               unsigned int    junk    :16;
+       } bits;
+       struct {
+               unsigned long long man  :64;
+               unsigned int    expsign :16;
+               unsigned int    junk    :16;
+       } xbits;
+};
+
+#define        LDBL_NBIT       0x80000000
+#define        mask_nbit_l(u)  ((u).bits.manh &= ~LDBL_NBIT)
+
+#define        LDBL_MANH_SIZE  32
+#define        LDBL_MANL_SIZE  32
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)(u).bits.manh;               \
+} while (0)
diff --git a/src/k_cos.c b/src/k_cos.c
new file mode 100644 (file)
index 0000000..f3054ef
--- /dev/null
@@ -0,0 +1,80 @@
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_cos.c,v 1.12 2008/02/19 12:54:14 bde Exp $");
+
+/*
+ * __kernel_cos( x,  y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x. 
+ *
+ * Algorithm
+ *     1. Since cos(-x) = cos(x), we need only to consider positive x.
+ *     2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ *     3. cos(x) is approximated by a polynomial of degree 14 on
+ *        [0,pi/4]
+ *                                      4            14
+ *             cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ *        where the remez error is
+ *     
+ *     |              2     4     6     8     10    12     14 |     -58
+ *     |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+ *     |                                                      | 
+ * 
+ *                    4     6     8     10    12     14 
+ *     4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+ *            cos(x) ~ 1 - x*x/2 + r
+ *        since cos(x+y) ~ cos(x) - sin(x)*y 
+ *                       ~ cos(x) - x*y,
+ *        a correction term is necessary in cos(x) and hence
+ *             cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ *        For better accuracy, rearrange to
+ *             cos(x+y) ~ w + (tmp + (r-x*y))
+ *        where w = 1 - x*x/2 and tmp is a tiny correction term
+ *        (1 - x*x/2 == w + tmp exactly in infinite precision).
+ *        The exactness of w + tmp in infinite precision depends on w
+ *        and tmp having the same precision as x.  If they have extra
+ *        precision due to compiler bugs, then the extra precision is
+ *        only good provided it is retained in all terms of the final
+ *        expression for cos().  Retention happens in all cases tested
+ *        under FreeBSD, so don't pessimize things by forcibly clipping
+ *        any extra precision in w.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+OLM_DLLEXPORT double
+__kernel_cos(double x, double y)
+{
+       double hz,z,r,w;
+
+       z  = x*x;
+       w  = z*z;
+       r  = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
+       hz = 0.5*z;
+       w  = one-hz;
+       return w + (((one-w)-hz) + (z*r-x*y));
+}
diff --git a/src/k_cosf.c b/src/k_cosf.c
new file mode 100644 (file)
index 0000000..6774db4
--- /dev/null
@@ -0,0 +1,48 @@
+/* k_cosf.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_COSDF
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_cosf.c,v 1.18 2009/06/03 08:16:34 ed Exp $");
+#endif
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */
+static const double
+one =  1.0,
+C0  = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */
+C1  =  0x155553e1053a42.0p-57, /*  0.0416666233237390631894 */
+C2  = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */
+C3  =  0x199342e0ee5069.0p-68; /*  0.0000243904487962774090654 */
+
+#ifndef INLINE_KERNEL_COSDF
+extern
+#endif
+//__inline float
+OLM_DLLEXPORT float
+__kernel_cosdf(double x)
+{
+       double r, w, z;
+
+       /* Try to optimize for parallel evaluation as in k_tanf.c. */
+       z = x*x;
+       w = z*z;
+       r = C2+z*C3;
+       return ((one+z*C0) + w*C1) + (w*z)*r;
+}
diff --git a/src/k_exp.c b/src/k_exp.c
new file mode 100644 (file)
index 0000000..4739e20
--- /dev/null
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_exp.c,v 1.1 2011/10/21 06:27:56 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const u_int32_t k = 1799;               /* constant for reduction */
+static const double kln2 =  1246.97177782734161156;    /* k * ln2 */
+
+/*
+ * Compute exp(x), scaled to avoid spurious overflow.  An exponent is
+ * returned separately in 'expt'.
+ *
+ * Input:  ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91
+ * Output: 2**1023 <= y < 2**1024
+ */
+static double
+__frexp_exp(double x, int *expt)
+{
+       double exp_x;
+       u_int32_t hx;
+
+       /*
+        * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to
+        * minimize |exp(kln2) - 2**k|.  We also scale the exponent of
+        * exp_x to MAX_EXP so that the result can be multiplied by
+        * a tiny number without losing accuracy due to denormalization.
+        */
+       exp_x = exp(x - kln2);
+       GET_HIGH_WORD(hx, exp_x);
+       *expt = (hx >> 20) - (0x3ff + 1023) + k;
+       SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20));
+       return (exp_x);
+}
+
+/*
+ * __ldexp_exp(x, expt) and __ldexp_cexp(x, expt) compute exp(x) * 2**expt.
+ * They are intended for large arguments (real part >= ln(DBL_MAX))
+ * where care is needed to avoid overflow.
+ *
+ * The present implementation is narrowly tailored for our hyperbolic and
+ * exponential functions.  We assume expt is small (0 or -1), and the caller
+ * has filtered out very large x, for which overflow would be inevitable.
+ */
+
+OLM_DLLEXPORT double
+__ldexp_exp(double x, int expt)
+{
+       double exp_x, scale;
+       int ex_expt;
+
+       exp_x = __frexp_exp(x, &ex_expt);
+       expt += ex_expt;
+       INSERT_WORDS(scale, (0x3ff + expt) << 20, 0);
+       return (exp_x * scale);
+}
+
+OLM_DLLEXPORT double complex
+__ldexp_cexp(double complex z, int expt)
+{
+       double x, y, exp_x, scale1, scale2;
+       int ex_expt, half_expt;
+
+       x = creal(z);
+       y = cimag(z);
+       exp_x = __frexp_exp(x, &ex_expt);
+       expt += ex_expt;
+
+       /*
+        * Arrange so that scale1 * scale2 == 2**expt.  We use this to
+        * compensate for scalbn being horrendously slow.
+        */
+       half_expt = expt / 2;
+       INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0);
+       half_expt = expt - half_expt;
+       INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0);
+
+       return (CMPLX(cos(y) * exp_x * scale1 * scale2,
+           sin(y) * exp_x * scale1 * scale2));
+}
diff --git a/src/k_expf.c b/src/k_expf.c
new file mode 100644 (file)
index 0000000..bbf094c
--- /dev/null
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_expf.c,v 1.1 2011/10/21 06:27:56 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const u_int32_t k = 235;                        /* constant for reduction */
+static const float kln2 =  162.88958740F;      /* k * ln2 */
+
+/*
+ * See k_exp.c for details.
+ *
+ * Input:  ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7
+ * Output: 2**127 <= y < 2**128
+ */
+static float
+__frexp_expf(float x, int *expt)
+{
+       double exp_x;
+       u_int32_t hx;
+
+       exp_x = expf(x - kln2);
+       GET_FLOAT_WORD(hx, exp_x);
+       *expt = (hx >> 23) - (0x7f + 127) + k;
+       SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23));
+       return (exp_x);
+}
+
+OLM_DLLEXPORT float
+__ldexp_expf(float x, int expt)
+{
+       float exp_x, scale;
+       int ex_expt;
+
+       exp_x = __frexp_expf(x, &ex_expt);
+       expt += ex_expt;
+       SET_FLOAT_WORD(scale, (0x7f + expt) << 23);
+       return (exp_x * scale);
+}
+
+OLM_DLLEXPORT float complex
+__ldexp_cexpf(float complex z, int expt)
+{
+       float x, y, exp_x, scale1, scale2;
+       int ex_expt, half_expt;
+
+       x = crealf(z);
+       y = cimagf(z);
+       exp_x = __frexp_expf(x, &ex_expt);
+       expt += ex_expt;
+
+       half_expt = expt / 2;
+       SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23);
+       half_expt = expt - half_expt;
+       SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23);
+
+       return (CMPLXF(cosf(y) * exp_x * scale1 * scale2,
+           sinf(y) * exp_x * scale1 * scale2));
+}
diff --git a/src/k_log.h b/src/k_log.h
new file mode 100644 (file)
index 0000000..a0943c4
--- /dev/null
@@ -0,0 +1,100 @@
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_log.h,v 1.2 2011/10/15 05:23:28 das Exp $");
+
+/*
+ * k_log1p(f):
+ * Return log(1+f) - f for 1+f in ~[sqrt(2)/2, sqrt(2)].
+ *
+ * The following describes the overall strategy for computing
+ * logarithms in base e.  The argument reduction and adding the final
+ * term of the polynomial are done by the caller for increased accuracy
+ * when different bases are used.
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *                     x = 2^k * (1+f), 
+ *        where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *   2. Approximation of log(1+f).
+ *     Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *              = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *              = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ *     a polynomial of degree 14 to approximate R The maximum error 
+ *     of this polynomial approximation is bounded by 2**-58.45. In
+ *     other words,
+ *                     2      4      6      8      10      12      14
+ *         R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
+ *     (the values of Lg1 to Lg7 are listed in the program)
+ *     and
+ *         |      2          14          |     -58.45
+ *         | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
+ *         |                             |
+ *     Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *     In order to guarantee error in log below 1ulp, we compute log
+ *     by
+ *             log(1+f) = f - s*(f - R)        (if f is not too large)
+ *             log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
+ *     
+ *     3. Finally,  log(x) = k*ln2 + log(1+f).  
+ *                         = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *        Here ln2 is split into two floating point number: 
+ *                     ln2_hi + ln2_lo,
+ *        where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *     log(x) is NaN with signal if x < 0 (including -INF) ; 
+ *     log(+INF) is +INF; log(0) is -INF with signal;
+ *     log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *     according to an error analysis, the error is always less than
+ *     1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+static const double
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+/*
+ * We always inline k_log1p(), since doing so produces a
+ * substantial performance improvement (~40% on amd64).
+ */
+static inline double
+k_log1p(double f)
+{
+       double hfsq,s,z,R,w,t1,t2;
+
+       s = f/(2.0+f);
+       z = s*s;
+       w = z*z;
+       t1= w*(Lg2+w*(Lg4+w*Lg6));
+       t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+       R = t2+t1;
+       hfsq=0.5*f*f;
+       return s*(hfsq+R);
+}
diff --git a/src/k_logf.h b/src/k_logf.h
new file mode 100644 (file)
index 0000000..1b665ae
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_logf.h,v 1.3 2011/10/15 05:23:28 das Exp $");
+
+/*
+ * Float version of k_log.h.  See the latter for most comments.
+ */
+
+static const float
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 =      0xaaaaaa.0p-24,     /* 0.66666662693 */
+Lg2 =      0xccce13.0p-25,     /* 0.40000972152 */
+Lg3 =      0x91e9ee.0p-25,     /* 0.28498786688 */
+Lg4 =      0xf89e26.0p-26;     /* 0.24279078841 */
+
+static inline float
+k_log1pf(float f)
+{
+       float hfsq,s,z,R,w,t1,t2;
+
+       s = f/((float)2.0+f);
+       z = s*s;
+       w = z*z;
+       t1= w*(Lg2+w*Lg4);
+       t2= z*(Lg1+w*Lg3);
+       R = t2+t1;
+       hfsq=(float)0.5*f*f;
+       return s*(hfsq+R);
+}
diff --git a/src/k_rem_pio2.c b/src/k_rem_pio2.c
new file mode 100644 (file)
index 0000000..9555d3a
--- /dev/null
@@ -0,0 +1,444 @@
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_rem_pio2.c,v 1.11 2008/02/25 11:43:20 bde Exp $");
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec)
+ * double x[],y[]; int e0,nx,prec;
+ * 
+ * __kernel_rem_pio2 return the last three digits of N with 
+ *             y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of 
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ *     x[]     The input value (must be positive) is broken into nx 
+ *             pieces of 24-bit integers in double precision format.
+ *             x[i] will be the i-th 24 bit of x. The scaled exponent 
+ *             of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 
+ *             match x's up to 24 bits.
+ *
+ *             Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ *                     e0 = ilogb(z)-23
+ *                     z  = scalbn(z,-e0)
+ *             for i = 0,1,2
+ *                     x[i] = floor(z)
+ *                     z    = (z-x[i])*2**24
+ *
+ *
+ *     y[]     ouput result in an array of double precision numbers.
+ *             The dimension of y[] is:
+ *                     24-bit  precision       1
+ *                     53-bit  precision       2
+ *                     64-bit  precision       2
+ *                     113-bit precision       3
+ *             The actual value is the sum of them. Thus for 113-bit
+ *             precison, one may have to do something like:
+ *
+ *             long double t,w,r_head, r_tail;
+ *             t = (long double)y[2] + (long double)y[1];
+ *             w = (long double)y[0];
+ *             r_head = t+w;
+ *             r_tail = w - (r_head - t);
+ *
+ *     e0      The exponent of x[0]. Must be <= 16360 or you need to
+ *              expand the ipio2 table.
+ *
+ *     nx      dimension of x[]
+ *
+ *     prec    an integer indicating the precision:
+ *                     0       24  bits (single)
+ *                     1       53  bits (double)
+ *                     2       64  bits (extended)
+ *                     3       113 bits (quad)
+ *
+ * External function:
+ *     double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ *     jk      jk+1 is the initial number of terms of ipio2[] needed
+ *             in the computation. The minimum and recommended value
+ *             for jk is 3,4,4,6 for single, double, extended, and quad.
+ *             jk+1 must be 2 larger than you might expect so that our
+ *             recomputation test works. (Up to 24 bits in the integer
+ *             part (the 24 bits of it that we compute) and 23 bits in
+ *             the fraction part may be lost to cancelation before we
+ *             recompute.)
+ *
+ *     jz      local integer variable indicating the number of 
+ *             terms of ipio2[] used. 
+ *
+ *     jx      nx - 1
+ *
+ *     jv      index for pointing to the suitable ipio2[] for the
+ *             computation. In general, we want
+ *                     ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ *             is an integer. Thus
+ *                     e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ *             Hence jv = max(0,(e0-3)/24).
+ *
+ *     jp      jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ *     q[]     double array with integral value, representing the
+ *             24-bits chunk of the product of x and 2/pi.
+ *
+ *     q0      the corresponding exponent of q[0]. Note that the
+ *             exponent for q[i] would be q0-24*i.
+ *
+ *     PIo2[]  double precision array, obtained by cutting pi/2
+ *             into 24 bits chunks. 
+ *
+ *     f[]     ipio2[] in floating point 
+ *
+ *     iq[]    integer array by breaking up q[] in 24-bits chunk.
+ *
+ *     fq[]    final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ *     ih      integer. If >0 it indicates q[] is >= 0.5, hence
+ *             it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const int init_jk[] = {3,4,4,6}; /* initial value for jk */
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ *
+ *             integer array, contains the (24*i)-th to (24*i+23)-th 
+ *             bit of 2/pi after binary point. The corresponding 
+ *             floating value is
+ *
+ *                     ipio2[i] * 2^(-24(i+1)).
+ *
+ * NB: This table must have at least (e0-3)/24 + jk terms.
+ *     For quad precision (e0 <= 16360, jk = 6), this is 686.
+ */
+static const int32_t ipio2[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 
+
+#if LDBL_MAX_EXP > 1024
+#if LDBL_MAX_EXP > 16384
+#error "ipio2 table needs to be expanded"
+#endif
+0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
+0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
+0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
+0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
+0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
+0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
+0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
+0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
+0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
+0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
+0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
+0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
+0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
+0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
+0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
+0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
+0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
+0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
+0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
+0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
+0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
+0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
+0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
+0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
+0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
+0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
+0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
+0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
+0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
+0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
+0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
+0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
+0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
+0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
+0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
+0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
+0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
+0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
+0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
+0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
+0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
+0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
+0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
+0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
+0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
+0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
+0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
+0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
+0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
+0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
+0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
+0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
+0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
+0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
+0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
+0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
+0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
+0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
+0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
+0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
+0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
+0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
+0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
+0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
+0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
+0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
+0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
+0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
+0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
+0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
+0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
+0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
+0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
+0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
+0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
+0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
+0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
+0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
+0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
+0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
+0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
+0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
+0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
+0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
+0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
+0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
+0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
+0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
+0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
+0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
+0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
+0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
+0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
+0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
+0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
+0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
+0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
+0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
+0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
+0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
+0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
+0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
+0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
+0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
+#endif
+
+};
+
+static const double PIo2[] = {
+  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double                    
+zero   = 0.0,
+one    = 1.0,
+two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+OLM_DLLEXPORT int
+__kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec)
+{
+       int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+       double z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+       jk = init_jk[prec];
+       jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+       jx =  nx-1;
+       jv = (e0-3)/24; if(jv<0) jv=0;
+       q0 =  e0-24*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+       j = jv-jx; m = jx+jk;
+       for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+       for (i=0;i<=jk;i++) {
+           for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+           q[i] = fw;
+       }
+
+       jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+       for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+           fw    =  (double)((int32_t)(twon24* z));
+           iq[i] =  (int32_t)(z-two24*fw);
+           z     =  q[j-1]+fw;
+       }
+
+    /* compute n */
+       z  = scalbn(z,q0);              /* actual value of z */
+       z -= 8.0*floor(z*0.125);                /* trim off integer >= 8 */
+       n  = (int32_t) z;
+       z -= (double)n;
+       ih = 0;
+       if(q0>0) {      /* need iq[jz-1] to determine n */
+           i  = (iq[jz-1]>>(24-q0)); n += i;
+           iq[jz-1] -= i<<(24-q0);
+           ih = iq[jz-1]>>(23-q0);
+       } 
+       else if(q0==0) ih = iq[jz-1]>>23;
+       else if(z>=0.5) ih=2;
+
+       if(ih>0) {      /* q > 0.5 */
+           n += 1; carry = 0;
+           for(i=0;i<jz ;i++) {        /* compute 1-q */
+               j = iq[i];
+               if(carry==0) {
+                   if(j!=0) {
+                       carry = 1; iq[i] = 0x1000000- j;
+                   }
+               } else  iq[i] = 0xffffff - j;
+           }
+           if(q0>0) {          /* rare case: chance is 1 in 12 */
+               switch(q0) {
+               case 1:
+                  iq[jz-1] &= 0x7fffff; break;
+               case 2:
+                  iq[jz-1] &= 0x3fffff; break;
+               }
+           }
+           if(ih==2) {
+               z = one - z;
+               if(carry!=0) z -= scalbn(one,q0);
+           }
+       }
+
+    /* check if recomputation is needed */
+       if(z==zero) {
+           j = 0;
+           for (i=jz-1;i>=jk;i--) j |= iq[i];
+           if(j==0) { /* need recomputation */
+               for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+               for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                   f[jx+i] = (double) ipio2[jv+i];
+                   for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                   q[i] = fw;
+               }
+               jz += k;
+               goto recompute;
+           }
+       }
+
+    /* chop off zero terms */
+       if(z==0.0) {
+           jz -= 1; q0 -= 24;
+           while(iq[jz]==0) { jz--; q0-=24;}
+       } else { /* break z into 24-bit if necessary */
+           z = scalbn(z,-q0);
+           if(z>=two24) { 
+               fw = (double)((int32_t)(twon24*z));
+               iq[jz] = (int32_t)(z-two24*fw);
+               jz += 1; q0 += 24;
+               iq[jz] = (int32_t) fw;
+           } else iq[jz] = (int32_t) z ;
+       }
+
+    /* convert integer "bit" chunk to floating-point value */
+       fw = scalbn(one,q0);
+       for(i=jz;i>=0;i--) {
+           q[i] = fw*(double)iq[i]; fw*=twon24;
+       }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+       for(i=jz;i>=0;i--) {
+           for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+           fq[jz-i] = fw;
+       }
+
+    /* compress fq[] into y[] */
+       switch(prec) {
+           case 0:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i];
+               y[0] = (ih==0)? fw: -fw; 
+               break;
+           case 1:
+           case 2:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i]; 
+               STRICT_ASSIGN(double,fw,fw);
+               y[0] = (ih==0)? fw: -fw; 
+               fw = fq[0]-fw;
+               for (i=1;i<=jz;i++) fw += fq[i];
+               y[1] = (ih==0)? fw: -fw; 
+               break;
+           case 3:     /* painful */
+               for (i=jz;i>0;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (i=jz;i>1;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+               if(ih==0) {
+                   y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+               } else {
+                   y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+               }
+       }
+       return n&7;
+}
diff --git a/src/k_sin.c b/src/k_sin.c
new file mode 100644 (file)
index 0000000..0b3de39
--- /dev/null
@@ -0,0 +1,71 @@
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_sin.c,v 1.11 2008/02/19 12:54:14 bde Exp $");
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). 
+ *
+ * Algorithm
+ *     1. Since sin(-x) = -sin(x), we need only to consider positive x. 
+ *     2. Callers must return sin(-0) = -0 without calling here since our
+ *        odd polynomial is not evaluated in a way that preserves -0.
+ *        Callers may do the optimization sin(x) ~ x for tiny x.
+ *     3. sin(x) is approximated by a polynomial of degree 13 on
+ *        [0,pi/4]
+ *                              3            13
+ *             sin(x) ~ x + S1*x + ... + S6*x
+ *        where
+ *     
+ *     |sin(x)         2     4     6     8     10     12  |     -58
+ *     |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+ *     |  x                                               | 
+ * 
+ *     4. sin(x+y) = sin(x) + sin'(x')*y
+ *                 ~ sin(x) + (1-x*x/2)*y
+ *        For better accuracy, let 
+ *                  3      2      2      2      2
+ *             r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ *        then                   3    2
+ *             sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6  =  1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+OLM_DLLEXPORT double
+__kernel_sin(double x, double y, int iy)
+{
+       double z,r,v,w;
+
+       z       =  x*x;
+       w       =  z*z;
+       r       =  S2+z*(S3+z*S4) + z*w*(S5+z*S6);
+       v       =  z*x;
+       if(iy==0) return x+v*(S1+z*r);
+       else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/k_sinf.c b/src/k_sinf.c
new file mode 100644 (file)
index 0000000..15c8e03
--- /dev/null
@@ -0,0 +1,48 @@
+/* k_sinf.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_SINDF
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_sinf.c,v 1.16 2009/06/03 08:16:34 ed Exp $");
+#endif
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */
+static const double
+S1 = -0x15555554cbac77.0p-55,  /* -0.166666666416265235595 */
+S2 =  0x111110896efbb2.0p-59,  /*  0.0083333293858894631756 */
+S3 = -0x1a00f9e2cae774.0p-65,  /* -0.000198393348360966317347 */
+S4 =  0x16cd878c3b46a7.0p-71;  /*  0.0000027183114939898219064 */
+
+#ifndef INLINE_KERNEL_SINDF
+extern
+#endif
+//__inline float
+OLM_DLLEXPORT float 
+__kernel_sindf(double x)
+{
+       double r, s, w, z;
+
+       /* Try to optimize for parallel evaluation as in k_tanf.c. */
+       z = x*x;
+       w = z*z;
+       r = S3+z*S4;
+       s = z*x;
+       return (x + s*(S1+z*S2)) + s*w*r;
+}
diff --git a/src/k_tan.c b/src/k_tan.c
new file mode 100644 (file)
index 0000000..41f754b
--- /dev/null
@@ -0,0 +1,134 @@
+/* @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* INDENT OFF */
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_tan.c,v 1.13 2008/02/22 02:30:35 das Exp $");
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.
+ *
+ * Algorithm
+ *     1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ *     2. Callers must return tan(-0) = -0 without calling here since our
+ *        odd polynomial is not evaluated in a way that preserves -0.
+ *        Callers may do the optimization tan(x) ~ x for tiny x.
+ *     3. tan(x) is approximated by a odd polynomial of degree 27 on
+ *        [0,0.67434]
+ *                              3             27
+ *             tan(x) ~ x + T1*x + ... + T13*x
+ *        where
+ *
+ *             |tan(x)         2     4            26   |     -59.2
+ *             |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+ *             |  x                                    |
+ *
+ *        Note: tan(x+y) = tan(x) + tan'(x)*y
+ *                       ~ tan(x) + (1+x*x)*y
+ *        Therefore, for better accuracy in computing tan(x+y), let
+ *                  3      2      2       2       2
+ *             r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ *        then
+ *                                 3    2
+ *             tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+ *             tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ *                    = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double xxx[] = {
+                3.33333333333334091986e-01,    /* 3FD55555, 55555563 */
+                1.33333333333201242699e-01,    /* 3FC11111, 1110FE7A */
+                5.39682539762260521377e-02,    /* 3FABA1BA, 1BB341FE */
+                2.18694882948595424599e-02,    /* 3F9664F4, 8406D637 */
+                8.86323982359930005737e-03,    /* 3F8226E3, E96E8493 */
+                3.59207910759131235356e-03,    /* 3F6D6D22, C9560328 */
+                1.45620945432529025516e-03,    /* 3F57DBC8, FEE08315 */
+                5.88041240820264096874e-04,    /* 3F4344D8, F2F26501 */
+                2.46463134818469906812e-04,    /* 3F3026F7, 1A8D1068 */
+                7.81794442939557092300e-05,    /* 3F147E88, A03792A6 */
+                7.14072491382608190305e-05,    /* 3F12B80F, 32F0A7E9 */
+               -1.85586374855275456654e-05,    /* BEF375CB, DB605373 */
+                2.59073051863633712884e-05,    /* 3EFB2A70, 74BF7AD4 */
+/* one */       1.00000000000000000000e+00,    /* 3FF00000, 00000000 */
+/* pio4 */      7.85398163397448278999e-01,    /* 3FE921FB, 54442D18 */
+/* pio4lo */    3.06161699786838301793e-17     /* 3C81A626, 33145C07 */
+};
+#define        one     xxx[13]
+#define        pio4    xxx[14]
+#define        pio4lo  xxx[15]
+#define        T       xxx
+/* INDENT ON */
+
+double
+__kernel_tan(double x, double y, int iy) {
+       double z, r, v, w, s;
+       int32_t ix, hx;
+
+       GET_HIGH_WORD(hx,x);
+       ix = hx & 0x7fffffff;                   /* high word of |x| */
+       if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */
+               if (hx < 0) {
+                       x = -x;
+                       y = -y;
+               }
+               z = pio4 - x;
+               w = pio4lo - y;
+               x = z + w;
+               y = 0.0;
+       }
+       z = x * x;
+       w = z * z;
+       /*
+        * Break x^5*(T[1]+x^2*T[2]+...) into
+        * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+        * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+        */
+       r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] +
+               w * T[11]))));
+       v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] +
+               w * T[12])))));
+       s = z * x;
+       r = y + z * (s * (r + v) + y);
+       r += T[0] * s;
+       w = x + r;
+       if (ix >= 0x3FE59428) {
+               v = (double) iy;
+               return (double) (1 - ((hx >> 30) & 2)) *
+                       (v - 2.0 * (x - (w * w / (w + v) - r)));
+       }
+       if (iy == 1)
+               return w;
+       else {
+               /*
+                * if allow error up to 2 ulp, simply return
+                * -1.0 / (x+r) here
+                */
+               /* compute -1.0 / (x+r) accurately */
+               double a, t;
+               z = w;
+               SET_LOW_WORD(z,0);
+               v = r - (z - x);        /* z+v = r+x */
+               t = a = -1.0 / w;       /* a = -1.0/w */
+               SET_LOW_WORD(t,0);
+               s = 1.0 + t * z;
+               return t + a * (s + t * v);
+       }
+}
diff --git a/src/k_tanf.c b/src/k_tanf.c
new file mode 100644 (file)
index 0000000..9c17d1b
--- /dev/null
@@ -0,0 +1,68 @@
+/* k_tanf.c -- float version of k_tan.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef INLINE_KERNEL_TANDF
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/k_tanf.c,v 1.23 2009/06/03 08:16:34 ed Exp $");
+#endif
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */
+static const double
+T[] =  {
+  0x15554d3418c99f.0p-54,      /* 0.333331395030791399758 */
+  0x1112fd38999f72.0p-55,      /* 0.133392002712976742718 */
+  0x1b54c91d865afe.0p-57,      /* 0.0533812378445670393523 */
+  0x191df3908c33ce.0p-58,      /* 0.0245283181166547278873 */
+  0x185dadfcecf44e.0p-61,      /* 0.00297435743359967304927 */
+  0x1362b9bf971bcd.0p-59,      /* 0.00946564784943673166728 */
+};
+
+#ifndef INLINE_KERNEL_TANDF
+extern
+#endif
+//__inline float
+OLM_DLLEXPORT float
+__kernel_tandf(double x, int iy)
+{
+       double z,r,w,s,t,u;
+
+       z       =  x*x;
+       /*
+        * Split up the polynomial into small independent terms to give
+        * opportunities for parallel evaluation.  The chosen splitting is
+        * micro-optimized for Athlons (XP, X64).  It costs 2 multiplications
+        * relative to Horner's method on sequential machines.
+        *
+        * We add the small terms from lowest degree up for efficiency on
+        * non-sequential machines (the lowest degree terms tend to be ready
+        * earlier).  Apart from this, we don't care about order of
+        * operations, and don't need to to care since we have precision to
+        * spare.  However, the chosen splitting is good for accuracy too,
+        * and would give results as accurate as Horner's method if the
+        * small terms were added from highest degree down.
+        */
+       r = T[4]+z*T[5];
+       t = T[2]+z*T[3];
+       w = z*z;
+       s = z*x;
+       u = T[0]+z*T[1];
+       r = (x+s*u)+(s*w)*(t+w*r);
+       if(iy==1) return r;
+       else return -1.0/r;
+}
diff --git a/src/math_private.h b/src/math_private.h
new file mode 100644 (file)
index 0000000..5c98046
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ * $FreeBSD: src/lib/msun/src/math_private.h,v 1.34 2011/10/21 06:27:56 das Exp $
+ */
+
+#ifndef _MATH_PRIVATE_H_
+#define        _MATH_PRIVATE_H_
+
+#include <openlibm_complex.h>
+
+#include "cdefs-compat.h"
+#include "types-compat.h"
+#include "fpmath.h"
+#include <stdint.h>
+#include "math_private_openbsd.h"
+
+/*
+ * The original fdlibm code used statements like:
+ *     n0 = ((*(int*)&one)>>29)^1;             * index of high word *
+ *     ix0 = *(n0+(int*)&x);                   * high word of x *
+ *     ix1 = *((1-n0)+(int*)&x);               * low word of x *
+ * to dig two 32 bit words out of the 64 bit IEEE floating point
+ * value.  That is non-ANSI, and, moreover, the gcc instruction
+ * scheduler gets it wrong.  We instead use the following macros.
+ * Unlike the original code, we determine the endianness at compile
+ * time, not at run time; I don't see much benefit to selecting
+ * endianness at run time.
+ */
+
+/*
+ * A union which permits us to convert between a double and two 32 bit
+ * ints.
+ */
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
+
+typedef union
+{
+  double value;
+  struct
+  {
+    u_int32_t msw;
+    u_int32_t lsw;
+  } parts;
+  struct
+  {
+    u_int64_t w;
+  } xparts;
+} ieee_double_shape_type;
+
+#endif
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+typedef union
+{
+  double value;
+  struct
+  {
+    u_int32_t lsw;
+    u_int32_t msw;
+  } parts;
+  struct
+  {
+    u_int64_t w;
+  } xparts;
+} ieee_double_shape_type;
+
+#endif
+
+/* Get two 32 bit ints from a double.  */
+
+#define EXTRACT_WORDS(ix0,ix1,d)                               \
+do {                                                           \
+  ieee_double_shape_type ew_u;                                 \
+  ew_u.value = (d);                                            \
+  (ix0) = ew_u.parts.msw;                                      \
+  (ix1) = ew_u.parts.lsw;                                      \
+} while (0)
+
+/* Get a 64-bit int from a double. */
+#define EXTRACT_WORD64(ix,d)                                   \
+do {                                                           \
+  ieee_double_shape_type ew_u;                                 \
+  ew_u.value = (d);                                            \
+  (ix) = ew_u.xparts.w;                                                \
+} while (0)
+
+/* Get the more significant 32 bit int from a double.  */
+
+#define GET_HIGH_WORD(i,d)                                     \
+do {                                                           \
+  ieee_double_shape_type gh_u;                                 \
+  gh_u.value = (d);                                            \
+  (i) = gh_u.parts.msw;                                                \
+} while (0)
+
+/* Get the less significant 32 bit int from a double.  */
+
+#define GET_LOW_WORD(i,d)                                      \
+do {                                                           \
+  ieee_double_shape_type gl_u;                                 \
+  gl_u.value = (d);                                            \
+  (i) = gl_u.parts.lsw;                                                \
+} while (0)
+
+/* Set a double from two 32 bit ints.  */
+
+#define INSERT_WORDS(d,ix0,ix1)                                        \
+do {                                                           \
+  ieee_double_shape_type iw_u;                                 \
+  iw_u.parts.msw = (ix0);                                      \
+  iw_u.parts.lsw = (ix1);                                      \
+  (d) = iw_u.value;                                            \
+} while (0)
+
+/* Set a double from a 64-bit int. */
+#define INSERT_WORD64(d,ix)                                    \
+do {                                                           \
+  ieee_double_shape_type iw_u;                                 \
+  iw_u.xparts.w = (ix);                                                \
+  (d) = iw_u.value;                                            \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int.  */
+
+#define SET_HIGH_WORD(d,v)                                     \
+do {                                                           \
+  ieee_double_shape_type sh_u;                                 \
+  sh_u.value = (d);                                            \
+  sh_u.parts.msw = (v);                                                \
+  (d) = sh_u.value;                                            \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int.  */
+
+#define SET_LOW_WORD(d,v)                                      \
+do {                                                           \
+  ieee_double_shape_type sl_u;                                 \
+  sl_u.value = (d);                                            \
+  sl_u.parts.lsw = (v);                                                \
+  (d) = sl_u.value;                                            \
+} while (0)
+
+/*
+ * A union which permits us to convert between a float and a 32 bit
+ * int.
+ */
+
+typedef union
+{
+  float value;
+  /* FIXME: Assumes 32 bit int.  */
+  unsigned int word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float.  */
+
+#define GET_FLOAT_WORD(i,d)                                    \
+do {                                                           \
+  ieee_float_shape_type gf_u;                                  \
+  gf_u.value = (d);                                            \
+  (i) = gf_u.word;                                             \
+} while (0)
+
+/* Set a float from a 32 bit int.  */
+
+#define SET_FLOAT_WORD(d,i)                                    \
+do {                                                           \
+  ieee_float_shape_type sf_u;                                  \
+  sf_u.word = (i);                                             \
+  (d) = sf_u.value;                                            \
+} while (0)
+
+/* Get expsign as a 16 bit int from a long double.  */
+
+#define        GET_LDBL_EXPSIGN(i,d)                                   \
+do {                                                           \
+  union IEEEl2bits ge_u;                                       \
+  ge_u.e = (d);                                                        \
+  (i) = ge_u.xbits.expsign;                                    \
+} while (0)
+
+/* Set expsign of a long double from a 16 bit int.  */
+
+#define        SET_LDBL_EXPSIGN(d,v)                                   \
+do {                                                           \
+  union IEEEl2bits se_u;                                       \
+  se_u.e = (d);                                                        \
+  se_u.xbits.expsign = (v);                                    \
+  (d) = se_u.e;                                                        \
+} while (0)
+
+
+//VBS
+#define        STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
+
+/* VBS
+#ifdef FLT_EVAL_METHOD
+// Attempt to get strict C99 semantics for assignment with non-C99 compilers.
+#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
+#define        STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
+#else
+#define        STRICT_ASSIGN(type, lval, rval) do {    \
+       volatile type __lval;                   \
+                                               \
+       if (sizeof(type) >= sizeof(double))     \
+               (lval) = (rval);                \
+       else {                                  \
+               __lval = (rval);                \
+               (lval) = __lval;                \
+       }                                       \
+} while (0)
+#endif
+#endif
+*/
+
+/*
+ * Common routine to process the arguments to nan(), nanf(), and nanl().
+ */
+void __scan_nan(u_int32_t *__words, int __num_words, const char *__s);
+
+#ifdef __GNUCLIKE_ASM
+
+/* Asm versions of some functions. */
+
+#ifdef __amd64__
+static __inline int
+irint(double x)
+{
+       int n;
+
+       __asm__("cvtsd2si %1,%0" : "=r" (n) : "x" (x));
+       return (n);
+}
+#define        HAVE_EFFICIENT_IRINT
+#endif
+
+#ifdef __i386__
+static __inline int
+irint(double x)
+{
+       int n;
+
+       __asm__("fistl %0" : "=m" (n) : "t" (x));
+       return (n);
+}
+#define        HAVE_EFFICIENT_IRINT
+#endif
+
+#endif /* __GNUCLIKE_ASM */
+
+/*
+ * ieee style elementary functions
+ *
+ * We rename functions here to improve other sources' diffability
+ * against fdlibm.
+ */
+#define        __ieee754_sqrt  sqrt
+#define        __ieee754_acos  acos
+#define        __ieee754_acosh acosh
+#define        __ieee754_log   log
+#define        __ieee754_log2  log2
+#define        __ieee754_atanh atanh
+#define        __ieee754_asin  asin
+#define        __ieee754_atan2 atan2
+#define        __ieee754_exp   exp
+#define        __ieee754_cosh  cosh
+#define        __ieee754_fmod  fmod
+#define        __ieee754_pow   pow
+#define        __ieee754_lgamma lgamma
+#define        __ieee754_lgamma_r lgamma_r
+#define        __ieee754_log10 log10
+#define        __ieee754_sinh  sinh
+#define        __ieee754_hypot hypot
+#define        __ieee754_j0    j0
+#define        __ieee754_j1    j1
+#define        __ieee754_y0    y0
+#define        __ieee754_y1    y1
+#define        __ieee754_jn    jn
+#define        __ieee754_yn    yn
+#define        __ieee754_remainder remainder
+#define        __ieee754_sqrtf sqrtf
+#define        __ieee754_acosf acosf
+#define        __ieee754_acoshf acoshf
+#define        __ieee754_logf  logf
+#define        __ieee754_atanhf atanhf
+#define        __ieee754_asinf asinf
+#define        __ieee754_atan2f atan2f
+#define        __ieee754_expf  expf
+#define        __ieee754_coshf coshf
+#define        __ieee754_fmodf fmodf
+#define        __ieee754_powf  powf
+#define        __ieee754_lgammaf lgammaf
+#define        __ieee754_lgammaf_r lgammaf_r
+#define        __ieee754_log10f log10f
+#define        __ieee754_log2f log2f
+#define        __ieee754_sinhf sinhf
+#define        __ieee754_hypotf hypotf
+#define        __ieee754_j0f   j0f
+#define        __ieee754_j1f   j1f
+#define        __ieee754_y0f   y0f
+#define        __ieee754_y1f   y1f
+#define        __ieee754_jnf   jnf
+#define        __ieee754_ynf   ynf
+#define        __ieee754_remainderf remainderf
+
+/* fdlibm kernel function */
+int    __kernel_rem_pio2(double*,double*,int,int,int);
+
+/* double precision kernel functions */
+#ifdef INLINE_REM_PIO2
+__inline
+#endif
+int    __ieee754_rem_pio2(double,double*);
+double __kernel_sin(double,double,int);
+double __kernel_cos(double,double);
+double __kernel_tan(double,double,int);
+double __ldexp_exp(double,int);
+double complex __ldexp_cexp(double complex,int);
+
+/* float precision kernel functions */
+#ifdef INLINE_REM_PIO2F
+__inline
+#endif
+int    __ieee754_rem_pio2f(float,double*);
+#ifdef INLINE_KERNEL_SINDF
+__inline
+#endif
+float  __kernel_sindf(double);
+#ifdef INLINE_KERNEL_COSDF
+__inline
+#endif
+float  __kernel_cosdf(double);
+#ifdef INLINE_KERNEL_TANDF
+__inline
+#endif
+float  __kernel_tandf(double,int);
+float  __ldexp_expf(float,int);
+float complex __ldexp_cexpf(float complex,int);
+
+/* long double precision kernel functions */
+long double __kernel_sinl(long double, long double, int);
+long double __kernel_cosl(long double, long double);
+long double __kernel_tanl(long double, long double, int);
+
+#undef OLM_DLLEXPORT
+#ifdef _WIN32
+# ifdef IMPORT_EXPORTS
+#  define OLM_DLLEXPORT __declspec(dllimport)
+# else
+#  define OLM_DLLEXPORT __declspec(dllexport)
+# endif
+#else
+#define OLM_DLLEXPORT __attribute__ ((visibility("default")))
+#endif
+
+
+#endif /* !_MATH_PRIVATE_H_ */
diff --git a/src/math_private_openbsd.h b/src/math_private_openbsd.h
new file mode 100644 (file)
index 0000000..021670f
--- /dev/null
@@ -0,0 +1,218 @@
+/*     $OpenBSD: math_private.h,v 1.17 2014/06/02 19:31:17 kettenis Exp $      */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * from: @(#)fdlibm.h 5.1 93/09/24
+ */
+
+#ifndef _MATH_PRIVATE_OPENBSD_H_
+#define _MATH_PRIVATE_OPENBSD_H_
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
+
+typedef union
+{
+  long double value;
+  struct {
+    u_int32_t mswhi;
+    u_int32_t mswlo;
+    u_int32_t lswhi;
+    u_int32_t lswlo;
+  } parts32;
+  struct {
+    u_int64_t msw;
+    u_int64_t lsw;
+  } parts64;
+} ieee_quad_shape_type;
+
+#endif
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+typedef union
+{
+  long double value;
+  struct {
+    u_int32_t lswlo;
+    u_int32_t lswhi;
+    u_int32_t mswlo;
+    u_int32_t mswhi;
+  } parts32;
+  struct {
+    u_int64_t lsw;
+    u_int64_t msw;
+  } parts64;
+} ieee_quad_shape_type;
+
+#endif
+
+/* Get two 64 bit ints from a long double.  */
+
+#define GET_LDOUBLE_WORDS64(ix0,ix1,d)                         \
+do {                                                           \
+  ieee_quad_shape_type qw_u;                                   \
+  qw_u.value = (d);                                            \
+  (ix0) = qw_u.parts64.msw;                                    \
+  (ix1) = qw_u.parts64.lsw;                                    \
+} while (0)
+
+/* Set a long double from two 64 bit ints.  */
+
+#define SET_LDOUBLE_WORDS64(d,ix0,ix1)                         \
+do {                                                           \
+  ieee_quad_shape_type qw_u;                                   \
+  qw_u.parts64.msw = (ix0);                                    \
+  qw_u.parts64.lsw = (ix1);                                    \
+  (d) = qw_u.value;                                            \
+} while (0)
+
+/* Get the more significant 64 bits of a long double mantissa.  */
+
+#define GET_LDOUBLE_MSW64(v,d)                                 \
+do {                                                           \
+  ieee_quad_shape_type sh_u;                                   \
+  sh_u.value = (d);                                            \
+  (v) = sh_u.parts64.msw;                                      \
+} while (0)
+
+/* Set the more significant 64 bits of a long double mantissa from an int.  */
+
+#define SET_LDOUBLE_MSW64(d,v)                                 \
+do {                                                           \
+  ieee_quad_shape_type sh_u;                                   \
+  sh_u.value = (d);                                            \
+  sh_u.parts64.msw = (v);                                      \
+  (d) = sh_u.value;                                            \
+} while (0)
+
+/* Get the least significant 64 bits of a long double mantissa.  */
+
+#define GET_LDOUBLE_LSW64(v,d)                                 \
+do {                                                           \
+  ieee_quad_shape_type sh_u;                                   \
+  sh_u.value = (d);                                            \
+  (v) = sh_u.parts64.lsw;                                      \
+} while (0)
+
+/* A union which permits us to convert between a long double and
+   three 32 bit ints.  */
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
+
+typedef union
+{
+  long double value;
+  struct {
+#ifdef __LP64__
+    int padh:32;
+#endif
+    int exp:16;
+    int padl:16;
+    u_int32_t msw;
+    u_int32_t lsw;
+  } parts;
+} ieee_extended_shape_type;
+
+#endif
+
+#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+typedef union
+{
+  long double value;
+  struct {
+    u_int32_t lsw;
+    u_int32_t msw;
+    int exp:16;
+    int padl:16;
+#ifdef __LP64__
+    int padh:32;
+#endif
+  } parts;
+} ieee_extended_shape_type;
+
+#endif
+
+/* Get three 32 bit ints from a double.  */
+
+#define GET_LDOUBLE_WORDS(se,ix0,ix1,d)                                \
+do {                                                           \
+  ieee_extended_shape_type ew_u;                               \
+  ew_u.value = (d);                                            \
+  (se) = ew_u.parts.exp;                                       \
+  (ix0) = ew_u.parts.msw;                                      \
+  (ix1) = ew_u.parts.lsw;                                      \
+} while (0)
+
+/* Set a double from two 32 bit ints.  */
+
+#define SET_LDOUBLE_WORDS(d,se,ix0,ix1)                                \
+do {                                                           \
+  ieee_extended_shape_type iw_u;                               \
+  iw_u.parts.exp = (se);                                       \
+  iw_u.parts.msw = (ix0);                                      \
+  iw_u.parts.lsw = (ix1);                                      \
+  (d) = iw_u.value;                                            \
+} while (0)
+
+/* Get the more significant 32 bits of a long double mantissa.  */
+
+#define GET_LDOUBLE_MSW(v,d)                                   \
+do {                                                           \
+  ieee_extended_shape_type sh_u;                               \
+  sh_u.value = (d);                                            \
+  (v) = sh_u.parts.msw;                                                \
+} while (0)
+
+/* Set the more significant 32 bits of a long double mantissa from an int.  */
+
+#define SET_LDOUBLE_MSW(d,v)                                   \
+do {                                                           \
+  ieee_extended_shape_type sh_u;                               \
+  sh_u.value = (d);                                            \
+  sh_u.parts.msw = (v);                                                \
+  (d) = sh_u.value;                                            \
+} while (0)
+
+/* Get int from the exponent of a long double.  */
+
+#define GET_LDOUBLE_EXP(se,d)                                  \
+do {                                                           \
+  ieee_extended_shape_type ge_u;                               \
+  ge_u.value = (d);                                            \
+  (se) = ge_u.parts.exp;                                       \
+} while (0)
+
+/* Set exponent of a long double from an int.  */
+
+#define SET_LDOUBLE_EXP(d,se)                                  \
+do {                                                           \
+  ieee_extended_shape_type se_u;                               \
+  se_u.value = (d);                                            \
+  se_u.parts.exp = (se);                                       \
+  (d) = se_u.value;                                            \
+} while (0)
+
+/*
+ * Common routine to process the arguments to nan(), nanf(), and nanl().
+ */
+void __scan_nan(uint32_t *__words, int __num_words, const char *__s);
+
+/*
+ * Functions internal to the math package, yet not static.
+ */
+double __exp__D(double, double);
+struct Double __log__D(double);
+long double __p1evll(long double, void *, int);
+long double __polevll(long double, void *, int);
+
+#endif /* _MATH_PRIVATE_OPENBSD_H_ */
diff --git a/src/mips_fpmath.h b/src/mips_fpmath.h
new file mode 100644 (file)
index 0000000..50f119f
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2002, 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+#ifndef __MIPSEB__
+               unsigned int    manl    :32;
+               unsigned int    manh    :20;
+               unsigned int    exp     :11;
+               unsigned int    sign    :1;
+#else
+               unsigned int            sign    :1;
+               unsigned int            exp     :11;
+               unsigned int            manh    :20;
+               unsigned int            manl    :32;
+#endif
+       } bits;
+};
+
+#define        LDBL_NBIT       0
+#define        mask_nbit_l(u)  ((void)0)
+#define        LDBL_IMPLICIT_NBIT
+
+#define        LDBL_MANH_SIZE  20
+#define        LDBL_MANL_SIZE  32
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)(u).bits.manh;               \
+} while(0)
+
diff --git a/src/polevll.c b/src/polevll.c
new file mode 100644 (file)
index 0000000..1c785d8
--- /dev/null
@@ -0,0 +1,104 @@
+/*     $OpenBSD: polevll.c,v 1.2 2013/11/12 20:35:09 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     polevll.c
+ *                                                     p1evll.c
+ *
+ *     Evaluate polynomial
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * int N;
+ * long double x, y, coef[N+1], polevl[];
+ *
+ * y = polevll( x, coef, N );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Evaluates polynomial of degree N:
+ *
+ *                     2          N
+ * y  =  C  + C x + C x  +...+ C x
+ *        0    1     2          N
+ *
+ * Coefficients are stored in reverse order:
+ *
+ * coef[0] = C  , ..., coef[N] = C  .
+ *            N                   0
+ *
+ *  The function p1evll() assumes that coef[N] = 1.0 and is
+ * omitted from the array.  Its calling arguments are
+ * otherwise the same as polevll().
+ *
+ *
+ * SPEED:
+ *
+ * In the interest of speed, there are no checks for out
+ * of bounds arithmetic.  This routine is used by most of
+ * the functions in the library.  Depending on available
+ * equipment features, the user may wish to rewrite the
+ * program in microcode or assembly language.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * Polynomial evaluator:
+ *  P[0] x^n  +  P[1] x^(n-1)  +  ...  +  P[n]
+ */
+long double
+__polevll(long double x, void *PP, int n)
+{
+       long double y;
+       long double *P;
+
+       P = (long double *)PP;
+       y = *P++;
+       do {
+               y = y * x + *P++;
+       } while (--n);
+
+       return (y);
+}
+
+/*
+ * Polynomial evaluator:
+ *  x^n  +  P[0] x^(n-1)  +  P[1] x^(n-2)  +  ...  +  P[n]
+ */
+long double
+__p1evll(long double x, void *PP, int n)
+{
+       long double y;
+       long double *P;
+
+       P = (long double *)PP;
+       n -= 1;
+       y = x + *P++;
+       do {
+               y = y * x + *P++;
+       } while (--n);
+
+       return (y);
+}
diff --git a/src/powerpc_fpmath.h b/src/powerpc_fpmath.h
new file mode 100644 (file)
index 0000000..6d80eb4
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003 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.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+               unsigned int            sign    :1;
+               unsigned int            exp     :11;
+               unsigned int            manh    :20;
+               unsigned int            manl    :32;
+       } bits;
+};
+
+#define        mask_nbit_l(u)  ((void)0)
+#define        LDBL_IMPLICIT_NBIT
+#define        LDBL_NBIT       0
+
+#define        LDBL_MANH_SIZE  20
+#define        LDBL_MANL_SIZE  32
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)(u).bits.manh;               \
+} while(0)
diff --git a/src/s_asinh.c b/src/s_asinh.c
new file mode 100644 (file)
index 0000000..1f9bc09
--- /dev/null
@@ -0,0 +1,57 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_asinh.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+/* asinh(x)
+ * Method :
+ *     Based on
+ *             asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ *     we have
+ *     asinh(x) := x  if  1+x*x=1,
+ *              := sign(x)*(log(x)+ln2)) for large |x|, else
+ *              := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ *              := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge=  1.00000000000000000000e+300;
+
+OLM_DLLEXPORT double
+asinh(double x)
+{
+       double t,w;
+       int32_t hx,ix;
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) return x+x;  /* x is inf or NaN */
+       if(ix< 0x3e300000) {    /* |x|<2**-28 */
+           if(huge+x>one) return x;    /* return x inexact except 0 */
+       }
+       if(ix>0x41b00000) {     /* |x| > 2**28 */
+           w = __ieee754_log(fabs(x))+ln2;
+       } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+           t = fabs(x);
+           w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t));
+       } else {                /* 2.0 > |x| > 2**-28 */
+           t = x*x;
+           w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t)));
+       }
+       if(hx>0) return w; else return -w;
+}
diff --git a/src/s_asinhf.c b/src/s_asinhf.c
new file mode 100644 (file)
index 0000000..c9d3694
--- /dev/null
@@ -0,0 +1,49 @@
+/* s_asinhf.c -- float version of s_asinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_asinhf.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+ln2 =  6.9314718246e-01, /* 0x3f317218 */
+huge=  1.0000000000e+30;
+
+OLM_DLLEXPORT float
+asinhf(float x)
+{
+       float t,w;
+       int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) return x+x;  /* x is inf or NaN */
+       if(ix< 0x31800000) {    /* |x|<2**-28 */
+           if(huge+x>one) return x;    /* return x inexact except 0 */
+       }
+       if(ix>0x4d800000) {     /* |x| > 2**28 */
+           w = __ieee754_logf(fabsf(x))+ln2;
+       } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+           t = fabsf(x);
+           w = __ieee754_logf((float)2.0*t+one/(__ieee754_sqrtf(x*x+one)+t));
+       } else {                /* 2.0 > |x| > 2**-28 */
+           t = x*x;
+           w =log1pf(fabsf(x)+t/(one+__ieee754_sqrtf(one+t)));
+       }
+       if(hx>0) return w; else return -w;
+}
diff --git a/src/s_atan.c b/src/s_atan.c
new file mode 100644 (file)
index 0000000..f87e486
--- /dev/null
@@ -0,0 +1,124 @@
+/* @(#)s_atan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_atan.c,v 1.13 2011/02/10 07:37:50 das Exp $");
+
+/* atan(x)
+ * Method
+ *   1. Reduce x to positive by atan(x) = -atan(-x).
+ *   2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ *      is further reduced to one of the following intervals and the
+ *      arctangent of t is evaluated by the corresponding formula:
+ *
+ *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double atanhi[] = {
+  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+       static const double
+one   = 1.0,
+huge   = 1.0e300;
+
+OLM_DLLEXPORT double
+atan(double x)
+{
+       double w,s1,s2,z;
+       int32_t ix,hx,id;
+
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x44100000) {    /* if |x| >= 2^66 */
+           u_int32_t low;
+           GET_LOW_WORD(low,x);
+           if(ix>0x7ff00000||
+               (ix==0x7ff00000&&(low!=0)))
+               return x+x;             /* NaN */
+           if(hx>0) return  atanhi[3]+*(volatile double *)&atanlo[3];
+           else     return -atanhi[3]-*(volatile double *)&atanlo[3];
+       } if (ix < 0x3fdc0000) {        /* |x| < 0.4375 */
+           if (ix < 0x3e400000) {      /* |x| < 2^-27 */
+               if(huge+x>one) return x;        /* raise inexact */
+           }
+           id = -1;
+       } else {
+       x = fabs(x);
+       if (ix < 0x3ff30000) {          /* |x| < 1.1875 */
+           if (ix < 0x3fe60000) {      /* 7/16 <=|x|<11/16 */
+               id = 0; x = (2.0*x-one)/(2.0+x);
+           } else {                    /* 11/16<=|x|< 19/16 */
+               id = 1; x  = (x-one)/(x+one);
+           }
+       } else {
+           if (ix < 0x40038000) {      /* |x| < 2.4375 */
+               id = 2; x  = (x-1.5)/(one+1.5*x);
+           } else {                    /* 2.4375 <= |x| < 2^66 */
+               id = 3; x  = -1.0/x;
+           }
+       }}
+    /* end of argument reduction */
+       z = x*x;
+       w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+       s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+       s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+       if (id<0) return x - x*(s1+s2);
+       else {
+           z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+           return (hx<0)? -z:z;
+       }
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(atan, atanl);
+#endif
diff --git a/src/s_atanf.c b/src/s_atanf.c
new file mode 100644 (file)
index 0000000..cdba6a3
--- /dev/null
@@ -0,0 +1,93 @@
+/* s_atanf.c -- float version of s_atan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_atanf.c,v 1.10 2008/08/01 01:24:25 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float atanhi[] = {
+  4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
+  7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
+  9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
+  1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
+};
+
+static const float atanlo[] = {
+  5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
+  3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
+  3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
+  7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
+};
+
+static const float aT[] = {
+  3.3333328366e-01,
+ -1.9999158382e-01,
+  1.4253635705e-01,
+ -1.0648017377e-01,
+  6.1687607318e-02,
+};
+
+static const float
+one   = 1.0,
+huge   = 1.0e30;
+
+OLM_DLLEXPORT float
+atanf(float x)
+{
+       float w,s1,s2,z;
+       int32_t ix,hx,id;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x4c800000) {    /* if |x| >= 2**26 */
+           if(ix>0x7f800000)
+               return x+x;             /* NaN */
+           if(hx>0) return  atanhi[3]+*(volatile float *)&atanlo[3];
+           else     return -atanhi[3]-*(volatile float *)&atanlo[3];
+       } if (ix < 0x3ee00000) {        /* |x| < 0.4375 */
+           if (ix < 0x39800000) {      /* |x| < 2**-12 */
+               if(huge+x>one) return x;        /* raise inexact */
+           }
+           id = -1;
+       } else {
+       x = fabsf(x);
+       if (ix < 0x3f980000) {          /* |x| < 1.1875 */
+           if (ix < 0x3f300000) {      /* 7/16 <=|x|<11/16 */
+               id = 0; x = ((float)2.0*x-one)/((float)2.0+x);
+           } else {                    /* 11/16<=|x|< 19/16 */
+               id = 1; x  = (x-one)/(x+one);
+           }
+       } else {
+           if (ix < 0x401c0000) {      /* |x| < 2.4375 */
+               id = 2; x  = (x-(float)1.5)/(one+(float)1.5*x);
+           } else {                    /* 2.4375 <= |x| < 2**26 */
+               id = 3; x  = -(float)1.0/x;
+           }
+       }}
+    /* end of argument reduction */
+       z = x*x;
+       w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+       s1 = z*(aT[0]+w*(aT[2]+w*aT[4]));
+       s2 = w*(aT[1]+w*aT[3]);
+       if (id<0) return x - x*(s1+s2);
+       else {
+           z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+           return (hx<0)? -z:z;
+       }
+}
diff --git a/src/s_atanl.c b/src/s_atanl.c
new file mode 100644 (file)
index 0000000..4edfa5a
--- /dev/null
@@ -0,0 +1,85 @@
+/* @(#)s_atan.c 5.1 93/09/24 */
+/* FreeBSD: head/lib/msun/src/s_atan.c 176451 2008-02-22 02:30:36Z das */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_atanl.c,v 1.1 2008/07/31 22:41:26 das Exp $");
+
+/*
+ * See comments in s_atan.c.
+ * Converted to long double by David Schultz <das@FreeBSD.ORG>.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "invtrig.h"
+#include "math_private.h"
+
+static const long double
+one   = 1.0,
+huge   = 1.0e300;
+
+OLM_DLLEXPORT long double
+atanl(long double x)
+{
+       union IEEEl2bits u;
+       long double w,s1,s2,z;
+       int id;
+       int16_t expsign, expt;
+       int32_t expman;
+
+       u.e = x;
+       expsign = u.xbits.expsign;
+       expt = expsign & 0x7fff;
+       if(expt >= ATAN_CONST) {        /* if |x| is large, atan(x)~=pi/2 */
+           if(expt == BIAS + LDBL_MAX_EXP &&
+              ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)!=0)
+               return x+x;             /* NaN */
+           if(expsign>0) return  atanhi[3]+atanlo[3];
+           else     return -atanhi[3]-atanlo[3];
+       }
+       /* Extract the exponent and the first few bits of the mantissa. */
+       /* XXX There should be a more convenient way to do this. */
+       expman = (expt << 8) | ((u.bits.manh >> (MANH_SIZE - 9)) & 0xff);
+       if (expman < ((BIAS - 2) << 8) + 0xc0) {        /* |x| < 0.4375 */
+           if (expt < ATAN_LINEAR) {   /* if |x| is small, atanl(x)~=x */
+               if(huge+x>one) return x;        /* raise inexact */
+           }
+           id = -1;
+       } else {
+       x = fabsl(x);
+       if (expman < (BIAS << 8) + 0x30) {              /* |x| < 1.1875 */
+           if (expman < ((BIAS - 1) << 8) + 0x60) {    /* 7/16 <=|x|<11/16 */
+               id = 0; x = (2.0*x-one)/(2.0+x);
+           } else {                    /* 11/16<=|x|< 19/16 */
+               id = 1; x  = (x-one)/(x+one);
+           }
+       } else {
+           if (expman < ((BIAS + 1) << 8) + 0x38) {    /* |x| < 2.4375 */
+               id = 2; x  = (x-1.5)/(one+1.5*x);
+           } else {                    /* 2.4375 <= |x| < 2^ATAN_CONST */
+               id = 3; x  = -1.0/x;
+           }
+       }}
+    /* end of argument reduction */
+       z = x*x;
+       w = z*z;
+    /* break sum aT[i]z**(i+1) into odd and even poly */
+       s1 = z*T_even(w);
+       s2 = w*T_odd(w);
+       if (id<0) return x - x*(s1+s2);
+       else {
+           z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+           return (expsign<0)? -z:z;
+       }
+}
diff --git a/src/s_cabs.c b/src/s_cabs.c
new file mode 100644 (file)
index 0000000..f163582
--- /dev/null
@@ -0,0 +1,30 @@
+/*     $OpenBSD: s_cabs.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double
+cabs(double complex z)
+{
+       return hypot(__real__ z, __imag__ z);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(cabsl, cabs);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_cabsf.c b/src/s_cabsf.c
new file mode 100644 (file)
index 0000000..8d9bd96
--- /dev/null
@@ -0,0 +1,25 @@
+/*     $OpenBSD: s_cabsf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $    */
+/*
+ * Copyright (c) 2008 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float
+cabsf(float complex z)
+{
+       return hypotf(__real__ z, __imag__ z);
+}
diff --git a/src/s_cabsl.c b/src/s_cabsl.c
new file mode 100644 (file)
index 0000000..847ded7
--- /dev/null
@@ -0,0 +1,26 @@
+/*     $OpenBSD: s_cabsl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $    */
+
+/*
+ * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double
+cabsl(long double complex z)
+{
+       return hypotl(__real__ z, __imag__ z);
+}
diff --git a/src/s_cacos.c b/src/s_cacos.c
new file mode 100644 (file)
index 0000000..9a8e7fb
--- /dev/null
@@ -0,0 +1,65 @@
+/*     $OpenBSD: s_cacos.c,v 1.6 2013/07/03 04:46:36 espie Exp $       */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacos()
+ *
+ *     Complex circular arc cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex cacos();
+ * double complex z, w;
+ *
+ * w = cacos (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ *
+ * w = arccos z  =  PI/2 - arcsin z.
+ *
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5200      1.6e-15      2.8e-16
+ *    IEEE      -10,+10     30000      1.8e-14      2.2e-15
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+cacos(double complex z)
+{
+       double complex w;
+
+       w = casin (z);
+       w = (M_PI_2 - creal (w)) - cimag (w) * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(cacosl, cacos);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_cacosf.c b/src/s_cacosf.c
new file mode 100644 (file)
index 0000000..f3c0eb9
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: s_cacosf.c,v 1.2 2011/07/20 19:28:33 martynas Exp $   */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacosf()
+ *
+ *     Complex circular arc cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void cacosf();
+ * cmplxf z, w;
+ *
+ * cacosf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ *
+ * w = arccos z  =  PI/2 - arcsin z.
+ *
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       9.2e-6       1.2e-6
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+cacosf(float complex z)
+{
+       float complex w;
+
+       w = casinf( z );
+       w = ((float)M_PI_2 - crealf (w)) - cimagf (w) * I;
+       return (w);
+}
diff --git a/src/s_cacosh.c b/src/s_cacosh.c
new file mode 100644 (file)
index 0000000..244f437
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: s_cacosh.c,v 1.6 2013/07/03 04:46:36 espie Exp $      */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacosh
+ *
+ *     Complex inverse hyperbolic cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex cacosh();
+ * double complex z, w;
+ *
+ * w = cacosh (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * acosh z = i acos z .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.6e-14     2.1e-15
+ *
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+cacosh(double complex z)
+{
+       double complex w;
+
+       w = I * cacos (z);
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(cacoshl, cacosh);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_cacoshf.c b/src/s_cacoshf.c
new file mode 100644 (file)
index 0000000..f3c40ae
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $OpenBSD: s_cacoshf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $  */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacoshf
+ *
+ *     Complex inverse hyperbolic cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex cacoshf();
+ * float complex z, w;
+ *
+ * w = cacoshf (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * acosh z = i acos z .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.6e-14     2.1e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+cacoshf(float complex z)
+{
+       float complex w;
+
+       w = I * cacosf (z);
+       return (w);
+}
diff --git a/src/s_cacoshl.c b/src/s_cacoshl.c
new file mode 100644 (file)
index 0000000..5e5ae31
--- /dev/null
@@ -0,0 +1,56 @@
+/*     $OpenBSD: s_cacoshl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $  */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacoshl
+ *
+ *     Complex inverse hyperbolic cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex cacoshl();
+ * long double complex z, w;
+ *
+ * w = cacoshl (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * acosh z = i acos z .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.6e-14     2.1e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+cacoshl(long double complex z)
+{
+       long double complex w;
+
+       w = I * cacosl(z);
+       return (w);
+}
diff --git a/src/s_cacosl.c b/src/s_cacosl.c
new file mode 100644 (file)
index 0000000..8a7b8a1
--- /dev/null
@@ -0,0 +1,63 @@
+/*     $OpenBSD: s_cacosl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cacosl()
+ *
+ *     Complex circular arc cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex cacosl();
+ * long double complex z, w;
+ *
+ * w = cacosl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ *
+ * w = arccos z  =  PI/2 - arcsin z.
+ *
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5200      1.6e-15      2.8e-16
+ *    IEEE      -10,+10     30000      1.8e-14      2.2e-15
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+static const long double PIO2L = 1.570796326794896619231321691639751442098585L;
+
+long double complex
+cacosl(long double complex z)
+{
+       long double complex w;
+
+       w = casinl(z);
+       w = (PIO2L - creall(w)) - cimagl(w) * I;
+       return (w);
+}
diff --git a/src/s_carg.c b/src/s_carg.c
new file mode 100644 (file)
index 0000000..2ebfe17
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_carg.c,v 1.1 2007/12/12 23:43:51 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+carg(double complex z)
+{
+
+       return (atan2(cimag(z), creal(z)));
+}
diff --git a/src/s_cargf.c b/src/s_cargf.c
new file mode 100644 (file)
index 0000000..41e320b
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cargf.c,v 1.1 2007/12/12 23:43:51 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+cargf(float complex z)
+{
+
+       return (atan2f(cimagf(z), crealf(z)));
+}
diff --git a/src/s_cargl.c b/src/s_cargl.c
new file mode 100644 (file)
index 0000000..5052133
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2005-2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cargl.c,v 1.1 2008/07/31 22:41:26 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+cargl(long double complex z)
+{
+
+       return (atan2l(cimagl(z), creall(z)));
+}
diff --git a/src/s_casin.c b/src/s_casin.c
new file mode 100644 (file)
index 0000000..82939f1
--- /dev/null
@@ -0,0 +1,134 @@
+/*     $OpenBSD: s_casin.c,v 1.6 2013/07/03 04:46:36 espie Exp $       */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casin()
+ *
+ *     Complex circular arc sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex casin();
+ * double complex z, w;
+ *
+ * w = casin (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse complex sine:
+ *
+ *                               2
+ * w = -i clog( iz + csqrt( 1 - z ) ).
+ *
+ * casin(z) = -i casinh(iz)
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10     10100       2.1e-15     3.4e-16
+ *    IEEE      -10,+10     30000       2.2e-14     2.7e-15
+ * Larger relative error can be observed for z near zero.
+ * Also tested by csin(casin(z)) = z.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+casin(double complex z)
+{
+       double complex w;
+       static double complex ca, ct, zz, z2;
+       double x, y;
+
+       x = creal (z);
+       y = cimag (z);
+
+       if (y == 0.0) {
+               if (fabs(x) > 1.0) {
+                       w = M_PI_2 + 0.0 * I;
+                       /*mtherr ("casin", DOMAIN);*/
+               }
+               else {
+                       w = asin (x) + 0.0 * I;
+               }
+               return (w);
+       }
+
+       /* Power series expansion */
+       /*
+       b = cabs(z);
+       if( b < 0.125 ) {
+               z2.r = (x - y) * (x + y);
+               z2.i = 2.0 * x * y;
+
+               cn = 1.0;
+               n = 1.0;
+               ca.r = x;
+               ca.i = y;
+               sum.r = x;
+               sum.i = y;
+               do {
+                       ct.r = z2.r * ca.r  -  z2.i * ca.i;
+                       ct.i = z2.r * ca.i  +  z2.i * ca.r;
+                       ca.r = ct.r;
+                       ca.i = ct.i;
+
+                       cn *= n;
+                       n += 1.0;
+                       cn /= n;
+                       n += 1.0;
+                       b = cn/n;
+
+                       ct.r *= b;
+                       ct.i *= b;
+                       sum.r += ct.r;
+                       sum.i += ct.i;
+                       b = fabs(ct.r) + fabs(ct.i);
+               }
+               while( b > MACHEP );
+               w->r = sum.r;
+               w->i = sum.i;
+               return;
+       }
+       */
+
+       ca = x + y * I;
+       ct = ca * I;
+       /* sqrt( 1 - z*z) */
+       /* cmul( &ca, &ca, &zz ) */
+       /*x * x  -  y * y */
+       zz = (x - y) * (x + y) + (2.0 * x * y) * I;
+
+       zz = 1.0 - creal(zz) - cimag(zz) * I;
+       z2 = csqrt (zz);
+
+       zz = ct + z2;
+       zz = clog (zz);
+       /* multiply by 1/i = -i */
+       w = zz * (-1.0 * I);
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(casinl, casin);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_casinf.c b/src/s_casinf.c
new file mode 100644 (file)
index 0000000..1573264
--- /dev/null
@@ -0,0 +1,132 @@
+/*     $OpenBSD: s_casinf.c,v 1.3 2011/07/20 19:28:33 martynas Exp $   */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casinf()
+ *
+ *     Complex circular arc sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void casinf();
+ * cmplxf z, w;
+ *
+ * casinf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse complex sine:
+ *
+ *                               2
+ * w = -i clog( iz + csqrt( 1 - z ) ).
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.1e-5      1.5e-6
+ * Larger relative error can be observed for z near zero.
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+casinf(float complex z)
+{
+       float complex w;
+       float x, y;
+       static float complex ca, ct, zz, z2;
+       /*
+       float cn, n;
+       static float a, b, s, t, u, v, y2;
+       static cmplxf sum;
+       */
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       if(y == 0.0f) {
+               if(fabsf(x) > 1.0f) {
+                       w = (float)M_PI_2 + 0.0f * I;
+                       /*mtherr( "casinf", DOMAIN );*/
+               }
+               else {
+                       w = asinf (x) + 0.0f * I;
+               }
+               return (w);
+       }
+
+       /* Power series expansion */
+       /*
+       b = cabsf(z);
+       if(b < 0.125) {
+               z2.r = (x - y) * (x + y);
+               z2.i = 2.0 * x * y;
+
+               cn = 1.0;
+               n = 1.0;
+               ca.r = x;
+               ca.i = y;
+               sum.r = x;
+               sum.i = y;
+               do {
+                       ct.r = z2.r * ca.r  -  z2.i * ca.i;
+                       ct.i = z2.r * ca.i  +  z2.i * ca.r;
+                       ca.r = ct.r;
+                       ca.i = ct.i;
+
+                       cn *= n;
+                       n += 1.0;
+                       cn /= n;
+                       n += 1.0;
+                       b = cn/n;
+
+                       ct.r *= b;
+                       ct.i *= b;
+                       sum.r += ct.r;
+                       sum.i += ct.i;
+                       b = fabsf(ct.r) + fabsf(ct.i);
+               }
+               while(b > MACHEPF);
+               w->r = sum.r;
+               w->i = sum.i;
+               return;
+       }
+       */
+
+
+       ca = x + y * I;
+       ct = ca * I;    /* iz */
+       /* sqrt( 1 - z*z) */
+       /* cmul( &ca, &ca, &zz ) */
+       /*x * x  -  y * y */
+       zz = (x - y) * (x + y) + (2.0f * x * y) * I;
+       zz = 1.0f - crealf(zz) - cimagf(zz) * I;
+       z2 = csqrtf (zz);
+
+       zz = ct + z2;
+       zz = clogf (zz);
+       /* multiply by 1/i = -i */
+       w = zz * (-1.0f * I);
+       return (w);
+}
diff --git a/src/s_casinh.c b/src/s_casinh.c
new file mode 100644 (file)
index 0000000..d3ca8b0
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: s_casinh.c,v 1.6 2013/07/03 04:46:36 espie Exp $      */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casinh
+ *
+ *     Complex inverse hyperbolic sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex casinh();
+ * double complex z, w;
+ *
+ * w = casinh (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * casinh z = -i casin iz .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.8e-14     2.6e-15
+ *
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+casinh(double complex z)
+{
+       double complex w;
+
+       w = -1.0 * I * casin (z * I);
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(casinhl, casinh);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_casinhf.c b/src/s_casinhf.c
new file mode 100644 (file)
index 0000000..8894624
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $OpenBSD: s_casinhf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $  */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casinhf
+ *
+ *     Complex inverse hyperbolic sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex casinhf();
+ * float complex z, w;
+ *
+ * w = casinhf (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * casinh z = -i casin iz .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.8e-14     2.6e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+casinhf(float complex z)
+{
+       float complex w;
+
+       w = -1.0f * I * casinf (z * I);
+       return (w);
+}
diff --git a/src/s_casinhl.c b/src/s_casinhl.c
new file mode 100644 (file)
index 0000000..33ae217
--- /dev/null
@@ -0,0 +1,56 @@
+/*     $OpenBSD: s_casinhl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $  */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casinhl
+ *
+ *     Complex inverse hyperbolic sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex casinhf();
+ * long double complex z, w;
+ *
+ * w = casinhl (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * casinh z = -i casin iz .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.8e-14     2.6e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+casinhl(long double complex z)
+{
+       long double complex w;
+
+       w = -1.0L * I * casinl(z * I);
+       return (w);
+}
diff --git a/src/s_casinl.c b/src/s_casinl.c
new file mode 100644 (file)
index 0000000..b346272
--- /dev/null
@@ -0,0 +1,130 @@
+/*     $OpenBSD: s_casinl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     casinl()
+ *
+ *     Complex circular arc sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex casinl();
+ * long double complex z, w;
+ *
+ * w = casinl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse complex sine:
+ *
+ *                               2
+ * w = -i clog( iz + csqrt( 1 - z ) ).
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10     10100       2.1e-15     3.4e-16
+ *    IEEE      -10,+10     30000       2.2e-14     2.7e-15
+ * Larger relative error can be observed for z near zero.
+ * Also tested by csin(casin(z)) = z.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#if    LDBL_MANT_DIG == 64
+static const long double MACHEPL= 5.42101086242752217003726400434970855712890625E-20L;
+#elif  LDBL_MANT_DIG == 113
+static const long double MACHEPL = 9.629649721936179265279889712924636592690508e-35L;
+#endif
+
+static const long double PIO2L = 1.570796326794896619231321691639751442098585L;
+
+long double complex
+casinl(long double complex z)
+{
+       long double complex w;
+       long double x, y, b;
+       static long double complex ca, ct, zz, z2;
+
+       x = creall(z);
+       y = cimagl(z);
+
+       if (y == 0.0L) {
+               if (fabsl(x) > 1.0L) {
+                       w = PIO2L + 0.0L * I;
+                       /*mtherr( "casinl", DOMAIN );*/
+               }
+               else {
+                       w = asinl(x) + 0.0L * I;
+               }
+               return (w);
+       }
+
+       /* Power series expansion */
+       b = cabsl(z);
+       if (b < 0.125L) {
+               long double complex sum;
+               long double n, cn;
+
+               z2 = (x - y) * (x + y) + (2.0L * x * y) * I;
+               cn = 1.0L;
+               n = 1.0L;
+               ca = x + y * I;
+               sum = x + y * I;
+               do {
+                       ct = z2 * ca;
+                       ca = ct;
+
+                       cn *= n;
+                       n += 1.0L;
+                       cn /= n;
+                       n += 1.0L;
+                       b = cn/n;
+
+                       ct *= b;
+                       sum += ct;
+                       b = cabsl(ct);
+               }
+
+               while (b > MACHEPL);
+               w = sum;
+               return w;
+       }
+
+       ca = x + y * I;
+       ct = ca * I;    /* iz */
+       /* sqrt(1 - z*z) */
+       /* cmul(&ca, &ca, &zz) */
+       /* x * x  -  y * y */
+       zz = (x - y) * (x + y) + (2.0L * x * y) * I;
+       zz = 1.0L - creall(zz) - cimagl(zz) * I;
+       z2 = csqrtl(zz);
+
+       zz = ct + z2;
+       zz = clogl(zz);
+       /* multiply by 1/i = -i */
+       w = zz * (-1.0L * I);
+       return (w);
+}
diff --git a/src/s_catan.c b/src/s_catan.c
new file mode 100644 (file)
index 0000000..2e8bdbb
--- /dev/null
@@ -0,0 +1,131 @@
+/*     $OpenBSD: s_catan.c,v 1.6 2013/07/03 04:46:36 espie Exp $       */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catan()
+ *
+ *     Complex circular arc tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex catan();
+ * double complex z, w;
+ *
+ * w = catan (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ * catan(z) = -i catanh(iz).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5900       1.3e-16     7.8e-18
+ *    IEEE      -10,+10     30000       2.3e-15     8.5e-17
+ * The check catan( ctan(z) )  =  z, with |x| and |y| < PI/2,
+ * had peak relative error 1.5e-16, rms relative error
+ * 2.9e-17.  See also clog().
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#define MAXNUM 1.0e308
+
+static const double DP1 = 3.14159265160560607910E0;
+static const double DP2 = 1.98418714791870343106E-9;
+static const double DP3 = 1.14423774522196636802E-17;
+
+static double
+_redupi(double x)
+{
+       double t;
+       long i;
+
+       t = x/M_PI;
+       if(t >= 0.0)
+               t += 0.5;
+       else
+               t -= 0.5;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return (t);
+}
+
+double complex
+catan(double complex z)
+{
+       double complex w;
+       double a, t, x, x2, y;
+
+       x = creal (z);
+       y = cimag (z);
+
+       if ((x == 0.0) && (y > 1.0))
+               goto ovrf;
+
+       x2 = x * x;
+       a = 1.0 - x2 - (y * y);
+       if (a == 0.0)
+               goto ovrf;
+
+       t = 0.5 * atan2 (2.0 * x, a);
+       w = _redupi (t);
+
+       t = y - 1.0;
+       a = x2 + (t * t);
+       if (a == 0.0)
+       goto ovrf;
+
+       t = y + 1.0;
+       a = (x2 + (t * t))/a;
+       w = w + (0.25 * log (a)) * I;
+       return (w);
+
+ovrf:
+       /*mtherr ("catan", OVERFLOW);*/
+       w = MAXNUM + MAXNUM * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(catanl, catan);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_catanf.c b/src/s_catanf.c
new file mode 100644 (file)
index 0000000..d40cb56
--- /dev/null
@@ -0,0 +1,124 @@
+/*     $OpenBSD: s_catanf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $   */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catanf()
+ *
+ *     Complex circular arc tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex catanf();
+ * float complex z, w;
+ *
+ * w = catanf( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000        2.3e-6      5.2e-8
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#define MAXNUMF 1.0e38F
+
+static const double DP1 = 3.140625;
+static const double DP2 = 9.67502593994140625E-4;
+static const double DP3 = 1.509957990978376432E-7;
+
+static float
+_redupif(float xx)
+{
+       float x, t;
+       long i;
+
+       x = xx;
+       t = x/(float)M_PI;
+       if(t >= 0.0)
+               t += 0.5;
+       else
+               t -= 0.5;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return(t);
+}
+
+float complex
+catanf(float complex z)
+{
+       float complex w;
+       float a, t, x, x2, y;
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       if((x == 0.0f) && (y > 1.0f))
+               goto ovrf;
+
+       x2 = x * x;
+       a = 1.0f - x2 - (y * y);
+       if (a == 0.0f)
+               goto ovrf;
+
+       t = 0.5f * atan2f(2.0f * x, a);
+       w = _redupif(t);
+
+       t = y - 1.0f;
+       a = x2 + (t * t);
+       if(a == 0.0f)
+               goto ovrf;
+
+       t = y + 1.0f;
+       a = (x2 + (t * t))/a;
+       w = w + (0.25f * logf (a)) * I;
+       return (w);
+
+ovrf:
+       /*mtherr( "catanf", OVERFLOW );*/
+       w = MAXNUMF + MAXNUMF * I;
+       return (w);
+}
diff --git a/src/s_catanh.c b/src/s_catanh.c
new file mode 100644 (file)
index 0000000..f4391ee
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: s_catanh.c,v 1.6 2013/07/03 04:46:36 espie Exp $      */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catanh
+ *
+ *     Complex inverse hyperbolic tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex catanh();
+ * double complex z, w;
+ *
+ * w = catanh (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse tanh, equal to  -i catan (iz);
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       2.3e-16     6.2e-17
+ *
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+catanh(double complex z)
+{
+       double complex w;
+
+       w = -1.0 * I * catan (z * I);
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(catanhl, catanh);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_catanhf.c b/src/s_catanhf.c
new file mode 100644 (file)
index 0000000..7d43825
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $OpenBSD: s_catanhf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $  */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catanhf
+ *
+ *     Complex inverse hyperbolic tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex catanhf();
+ * float complex z, w;
+ *
+ * w = catanhf (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse tanh, equal to  -i catan (iz);
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       2.3e-16     6.2e-17
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+catanhf(float complex z)
+{
+       float complex w;
+
+       w = -1.0f * I * catanf (z * I);
+       return (w);
+}
diff --git a/src/s_catanhl.c b/src/s_catanhl.c
new file mode 100644 (file)
index 0000000..711a268
--- /dev/null
@@ -0,0 +1,56 @@
+/*     $OpenBSD: s_catanhl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $  */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catanhl
+ *
+ *     Complex inverse hyperbolic tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex catanhl();
+ * long double complex z, w;
+ *
+ * w = catanhl (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Inverse tanh, equal to  -i catan (iz);
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       2.3e-16     6.2e-17
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+catanhl(long double complex z)
+{
+       long double complex w;
+
+       w = -1.0L * I * catanl(z * I);
+       return (w);
+}
diff --git a/src/s_catanl.c b/src/s_catanl.c
new file mode 100644 (file)
index 0000000..acd51b0
--- /dev/null
@@ -0,0 +1,127 @@
+/*     $OpenBSD: s_catanl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     catanl()
+ *
+ *     Complex circular arc tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex catanl();
+ * long double complex z, w;
+ *
+ * w = catanl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5900       1.3e-16     7.8e-18
+ *    IEEE      -10,+10     30000       2.3e-15     8.5e-17
+ * The check catan( ctan(z) )  =  z, with |x| and |y| < PI/2,
+ * had peak relative error 1.5e-16, rms relative error
+ * 2.9e-17.  See also clog().
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+static const long double PIL = 3.141592653589793238462643383279502884197169L;
+static const long double DP1 = 3.14159265358979323829596852490908531763125L;
+static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L;
+static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L;
+
+static long double
+redupil(long double x)
+{
+       long double t;
+       long i;
+
+       t = x / PIL;
+       if (t >= 0.0L)
+               t += 0.5L;
+       else
+               t -= 0.5L;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return (t);
+}
+
+long double complex
+catanl(long double complex z)
+{
+       long double complex w;
+       long double a, t, x, x2, y;
+
+       x = creall(z);
+       y = cimagl(z);
+
+       if ((x == 0.0L) && (y > 1.0L))
+               goto ovrf;
+
+       x2 = x * x;
+       a = 1.0L - x2 - (y * y);
+       if (a == 0.0L)
+               goto ovrf;
+
+       t = atan2l(2.0L * x, a) * 0.5L;
+       w = redupil(t);
+
+       t = y - 1.0L;
+       a = x2 + (t * t);
+       if (a == 0.0L)
+               goto ovrf;
+
+       t = y + 1.0L;
+       a = (x2 + (t * t)) / a;
+       w = w + (0.25L * logl(a)) * I;
+       return (w);
+
+ovrf:
+       /*mtherr( "catanl", OVERFLOW );*/
+       w = LDBL_MAX + LDBL_MAX * I;
+       return (w);
+}
diff --git a/src/s_cbrt.c b/src/s_cbrt.c
new file mode 100644 (file)
index 0000000..dd3c141
--- /dev/null
@@ -0,0 +1,118 @@
+/* @(#)s_cbrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * Optimized by Bruce D. Evans.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrt.c,v 1.17 2011/03/12 16:50:39 kargl Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const u_int32_t
+       B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */
+       B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */
+
+/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */
+static const double
+P0 =  1.87595182427177009643,          /* 0x3ffe03e6, 0x0f61e692 */
+P1 = -1.88497979543377169875,          /* 0xbffe28e0, 0x92f02420 */
+P2 =  1.621429720105354466140,         /* 0x3ff9f160, 0x4a49d6c2 */
+P3 = -0.758397934778766047437,         /* 0xbfe844cb, 0xbee751d9 */
+P4 =  0.145996192886612446982;         /* 0x3fc2b000, 0xd4e4edd7 */
+
+OLM_DLLEXPORT double
+cbrt(double x)
+{
+       int32_t hx;
+       union {
+           double value;
+           u_int64_t bits;
+       } u;
+       double r,s,t=0.0,w;
+       u_int32_t sign;
+       u_int32_t high,low;
+
+       EXTRACT_WORDS(hx,low,x);
+       sign=hx&0x80000000;             /* sign= sign(x) */
+       hx  ^=sign;
+       if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+
+    /*
+     * Rough cbrt to 5 bits:
+     *    cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3)
+     * where e is integral and >= 0, m is real and in [0, 1), and "/" and
+     * "%" are integer division and modulus with rounding towards minus
+     * infinity.  The RHS is always >= the LHS and has a maximum relative
+     * error of about 1 in 16.  Adding a bias of -0.03306235651 to the
+     * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE
+     * floating point representation, for finite positive normal values,
+     * ordinary integer divison of the value in bits magically gives
+     * almost exactly the RHS of the above provided we first subtract the
+     * exponent bias (1023 for doubles) and later add it back.  We do the
+     * subtraction virtually to keep e >= 0 so that ordinary integer
+     * division rounds towards minus infinity; this is also efficient.
+     */
+       if(hx<0x00100000) {             /* zero or subnormal? */
+           if((hx|low)==0)
+               return(x);              /* cbrt(0) is itself */
+           SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */
+           t*=x;
+           GET_HIGH_WORD(high,t);
+           INSERT_WORDS(t,sign|((high&0x7fffffff)/3+B2),0);
+       } else
+           INSERT_WORDS(t,sign|(hx/3+B1),0);
+
+    /*
+     * New cbrt to 23 bits:
+     *    cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x)
+     * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r)
+     * to within 2**-23.5 when |r - 1| < 1/10.  The rough approximation
+     * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this
+     * gives us bounds for r = t**3/x.
+     *
+     * Try to optimize for parallel evaluation as in k_tanf.c.
+     */
+       r=(t*t)*(t/x);
+       t=t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4));
+
+    /*
+     * Round t away from zero to 23 bits (sloppily except for ensuring that
+     * the result is larger in magnitude than cbrt(x) but not much more than
+     * 2 23-bit ulps larger).  With rounding towards zero, the error bound
+     * would be ~5/6 instead of ~4/6.  With a maximum error of 2 23-bit ulps
+     * in the rounded t, the infinite-precision error in the Newton
+     * approximation barely affects third digit in the final error
+     * 0.667; the error in the rounded t can be up to about 3 23-bit ulps
+     * before the final error is larger than 0.667 ulps.
+     */
+       u.value=t;
+       u.bits=(u.bits+0x80000000)&0xffffffffc0000000ULL;
+       t=u.value;
+
+    /* one step Newton iteration to 53 bits with error < 0.667 ulps */
+       s=t*t;                          /* t*t is exact */
+       r=x/s;                          /* error <= 0.5 ulps; |r| < |t| */
+       w=t+t;                          /* t+t is exact */
+       r=(r-t)/(w+r);                  /* r-t is exact; w+r ~= 3*t */
+       t=t+t*r;                        /* error <= 0.5 + 0.5/3 + epsilon */
+
+       return(t);
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(cbrt, cbrtl);
+#endif
diff --git a/src/s_cbrtf.c b/src/s_cbrtf.c
new file mode 100644 (file)
index 0000000..6a3a762
--- /dev/null
@@ -0,0 +1,74 @@
+/* s_cbrtf.c -- float version of s_cbrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrtf.c,v 1.18 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/* cbrtf(x)
+ * Return cube root of x
+ */
+static const unsigned
+       B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */
+       B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
+
+OLM_DLLEXPORT float
+cbrtf(float x)
+{
+       double r,T;
+       float t;
+       int32_t hx;
+       u_int32_t sign;
+       u_int32_t high;
+
+       GET_FLOAT_WORD(hx,x);
+       sign=hx&0x80000000;             /* sign= sign(x) */
+       hx  ^=sign;
+       if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */
+
+    /* rough cbrt to 5 bits */
+       if(hx<0x00800000) {             /* zero or subnormal? */
+           if(hx==0)
+               return(x);              /* cbrt(+-0) is itself */
+           SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */
+           t*=x;
+           GET_FLOAT_WORD(high,t);
+           SET_FLOAT_WORD(t,sign|((high&0x7fffffff)/3+B2));
+       } else
+           SET_FLOAT_WORD(t,sign|(hx/3+B1));
+
+    /*
+     * First step Newton iteration (solving t*t-x/t == 0) to 16 bits.  In
+     * double precision so that its terms can be arranged for efficiency
+     * without causing overflow or underflow.
+     */
+       T=t;
+       r=T*T*T;
+       T=T*((double)x+x+r)/(x+r+r);
+
+    /*
+     * Second step Newton iteration to 47 bits.  In double precision for
+     * efficiency and accuracy.
+     */
+       r=T*T*T;
+       T=T*((double)x+x+r)/(x+r+r);
+
+    /* rounding to 24 bits is perfect in round-to-nearest mode */
+       return(T);
+}
diff --git a/src/s_cbrtl.c b/src/s_cbrtl.c
new file mode 100644 (file)
index 0000000..2fe0360
--- /dev/null
@@ -0,0 +1,161 @@
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * The argument reduction and testing for exceptional cases was
+ * written by Steven G. Kargl with input from Bruce D. Evans
+ * and David A. Schultz.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrtl.c,v 1.1 2011/03/12 19:37:35 kargl Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+// VBS
+//#include <ieeefp.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+#if defined(__i386__)
+#include "i387/bsd_ieeefp.h"
+#endif
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+
+static const unsigned
+    B1 = 709958130;    /* B1 = (127-127.0/3-0.03306235651)*2**23 */
+
+OLM_DLLEXPORT long double
+cbrtl(long double x)
+{
+       union IEEEl2bits u, v;
+       long double r, s, t, w;
+       double dr, dt, dx;
+       float ft, fx;
+       u_int32_t hx;
+       u_int16_t expsign;
+       int k;
+
+       u.e = x;
+       expsign = u.xbits.expsign;
+       k = expsign & 0x7fff;
+
+       /*
+        * If x = +-Inf, then cbrt(x) = +-Inf.
+        * If x = NaN, then cbrt(x) = NaN.
+        */
+       if (k == BIAS + LDBL_MAX_EXP)
+               return (x + x);
+
+#ifdef __i386__
+       fp_prec_t oprec;
+
+       oprec = fpgetprec();
+       if (oprec != FP_PE)
+               fpsetprec(FP_PE);
+#endif
+
+       if (k == 0) {
+               /* If x = +-0, then cbrt(x) = +-0. */
+               if ((u.bits.manh | u.bits.manl) == 0) {
+#ifdef __i386__
+                       if (oprec != FP_PE)
+                               fpsetprec(oprec);
+#endif
+                       return (x);
+               }
+               /* Adjust subnormal numbers. */
+               u.e *= 0x1.0p514;
+               k = u.bits.exp;
+               k -= BIAS + 514;
+       } else
+               k -= BIAS;
+       u.xbits.expsign = BIAS;
+       v.e = 1; 
+
+       x = u.e;
+       switch (k % 3) {
+       case 1:
+       case -2:
+               x = 2*x;
+               k--;
+               break;
+       case 2:
+       case -1:
+               x = 4*x;
+               k -= 2;
+               break;
+       }
+       v.xbits.expsign = (expsign & 0x8000) | (BIAS + k / 3);
+
+       /*
+        * The following is the guts of s_cbrtf, with the handling of
+        * special values removed and extra care for accuracy not taken,
+        * but with most of the extra accuracy not discarded.
+        */
+
+       /* ~5-bit estimate: */
+       fx = x;
+       GET_FLOAT_WORD(hx, fx);
+       SET_FLOAT_WORD(ft, ((hx & 0x7fffffff) / 3 + B1));
+
+       /* ~16-bit estimate: */
+       dx = x;
+       dt = ft;
+       dr = dt * dt * dt;
+       dt = dt * (dx + dx + dr) / (dx + dr + dr);
+
+       /* ~47-bit estimate: */
+       dr = dt * dt * dt;
+       dt = dt * (dx + dx + dr) / (dx + dr + dr);
+
+#if LDBL_MANT_DIG == 64
+       /*
+        * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8).
+        * Round it away from zero to 32 bits (32 so that t*t is exact, and
+        * away from zero for technical reasons).
+        */
+       volatile double vd2 = 0x1.0p32;
+       volatile double vd1 = 0x1.0p-31;
+       #define vd ((long double)vd2 + vd1)
+
+       t = dt + vd - 0x1.0p32;
+#elif LDBL_MANT_DIG == 113
+       /*
+        * Round dt away from zero to 47 bits.  Since we don't trust the 47,
+        * add 2 47-bit ulps instead of 1 to round up.  Rounding is slow and
+        * might be avoidable in this case, since on most machines dt will
+        * have been evaluated in 53-bit precision and the technical reasons
+        * for rounding up might not apply to either case in cbrtl() since
+        * dt is much more accurate than needed.
+        */
+       t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60;
+#else
+#error "Unsupported long double format"
+#endif
+
+       /*
+        * Final step Newton iteration to 64 or 113 bits with
+        * error < 0.667 ulps
+        */
+       s=t*t;                          /* t*t is exact */
+       r=x/s;                          /* error <= 0.5 ulps; |r| < |t| */
+       w=t+t;                          /* t+t is exact */
+       r=(r-t)/(w+r);                  /* r-t is exact; w+r ~= 3*t */
+       t=t+t*r;                        /* error <= 0.5 + 0.5/3 + epsilon */
+
+       t *= v.e;
+#ifdef __i386__
+       if (oprec != FP_PE)
+               fpsetprec(oprec);
+#endif
+       return (t);
+}
diff --git a/src/s_ccos.c b/src/s_ccos.c
new file mode 100644 (file)
index 0000000..48f2b7b
--- /dev/null
@@ -0,0 +1,89 @@
+/*     $OpenBSD: s_ccos.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ccos()
+ *
+ *     Complex circular cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex ccos();
+ * double complex z, w;
+ *
+ * w = ccos (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = cos x  cosh y  -  i sin x sinh y.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      8400       4.5e-17     1.3e-17
+ *    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+/* calculate cosh and sinh */
+
+static void
+_cchsh(double x, double *c, double *s)
+{
+       double e, ei;
+
+       if (fabs(x) <= 0.5) {
+               *c = cosh(x);
+               *s = sinh(x);
+       }
+       else {
+               e = exp(x);
+               ei = 0.5/e;
+               e = 0.5 * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+double complex
+ccos(double complex z)
+{
+       double complex w;
+       double ch, sh;
+
+       _cchsh( cimag(z), &ch, &sh );
+       w = cos(creal (z)) * ch - (sin (creal (z)) * sh) * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(ccosl, ccos);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_ccosf.c b/src/s_ccosf.c
new file mode 100644 (file)
index 0000000..ce382f0
--- /dev/null
@@ -0,0 +1,84 @@
+/*     $OpenBSD: s_ccosf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $    */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ccosf()
+ *
+ *     Complex circular cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void ccosf();
+ * cmplxf z, w;
+ *
+ * ccosf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = cos x  cosh y  -  i sin x sinh y.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.8e-7       5.5e-8
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+/* calculate cosh and sinh */
+
+static void
+_cchshf(float xx, float *c, float *s)
+{
+       float x, e, ei;
+
+       x = xx;
+       if(fabsf(x) <= 0.5f) {
+               *c = coshf(x);
+               *s = sinhf(x);
+       }
+       else {
+               e = expf(x);
+               ei = 0.5f/e;
+               e = 0.5f * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+float complex
+ccosf(float complex z)
+{
+       float complex w;
+       float ch, sh;
+
+       _cchshf( cimagf(z), &ch, &sh );
+       w = cosf( crealf(z) ) * ch + ( -sinf( crealf(z) ) * sh) * I;
+       return (w);
+}
diff --git a/src/s_ccosh.c b/src/s_ccosh.c
new file mode 100644 (file)
index 0000000..110494a
--- /dev/null
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and 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.
+ *
+ * cosh(z) = cosh(x+iy)
+ *         = cosh(x) cos(y) + i sinh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ccosh.c,v 1.2 2011/10/21 06:29:32 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double huge = 0x1p1023;
+
+OLM_DLLEXPORT double complex
+ccosh(double complex z)
+{
+       double x, y, h;
+       int32_t hx, hy, ix, iy, lx, ly;
+
+       x = creal(z);
+       y = cimag(z);
+
+       EXTRACT_WORDS(hx, lx, x);
+       EXTRACT_WORDS(hy, ly, y);
+
+       ix = 0x7fffffff & hx;
+       iy = 0x7fffffff & hy;
+
+       /* Handle the nearly-non-exceptional cases where x and y are finite. */
+       if (ix < 0x7ff00000 && iy < 0x7ff00000) {
+               if ((iy | ly) == 0)
+                       return (CMPLX(cosh(x), x * y));
+               if (ix < 0x40360000)    /* small x: normal case */
+                       return (CMPLX(cosh(x) * cos(y), sinh(x) * sin(y)));
+
+               /* |x| >= 22, so cosh(x) ~= exp(|x|) */
+               if (ix < 0x40862e42) {
+                       /* x < 710: exp(|x|) won't overflow */
+                       h = exp(fabs(x)) * 0.5;
+                       return (CMPLX(h * cos(y), copysign(h, x) * sin(y)));
+               } else if (ix < 0x4096bbaa) {
+                       /* x < 1455: scale to avoid overflow */
+                       z = __ldexp_cexp(CMPLX(fabs(x), y), -1);
+                       return (CMPLX(creal(z), cimag(z) * copysign(1, x)));
+               } else {
+                       /* x >= 1455: the result always overflows */
+                       h = huge * x;
+                       return (CMPLX(h * h * cos(y), h * sin(y)));
+               }
+       }
+
+       /*
+        * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0.
+        * The sign of 0 in the result is unspecified.  Choice = normally
+        * the same as dNaN.  Raise the invalid floating-point exception.
+        *
+        * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0.
+        * The sign of 0 in the result is unspecified.  Choice = normally
+        * the same as d(NaN).
+        */
+       if ((ix | lx) == 0 && iy >= 0x7ff00000)
+               return (CMPLX(y - y, copysign(0, x * (y - y))));
+
+       /*
+        * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0.
+        *
+        * cosh(NaN +- I 0)   = d(NaN) + I sign(d(NaN, +-0))0.
+        * The sign of 0 in the result is unspecified.
+        */
+       if ((iy | ly) == 0 && ix >= 0x7ff00000) {
+               if (((hx & 0xfffff) | lx) == 0)
+                       return (CMPLX(x * x, copysign(0, x) * y));
+               return (CMPLX(x * x, copysign(0, (x + x) * y)));
+       }
+
+       /*
+        * cosh(x +- I Inf) = dNaN + I dNaN.
+        * Raise the invalid floating-point exception for finite nonzero x.
+        *
+        * cosh(x + I NaN) = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception for finite
+        * nonzero x.  Choice = don't raise (except for signaling NaNs).
+        */
+       if (ix < 0x7ff00000 && iy >= 0x7ff00000)
+               return (CMPLX(y - y, x * (y - y)));
+
+       /*
+        * cosh(+-Inf + I NaN)  = +Inf + I d(NaN).
+        *
+        * cosh(+-Inf +- I Inf) = +Inf + I dNaN.
+        * The sign of Inf in the result is unspecified.  Choice = always +.
+        * Raise the invalid floating-point exception.
+        *
+        * cosh(+-Inf + I y)   = +Inf cos(y) +- I Inf sin(y)
+        */
+       if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+               if (iy >= 0x7ff00000)
+                       return (CMPLX(x * x, x * (y - y)));
+               return (CMPLX((x * x) * cos(y), x * sin(y)));
+       }
+
+       /*
+        * cosh(NaN + I NaN)  = d(NaN) + I d(NaN).
+        *
+        * cosh(NaN +- I Inf) = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception.
+        * Choice = raise.
+        *
+        * cosh(NaN + I y)    = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception for finite
+        * nonzero y.  Choice = don't raise (except for signaling NaNs).
+        */
+       return (CMPLX((x * x) * (y - y), (x + x) * (y - y)));
+}
+
+OLM_DLLEXPORT double complex
+ccos(double complex z)
+{
+
+       /* ccos(z) = ccosh(I * z) */
+       return (ccosh(CMPLX(-cimag(z), creal(z))));
+}
diff --git a/src/s_ccoshf.c b/src/s_ccoshf.c
new file mode 100644 (file)
index 0000000..53c8e7a
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and 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.  See s_ccosh.c for details.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ccoshf.c,v 1.2 2011/10/21 06:29:32 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float huge = 0x1p127;
+
+OLM_DLLEXPORT float complex
+ccoshf(float complex z)
+{
+       float x, y, h;
+       int32_t hx, hy, ix, iy;
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       GET_FLOAT_WORD(hx, x);
+       GET_FLOAT_WORD(hy, y);
+
+       ix = 0x7fffffff & hx;
+       iy = 0x7fffffff & hy;
+
+       if (ix < 0x7f800000 && iy < 0x7f800000) {
+               if (iy == 0)
+                       return (CMPLXF(coshf(x), x * y));
+               if (ix < 0x41100000)    /* small x: normal case */
+                       return (CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y)));
+
+               /* |x| >= 9, so cosh(x) ~= exp(|x|) */
+               if (ix < 0x42b17218) {
+                       /* x < 88.7: expf(|x|) won't overflow */
+                       h = expf(fabsf(x)) * 0.5f;
+                       return (CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y)));
+               } else if (ix < 0x4340b1e7) {
+                       /* x < 192.7: scale to avoid overflow */
+                       z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1);
+                       return (CMPLXF(crealf(z), cimagf(z) * copysignf(1, x)));
+               } else {
+                       /* x >= 192.7: the result always overflows */
+                       h = huge * x;
+                       return (CMPLXF(h * h * cosf(y), h * sinf(y)));
+               }
+       }
+
+       if (ix == 0 && iy >= 0x7f800000)
+               return (CMPLXF(y - y, copysignf(0, x * (y - y))));
+
+       if (iy == 0 && ix >= 0x7f800000) {
+               if ((hx & 0x7fffff) == 0)
+                       return (CMPLXF(x * x, copysignf(0, x) * y));
+               return (CMPLXF(x * x, copysignf(0, (x + x) * y)));
+       }
+
+       if (ix < 0x7f800000 && iy >= 0x7f800000)
+               return (CMPLXF(y - y, x * (y - y)));
+
+       if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+               if (iy >= 0x7f800000)
+                       return (CMPLXF(x * x, x * (y - y)));
+               return (CMPLXF((x * x) * cosf(y), x * sinf(y)));
+       }
+
+       return (CMPLXF((x * x) * (y - y), (x + x) * (y - y)));
+}
+
+OLM_DLLEXPORT float complex
+ccosf(float complex z)
+{
+
+       return (ccoshf(CMPLXF(-cimagf(z), crealf(z))));
+}
diff --git a/src/s_ccoshl.c b/src/s_ccoshl.c
new file mode 100644 (file)
index 0000000..0233d19
--- /dev/null
@@ -0,0 +1,59 @@
+/*     $OpenBSD: s_ccoshl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ccoshl
+ *
+ *     Complex hyperbolic cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex ccoshl();
+ * long double complex z, w;
+ *
+ * w = ccoshl (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * ccosh(z) = cosh x  cos y + i sinh x sin y .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       2.9e-16     8.1e-17
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+ccoshl(long double complex z)
+{
+       long double complex w;
+       long double x, y;
+
+       x = creall(z);
+       y = cimagl(z);
+       w = coshl(x) * cosl(y) + (sinhl(x) * sinl(y)) * I;
+       return (w);
+}
diff --git a/src/s_ccosl.c b/src/s_ccosl.c
new file mode 100644 (file)
index 0000000..0d50483
--- /dev/null
@@ -0,0 +1,82 @@
+/*     $OpenBSD: s_ccosl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ccosl()
+ *
+ *     Complex circular cosine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex ccosl();
+ * long double complex z, w;
+ *
+ * w = ccosl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = cos x  cosh y  -  i sin x sinh y.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      8400       4.5e-17     1.3e-17
+ *    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+static void
+cchshl(long double x, long double *c, long double *s)
+{
+       long double e, ei;
+
+       if(fabsl(x) <= 0.5L) {
+               *c = coshl(x);
+               *s = sinhl(x);
+       } else {
+               e = expl(x);
+               ei = 0.5L/e;
+               e = 0.5L * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+long double complex
+ccosl(long double complex z)
+{
+       long double complex w;
+       long double ch, sh;
+
+       cchshl(cimagl(z), &ch, &sh);
+       w = cosl(creall(z)) * ch + (-sinl(creall(z)) * sh) * I;
+       return (w);
+}
diff --git a/src/s_ceil.c b/src/s_ceil.c
new file mode 100644 (file)
index 0000000..bdac17f
--- /dev/null
@@ -0,0 +1,77 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ceil.c,v 1.11 2008/02/15 07:01:40 bde Exp $");
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+OLM_DLLEXPORT double
+ceil(double x)
+{
+       int32_t i0,i1,j0;
+       u_int32_t i,j;
+       EXTRACT_WORDS(i0,i1,x);
+       j0 = ((i0>>20)&0x7ff)-0x3ff;
+       if(j0<20) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0<0) {i0=0x80000000;i1=0;}
+                   else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+               }
+           } else {
+               i = (0x000fffff)>>j0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(i0>0) i0 += (0x00100000)>>j0;
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (j0>51) {
+           if(j0==0x400) return x+x;   /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(j0-20);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(i0>0) {
+                   if(j0==20) i0+=1;
+                   else {
+                       j = i1 + (1<<(52-j0));
+                       if(j<i1) i0+=1; /* got a carry */
+                       i1 = j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       INSERT_WORDS(x,i0,i1);
+       return x;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(ceil, ceill);
+#endif
diff --git a/src/s_ceilf.c b/src/s_ceilf.c
new file mode 100644 (file)
index 0000000..5e2a568
--- /dev/null
@@ -0,0 +1,53 @@
+/* s_ceilf.c -- float version of s_ceil.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ceilf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+OLM_DLLEXPORT float
+ceilf(float x)
+{
+       int32_t i0,j0;
+       u_int32_t i;
+
+       GET_FLOAT_WORD(i0,x);
+       j0 = ((i0>>23)&0xff)-0x7f;
+       if(j0<23) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0<0) {i0=0x80000000;}
+                   else if(i0!=0) { i0=0x3f800000;}
+               }
+           } else {
+               i = (0x007fffff)>>j0;
+               if((i0&i)==0) return x; /* x is integral */
+               if(huge+x>(float)0.0) { /* raise inexact flag */
+                   if(i0>0) i0 += (0x00800000)>>j0;
+                   i0 &= (~i);
+               }
+           }
+       } else {
+           if(j0==0x80) return x+x;    /* inf or NaN */
+           else return x;              /* x is integral */
+       }
+       SET_FLOAT_WORD(x,i0);
+       return x;
+}
diff --git a/src/s_ceill.c b/src/s_ceill.c
new file mode 100644 (file)
index 0000000..f525411
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * From: @(#)s_ceil.c 5.1 93/09/24
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ceill.c,v 1.9 2008/02/14 15:10:33 bde Exp $");
+
+/*
+ * ceill(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to ceill(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define        MANH_SIZE       (LDBL_MANH_SIZE + 1)
+#define        INC_MANH(u, c)  do {                                    \
+       u_int64_t o = u.bits.manh;                              \
+       u.bits.manh += (c);                                     \
+       if (u.bits.manh < o)                                    \
+               u.bits.exp++;                                   \
+} while (0)
+#else
+#define        MANH_SIZE       LDBL_MANH_SIZE
+#define        INC_MANH(u, c)  do {                                    \
+       u_int64_t o = u.bits.manh;                              \
+       u.bits.manh += (c);                                     \
+       if (u.bits.manh < o) {                                  \
+               u.bits.exp++;                                   \
+               u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1);    \
+       }                                                       \
+} while (0)
+#endif
+
+static const long double huge = 1.0e300;
+
+OLM_DLLEXPORT long double
+ceill(long double x)
+{
+       union IEEEl2bits u = { .e = x };
+       int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+       if (e < MANH_SIZE - 1) {
+               if (e < 0) {                    /* raise inexact if x != 0 */
+                       if (huge + x > 0.0)
+                               if (u.bits.exp > 0 ||
+                                   (u.bits.manh | u.bits.manl) != 0)
+                                       u.e = u.bits.sign ? -0.0 : 1.0;
+               } else {
+                       u_int64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+                       if (((u.bits.manh & m) | u.bits.manl) == 0)
+                               return (x);     /* x is integral */
+                       if (!u.bits.sign) {
+#ifdef LDBL_IMPLICIT_NBIT
+                               if (e == 0)
+                                       u.bits.exp++;
+                               else
+#endif
+                               INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
+                       }
+                       if (huge + x > 0.0) {   /* raise inexact flag */
+                               u.bits.manh &= ~m;
+                               u.bits.manl = 0;
+                       }
+               }
+       } else if (e < LDBL_MANT_DIG - 1) {
+               u_int64_t m = (u_int64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+               if ((u.bits.manl & m) == 0)
+                       return (x);     /* x is integral */
+               if (!u.bits.sign) {
+                       if (e == MANH_SIZE - 1)
+                               INC_MANH(u, 1);
+                       else {
+                               u_int64_t o = u.bits.manl;
+                               u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
+                               if (u.bits.manl < o)    /* got a carry */
+                                       INC_MANH(u, 1);
+                       }
+               }
+               if (huge + x > 0.0)             /* raise inexact flag */
+                       u.bits.manl &= ~m;
+       }
+       return (u.e);
+}
diff --git a/src/s_cexp.c b/src/s_cexp.c
new file mode 100644 (file)
index 0000000..1510721
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cexp.c,v 1.3 2011/10/21 06:27:56 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const u_int32_t
+exp_ovfl  = 0x40862e42,                        /* high bits of MAX_EXP * ln2 ~= 710 */
+cexp_ovfl = 0x4096b8e4;                        /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */
+
+OLM_DLLEXPORT double complex
+cexp(double complex z)
+{
+       double x, y, exp_x;
+       u_int32_t hx, hy, lx, ly;
+
+       x = creal(z);
+       y = cimag(z);
+
+       EXTRACT_WORDS(hy, ly, y);
+       hy &= 0x7fffffff;
+
+       /* cexp(x + I 0) = exp(x) + I 0 */
+       if ((hy | ly) == 0)
+               return (CMPLX(exp(x), y));
+       EXTRACT_WORDS(hx, lx, x);
+       /* cexp(0 + I y) = cos(y) + I sin(y) */
+       if (((hx & 0x7fffffff) | lx) == 0)
+               return (CMPLX(cos(y), sin(y)));
+
+       if (hy >= 0x7ff00000) {
+               if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) {
+                       /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
+                       return (CMPLX(y - y, y - y));
+               } else if (hx & 0x80000000) {
+                       /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
+                       return (CMPLX(0.0, 0.0));
+               } else {
+                       /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
+                       return (CMPLX(x, y - y));
+               }
+       }
+
+       if (hx >= exp_ovfl && hx <= cexp_ovfl) {
+               /*
+                * x is between 709.7 and 1454.3, so we must scale to avoid
+                * overflow in exp(x).
+                */
+               return (__ldexp_cexp(z, 0));
+       } else {
+               /*
+                * Cases covered here:
+                *  -  x < exp_ovfl and exp(x) won't overflow (common case)
+                *  -  x > cexp_ovfl, so exp(x) * s overflows for all s > 0
+                *  -  x = +-Inf (generated by exp())
+                *  -  x = NaN (spurious inexact exception from y)
+                */
+               exp_x = exp(x);
+               return (CMPLX(exp_x * cos(y), exp_x * sin(y)));
+       }
+}
diff --git a/src/s_cexpf.c b/src/s_cexpf.c
new file mode 100644 (file)
index 0000000..05f4544
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cexpf.c,v 1.3 2011/10/21 06:27:56 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const u_int32_t
+exp_ovfl  = 0x42b17218,                /* MAX_EXP * ln2 ~= 88.722839355 */
+cexp_ovfl = 0x43400074;                /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */
+
+OLM_DLLEXPORT float complex
+cexpf(float complex z)
+{
+       float x, y, exp_x;
+       u_int32_t hx, hy;
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       GET_FLOAT_WORD(hy, y);
+       hy &= 0x7fffffff;
+
+       /* cexp(x + I 0) = exp(x) + I 0 */
+       if (hy == 0)
+               return (CMPLXF(expf(x), y));
+       GET_FLOAT_WORD(hx, x);
+       /* cexp(0 + I y) = cos(y) + I sin(y) */
+       if ((hx & 0x7fffffff) == 0)
+               return (CMPLXF(cosf(y), sinf(y)));
+
+       if (hy >= 0x7f800000) {
+               if ((hx & 0x7fffffff) != 0x7f800000) {
+                       /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
+                       return (CMPLXF(y - y, y - y));
+               } else if (hx & 0x80000000) {
+                       /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
+                       return (CMPLXF(0.0, 0.0));
+               } else {
+                       /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
+                       return (CMPLXF(x, y - y));
+               }
+       }
+
+       if (hx >= exp_ovfl && hx <= cexp_ovfl) {
+               /*
+                * x is between 88.7 and 192, so we must scale to avoid
+                * overflow in expf(x).
+                */
+               return (__ldexp_cexpf(z, 0));
+       } else {
+               /*
+                * Cases covered here:
+                *  -  x < exp_ovfl and exp(x) won't overflow (common case)
+                *  -  x > cexp_ovfl, so exp(x) * s overflows for all s > 0
+                *  -  x = +-Inf (generated by exp())
+                *  -  x = NaN (spurious inexact exception from y)
+                */
+               exp_x = expf(x);
+               return (CMPLXF(exp_x * cosf(y), exp_x * sinf(y)));
+       }
+}
diff --git a/src/s_cexpl.c b/src/s_cexpl.c
new file mode 100644 (file)
index 0000000..f143d88
--- /dev/null
@@ -0,0 +1,69 @@
+/*     $OpenBSD: s_cexpl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cexpl()
+ *
+ *     Complex exponential function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex cexpl();
+ * long double complex z, w;
+ *
+ * w = cexpl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns the exponential of the complex argument z
+ * into the complex result w.
+ *
+ * If
+ *     z = x + iy,
+ *     r = exp(x),
+ *
+ * then
+ *
+ *     w = r cos y + i r sin y.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      8700       3.7e-17     1.1e-17
+ *    IEEE      -10,+10     30000       3.0e-16     8.7e-17
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+cexpl(long double complex z)
+{
+       long double complex w;
+       long double r;
+
+       r = expl(creall(z));
+       w = r * cosl(cimagl(z)) + (r * sinl(cimagl(z))) * I;
+       return (w);
+}
diff --git a/src/s_cimag.c b/src/s_cimag.c
new file mode 100644 (file)
index 0000000..456ae99
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_cimag.c,v 1.3 2009/03/14 18:24:15 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+cimag(double complex z)
+{
+       return (__imag__ z);
+}
diff --git a/src/s_cimagf.c b/src/s_cimagf.c
new file mode 100644 (file)
index 0000000..8287412
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_cimagf.c,v 1.3 2009/03/14 18:24:15 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+cimagf(float complex z)
+{
+       return (__imag__ z);
+}
diff --git a/src/s_cimagl.c b/src/s_cimagl.c
new file mode 100644 (file)
index 0000000..588c6a3
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_cimagl.c,v 1.3 2009/03/14 18:24:15 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+cimagl(long double complex z)
+{
+       return (__imag__ z);
+}
diff --git a/src/s_clog.c b/src/s_clog.c
new file mode 100644 (file)
index 0000000..30ea5ea
--- /dev/null
@@ -0,0 +1,77 @@
+/*     $OpenBSD: s_clog.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     clog.c
+ *
+ *     Complex natural logarithm
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex clog();
+ * double complex z, w;
+ *
+ * w = clog (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns complex logarithm to the base e (2.718...) of
+ * the complex argument x.
+ *
+ * If z = x + iy, r = sqrt( x**2 + y**2 ),
+ * then
+ *       w = log(r) + i arctan(y/x).
+ * 
+ * The arctangent ranges from -PI to +PI.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      7000       8.5e-17     1.9e-17
+ *    IEEE      -10,+10     30000       5.0e-15     1.1e-16
+ *
+ * Larger relative error can be observed for z near 1 +i0.
+ * In IEEE arithmetic the peak absolute error is 5.2e-16, rms
+ * absolute error 1.0e-16.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+double complex
+clog(double complex z)
+{
+       double complex w;
+       double p, rr;
+
+       /*rr = sqrt( z->r * z->r  +  z->i * z->i );*/
+       rr = cabs(z);
+       p = log(rr);
+       rr = atan2 (cimag (z), creal (z));
+       w = p + rr * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(clogl, clog);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_clogf.c b/src/s_clogf.c
new file mode 100644 (file)
index 0000000..e157aae
--- /dev/null
@@ -0,0 +1,72 @@
+/*     $OpenBSD: s_clogf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $    */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     clogf.c
+ *
+ *     Complex natural logarithm
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void clogf();
+ * cmplxf z, w;
+ *
+ * clogf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns complex logarithm to the base e (2.718...) of
+ * the complex argument x.
+ *
+ * If z = x + iy, r = sqrt( x**2 + y**2 ),
+ * then
+ *       w = log(r) + i arctan(y/x).
+ *
+ * The arctangent ranges from -PI to +PI.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.9e-6       6.2e-8
+ *
+ * Larger relative error can be observed for z near 1 +i0.
+ * In IEEE arithmetic the peak absolute error is 3.1e-7.
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+float complex
+clogf(float complex z)
+{
+       float complex w;
+       float p, rr, x, y;
+
+       x = crealf(z);
+       y = cimagf(z);
+       rr = atan2f(y, x);
+       p = cabsf(z);
+       p = logf(p);
+       w = p + rr * I;
+       return (w);
+}
diff --git a/src/s_clogl.c b/src/s_clogl.c
new file mode 100644 (file)
index 0000000..c337103
--- /dev/null
@@ -0,0 +1,73 @@
+/*     $OpenBSD: s_clogl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     clogl.c
+ *
+ *     Complex natural logarithm
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex clogl();
+ * long double complex z, w;
+ *
+ * w = clogl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns complex logarithm to the base e (2.718...) of
+ * the complex argument x.
+ *
+ * If z = x + iy, r = sqrt( x**2 + y**2 ),
+ * then
+ *       w = log(r) + i arctan(y/x).
+ *
+ * The arctangent ranges from -PI to +PI.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      7000       8.5e-17     1.9e-17
+ *    IEEE      -10,+10     30000       5.0e-15     1.1e-16
+ *
+ * Larger relative error can be observed for z near 1 +i0.
+ * In IEEE arithmetic the peak absolute error is 5.2e-16, rms
+ * absolute error 1.0e-16.
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+clogl(long double complex z)
+{
+       long double complex w;
+       long double p, rr;
+
+       /*rr = sqrt(z->r * z->r  +  z->i * z->i);*/
+       p = cabsl(z);
+       p = logl(p);
+       rr = atan2l(cimagl(z), creall(z));
+       w = p + rr * I;
+       return (w);
+}
diff --git a/src/s_conj.c b/src/s_conj.c
new file mode 100644 (file)
index 0000000..a7c0940
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_conj.c,v 1.2 2008/08/07 14:39:56 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double complex
+conj(double complex z)
+{
+
+       return (CMPLX(creal(z), -cimag(z)));
+}
diff --git a/src/s_conjf.c b/src/s_conjf.c
new file mode 100644 (file)
index 0000000..d2ff743
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_conjf.c,v 1.2 2008/08/07 14:39:56 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float complex
+conjf(float complex z)
+{
+
+       return (CMPLXF(crealf(z), -cimagf(z)));
+}
diff --git a/src/s_conjl.c b/src/s_conjl.c
new file mode 100644 (file)
index 0000000..e4d7a01
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_conjl.c,v 1.2 2008/08/07 14:39:56 das Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double complex
+conjl(long double complex z)
+{
+
+       return (CMPLXL(creall(z), -cimagl(z)));
+}
diff --git a/src/s_copysign.c b/src/s_copysign.c
new file mode 100644 (file)
index 0000000..a52701f
--- /dev/null
@@ -0,0 +1,34 @@
+/* @(#)s_copysign.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_copysign.c,v 1.10 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+copysign(double x, double y)
+{
+       u_int32_t hx,hy;
+       GET_HIGH_WORD(hx,x);
+       GET_HIGH_WORD(hy,y);
+       SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
+        return x;
+}
diff --git a/src/s_copysignf.c b/src/s_copysignf.c
new file mode 100644 (file)
index 0000000..945b3fd
--- /dev/null
@@ -0,0 +1,37 @@
+/* s_copysignf.c -- float version of s_copysign.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_copysignf.c,v 1.10 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+copysignf(float x, float y)
+{
+       u_int32_t ix,iy;
+       GET_FLOAT_WORD(ix,x);
+       GET_FLOAT_WORD(iy,y);
+       SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+        return x;
+}
diff --git a/src/s_copysignl.c b/src/s_copysignl.c
new file mode 100644 (file)
index 0000000..6cae5d3
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_copysignl.c,v 1.2 2007/01/07 07:54:21 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+copysignl(long double x, long double y)
+{
+       union IEEEl2bits ux, uy;
+
+       ux.e = x;
+       uy.e = y;
+       ux.bits.sign = uy.bits.sign;
+       return (ux.e);
+}
diff --git a/src/s_cos.c b/src/s_cos.c
new file mode 100644 (file)
index 0000000..ea84163
--- /dev/null
@@ -0,0 +1,89 @@
+/* @(#)s_cos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cos.c,v 1.13 2011/02/10 07:37:50 das Exp $");
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ *     __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *     __kernel_cos            ... cosine function on [-pi/4,pi/4]
+ *     __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *     [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *     in [-pi/4 , +pi/4], and let n = k mod 4.
+ *     We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *         0          S           C             T
+ *         1          C          -S            -1/T
+ *         2         -S          -C             T
+ *         3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *     TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define INLINE_REM_PIO2
+#include "math_private.h"
+//#include "e_rem_pio2.c"
+
+OLM_DLLEXPORT double
+cos(double x)
+{
+       double y[2],z=0.0;
+       int32_t n, ix;
+
+    /* High word of x. */
+       GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+       ix &= 0x7fffffff;
+       if(ix <= 0x3fe921fb) {
+           if(ix<0x3e46a09e)                   /* if x < 2**-27 * sqrt(2) */
+               if(((int)x)==0) return 1.0;     /* generate inexact */
+           return __kernel_cos(x,z);
+       }
+
+    /* cos(Inf or NaN) is NaN */
+       else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2(x,y);
+           switch(n&3) {
+               case 0: return  __kernel_cos(y[0],y[1]);
+               case 1: return -__kernel_sin(y[0],y[1],1);
+               case 2: return -__kernel_cos(y[0],y[1]);
+               default:
+                       return  __kernel_sin(y[0],y[1],1);
+           }
+       }
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(cos, cosl);
+#endif
diff --git a/src/s_cosf.c b/src/s_cosf.c
new file mode 100644 (file)
index 0000000..57ec7c7
--- /dev/null
@@ -0,0 +1,85 @@
+/* s_cosf.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cosf.c,v 1.18 2008/02/25 22:19:17 bde Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define      INLINE_KERNEL_COSDF
+//#define      INLINE_KERNEL_SINDF
+//#define INLINE_REM_PIO2F
+#include "math_private.h"
+//#include "e_rem_pio2f.c"
+//#include "k_cosf.c"
+//#include "k_sinf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+c1pio2 = 1*M_PI_2,                     /* 0x3FF921FB, 0x54442D18 */
+c2pio2 = 2*M_PI_2,                     /* 0x400921FB, 0x54442D18 */
+c3pio2 = 3*M_PI_2,                     /* 0x4012D97C, 0x7F3321D2 */
+c4pio2 = 4*M_PI_2;                     /* 0x401921FB, 0x54442D18 */
+
+OLM_DLLEXPORT float
+cosf(float x)
+{
+       double y;
+       int32_t n, hx, ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx & 0x7fffffff;
+
+       if(ix <= 0x3f490fda) {          /* |x| ~<= pi/4 */
+           if(ix<0x39800000)           /* |x| < 2**-12 */
+               if(((int)x)==0) return 1.0;     /* 1 with inexact if x != 0 */
+           return __kernel_cosdf(x);
+       }
+       if(ix<=0x407b53d1) {            /* |x| ~<= 5*pi/4 */
+           if(ix<=0x4016cbe3) {        /* |x|  ~> 3*pi/4 */
+               if(hx>0)
+                   return __kernel_sindf(c1pio2 - x);
+               else
+                   return __kernel_sindf(x + c1pio2);
+           } else
+               return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2));
+       }
+       if(ix<=0x40e231d5) {            /* |x| ~<= 9*pi/4 */
+           if(ix<=0x40afeddf) {        /* |x|  ~> 7*pi/4 */
+               if(hx>0)
+                   return __kernel_sindf(x - c3pio2);
+               else
+                   return __kernel_sindf(-c3pio2 - x);
+           } else
+               return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2));
+       }
+
+    /* cos(Inf or NaN) is NaN */
+       else if (ix>=0x7f800000) return x-x;
+
+    /* general argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2f(x,&y);
+           switch(n&3) {
+               case 0: return  __kernel_cosdf(y);
+               case 1: return  __kernel_sindf(-y);
+               case 2: return -__kernel_cosdf(y);
+               default:
+                       return  __kernel_sindf(y);
+           }
+       }
+}
diff --git a/src/s_cosl.c b/src/s_cosl.c
new file mode 100644 (file)
index 0000000..886d3e3
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2007 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cosl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $");
+
+/*
+ * Limited testing on pseudorandom numbers drawn within [-2e8:4e8] shows
+ * an accuracy of <= 0.7412 ULP.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#if LDBL_MANT_DIG == 64
+#include "../ld80/e_rem_pio2l.h"
+#elif LDBL_MANT_DIG == 113
+#include "../ld128/e_rem_pio2l.h"
+#else
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT long double
+cosl(long double x)
+{
+       union IEEEl2bits z;
+       int e0;
+       long double y[2];
+       long double hi, lo;
+
+       z.e = x;
+       z.bits.sign = 0;
+
+       /* If x = +-0 or x is a subnormal number, then cos(x) = 1 */
+       if (z.bits.exp == 0)
+               return (1.0);
+
+       /* If x = NaN or Inf, then cos(x) = NaN. */
+       if (z.bits.exp == 32767)
+               return ((x - x) / (x - x));
+
+       /* Optimize the case where x is already within range. */
+       if (z.e < M_PI_4)
+               return (__kernel_cosl(z.e, 0));
+
+       e0 = __ieee754_rem_pio2l(x, y);
+       hi = y[0];
+       lo = y[1];
+
+       switch (e0 & 3) {
+       case 0:
+           hi = __kernel_cosl(hi, lo);
+           break;
+       case 1:
+           hi = - __kernel_sinl(hi, lo, 1);
+           break;
+       case 2:
+           hi = - __kernel_cosl(hi, lo);
+           break;
+       case 3:
+           hi = __kernel_sinl(hi, lo, 1);
+           break;
+       }
+       
+       return (hi);
+}
diff --git a/src/s_cpow.c b/src/s_cpow.c
new file mode 100644 (file)
index 0000000..d99621f
--- /dev/null
@@ -0,0 +1,78 @@
+/*     $OpenBSD: s_cpow.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cpow
+ *
+ *     Complex power function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex cpow();
+ * double complex a, z, w;
+ *
+ * w = cpow (a, z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Raises complex A to the complex Zth power.
+ * Definition is per AMS55 # 4.2.8,
+ * analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       9.4e-15     1.5e-15
+ *
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double complex
+cpow(double complex a, double complex z)
+{
+       double complex w;
+       double x, y, r, theta, absa, arga;
+
+       x = creal (z);
+       y = cimag (z);
+       absa = cabs (a);
+       if (absa == 0.0) {
+               return (0.0 + 0.0 * I);
+       }
+       arga = carg (a);
+       r = pow (absa, x);
+       theta = x * arga;
+       if (y != 0.0) {
+               r = r * exp (-y * arga);
+               theta = theta + y * log (absa);
+       }
+       w = r * cos (theta) + (r * sin (theta)) * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(cpowl, cpow);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_cpowf.c b/src/s_cpowf.c
new file mode 100644 (file)
index 0000000..764053d
--- /dev/null
@@ -0,0 +1,73 @@
+/*     $OpenBSD: s_cpowf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $    */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cpowf
+ *
+ *     Complex power function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex cpowf();
+ * float complex a, z, w;
+ *
+ * w = cpowf (a, z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Raises complex A to the complex Zth power.
+ * Definition is per AMS55 # 4.2.8,
+ * analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       9.4e-15     1.5e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float complex
+cpowf(float complex a, float complex z)
+{
+       float complex w;
+       float x, y, r, theta, absa, arga;
+
+       x = crealf(z);
+       y = cimagf(z);
+       absa = cabsf (a);
+       if (absa == 0.0f) {
+               return (0.0f + 0.0f * I);
+       }
+       arga = cargf (a);
+       r = powf (absa, x);
+       theta = x * arga;
+       if (y != 0.0f) {
+               r = r * expf (-y * arga);
+               theta = theta + y * logf (absa);
+       }
+       w = r * cosf (theta) + (r * sinf (theta)) * I;
+       return (w);
+}
diff --git a/src/s_cpowl.c b/src/s_cpowl.c
new file mode 100644 (file)
index 0000000..81c9afd
--- /dev/null
@@ -0,0 +1,74 @@
+/*     $OpenBSD: s_cpowl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     cpowl
+ *
+ *     Complex power function
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex cpowl();
+ * long double complex a, z, w;
+ *
+ * w = cpowl (a, z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Raises complex A to the complex Zth power.
+ * Definition is per AMS55 # 4.2.8,
+ * analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       9.4e-15     1.5e-15
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double complex
+cpowl(long double complex a, long double complex z)
+{
+       long double complex w;
+       long double x, y, r, theta, absa, arga;
+
+       x = creall(z);
+       y = cimagl(z);
+       absa = cabsl(a);
+       if (absa == 0.0L) {
+               return (0.0L + 0.0L * I);
+       }
+       arga = cargl(a);
+       r = powl(absa, x);
+       theta = x * arga;
+       if (y != 0.0L) {
+               r = r * expl(-y * arga);
+               theta = theta + y * logl(absa);
+       }
+       w = r * cosl(theta) + (r * sinl(theta)) * I;
+       return (w);
+}
diff --git a/src/s_cproj.c b/src/s_cproj.c
new file mode 100644 (file)
index 0000000..89dfc55
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cproj.c,v 1.1 2008/08/07 15:07:48 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double complex
+cproj(double complex z)
+{
+
+       if (!isinf(creal(z)) && !isinf(cimag(z)))
+               return (z);
+       else
+               return (CMPLX(INFINITY, copysign(0.0, cimag(z))));
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(cproj, cprojl);
+#endif
diff --git a/src/s_cprojf.c b/src/s_cprojf.c
new file mode 100644 (file)
index 0000000..717c165
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cprojf.c,v 1.1 2008/08/07 15:07:48 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float complex
+cprojf(float complex z)
+{
+
+       if (!isinf(crealf(z)) && !isinf(cimagf(z)))
+               return (z);
+       else
+               return (CMPLXF(INFINITY, copysignf(0.0, cimagf(z))));
+}
diff --git a/src/s_cprojl.c b/src/s_cprojl.c
new file mode 100644 (file)
index 0000000..753ab4c
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_cprojl.c,v 1.1 2008/08/07 15:07:48 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double complex
+cprojl(long double complex z)
+{
+
+       if (!isinf(creall(z)) && !isinf(cimagl(z)))
+               return (z);
+       else
+               return (CMPLXL(INFINITY, copysignl(0.0, cimagl(z))));
+}
diff --git a/src/s_creal.c b/src/s_creal.c
new file mode 100644 (file)
index 0000000..28a0fbf
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_creal.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+creal(double complex z)
+{
+       return z;
+}
diff --git a/src/s_crealf.c b/src/s_crealf.c
new file mode 100644 (file)
index 0000000..9aaed5f
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_crealf.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+crealf(float complex z)
+{
+       return z;
+}
diff --git a/src/s_creall.c b/src/s_creall.c
new file mode 100644 (file)
index 0000000..576666e
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Stefan Farfeleder
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_creall.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $
+ */
+
+#include <openlibm_complex.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+creall(long double complex z)
+{
+       return z;
+}
diff --git a/src/s_csin.c b/src/s_csin.c
new file mode 100644 (file)
index 0000000..8560e0b
--- /dev/null
@@ -0,0 +1,91 @@
+/*     $OpenBSD: s_csin.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     csin()
+ *
+ *     Complex circular sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex csin();
+ * double complex z, w;
+ *
+ * w = csin (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = sin x  cosh y  +  i cos x sinh y.
+ *
+ * csin(z) = -i csinh(iz).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      8400       5.3e-17     1.3e-17
+ *    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+ * Also tested by csin(casin(z)) = z.
+ *
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+/* calculate cosh and sinh */
+
+static void
+cchsh(double x, double *c, double *s)
+{
+       double e, ei;
+
+       if (fabs(x) <= 0.5) {
+               *c = cosh(x);
+               *s = sinh(x);
+       }
+       else {
+               e = exp(x);
+               ei = 0.5/e;
+               e = 0.5 * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+double complex
+csin(double complex z)
+{
+       double complex w;
+       double ch, sh;
+
+       cchsh( cimag (z), &ch, &sh );
+       w = sin (creal(z)) * ch + (cos (creal(z)) * sh) * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(csinl, csin);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_csinf.c b/src/s_csinf.c
new file mode 100644 (file)
index 0000000..42aa981
--- /dev/null
@@ -0,0 +1,85 @@
+/*     $OpenBSD: s_csinf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $    */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     csinf()
+ *
+ *     Complex circular sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void csinf();
+ * cmplxf z, w;
+ *
+ * csinf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = sin x  cosh y  +  i cos x sinh y.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.9e-7      5.5e-8
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+/* calculate cosh and sinh */
+
+static void
+cchshf(float xx, float *c, float *s)
+{
+       float x, e, ei;
+
+       x = xx;
+       if(fabsf(x) <= 0.5f) {
+               *c = coshf(x);
+               *s = sinhf(x);
+       }
+       else {
+               e = expf(x);
+               ei = 0.5f/e;
+               e = 0.5f * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+float complex
+csinf(float complex z)
+{
+       float complex w;
+       float ch, sh;
+
+       cchshf(cimagf(z), &ch, &sh);
+       w = sinf(crealf(z)) * ch  + (cosf(crealf(z)) * sh) * I;
+       return (w);
+}
diff --git a/src/s_csinh.c b/src/s_csinh.c
new file mode 100644 (file)
index 0000000..3838f25
--- /dev/null
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and 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 sine of a complex argument z = x + i y.
+ *
+ * sinh(z) = sinh(x+iy)
+ *         = sinh(x) cos(y) + i cosh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_csinh.c,v 1.2 2011/10/21 06:29:32 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double huge = 0x1p1023;
+
+OLM_DLLEXPORT double complex
+csinh(double complex z)
+{
+       double x, y, h;
+       int32_t hx, hy, ix, iy, lx, ly;
+
+       x = creal(z);
+       y = cimag(z);
+
+       EXTRACT_WORDS(hx, lx, x);
+       EXTRACT_WORDS(hy, ly, y);
+
+       ix = 0x7fffffff & hx;
+       iy = 0x7fffffff & hy;
+
+       /* Handle the nearly-non-exceptional cases where x and y are finite. */
+       if (ix < 0x7ff00000 && iy < 0x7ff00000) {
+               if ((iy | ly) == 0)
+                       return (CMPLX(sinh(x), y));
+               if (ix < 0x40360000)    /* small x: normal case */
+                       return (CMPLX(sinh(x) * cos(y), cosh(x) * sin(y)));
+
+               /* |x| >= 22, so cosh(x) ~= exp(|x|) */
+               if (ix < 0x40862e42) {
+                       /* x < 710: exp(|x|) won't overflow */
+                       h = exp(fabs(x)) * 0.5;
+                       return (CMPLX(copysign(h, x) * cos(y), h * sin(y)));
+               } else if (ix < 0x4096bbaa) {
+                       /* x < 1455: scale to avoid overflow */
+                       z = __ldexp_cexp(CMPLX(fabs(x), y), -1);
+                       return (CMPLX(creal(z) * copysign(1, x), cimag(z)));
+               } else {
+                       /* x >= 1455: the result always overflows */
+                       h = huge * x;
+                       return (CMPLX(h * cos(y), h * h * sin(y)));
+               }
+       }
+
+       /*
+        * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
+        * The sign of 0 in the result is unspecified.  Choice = normally
+        * the same as dNaN.  Raise the invalid floating-point exception.
+        *
+        * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
+        * The sign of 0 in the result is unspecified.  Choice = normally
+        * the same as d(NaN).
+        */
+       if ((ix | lx) == 0 && iy >= 0x7ff00000)
+               return (CMPLX(copysign(0, x * (y - y)), y - y));
+
+       /*
+        * sinh(+-Inf +- I 0) = +-Inf + I +-0.
+        *
+        * sinh(NaN +- I 0)   = d(NaN) + I +-0.
+        */
+       if ((iy | ly) == 0 && ix >= 0x7ff00000) {
+               if (((hx & 0xfffff) | lx) == 0)
+                       return (CMPLX(x, y));
+               return (CMPLX(x, copysign(0, y)));
+       }
+
+       /*
+        * sinh(x +- I Inf) = dNaN + I dNaN.
+        * Raise the invalid floating-point exception for finite nonzero x.
+        *
+        * sinh(x + I NaN) = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception for finite
+        * nonzero x.  Choice = don't raise (except for signaling NaNs).
+        */
+       if (ix < 0x7ff00000 && iy >= 0x7ff00000)
+               return (CMPLX(y - y, x * (y - y)));
+
+       /*
+        * sinh(+-Inf + I NaN)  = +-Inf + I d(NaN).
+        * The sign of Inf in the result is unspecified.  Choice = normally
+        * the same as d(NaN).
+        *
+        * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
+        * The sign of Inf in the result is unspecified.  Choice = always +.
+        * Raise the invalid floating-point exception.
+        *
+        * sinh(+-Inf + I y)   = +-Inf cos(y) + I Inf sin(y)
+        */
+       if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+               if (iy >= 0x7ff00000)
+                       return (CMPLX(x * x, x * (y - y)));
+               return (CMPLX(x * cos(y), INFINITY * sin(y)));
+       }
+
+       /*
+        * sinh(NaN + I NaN)  = d(NaN) + I d(NaN).
+        *
+        * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception.
+        * Choice = raise.
+        *
+        * sinh(NaN + I y)    = d(NaN) + I d(NaN).
+        * Optionally raises the invalid floating-point exception for finite
+        * nonzero y.  Choice = don't raise (except for signaling NaNs).
+        */
+       return (CMPLX((x * x) * (y - y), (x + x) * (y - y)));
+}
+
+OLM_DLLEXPORT double complex
+csin(double complex z)
+{
+
+       /* csin(z) = -I * csinh(I * z) */
+       z = csinh(CMPLX(-cimag(z), creal(z)));
+       return (CMPLX(cimag(z), -creal(z)));
+}
diff --git a/src/s_csinhf.c b/src/s_csinhf.c
new file mode 100644 (file)
index 0000000..94954b0
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and 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 sine of a complex argument z.  See s_csinh.c for details.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_csinhf.c,v 1.2 2011/10/21 06:29:32 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float huge = 0x1p127;
+
+OLM_DLLEXPORT float complex
+csinhf(float complex z)
+{
+       float x, y, h;
+       int32_t hx, hy, ix, iy;
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       GET_FLOAT_WORD(hx, x);
+       GET_FLOAT_WORD(hy, y);
+
+       ix = 0x7fffffff & hx;
+       iy = 0x7fffffff & hy;
+
+       if (ix < 0x7f800000 && iy < 0x7f800000) {
+               if (iy == 0)
+                       return (CMPLXF(sinhf(x), y));
+               if (ix < 0x41100000)    /* small x: normal case */
+                       return (CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y)));
+
+               /* |x| >= 9, so cosh(x) ~= exp(|x|) */
+               if (ix < 0x42b17218) {
+                       /* x < 88.7: expf(|x|) won't overflow */
+                       h = expf(fabsf(x)) * 0.5f;
+                       return (CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y)));
+               } else if (ix < 0x4340b1e7) {
+                       /* x < 192.7: scale to avoid overflow */
+                       z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1);
+                       return (CMPLXF(crealf(z) * copysignf(1, x), cimagf(z)));
+               } else {
+                       /* x >= 192.7: the result always overflows */
+                       h = huge * x;
+                       return (CMPLXF(h * cosf(y), h * h * sinf(y)));
+               }
+       }
+
+       if (ix == 0 && iy >= 0x7f800000)
+               return (CMPLXF(copysignf(0, x * (y - y)), y - y));
+
+       if (iy == 0 && ix >= 0x7f800000) {
+               if ((hx & 0x7fffff) == 0)
+                       return (CMPLXF(x, y));
+               return (CMPLXF(x, copysignf(0, y)));
+       }
+
+       if (ix < 0x7f800000 && iy >= 0x7f800000)
+               return (CMPLXF(y - y, x * (y - y)));
+
+       if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+               if (iy >= 0x7f800000)
+                       return (CMPLXF(x * x, x * (y - y)));
+               return (CMPLXF(x * cosf(y), INFINITY * sinf(y)));
+       }
+
+       return (CMPLXF((x * x) * (y - y), (x + x) * (y - y)));
+}
+
+OLM_DLLEXPORT float complex
+csinf(float complex z)
+{
+
+       z = csinhf(CMPLXF(-cimagf(z), crealf(z)));
+       return (CMPLXF(cimagf(z), -crealf(z)));
+}
diff --git a/src/s_csinhl.c b/src/s_csinhl.c
new file mode 100644 (file)
index 0000000..57b577f
--- /dev/null
@@ -0,0 +1,58 @@
+/*     $OpenBSD: s_csinhl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     csinhl
+ *
+ *     Complex hyperbolic sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex csinhl();
+ * long double complex z, w;
+ *
+ * w = csinhl (z);
+ *
+ * DESCRIPTION:
+ *
+ * csinh z = (cexp(z) - cexp(-z))/2
+ *         = sinh x * cos y  +  i cosh x * sin y .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       3.1e-16     8.2e-17
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+csinhl(long double complex z)
+{
+       long double complex w;
+       long double x, y;
+
+       x = creall(z);
+       y = cimagl(z);
+       w = sinhl(x) * cosl(y) + (coshl(x) * sinl(y)) * I;
+       return (w);
+}
diff --git a/src/s_csinl.c b/src/s_csinl.c
new file mode 100644 (file)
index 0000000..3470ac5
--- /dev/null
@@ -0,0 +1,84 @@
+/*     $OpenBSD: s_csinl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     csinl()
+ *
+ *     Complex circular sine
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex csinl();
+ * long double complex z, w;
+ *
+ * w = csinl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *     w = sin x  cosh y  +  i cos x sinh y.
+ *
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      8400       5.3e-17     1.3e-17
+ *    IEEE      -10,+10     30000       3.8e-16     1.0e-16
+ * Also tested by csin(casin(z)) = z.
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+static void
+cchshl(long double x, long double *c, long double *s)
+{
+       long double e, ei;
+
+       if(fabsl(x) <= 0.5L) {
+               *c = coshl(x);
+               *s = sinhl(x);
+       } else {
+               e = expl(x);
+               ei = 0.5L/e;
+               e = 0.5L * e;
+               *s = e - ei;
+               *c = e + ei;
+       }
+}
+
+long double complex
+csinl(long double complex z)
+{
+       long double complex w;
+       long double ch, sh;
+
+       cchshl(cimagl(z), &ch, &sh);
+       w = sinl(creall(z)) * ch + (cosl(creall(z)) * sh) * I;
+       return (w);
+}
diff --git a/src/s_csqrt.c b/src/s_csqrt.c
new file mode 100644 (file)
index 0000000..105592f
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_csqrt.c,v 1.4 2008/08/08 00:15:16 das Exp $");
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * 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.
+ */
+#ifndef __GNUC__
+#pragma        STDC CX_LIMITED_RANGE   ON
+#endif
+
+/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */
+#define        THRESH  0x1.a827999fcef32p+1022
+
+OLM_DLLEXPORT 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)
+               return (result * 2);
+       else
+               return (result);
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(csqrt, csqrtl);
+#endif
diff --git a/src/s_csqrtf.c b/src/s_csqrtf.c
new file mode 100644 (file)
index 0000000..a131829
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_csqrtf.c,v 1.3 2008/08/08 00:15:16 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * 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.
+ */
+#ifndef __GNUC__
+#pragma        STDC CX_LIMITED_RANGE   ON
+#endif
+
+OLM_DLLEXPORT float complex
+csqrtf(float complex z)
+{
+       float a = crealf(z), b = cimagf(z);
+       double t;
+
+       /* Handle special cases. */
+       if (z == 0)
+               return (CMPLXF(0, b));
+       if (isinf(b))
+               return (CMPLXF(INFINITY, b));
+       if (isnan(a)) {
+               t = (b - b) / (b - b);  /* raise invalid if b is not a NaN */
+               return (CMPLXF(a, t));  /* return NaN + NaN i */
+       }
+       if (isinf(a)) {
+               /*
+                * csqrtf(inf + NaN i)  = inf +  NaN i
+                * csqrtf(inf + y i)    = inf +  0 i
+                * csqrtf(-inf + NaN i) = NaN +- inf i
+                * csqrtf(-inf + y i)   = 0   +  inf i
+                */
+               if (signbit(a))
+                       return (CMPLXF(fabsf(b - b), copysignf(a, b)));
+               else
+                       return (CMPLXF(a, copysignf(b - b, b)));
+       }
+       /*
+        * The remaining special case (b is NaN) is handled just fine by
+        * the normal code path below.
+        */
+
+       /*
+        * We compute t in double precision to avoid overflow and to
+        * provide correct rounding in nearly all cases.
+        * This is Algorithm 312, CACM vol 10, Oct 1967.
+        */
+       if (a >= 0) {
+               t = sqrt((a + hypot(a, b)) * 0.5);
+               return (CMPLXF(t, b / (2.0 * t)));
+       } else {
+               t = sqrt((-a + hypot(a, b)) * 0.5);
+               return (CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b)));
+       }
+}
diff --git a/src/s_csqrtl.c b/src/s_csqrtl.c
new file mode 100644 (file)
index 0000000..da97fb2
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2007-2008 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.
+ */
+
+#include "cdefs-compat.h"
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * 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.
+ */
+#ifndef __GNUC__
+#pragma        STDC CX_LIMITED_RANGE   ON
+#endif
+
+/* We risk spurious overflow for components >= LDBL_MAX / (1 + sqrt(2)). */
+#define        THRESH  (LDBL_MAX / 2.414213562373095048801688724209698L)
+
+OLM_DLLEXPORT long double complex
+csqrtl(long double complex z)
+{
+       long double complex result;
+       long double a, b;
+       long double t;
+       int scale;
+
+       a = creall(z);
+       b = cimagl(z);
+
+       /* Handle special cases. */
+       if (z == 0)
+               return (CMPLXL(0, b));
+       if (isinf(b))
+               return (CMPLXL(INFINITY, b));
+       if (isnan(a)) {
+               t = (b - b) / (b - b);  /* raise invalid if b is not a NaN */
+               return (CMPLXL(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 (CMPLXL(fabsl(b - b), copysignl(a, b)));
+               else
+                       return (CMPLXL(a, copysignl(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 (fabsl(a) >= THRESH || fabsl(b) >= THRESH) {
+               a *= 0.25;
+               b *= 0.25;
+               scale = 1;
+       } else {
+               scale = 0;
+       }
+
+       /* Algorithm 312, CACM vol 10, Oct 1967. */
+       if (a >= 0) {
+               t = sqrtl((a + hypotl(a, b)) * 0.5);
+               result = CMPLXL(t, b / (2 * t));
+       } else {
+               t = sqrtl((-a + hypotl(a, b)) * 0.5);
+               result = CMPLXL(fabsl(b) / (2 * t), copysignl(t, b));
+       }
+
+       /* Rescale. */
+       if (scale)
+               return (result * 2);
+       else
+               return (result);
+}
diff --git a/src/s_ctan.c b/src/s_ctan.c
new file mode 100644 (file)
index 0000000..5082e39
--- /dev/null
@@ -0,0 +1,157 @@
+/*     $OpenBSD: s_ctan.c,v 1.6 2013/07/03 04:46:36 espie Exp $        */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ctan()
+ *
+ *     Complex circular tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex ctan();
+ * double complex z, w;
+ *
+ * w = ctan (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *           sin 2x  +  i sinh 2y
+ *     w  =  --------------------.
+ *            cos 2x  +  cosh 2y
+ *
+ * On the real axis the denominator is zero at odd multiples
+ * of PI/2.  The denominator is evaluated by its Taylor
+ * series near these points.
+ *
+ * ctan(z) = -i ctanh(iz).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5200       7.1e-17     1.6e-17
+ *    IEEE      -10,+10     30000       7.2e-16     1.2e-16
+ * Also tested by ctan * ccot = 1 and catan(ctan(z))  =  z.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#define MACHEP 1.1e-16
+#define MAXNUM 1.0e308
+
+static const double DP1 = 3.14159265160560607910E0;
+static const double DP2 = 1.98418714791870343106E-9;
+static const double DP3 = 1.14423774522196636802E-17;
+
+static double
+_redupi(double x)
+{
+       double t;
+       long i;
+
+       t = x/M_PI;
+       if (t >= 0.0)
+               t += 0.5;
+       else
+               t -= 0.5;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return (t);
+}
+
+/*  Taylor series expansion for cosh(2y) - cos(2x)     */
+
+static double
+_ctans(double complex z)
+{
+       double f, x, x2, y, y2, rn, t;
+       double d;
+
+       x = fabs (2.0 * creal (z));
+       y = fabs (2.0 * cimag(z));
+
+       x = _redupi(x);
+
+       x = x * x;
+       y = y * y;
+       x2 = 1.0;
+       y2 = 1.0;
+       f = 1.0;
+       rn = 0.0;
+       d = 0.0;
+       do {
+               rn += 1.0;
+               f *= rn;
+               rn += 1.0;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 + x2;
+               t /= f;
+               d += t;
+
+               rn += 1.0;
+               f *= rn;
+               rn += 1.0;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 - x2;
+               t /= f;
+               d += t;
+       }
+       while (fabs(t/d) > MACHEP)
+               ;
+       return (d);
+}
+
+double complex
+ctan(double complex z)
+{
+       double complex w;
+       double d;
+
+       d = cos (2.0 * creal (z)) + cosh (2.0 * cimag (z));
+
+       if (fabs(d) < 0.25)
+               d = _ctans (z);
+
+       if (d == 0.0) {
+               /*mtherr ("ctan", OVERFLOW);*/
+               w = MAXNUM + MAXNUM * I;
+               return (w);
+       }
+
+       w = sin (2.0 * creal(z)) / d + (sinh (2.0 * cimag(z)) / d) * I;
+       return (w);
+}
+
+#if    LDBL_MANT_DIG == DBL_MANT_DIG
+__strong_alias(ctanl, ctan);
+#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */
diff --git a/src/s_ctanf.c b/src/s_ctanf.c
new file mode 100644 (file)
index 0000000..3bb3742
--- /dev/null
@@ -0,0 +1,148 @@
+/*     $OpenBSD: s_ctanf.c,v 1.2 2011/07/20 19:28:33 martynas Exp $    */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ctanf()
+ *
+ *     Complex circular tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * void ctanf();
+ * cmplxf z, w;
+ *
+ * ctanf( &z, &w );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *           sin 2x  +  i sinh 2y
+ *     w  =  --------------------.
+ *            cos 2x  +  cosh 2y
+ *
+ * On the real axis the denominator is zero at odd multiples
+ * of PI/2.  The denominator is evaluated by its Taylor
+ * series near these points.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       3.3e-7       5.1e-8
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#define MACHEPF 3.0e-8
+#define MAXNUMF 1.0e38f
+
+static const double DP1 = 3.140625;
+static const double DP2 = 9.67502593994140625E-4;
+static const double DP3 = 1.509957990978376432E-7;
+
+static float
+_redupif(float xx)
+{
+       float x, t;
+       long i;
+
+       x = xx;
+       t = x/(float)M_PI;
+       if(t >= 0.0)
+               t += 0.5;
+       else
+               t -= 0.5;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return(t);
+}
+
+/*  Taylor series expansion for cosh(2y) - cos(2x)     */
+
+static float
+_ctansf(float complex z)
+{
+       float f, x, x2, y, y2, rn, t, d;
+
+       x = fabsf(2.0f * crealf(z));
+       y = fabsf(2.0f * cimagf(z));
+
+       x = _redupif(x);
+
+       x = x * x;
+       y = y * y;
+       x2 = 1.0f;
+       y2 = 1.0f;
+       f = 1.0f;
+       rn = 0.0f;
+       d = 0.0f;
+       do {
+               rn += 1.0f;
+               f *= rn;
+               rn += 1.0f;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 + x2;
+               t /= f;
+               d += t;
+
+               rn += 1.0f;
+               f *= rn;
+               rn += 1.0f;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 - x2;
+               t /= f;
+               d += t;
+       }
+       while (fabsf(t/d) > MACHEPF)
+               ;
+       return(d);
+}
+
+float complex
+ctanf(float complex z)
+{
+       float complex w;
+       float d;
+
+       d = cosf( 2.0f * crealf(z) ) + coshf( 2.0f * cimagf(z) );
+
+       if(fabsf(d) < 0.25f)
+               d = _ctansf(z);
+
+       if (d == 0.0f) {
+               /*mtherr( "ctanf", OVERFLOW );*/
+               w = MAXNUMF + MAXNUMF * I;
+               return (w);
+       }
+       w = sinf (2.0f * crealf(z)) / d + (sinhf (2.0f * cimagf(z)) / d) * I;
+       return (w);
+}
diff --git a/src/s_ctanh.c b/src/s_ctanh.c
new file mode 100644 (file)
index 0000000..8d452ee
--- /dev/null
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2011 David Schultz
+ * 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 tangent of a complex argument z = x + i y.
+ *
+ * The algorithm is from:
+ *
+ *   W. Kahan.  Branch Cuts for Complex Elementary Functions or Much
+ *   Ado About Nothing's Sign Bit.  In The State of the Art in
+ *   Numerical Analysis, pp. 165 ff.  Iserles and Powell, eds., 1987.
+ *
+ * Method:
+ *
+ *   Let t    = tan(x)
+ *       beta = 1/cos^2(y)
+ *       s    = sinh(x)
+ *       rho  = cosh(x)
+ *
+ *   We have:
+ *
+ *   tanh(z) = sinh(z) / cosh(z)
+ *
+ *             sinh(x) cos(y) + i cosh(x) sin(y)
+ *           = ---------------------------------
+ *             cosh(x) cos(y) + i sinh(x) sin(y)
+ *
+ *             cosh(x) sinh(x) / cos^2(y) + i tan(y)
+ *           = -------------------------------------
+ *                    1 + sinh^2(x) / cos^2(y)
+ *
+ *             beta rho s + i t
+ *           = ----------------
+ *               1 + beta s^2
+ *
+ * Modifications:
+ *
+ *   I omitted the original algorithm's handling of overflow in tan(x) after
+ *   verifying with nearpi.c that this can't happen in IEEE single or double
+ *   precision.  I also handle large x differently.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ctanh.c,v 1.2 2011/10/21 06:30:16 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double complex
+ctanh(double complex z)
+{
+       double x, y;
+       double t, beta, s, rho, denom;
+       u_int32_t hx, ix, lx;
+
+       x = creal(z);
+       y = cimag(z);
+
+       EXTRACT_WORDS(hx, lx, x);
+       ix = hx & 0x7fffffff;
+
+       /*
+        * ctanh(NaN + i 0) = NaN + i 0
+        *
+        * ctanh(NaN + i y) = NaN + i NaN               for y != 0
+        *
+        * The imaginary part has the sign of x*sin(2*y), but there's no
+        * special effort to get this right.
+        *
+        * ctanh(+-Inf +- i Inf) = +-1 +- 0
+        *
+        * ctanh(+-Inf + i y) = +-1 + 0 sin(2y)         for y finite
+        *
+        * The imaginary part of the sign is unspecified.  This special
+        * case is only needed to avoid a spurious invalid exception when
+        * y is infinite.
+        */
+       if (ix >= 0x7ff00000) {
+               if ((ix & 0xfffff) | lx)        /* x is NaN */
+                       return (CMPLX(x, (y == 0 ? y : x * y)));
+               SET_HIGH_WORD(x, hx - 0x40000000);      /* x = copysign(1, x) */
+               return (CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))));
+       }
+
+       /*
+        * ctanh(x + i NAN) = NaN + i NaN
+        * ctanh(x +- i Inf) = NaN + i NaN
+        */
+       if (!isfinite(y))
+               return (CMPLX(y - y, y - y));
+
+       /*
+        * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the
+        * approximation sinh^2(huge) ~= exp(2*huge) / 4.
+        * We use a modified formula to avoid spurious overflow.
+        */
+       if (ix >= 0x40360000) { /* x >= 22 */
+               double exp_mx = exp(-fabs(x));
+               return (CMPLX(copysign(1, x),
+                   4 * sin(y) * cos(y) * exp_mx * exp_mx));
+       }
+
+       /* Kahan's algorithm */
+       t = tan(y);
+       beta = 1.0 + t * t;     /* = 1 / cos^2(y) */
+       s = sinh(x);
+       rho = sqrt(1 + s * s);  /* = cosh(x) */
+       denom = 1 + beta * s * s;
+       return (CMPLX((beta * rho * s) / denom, t / denom));
+}
+
+OLM_DLLEXPORT double complex
+ctan(double complex z)
+{
+
+       /* ctan(z) = -I * ctanh(I * z) */
+       z = ctanh(CMPLX(-cimag(z), creal(z)));
+       return (CMPLX(cimag(z), -creal(z)));
+}
diff --git a/src/s_ctanhf.c b/src/s_ctanhf.c
new file mode 100644 (file)
index 0000000..b2f8f19
--- /dev/null
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2011 David Schultz
+ * 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 tangent of a complex argument z.  See s_ctanh.c for details.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ctanhf.c,v 1.2 2011/10/21 06:30:16 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float complex
+ctanhf(float complex z)
+{
+       float x, y;
+       float t, beta, s, rho, denom;
+       u_int32_t hx, ix;
+
+       x = crealf(z);
+       y = cimagf(z);
+
+       GET_FLOAT_WORD(hx, x);
+       ix = hx & 0x7fffffff;
+
+       if (ix >= 0x7f800000) {
+               if (ix & 0x7fffff)
+                       return (CMPLXF(x, (y == 0 ? y : x * y)));
+               SET_FLOAT_WORD(x, hx - 0x40000000);
+               return (CMPLXF(x,
+                   copysignf(0, isinf(y) ? y : sinf(y) * cosf(y))));
+       }
+
+       if (!isfinite(y))
+               return (CMPLXF(y - y, y - y));
+
+       if (ix >= 0x41300000) { /* x >= 11 */
+               float exp_mx = expf(-fabsf(x));
+               return (CMPLXF(copysignf(1, x),
+                   4 * sinf(y) * cosf(y) * exp_mx * exp_mx));
+       }
+
+       t = tanf(y);
+       beta = 1.0 + t * t;
+       s = sinhf(x);
+       rho = sqrtf(1 + s * s);
+       denom = 1 + beta * s * s;
+       return (CMPLXF((beta * rho * s) / denom, t / denom));
+}
+
+OLM_DLLEXPORT float complex
+ctanf(float complex z)
+{
+
+       z = ctanhf(CMPLXF(-cimagf(z), crealf(z)));
+       return (CMPLXF(cimagf(z), -crealf(z)));
+}
+
diff --git a/src/s_ctanhl.c b/src/s_ctanhl.c
new file mode 100644 (file)
index 0000000..6d996d4
--- /dev/null
@@ -0,0 +1,60 @@
+/*     $OpenBSD: s_ctanhl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $   */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ctanhl
+ *
+ *     Complex hyperbolic tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex ctanhl();
+ * long double complex z, w;
+ *
+ * w = ctanhl (z);
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * tanh z = (sinh 2x  +  i sin 2y) / (cosh 2x + cos 2y) .
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000       1.7e-14     2.4e-16
+ *
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+long double complex
+ctanhl(long double complex z)
+{
+       long double complex w;
+       long double x, y, d;
+
+       x = creall(z);
+       y = cimagl(z);
+       d = coshl(2.0L * x) + cosl(2.0L * y);
+       w = sinhl(2.0L * x) / d + (sinl(2.0L * y) / d) * I;
+       return (w);
+}
diff --git a/src/s_ctanl.c b/src/s_ctanl.c
new file mode 100644 (file)
index 0000000..cf33ced
--- /dev/null
@@ -0,0 +1,157 @@
+/*     $OpenBSD: s_ctanl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $    */
+
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*                                                     ctanl()
+ *
+ *     Complex circular tangent
+ *
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex ctanl();
+ * long double complex z, w;
+ *
+ * w = ctanl( z );
+ *
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *
+ *           sin 2x  +  i sinh 2y
+ *     w  =  --------------------.
+ *            cos 2x  +  cosh 2y
+ *
+ * On the real axis the denominator is zero at odd multiples
+ * of PI/2.  The denominator is evaluated by its Taylor
+ * series near these points.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5200       7.1e-17     1.6e-17
+ *    IEEE      -10,+10     30000       7.2e-16     1.2e-16
+ * Also tested by ctan * ccot = 1 and catan(ctan(z))  =  z.
+ */
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#if    LDBL_MANT_DIG == 64
+static const long double MACHEPL= 5.42101086242752217003726400434970855712890625E-20L;
+#elif  LDBL_MANT_DIG == 113
+static const long double MACHEPL = 9.629649721936179265279889712924636592690508e-35L;
+#endif
+
+static const long double PIL = 3.141592653589793238462643383279502884197169L;
+static const long double DP1 = 3.14159265358979323829596852490908531763125L;
+static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L;
+static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L;
+
+static long double
+redupil(long double x)
+{
+       long double t;
+       long i;
+
+       t = x / PIL;
+       if (t >= 0.0L)
+               t += 0.5L;
+       else
+               t -= 0.5L;
+
+       i = t;  /* the multiple */
+       t = i;
+       t = ((x - t * DP1) - t * DP2) - t * DP3;
+       return (t);
+}
+
+static long double
+ctansl(long double complex z)
+{
+       long double f, x, x2, y, y2, rn, t;
+       long double d;
+
+       x = fabsl(2.0L * creall(z));
+       y = fabsl(2.0L * cimagl(z));
+
+       x = redupil(x);
+
+       x = x * x;
+       y = y * y;
+       x2 = 1.0L;
+       y2 = 1.0L;
+       f = 1.0L;
+       rn = 0.0L;
+       d = 0.0L;
+       do {
+               rn += 1.0L;
+               f *= rn;
+               rn += 1.0L;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 + x2;
+               t /= f;
+               d += t;
+
+               rn += 1.0L;
+               f *= rn;
+               rn += 1.0L;
+               f *= rn;
+               x2 *= x;
+               y2 *= y;
+               t = y2 - x2;
+               t /= f;
+               d += t;
+       }
+       while (fabsl(t/d) > MACHEPL);
+       return(d);
+}
+
+long double complex
+ctanl(long double complex z)
+{
+       long double complex w;
+       long double d, x, y;
+
+       x = creall(z);
+       y = cimagl(z);
+       d = cosl(2.0L * x) + coshl(2.0L * y);
+
+       if (fabsl(d) < 0.25L) {
+               d = fabsl(d);
+               d = ctansl(z);
+       }
+       if (d == 0.0L) {
+               /*mtherr( "ctan", OVERFLOW );*/
+               w = LDBL_MAX + LDBL_MAX * I;
+               return (w);
+       }
+
+       w = sinl(2.0L * x) / d + (sinhl(2.0L * y) / d) * I;
+       return (w);
+}
diff --git a/src/s_erf.c b/src/s_erf.c
new file mode 100644 (file)
index 0000000..33ef913
--- /dev/null
@@ -0,0 +1,301 @@
+/* @(#)s_erf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_erf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+/* double erf(double x)
+ * double erfc(double x)
+ *                          x
+ *                   2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *                sqrt(pi) \|
+ *                          0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that
+ *             erf(-x) = -erf(x)
+ *             erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *     1. For |x| in [0, 0.84375]
+ *         erf(x)  = x + x*R(x^2)
+ *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+ *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+ *        where R = P/Q where P is an odd poly of degree 8 and
+ *        Q is an odd poly of degree 10.
+ *                                              -57.90
+ *                     | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ *        Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *        and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *        is close to one. The interval is chosen because the fix
+ *        point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ *        near 0.6174), and by some experiment, 0.84375 is chosen to
+ *        guarantee the error is less than one ulp for erf.
+ *
+ *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *             erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+ *             erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+ *                       1+(c+P1(s)/Q1(s))    if x < 0
+ *             |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ *        Remark: here we use the taylor series expansion at x=1.
+ *             erf(1+s) = erf(1) + s*Poly(s)
+ *                      = 0.845.. + P1(s)/Q1(s)
+ *        That is, we use rational approximation to approximate
+ *                     erf(1+s) - (c = (single)0.84506291151)
+ *        Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *        where
+ *             P1(s) = degree 6 poly in s
+ *             Q1(s) = degree 6 poly in s
+ *
+ *      3. For x in [1.25,1/0.35(~2.857143)],
+ *             erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ *             erf(x)  = 1 - erfc(x)
+ *        where
+ *             R1(z) = degree 7 poly in z, (z=1/x^2)
+ *             S1(z) = degree 8 poly in z
+ *
+ *      4. For x in [1/0.35,28]
+ *             erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ *                     = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ *                     = 2.0 - tiny            (if x <= -6)
+ *             erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ *             erf(x)  = sign(x)*(1.0 - tiny)
+ *        where
+ *             R2(z) = degree 6 poly in z, (z=1/x^2)
+ *             S2(z) = degree 7 poly in z
+ *
+ *      Note1:
+ *        To compute exp(-x*x-0.5625+R/S), let s be a single
+ *        precision number and s := x; then
+ *             -x*x = -s*s + (s-x)*(s+x)
+ *             exp(-x*x-0.5626+R/S) =
+ *                     exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *        Here 4 and 5 make use of the asymptotic series
+ *                       exp(-x*x)
+ *             erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *                       x*sqrt(pi)
+ *        We use rational approximation to approximate
+ *             g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ *        Here is the error bound for R1/S1 and R2/S2
+ *             |R1/S1 - f(x)|  < 2**(-62.57)
+ *             |R2/S2 - f(x)|  < 2**(-61.52)
+ *
+ *      5. For inf > x >= 28
+ *             erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *             erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *                     = 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *             erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *             erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ *             erfc/erf(NaN) is NaN
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+tiny       = 1e-300,
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+       /* c = (float)0.84506291151 */
+erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+OLM_DLLEXPORT double
+erf(double x)
+{
+       int32_t hx,ix,i;
+       double R,S,P,Q,s,y,z,r;
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) {            /* erf(nan)=nan */
+           i = ((u_int32_t)hx>>31)<<1;
+           return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+       }
+
+       if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+           if(ix < 0x3e300000) {       /* |x|<2**-28 */
+               if (ix < 0x00800000)
+                   return 0.125*(8.0*x+efx8*x);  /*avoid underflow */
+               return x + efx*x;
+           }
+           z = x*x;
+           r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+           s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+           y = r/s;
+           return x + x*y;
+       }
+       if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+           s = fabs(x)-one;
+           P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+           Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+           if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+       }
+       if (ix >= 0x40180000) {         /* inf>|x|>=6 */
+           if(hx>=0) return one-tiny; else return tiny-one;
+       }
+       x = fabs(x);
+       s = one/(x*x);
+       if(ix< 0x4006DB6E) {    /* |x| < 1/0.35 */
+           R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                               ra5+s*(ra6+s*ra7))))));
+           S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                               sa5+s*(sa6+s*(sa7+s*sa8)))))));
+       } else {        /* |x| >= 1/0.35 */
+           R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                               rb5+s*rb6)))));
+           S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                               sb5+s*(sb6+s*sb7))))));
+       }
+       z  = x;
+       SET_LOW_WORD(z,0);
+       r  =  __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+       if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+OLM_DLLEXPORT double
+erfc(double x)
+{
+       int32_t hx,ix;
+       double R,S,P,Q,s,y,z,r;
+       GET_HIGH_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7ff00000) {                    /* erfc(nan)=nan */
+                                               /* erfc(+-inf)=0,2 */
+           return (double)(((u_int32_t)hx>>31)<<1)+one/x;
+       }
+
+       if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+           if(ix < 0x3c700000)         /* |x|<2**-56 */
+               return one-x;
+           z = x*x;
+           r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+           s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+           y = r/s;
+           if(hx < 0x3fd00000) {       /* x<1/4 */
+               return one-(x+x*y);
+           } else {
+               r = x*y;
+               r += (x-half);
+               return half - r ;
+           }
+       }
+       if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+           s = fabs(x)-one;
+           P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+           Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+           if(hx>=0) {
+               z  = one-erx; return z - P/Q;
+           } else {
+               z = erx+P/Q; return one+z;
+           }
+       }
+       if (ix < 0x403c0000) {          /* |x|<28 */
+           x = fabs(x);
+           s = one/(x*x);
+           if(ix< 0x4006DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+               R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                               ra5+s*(ra6+s*ra7))))));
+               S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                               sa5+s*(sa6+s*(sa7+s*sa8)))))));
+           } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+               if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+               R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                               rb5+s*rb6)))));
+               S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                               sb5+s*(sb6+s*sb7))))));
+           }
+           z  = x;
+           SET_LOW_WORD(z,0);
+           r  =  __ieee754_exp(-z*z-0.5625)*
+                       __ieee754_exp((z-x)*(z+x)+R/S);
+           if(hx>0) return r/x; else return two-r/x;
+       } else {
+           if(hx>0) return tiny*tiny; else return two-tiny;
+       }
+}
diff --git a/src/s_erff.c b/src/s_erff.c
new file mode 100644 (file)
index 0000000..ed6030f
--- /dev/null
@@ -0,0 +1,184 @@
+/* s_erff.c -- float version of s_erf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_erff.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+tiny       = 1e-30,
+half=  5.0000000000e-01, /* 0x3F000000 */
+one =  1.0000000000e+00, /* 0x3F800000 */
+two =  2.0000000000e+00, /* 0x40000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx =  1.2837916613e-01, /* 0x3e0375d4 */
+efx8=  1.0270333290e+00, /* 0x3f8375d4 */
+/*
+ *  Domain [0, 0.84375], range ~[-5.4446e-10,5.5197e-10]:
+ *  |(erf(x) - x)/x - p(x)/q(x)| < 2**-31.
+ */
+pp0  =  1.28379166e-01F, /*  0x1.06eba8p-3 */
+pp1  = -3.36030394e-01F, /* -0x1.58185ap-2 */
+pp2  = -1.86260219e-03F, /* -0x1.e8451ep-10 */
+qq1  =  3.12324286e-01F, /*  0x1.3fd1f0p-2 */
+qq2  =  2.16070302e-02F, /*  0x1.620274p-6 */
+qq3  = -1.98859419e-03F, /* -0x1.04a626p-9 */
+/*
+ * Domain [0.84375, 1.25], range ~[-1.953e-11,1.940e-11]:
+ * |(erf(x) - erx) - p(x)/q(x)| < 2**-36.
+ */
+erx  =  8.42697144e-01F, /*  0x1.af7600p-1.  erf(1) rounded to 16 bits. */
+pa0  =  3.64939137e-06F, /*  0x1.e9d022p-19 */
+pa1  =  4.15109694e-01F, /*  0x1.a91284p-2 */
+pa2  = -1.65179938e-01F, /* -0x1.5249dcp-3 */
+pa3  =  1.10914491e-01F, /*  0x1.c64e46p-4 */
+qa1  =  6.02074385e-01F, /*  0x1.344318p-1 */
+qa2  =  5.35934687e-01F, /*  0x1.126608p-1 */
+qa3  =  1.68576106e-01F, /*  0x1.593e6ep-3 */
+qa4  =  5.62181212e-02F, /*  0x1.cc89f2p-5 */
+/*
+ * Domain [1.25,1/0.35], range ~[-7.043e-10,7.457e-10]:
+ * |log(x*erfc(x)) + x**2 + 0.5625 - r(x)/s(x)| < 2**-30
+ */
+ra0  = -9.87132732e-03F, /* -0x1.4376b2p-7 */
+ra1  = -5.53605914e-01F, /* -0x1.1b723cp-1 */
+ra2  = -2.17589188e+00F, /* -0x1.1683a0p+1 */
+ra3  = -1.43268085e+00F, /* -0x1.6ec42cp+0 */
+sa1  =  5.45995426e+00F, /*  0x1.5d6fe4p+2 */
+sa2  =  6.69798088e+00F, /*  0x1.acabb8p+2 */
+sa3  =  1.43113089e+00F, /*  0x1.6e5e98p+0 */
+sa4  = -5.77397496e-02F, /* -0x1.d90108p-5 */
+/*
+ * Domain [1/0.35, 11], range ~[-2.264e-13,2.336e-13]:
+ * |log(x*erfc(x)) + x**2 + 0.5625 - r(x)/s(x)| < 2**-42
+ */
+rb0  = -9.86494310e-03F, /* -0x1.434124p-7 */
+rb1  = -6.25171244e-01F, /* -0x1.401672p-1 */
+rb2  = -6.16498327e+00F, /* -0x1.8a8f16p+2 */
+rb3  = -1.66696873e+01F, /* -0x1.0ab70ap+4 */
+rb4  = -9.53764343e+00F, /* -0x1.313460p+3 */
+sb1  =  1.26884899e+01F, /*  0x1.96081cp+3 */
+sb2  =  4.51839523e+01F, /*  0x1.6978bcp+5 */
+sb3  =  4.72810211e+01F, /*  0x1.7a3f88p+5 */
+sb4  =  8.93033314e+00F; /*  0x1.1dc54ap+3 */
+
+
+OLM_DLLEXPORT float
+erff(float x)
+{
+       int32_t hx,ix,i;
+       float R,S,P,Q,s,y,z,r;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) {            /* erf(nan)=nan */
+           i = ((u_int32_t)hx>>31)<<1;
+           return (float)(1-i)+one/x;  /* erf(+-inf)=+-1 */
+       }
+
+       if(ix < 0x3f580000) {           /* |x|<0.84375 */
+            if(ix < 0x38800000) {       /* |x|<2**-14 */
+                if (ix < 0x04000000)    /* |x|<0x1p-119 */
+                    return (8*x+efx8*x)/8;      /* avoid spurious underflow */
+               return x + efx*x;
+           }
+           z = x*x;
+            r = pp0+z*(pp1+z*pp2);
+            s = one+z*(qq1+z*(qq2+z*qq3));
+           y = r/s;
+           return x + x*y;
+       }
+       if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+           s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*pa3));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*qa4)));
+           if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+       }
+       if (ix >= 0x40800000) {         /* inf>|x|>=4 */
+           if(hx>=0) return one-tiny; else return tiny-one;
+       }
+       x = fabsf(x);
+       s = one/(x*x);
+       if(ix< 0x4036DB6E) {    /* |x| < 1/0.35 */
+            R=ra0+s*(ra1+s*(ra2+s*ra3));
+            S=one+s*(sa1+s*(sa2+s*(sa3+s*sa4)));
+       } else {        /* |x| >= 1/0.35 */
+            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*rb4)));
+            S=one+s*(sb1+s*(sb2+s*(sb3+s*sb4)));
+        }
+        SET_FLOAT_WORD(z,hx&0xffffe000);
+        r  = expf(-z*z-0.5625F)*expf((z-x)*(z+x)+R/S);
+       if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+OLM_DLLEXPORT float
+erfcf(float x)
+{
+       int32_t hx,ix;
+       float R,S,P,Q,s,y,z,r;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix>=0x7f800000) {                    /* erfc(nan)=nan */
+                                               /* erfc(+-inf)=0,2 */
+           return (float)(((u_int32_t)hx>>31)<<1)+one/x;
+       }
+
+       if(ix < 0x3f580000) {           /* |x|<0.84375 */
+           if(ix < 0x33800000)         /* |x|<2**-56 */
+               return one-x;
+           z = x*x;
+            r = pp0+z*(pp1+z*pp2);
+            s = one+z*(qq1+z*(qq2+z*qq3));
+           y = r/s;
+           if(hx < 0x3e800000) {       /* x<1/4 */
+               return one-(x+x*y);
+           } else {
+               r = x*y;
+               r += (x-half);
+               return half - r ;
+           }
+       }
+       if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+           s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*pa3));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*qa4)));
+           if(hx>=0) {
+               z  = one-erx; return z - P/Q;
+           } else {
+               z = erx+P/Q; return one+z;
+           }
+       }
+       if (ix < 0x41300000) {          /* |x|<28 */
+           x = fabsf(x);
+           s = one/(x*x);
+           if(ix< 0x4036DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+                R=ra0+s*(ra1+s*(ra2+s*ra3));
+                S=one+s*(sa1+s*(sa2+s*(sa3+s*sa4)));
+           } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+                if(hx<0&&ix>=0x40a00000) return two-tiny;/* x < -5 */
+                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*rb4)));
+                S=one+s*(sb1+s*(sb2+s*(sb3+s*sb4)));
+           }
+            SET_FLOAT_WORD(z,hx&0xffffe000);
+            r  = expf(-z*z-0.5625F)*expf((z-x)*(z+x)+R/S);
+           if(hx>0) return r/x; else return two-r/x;
+       } else {
+           if(hx>0) return tiny*tiny; else return two-tiny;
+       }
+}
diff --git a/src/s_exp2.c b/src/s_exp2.c
new file mode 100644 (file)
index 0000000..e5faf7f
--- /dev/null
@@ -0,0 +1,396 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_exp2.c,v 1.7 2008/02/22 02:27:34 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#define        TBLBITS 8
+#define        TBLSIZE (1 << TBLBITS)
+
+static const double
+    huge     = 0x1p1000,
+    redux    = 0x1.8p52 / TBLSIZE,
+    P1      = 0x1.62e42fefa39efp-1,
+    P2      = 0x1.ebfbdff82c575p-3,
+    P3      = 0x1.c6b08d704a0a6p-5,
+    P4      = 0x1.3b2ab88f70400p-7,
+    P5      = 0x1.5d88003875c74p-10;
+
+static volatile double twom1000 = 0x1p-1000;
+
+static const double tbl[TBLSIZE * 2] = {
+/*     exp2(z + eps)           eps     */
+       0x1.6a09e667f3d5dp-1,    0x1.9880p-44,
+       0x1.6b052fa751744p-1,    0x1.8000p-50,
+       0x1.6c012750bd9fep-1,   -0x1.8780p-45,
+       0x1.6cfdcddd476bfp-1,    0x1.ec00p-46,
+       0x1.6dfb23c651a29p-1,   -0x1.8000p-50,
+       0x1.6ef9298593ae3p-1,   -0x1.c000p-52,
+       0x1.6ff7df9519386p-1,   -0x1.fd80p-45,
+       0x1.70f7466f42da3p-1,   -0x1.c880p-45,
+       0x1.71f75e8ec5fc3p-1,    0x1.3c00p-46,
+       0x1.72f8286eacf05p-1,   -0x1.8300p-44,
+       0x1.73f9a48a58152p-1,   -0x1.0c00p-47,
+       0x1.74fbd35d7ccfcp-1,    0x1.f880p-45,
+       0x1.75feb564267f1p-1,    0x1.3e00p-47,
+       0x1.77024b1ab6d48p-1,   -0x1.7d00p-45,
+       0x1.780694fde5d38p-1,   -0x1.d000p-50,
+       0x1.790b938ac1d00p-1,    0x1.3000p-49,
+       0x1.7a11473eb0178p-1,   -0x1.d000p-49,
+       0x1.7b17b0976d060p-1,    0x1.0400p-45,
+       0x1.7c1ed0130c133p-1,    0x1.0000p-53,
+       0x1.7d26a62ff8636p-1,   -0x1.6900p-45,
+       0x1.7e2f336cf4e3bp-1,   -0x1.2e00p-47,
+       0x1.7f3878491c3e8p-1,   -0x1.4580p-45,
+       0x1.80427543e1b4ep-1,    0x1.3000p-44,
+       0x1.814d2add1071ap-1,    0x1.f000p-47,
+       0x1.82589994ccd7ep-1,   -0x1.1c00p-45,
+       0x1.8364c1eb942d0p-1,    0x1.9d00p-45,
+       0x1.8471a4623cab5p-1,    0x1.7100p-43,
+       0x1.857f4179f5bbcp-1,    0x1.2600p-45,
+       0x1.868d99b4491afp-1,   -0x1.2c40p-44,
+       0x1.879cad931a395p-1,   -0x1.3000p-45,
+       0x1.88ac7d98a65b8p-1,   -0x1.a800p-45,
+       0x1.89bd0a4785800p-1,   -0x1.d000p-49,
+       0x1.8ace5422aa223p-1,    0x1.3280p-44,
+       0x1.8be05bad619fap-1,    0x1.2b40p-43,
+       0x1.8cf3216b54383p-1,   -0x1.ed00p-45,
+       0x1.8e06a5e08664cp-1,   -0x1.0500p-45,
+       0x1.8f1ae99157807p-1,    0x1.8280p-45,
+       0x1.902fed0282c0ep-1,   -0x1.cb00p-46,
+       0x1.9145b0b91ff96p-1,   -0x1.5e00p-47,
+       0x1.925c353aa2ff9p-1,    0x1.5400p-48,
+       0x1.93737b0cdc64ap-1,    0x1.7200p-46,
+       0x1.948b82b5f98aep-1,   -0x1.9000p-47,
+       0x1.95a44cbc852cbp-1,    0x1.5680p-45,
+       0x1.96bdd9a766f21p-1,   -0x1.6d00p-44,
+       0x1.97d829fde4e2ap-1,   -0x1.1000p-47,
+       0x1.98f33e47a23a3p-1,    0x1.d000p-45,
+       0x1.9a0f170ca0604p-1,   -0x1.8a40p-44,
+       0x1.9b2bb4d53ff89p-1,    0x1.55c0p-44,
+       0x1.9c49182a3f15bp-1,    0x1.6b80p-45,
+       0x1.9d674194bb8c5p-1,   -0x1.c000p-49,
+       0x1.9e86319e3238ep-1,    0x1.7d00p-46,
+       0x1.9fa5e8d07f302p-1,    0x1.6400p-46,
+       0x1.a0c667b5de54dp-1,   -0x1.5000p-48,
+       0x1.a1e7aed8eb8f6p-1,    0x1.9e00p-47,
+       0x1.a309bec4a2e27p-1,    0x1.ad80p-45,
+       0x1.a42c980460a5dp-1,   -0x1.af00p-46,
+       0x1.a5503b23e259bp-1,    0x1.b600p-47,
+       0x1.a674a8af46213p-1,    0x1.8880p-44,
+       0x1.a799e1330b3a7p-1,    0x1.1200p-46,
+       0x1.a8bfe53c12e8dp-1,    0x1.6c00p-47,
+       0x1.a9e6b5579fcd2p-1,   -0x1.9b80p-45,
+       0x1.ab0e521356fb8p-1,    0x1.b700p-45,
+       0x1.ac36bbfd3f381p-1,    0x1.9000p-50,
+       0x1.ad5ff3a3c2780p-1,    0x1.4000p-49,
+       0x1.ae89f995ad2a3p-1,   -0x1.c900p-45,
+       0x1.afb4ce622f367p-1,    0x1.6500p-46,
+       0x1.b0e07298db790p-1,    0x1.fd40p-45,
+       0x1.b20ce6c9a89a9p-1,    0x1.2700p-46,
+       0x1.b33a2b84f1a4bp-1,    0x1.d470p-43,
+       0x1.b468415b747e7p-1,   -0x1.8380p-44,
+       0x1.b59728de5593ap-1,    0x1.8000p-54,
+       0x1.b6c6e29f1c56ap-1,    0x1.ad00p-47,
+       0x1.b7f76f2fb5e50p-1,    0x1.e800p-50,
+       0x1.b928cf22749b2p-1,   -0x1.4c00p-47,
+       0x1.ba5b030a10603p-1,   -0x1.d700p-47,
+       0x1.bb8e0b79a6f66p-1,    0x1.d900p-47,
+       0x1.bcc1e904bc1ffp-1,    0x1.2a00p-47,
+       0x1.bdf69c3f3a16fp-1,   -0x1.f780p-46,
+       0x1.bf2c25bd71db8p-1,   -0x1.0a00p-46,
+       0x1.c06286141b2e9p-1,   -0x1.1400p-46,
+       0x1.c199bdd8552e0p-1,    0x1.be00p-47,
+       0x1.c2d1cd9fa64eep-1,   -0x1.9400p-47,
+       0x1.c40ab5fffd02fp-1,   -0x1.ed00p-47,
+       0x1.c544778fafd15p-1,    0x1.9660p-44,
+       0x1.c67f12e57d0cbp-1,   -0x1.a100p-46,
+       0x1.c7ba88988c1b6p-1,   -0x1.8458p-42,
+       0x1.c8f6d9406e733p-1,   -0x1.a480p-46,
+       0x1.ca3405751c4dfp-1,    0x1.b000p-51,
+       0x1.cb720dcef9094p-1,    0x1.1400p-47,
+       0x1.ccb0f2e6d1689p-1,    0x1.0200p-48,
+       0x1.cdf0b555dc412p-1,    0x1.3600p-48,
+       0x1.cf3155b5bab3bp-1,   -0x1.6900p-47,
+       0x1.d072d4a0789bcp-1,    0x1.9a00p-47,
+       0x1.d1b532b08c8fap-1,   -0x1.5e00p-46,
+       0x1.d2f87080d8a85p-1,    0x1.d280p-46,
+       0x1.d43c8eacaa203p-1,    0x1.1a00p-47,
+       0x1.d5818dcfba491p-1,    0x1.f000p-50,
+       0x1.d6c76e862e6a1p-1,   -0x1.3a00p-47,
+       0x1.d80e316c9834ep-1,   -0x1.cd80p-47,
+       0x1.d955d71ff6090p-1,    0x1.4c00p-48,
+       0x1.da9e603db32aep-1,    0x1.f900p-48,
+       0x1.dbe7cd63a8325p-1,    0x1.9800p-49,
+       0x1.dd321f301b445p-1,   -0x1.5200p-48,
+       0x1.de7d5641c05bfp-1,   -0x1.d700p-46,
+       0x1.dfc97337b9aecp-1,   -0x1.6140p-46,
+       0x1.e11676b197d5ep-1,    0x1.b480p-47,
+       0x1.e264614f5a3e7p-1,    0x1.0ce0p-43,
+       0x1.e3b333b16ee5cp-1,    0x1.c680p-47,
+       0x1.e502ee78b3fb4p-1,   -0x1.9300p-47,
+       0x1.e653924676d68p-1,   -0x1.5000p-49,
+       0x1.e7a51fbc74c44p-1,   -0x1.7f80p-47,
+       0x1.e8f7977cdb726p-1,   -0x1.3700p-48,
+       0x1.ea4afa2a490e8p-1,    0x1.5d00p-49,
+       0x1.eb9f4867ccae4p-1,    0x1.61a0p-46,
+       0x1.ecf482d8e680dp-1,    0x1.5500p-48,
+       0x1.ee4aaa2188514p-1,    0x1.6400p-51,
+       0x1.efa1bee615a13p-1,   -0x1.e800p-49,
+       0x1.f0f9c1cb64106p-1,   -0x1.a880p-48,
+       0x1.f252b376bb963p-1,   -0x1.c900p-45,
+       0x1.f3ac948dd7275p-1,    0x1.a000p-53,
+       0x1.f50765b6e4524p-1,   -0x1.4f00p-48,
+       0x1.f6632798844fdp-1,    0x1.a800p-51,
+       0x1.f7bfdad9cbe38p-1,    0x1.abc0p-48,
+       0x1.f91d802243c82p-1,   -0x1.4600p-50,
+       0x1.fa7c1819e908ep-1,   -0x1.b0c0p-47,
+       0x1.fbdba3692d511p-1,   -0x1.0e00p-51,
+       0x1.fd3c22b8f7194p-1,   -0x1.0de8p-46,
+       0x1.fe9d96b2a23eep-1,    0x1.e430p-49,
+       0x1.0000000000000p+0,    0x0.0000p+0,
+       0x1.00b1afa5abcbep+0,   -0x1.3400p-52,
+       0x1.0163da9fb3303p+0,   -0x1.2170p-46,
+       0x1.02168143b0282p+0,    0x1.a400p-52,
+       0x1.02c9a3e77806cp+0,    0x1.f980p-49,
+       0x1.037d42e11bbcap+0,   -0x1.7400p-51,
+       0x1.04315e86e7f89p+0,    0x1.8300p-50,
+       0x1.04e5f72f65467p+0,   -0x1.a3f0p-46,
+       0x1.059b0d315855ap+0,   -0x1.2840p-47,
+       0x1.0650a0e3c1f95p+0,    0x1.1600p-48,
+       0x1.0706b29ddf71ap+0,    0x1.5240p-46,
+       0x1.07bd42b72a82dp+0,   -0x1.9a00p-49,
+       0x1.0874518759bd0p+0,    0x1.6400p-49,
+       0x1.092bdf66607c8p+0,   -0x1.0780p-47,
+       0x1.09e3ecac6f383p+0,   -0x1.8000p-54,
+       0x1.0a9c79b1f3930p+0,    0x1.fa00p-48,
+       0x1.0b5586cf988fcp+0,   -0x1.ac80p-48,
+       0x1.0c0f145e46c8ap+0,    0x1.9c00p-50,
+       0x1.0cc922b724816p+0,    0x1.5200p-47,
+       0x1.0d83b23395dd8p+0,   -0x1.ad00p-48,
+       0x1.0e3ec32d3d1f3p+0,    0x1.bac0p-46,
+       0x1.0efa55fdfa9a6p+0,   -0x1.4e80p-47,
+       0x1.0fb66affed2f0p+0,   -0x1.d300p-47,
+       0x1.1073028d7234bp+0,    0x1.1500p-48,
+       0x1.11301d0125b5bp+0,    0x1.c000p-49,
+       0x1.11edbab5e2af9p+0,    0x1.6bc0p-46,
+       0x1.12abdc06c31d5p+0,    0x1.8400p-49,
+       0x1.136a814f2047dp+0,   -0x1.ed00p-47,
+       0x1.1429aaea92de9p+0,    0x1.8e00p-49,
+       0x1.14e95934f3138p+0,    0x1.b400p-49,
+       0x1.15a98c8a58e71p+0,    0x1.5300p-47,
+       0x1.166a45471c3dfp+0,    0x1.3380p-47,
+       0x1.172b83c7d5211p+0,    0x1.8d40p-45,
+       0x1.17ed48695bb9fp+0,   -0x1.5d00p-47,
+       0x1.18af9388c8d93p+0,   -0x1.c880p-46,
+       0x1.1972658375d66p+0,    0x1.1f00p-46,
+       0x1.1a35beb6fcba7p+0,    0x1.0480p-46,
+       0x1.1af99f81387e3p+0,   -0x1.7390p-43,
+       0x1.1bbe084045d54p+0,    0x1.4e40p-45,
+       0x1.1c82f95281c43p+0,   -0x1.a200p-47,
+       0x1.1d4873168b9b2p+0,    0x1.3800p-49,
+       0x1.1e0e75eb44031p+0,    0x1.ac00p-49,
+       0x1.1ed5022fcd938p+0,    0x1.1900p-47,
+       0x1.1f9c18438cdf7p+0,   -0x1.b780p-46,
+       0x1.2063b88628d8fp+0,    0x1.d940p-45,
+       0x1.212be3578a81ep+0,    0x1.8000p-50,
+       0x1.21f49917ddd41p+0,    0x1.b340p-45,
+       0x1.22bdda2791323p+0,    0x1.9f80p-46,
+       0x1.2387a6e7561e7p+0,   -0x1.9c80p-46,
+       0x1.2451ffb821427p+0,    0x1.2300p-47,
+       0x1.251ce4fb2a602p+0,   -0x1.3480p-46,
+       0x1.25e85711eceb0p+0,    0x1.2700p-46,
+       0x1.26b4565e27d16p+0,    0x1.1d00p-46,
+       0x1.2780e341de00fp+0,    0x1.1ee0p-44,
+       0x1.284dfe1f5633ep+0,   -0x1.4c00p-46,
+       0x1.291ba7591bb30p+0,   -0x1.3d80p-46,
+       0x1.29e9df51fdf09p+0,    0x1.8b00p-47,
+       0x1.2ab8a66d10e9bp+0,   -0x1.27c0p-45,
+       0x1.2b87fd0dada3ap+0,    0x1.a340p-45,
+       0x1.2c57e39771af9p+0,   -0x1.0800p-46,
+       0x1.2d285a6e402d9p+0,   -0x1.ed00p-47,
+       0x1.2df961f641579p+0,   -0x1.4200p-48,
+       0x1.2ecafa93e2ecfp+0,   -0x1.4980p-45,
+       0x1.2f9d24abd8822p+0,   -0x1.6300p-46,
+       0x1.306fe0a31b625p+0,   -0x1.2360p-44,
+       0x1.31432edeea50bp+0,   -0x1.0df8p-40,
+       0x1.32170fc4cd7b8p+0,   -0x1.2480p-45,
+       0x1.32eb83ba8e9a2p+0,   -0x1.5980p-45,
+       0x1.33c08b2641766p+0,    0x1.ed00p-46,
+       0x1.3496266e3fa27p+0,   -0x1.c000p-50,
+       0x1.356c55f929f0fp+0,   -0x1.0d80p-44,
+       0x1.36431a2de88b9p+0,    0x1.2c80p-45,
+       0x1.371a7373aaa39p+0,    0x1.0600p-45,
+       0x1.37f26231e74fep+0,   -0x1.6600p-46,
+       0x1.38cae6d05d838p+0,   -0x1.ae00p-47,
+       0x1.39a401b713ec3p+0,   -0x1.4720p-43,
+       0x1.3a7db34e5a020p+0,    0x1.8200p-47,
+       0x1.3b57fbfec6e95p+0,    0x1.e800p-44,
+       0x1.3c32dc313a8f2p+0,    0x1.f800p-49,
+       0x1.3d0e544ede122p+0,   -0x1.7a00p-46,
+       0x1.3dea64c1234bbp+0,    0x1.6300p-45,
+       0x1.3ec70df1c4eccp+0,   -0x1.8a60p-43,
+       0x1.3fa4504ac7e8cp+0,   -0x1.cdc0p-44,
+       0x1.40822c367a0bbp+0,    0x1.5b80p-45,
+       0x1.4160a21f72e95p+0,    0x1.ec00p-46,
+       0x1.423fb27094646p+0,   -0x1.3600p-46,
+       0x1.431f5d950a920p+0,    0x1.3980p-45,
+       0x1.43ffa3f84b9ebp+0,    0x1.a000p-48,
+       0x1.44e0860618919p+0,   -0x1.6c00p-48,
+       0x1.45c2042a7d201p+0,   -0x1.bc00p-47,
+       0x1.46a41ed1d0016p+0,   -0x1.2800p-46,
+       0x1.4786d668b3326p+0,    0x1.0e00p-44,
+       0x1.486a2b5c13c00p+0,   -0x1.d400p-45,
+       0x1.494e1e192af04p+0,    0x1.c200p-47,
+       0x1.4a32af0d7d372p+0,   -0x1.e500p-46,
+       0x1.4b17dea6db801p+0,    0x1.7800p-47,
+       0x1.4bfdad53629e1p+0,   -0x1.3800p-46,
+       0x1.4ce41b817c132p+0,    0x1.0800p-47,
+       0x1.4dcb299fddddbp+0,    0x1.c700p-45,
+       0x1.4eb2d81d8ab96p+0,   -0x1.ce00p-46,
+       0x1.4f9b2769d2d02p+0,    0x1.9200p-46,
+       0x1.508417f4531c1p+0,   -0x1.8c00p-47,
+       0x1.516daa2cf662ap+0,   -0x1.a000p-48,
+       0x1.5257de83f51eap+0,    0x1.a080p-43,
+       0x1.5342b569d4edap+0,   -0x1.6d80p-45,
+       0x1.542e2f4f6ac1ap+0,   -0x1.2440p-44,
+       0x1.551a4ca5d94dbp+0,    0x1.83c0p-43,
+       0x1.56070dde9116bp+0,    0x1.4b00p-45,
+       0x1.56f4736b529dep+0,    0x1.15a0p-43,
+       0x1.57e27dbe2c40ep+0,   -0x1.9e00p-45,
+       0x1.58d12d497c76fp+0,   -0x1.3080p-45,
+       0x1.59c0827ff0b4cp+0,    0x1.dec0p-43,
+       0x1.5ab07dd485427p+0,   -0x1.4000p-51,
+       0x1.5ba11fba87af4p+0,    0x1.0080p-44,
+       0x1.5c9268a59460bp+0,   -0x1.6c80p-45,
+       0x1.5d84590998e3fp+0,    0x1.69a0p-43,
+       0x1.5e76f15ad20e1p+0,   -0x1.b400p-46,
+       0x1.5f6a320dcebcap+0,    0x1.7700p-46,
+       0x1.605e1b976dcb8p+0,    0x1.6f80p-45,
+       0x1.6152ae6cdf715p+0,    0x1.1000p-47,
+       0x1.6247eb03a5531p+0,   -0x1.5d00p-46,
+       0x1.633dd1d1929b5p+0,   -0x1.2d00p-46,
+       0x1.6434634ccc313p+0,   -0x1.a800p-49,
+       0x1.652b9febc8efap+0,   -0x1.8600p-45,
+       0x1.6623882553397p+0,    0x1.1fe0p-40,
+       0x1.671c1c708328ep+0,   -0x1.7200p-44,
+       0x1.68155d44ca97ep+0,    0x1.6800p-49,
+       0x1.690f4b19e9471p+0,   -0x1.9780p-45,
+};
+
+/*
+ * exp2(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.503 ulp for normalized results.
+ *
+ * Method: (accurate tables)
+ *
+ *   Reduce x:
+ *     x = 2**k + y, for integer k and |y| <= 1/2.
+ *     Thus we have exp2(x) = 2**k * exp2(y).
+ *
+ *   Reduce y:
+ *     y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE.
+ *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]),
+ *     with |z - eps[i]| <= 2**-9 + 2**-39 for the table used.
+ *
+ *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via
+ *   a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61.
+ *   The values in exp2t[] and eps[] are chosen such that
+ *   exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such
+ *   that exp2t[i] is accurate to 2**-64.
+ *
+ *   Note that the range of i is +-TBLSIZE/2, so we actually index the tables
+ *   by i0 = i + TBLSIZE/2.  For cache efficiency, exp2t[] and eps[] are
+ *   virtual tables, interleaved in the real table tbl[].
+ *
+ *   This method is due to Gal, with many details due to Gal and Bachelis:
+ *
+ *     Gal, S. and Bachelis, B.  An Accurate Elementary Mathematical Library
+ *     for the IEEE Floating Point Standard.  TOMS 17(1), 26-46 (1991).
+ */
+OLM_DLLEXPORT double
+exp2(double x)
+{
+       double r, t, twopk, twopkp1000, z;
+       u_int32_t hx, ix, lx, i0;
+       int k;
+
+       /* Filter out exceptional cases. */
+       GET_HIGH_WORD(hx,x);
+       ix = hx & 0x7fffffff;           /* high word of |x| */
+       if(ix >= 0x40900000) {                  /* |x| >= 1024 */
+               if(ix >= 0x7ff00000) {
+                       GET_LOW_WORD(lx,x);
+                       if(((ix & 0xfffff) | lx) != 0 || (hx & 0x80000000) == 0)
+                               return (x + x); /* x is NaN or +Inf */
+                       else 
+                               return (0.0);   /* x is -Inf */
+               }
+               if(x >= 0x1.0p10)
+                       return (huge * huge); /* overflow */
+               if(x <= -0x1.0ccp10)
+                       return (twom1000 * twom1000); /* underflow */
+       } else if (ix < 0x3c900000) {           /* |x| < 0x1p-54 */
+               return (1.0 + x);
+       }
+
+       /* Reduce x, computing z, i0, and k. */
+       STRICT_ASSIGN(double, t, x + redux);
+       GET_LOW_WORD(i0, t);
+       i0 += TBLSIZE / 2;
+       k = (i0 >> TBLBITS) << 20;
+       i0 = (i0 & (TBLSIZE - 1)) << 1;
+       t -= redux;
+       z = x - t;
+
+       /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */
+       t = tbl[i0];            /* exp2t[i0] */
+       z -= tbl[i0 + 1];       /* eps[i0]   */
+       if (k >= -(1021 << 20))
+               INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
+       else
+               INSERT_WORDS(twopkp1000, 0x3ff00000 + k + (1000 << 20), 0);
+       r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
+
+       /* Scale by 2**(k>>20). */
+       if(k >= -(1021 << 20)) {
+               if (k == 1024 << 20)
+                       return (r * 2.0 * 0x1p1023);
+               return (r * twopk);
+       } else {
+               return (r * twopkp1000 * twom1000);
+       }
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(exp2, exp2l);
+#endif
diff --git a/src/s_exp2f.c b/src/s_exp2f.c
new file mode 100644 (file)
index 0000000..74bc9f3
--- /dev/null
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_exp2f.c,v 1.9 2008/02/22 02:27:34 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#define        TBLBITS 4
+#define        TBLSIZE (1 << TBLBITS)
+
+static const float
+    huge    = 0x1p100f,
+    redux   = 0x1.8p23f / TBLSIZE,
+    P1     = 0x1.62e430p-1f,
+    P2     = 0x1.ebfbe0p-3f,
+    P3     = 0x1.c6b348p-5f,
+    P4     = 0x1.3b2c9cp-7f;
+
+static volatile float twom100 = 0x1p-100f;
+
+static const double exp2ft[TBLSIZE] = {
+       0x1.6a09e667f3bcdp-1,
+       0x1.7a11473eb0187p-1,
+       0x1.8ace5422aa0dbp-1,
+       0x1.9c49182a3f090p-1,
+       0x1.ae89f995ad3adp-1,
+       0x1.c199bdd85529cp-1,
+       0x1.d5818dcfba487p-1,
+       0x1.ea4afa2a490dap-1,
+       0x1.0000000000000p+0,
+       0x1.0b5586cf9890fp+0,
+       0x1.172b83c7d517bp+0,
+       0x1.2387a6e756238p+0,
+       0x1.306fe0a31b715p+0,
+       0x1.3dea64c123422p+0,
+       0x1.4bfdad5362a27p+0,
+       0x1.5ab07dd485429p+0,
+};
+       
+/*
+ * exp2f(x): compute the base 2 exponential of x
+ *
+ * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927.
+ *
+ * Method: (equally-spaced tables)
+ *
+ *   Reduce x:
+ *     x = 2**k + y, for integer k and |y| <= 1/2.
+ *     Thus we have exp2f(x) = 2**k * exp2(y).
+ *
+ *   Reduce y:
+ *     y = i/TBLSIZE + z for integer i near y * TBLSIZE.
+ *     Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z),
+ *     with |z| <= 2**-(TBLSIZE+1).
+ *
+ *   We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a
+ *   degree-4 minimax polynomial with maximum error under 1.4 * 2**-33.
+ *   Using double precision for everything except the reduction makes
+ *   roundoff error insignificant and simplifies the scaling step.
+ *
+ *   This method is due to Tang, but I do not use his suggested parameters:
+ *
+ *     Tang, P.  Table-driven Implementation of the Exponential Function
+ *     in IEEE Floating-Point Arithmetic.  TOMS 15(2), 144-157 (1989).
+ */
+OLM_DLLEXPORT float
+exp2f(float x)
+{
+       double tv, twopk, u, z;
+       float t;
+       u_int32_t hx, ix, i0;
+       int32_t k;
+
+       /* Filter out exceptional cases. */
+       GET_FLOAT_WORD(hx, x);
+       ix = hx & 0x7fffffff;           /* high word of |x| */
+       if(ix >= 0x43000000) {                  /* |x| >= 128 */
+               if(ix >= 0x7f800000) {
+                       if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0)
+                               return (x + x); /* x is NaN or +Inf */
+                       else 
+                               return (0.0);   /* x is -Inf */
+               }
+               if(x >= 0x1.0p7f)
+                       return (huge * huge);   /* overflow */
+               if(x <= -0x1.2cp7f)
+                       return (twom100 * twom100); /* underflow */
+       } else if (ix <= 0x33000000) {          /* |x| <= 0x1p-25 */
+               return (1.0f + x);
+       }
+
+       /* Reduce x, computing z, i0, and k. */
+       STRICT_ASSIGN(float, t, x + redux);
+       GET_FLOAT_WORD(i0, t);
+       i0 += TBLSIZE / 2;
+       k = (i0 >> TBLBITS) << 20;
+       i0 &= TBLSIZE - 1;
+       t -= redux;
+       z = x - t;
+       INSERT_WORDS(twopk, 0x3ff00000 + k, 0);
+
+       /* Compute r = exp2(y) = exp2ft[i0] * p(z). */
+       tv = exp2ft[i0];
+       u = tv * z;
+       tv = tv + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4);
+
+       /* Scale by 2**(k>>20). */
+       return (tv * twopk);
+}
diff --git a/src/s_expm1.c b/src/s_expm1.c
new file mode 100644 (file)
index 0000000..369598d
--- /dev/null
@@ -0,0 +1,217 @@
+/* @(#)s_expm1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_expm1.c,v 1.12 2011/10/21 06:26:38 das Exp $");
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ *   1. Argument reduction:
+ *     Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
+ *
+ *      Here a correction term c will be computed to compensate
+ *     the error in r when rounded to a floating-point number.
+ *
+ *   2. Approximating expm1(r) by a special rational function on
+ *     the interval [0,0.34658]:
+ *     Since
+ *         r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ *     we define R1(r*r) by
+ *         r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ *     That is,
+ *         R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ *                  = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ *                  = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ *      We use a special Reme algorithm on [0,0.347] to generate
+ *     a polynomial of degree 5 in r*r to approximate R1. The
+ *     maximum error of this polynomial approximation is bounded
+ *     by 2**-61. In other words,
+ *         R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ *     where   Q1  =  -1.6666666666666567384E-2,
+ *             Q2  =   3.9682539681370365873E-4,
+ *             Q3  =  -9.9206344733435987357E-6,
+ *             Q4  =   2.5051361420808517002E-7,
+ *             Q5  =  -6.2843505682382617102E-9;
+ *             z   =  r*r,
+ *     with error bounded by
+ *         |                  5           |     -61
+ *         | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
+ *         |                              |
+ *
+ *     expm1(r) = exp(r)-1 is then computed by the following
+ *     specific way which minimize the accumulation rounding error:
+ *                            2     3
+ *                           r     r    [ 3 - (R1 + R1*r/2)  ]
+ *           expm1(r) = r + --- + --- * [--------------------]
+ *                           2     2    [ 6 - r*(3 - R1*r/2) ]
+ *
+ *     To compensate the error in the argument reduction, we use
+ *             expm1(r+c) = expm1(r) + c + expm1(r)*c
+ *                        ~ expm1(r) + c + r*c
+ *     Thus c+r*c will be added in as the correction terms for
+ *     expm1(r+c). Now rearrange the term to avoid optimization
+ *     screw up:
+ *                     (      2                                    2 )
+ *                     ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+ *      expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ *                     ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+ *                      (                                             )
+ *
+ *                = r - E
+ *   3. Scale back to obtain expm1(x):
+ *     From step 1, we have
+ *        expm1(x) = either 2^k*[expm1(r)+1] - 1
+ *                 = or     2^k*[expm1(r) + (1-2^-k)]
+ *   4. Implementation notes:
+ *     (A). To save one multiplication, we scale the coefficient Qi
+ *          to Qi*2^i, and replace z by (x^2)/2.
+ *     (B). To achieve maximum accuracy, we compute expm1(x) by
+ *       (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ *       (ii)  if k=0, return r-E
+ *       (iii) if k=-1, return 0.5*(r-E)-0.5
+ *        (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ *                    else          return  1.0+2.0*(r-E);
+ *       (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ *       (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ *       (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ *     expm1(INF) is INF, expm1(NaN) is NaN;
+ *     expm1(-INF) is -1, and
+ *     for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ *     according to an error analysis, the error is always less than
+ *     1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *     For IEEE double
+ *         if x >  7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+one            = 1.0,
+huge           = 1.0e+300,
+tiny           = 1.0e-300,
+o_threshold    = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi         = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo         = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2         = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */
+Q1  =  -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2  =   1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3  =  -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4  =   4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5  =  -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+OLM_DLLEXPORT double
+expm1(double x)
+{
+       double y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
+       int32_t k,xsb;
+       u_int32_t hx;
+
+       GET_HIGH_WORD(hx,x);
+       xsb = hx&0x80000000;            /* sign bit of x */
+       hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+       if(hx >= 0x4043687A) {                  /* if |x|>=56*ln2 */
+           if(hx >= 0x40862E42) {              /* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+                   u_int32_t low;
+                   GET_LOW_WORD(low,x);
+                   if(((hx&0xfffff)|low)!=0)
+                        return x+x;     /* NaN */
+                   else return (xsb==0)? x:-1.0;/* exp(+-inf)-1={inf,-1} */
+               }
+               if(x > o_threshold) return huge*huge; /* overflow */
+           }
+           if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+               if(x+tiny<0.0)          /* raise inexact */
+               return tiny-one;        /* return -1 */
+           }
+       }
+
+    /* argument reduction */
+       if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+           if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+               if(xsb==0)
+                   {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+               else
+                   {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+           } else {
+               k  = invln2*x+((xsb==0)?0.5:-0.5);
+               t  = k;
+               hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */
+               lo = t*ln2_lo;
+           }
+           STRICT_ASSIGN(double, x, hi - lo);
+           c  = (hi-x)-lo;
+       }
+       else if(hx < 0x3c900000) {      /* when |x|<2**-54, return x */
+           t = huge+x; /* return x with inexact flags when x!=0 */
+           return x - (t-(huge+x));
+       }
+       else k = 0;
+
+    /* x is now in primary range */
+       hfx = 0.5*x;
+       hxs = x*hfx;
+       r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+       t  = 3.0-r1*hfx;
+       e  = hxs*((r1-t)/(6.0 - x*t));
+       if(k==0) return x - (x*e-hxs);          /* c is 0 */
+       else {
+           INSERT_WORDS(twopk,0x3ff00000+(k<<20),0);   /* 2^k */
+           e  = (x*(e-c)-c);
+           e -= hxs;
+           if(k== -1) return 0.5*(x-e)-0.5;
+           if(k==1) {
+               if(x < -0.25) return -2.0*(e-(x+0.5));
+               else          return  one+2.0*(x-e);
+           }
+           if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+               y = one-(e-x);
+               if (k == 1024) y = y*2.0*0x1p1023;
+               else y = y*twopk;
+               return y-one;
+           }
+           t = one;
+           if(k<20) {
+               SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k));  /* t=1-2^-k */
+               y = t-(e-x);
+               y = y*twopk;
+          } else {
+               SET_HIGH_WORD(t,((0x3ff-k)<<20));       /* 2^-k */
+               y = x-(e+t);
+               y += one;
+               y = y*twopk;
+           }
+       }
+       return y;
+}
diff --git a/src/s_expm1f.c b/src/s_expm1f.c
new file mode 100644 (file)
index 0000000..cb7ceec
--- /dev/null
@@ -0,0 +1,123 @@
+/* s_expm1f.c -- float version of s_expm1.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_expm1f.c,v 1.12 2011/10/21 06:26:38 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+one            = 1.0,
+huge           = 1.0e+30,
+tiny           = 1.0e-30,
+o_threshold    = 8.8721679688e+01,/* 0x42b17180 */
+ln2_hi         = 6.9313812256e-01,/* 0x3f317180 */
+ln2_lo         = 9.0580006145e-06,/* 0x3717f7d1 */
+invln2         = 1.4426950216e+00,/* 0x3fb8aa3b */
+/*
+ * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
+ * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
+ * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
+ */
+Q1 = -3.3333212137e-2,         /* -0x888868.0p-28 */
+Q2 =  1.5807170421e-3;         /*  0xcf3010.0p-33 */
+
+OLM_DLLEXPORT float
+expm1f(float x)
+{
+       float y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
+       int32_t k,xsb;
+       u_int32_t hx;
+
+       GET_FLOAT_WORD(hx,x);
+       xsb = hx&0x80000000;            /* sign bit of x */
+       hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+       if(hx >= 0x4195b844) {                  /* if |x|>=27*ln2 */
+           if(hx >= 0x42b17218) {              /* if |x|>=88.721... */
+                if(hx>0x7f800000)
+                   return x+x;          /* NaN */
+               if(hx==0x7f800000)
+                   return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+               if(x > o_threshold) return huge*huge; /* overflow */
+           }
+           if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */
+               if(x+tiny<(float)0.0)   /* raise inexact */
+               return tiny-one;        /* return -1 */
+           }
+       }
+
+    /* argument reduction */
+       if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+           if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+               if(xsb==0)
+                   {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+               else
+                   {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+           } else {
+               k  = invln2*x+((xsb==0)?(float)0.5:(float)-0.5);
+               t  = k;
+               hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */
+               lo = t*ln2_lo;
+           }
+           STRICT_ASSIGN(float, x, hi - lo);
+           c  = (hi-x)-lo;
+       }
+       else if(hx < 0x33000000) {      /* when |x|<2**-25, return x */
+           t = huge+x; /* return x with inexact flags when x!=0 */
+           return x - (t-(huge+x));
+       }
+       else k = 0;
+
+    /* x is now in primary range */
+       hfx = (float)0.5*x;
+       hxs = x*hfx;
+       r1 = one+hxs*(Q1+hxs*Q2);
+       t  = (float)3.0-r1*hfx;
+       e  = hxs*((r1-t)/((float)6.0 - x*t));
+       if(k==0) return x - (x*e-hxs);          /* c is 0 */
+       else {
+           SET_FLOAT_WORD(twopk,0x3f800000+(k<<23));   /* 2^k */
+           e  = (x*(e-c)-c);
+           e -= hxs;
+           if(k== -1) return (float)0.5*(x-e)-(float)0.5;
+           if(k==1) {
+               if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5));
+               else          return  one+(float)2.0*(x-e);
+           }
+           if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+               y = one-(e-x);
+               if (k == 128) y = y*2.0F*0x1p127F;
+               else y = y*twopk;
+               return y-one;
+           }
+           t = one;
+           if(k<23) {
+               SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */
+               y = t-(e-x);
+               y = y*twopk;
+          } else {
+               SET_FLOAT_WORD(t,((0x7f-k)<<23));       /* 2^-k */
+               y = x-(e+t);
+               y += one;
+               y = y*twopk;
+           }
+       }
+       return y;
+}
diff --git a/src/s_fabs.c b/src/s_fabs.c
new file mode 100644 (file)
index 0000000..43ffc1a
--- /dev/null
@@ -0,0 +1,28 @@
+/* @(#)s_fabs.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+fabs(double x)
+{
+       u_int32_t high;
+       GET_HIGH_WORD(high,x);
+       SET_HIGH_WORD(x,high&0x7fffffff);
+        return x;
+}
diff --git a/src/s_fabsf.c b/src/s_fabsf.c
new file mode 100644 (file)
index 0000000..eeceee4
--- /dev/null
@@ -0,0 +1,34 @@
+/* s_fabsf.c -- float version of s_fabs.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fabsf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+fabsf(float x)
+{
+       u_int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       SET_FLOAT_WORD(x,ix&0x7fffffff);
+        return x;
+}
diff --git a/src/s_fabsl.c b/src/s_fabsl.c
new file mode 100644 (file)
index 0000000..6bc1971
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav
+ * 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
+ *    in this position and unchanged.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_fabsl.c,v 1.2 2003/10/25 19:53:28 des Exp $
+ */
+
+#include <openlibm_math.h>
+#include "math_private.h"
+#include "fpmath.h"
+
+OLM_DLLEXPORT long double
+fabsl(long double x)
+{
+       union IEEEl2bits u;
+
+       u.e = x;
+       u.bits.sign = 0;
+       return (u.e);
+}
diff --git a/src/s_fdim.c b/src/s_fdim.c
new file mode 100644 (file)
index 0000000..1781f72
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fdim.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+#include <openlibm_math.h>
+#include "math_private.h"
+
+#define        DECL(type, fn)                  \
+OLM_DLLEXPORT type                                     \
+fn(type x, type y)                     \
+{                                      \
+                                       \
+       if (isnan(x))                   \
+               return (x);             \
+       if (isnan(y))                   \
+               return (y);             \
+       return (x > y ? x - y : 0.0);   \
+}
+
+DECL(double, fdim)
+DECL(float, fdimf)
+DECL(long double, fdiml)
diff --git a/src/s_floor.c b/src/s_floor.c
new file mode 100644 (file)
index 0000000..1d67a21
--- /dev/null
@@ -0,0 +1,78 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_floor.c,v 1.11 2008/02/15 07:01:40 bde Exp $");
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floor(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+OLM_DLLEXPORT double
+floor(double x)
+{
+       int32_t i0,i1,j0;
+       u_int32_t i,j;
+       EXTRACT_WORDS(i0,i1,x);
+       j0 = ((i0>>20)&0x7ff)-0x3ff;
+       if(j0<20) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0>=0) {i0=i1=0;}
+                   else if(((i0&0x7fffffff)|i1)!=0)
+                       { i0=0xbff00000;i1=0;}
+               }
+           } else {
+               i = (0x000fffff)>>j0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   if(i0<0) i0 += (0x00100000)>>j0;
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (j0>51) {
+           if(j0==0x400) return x+x;   /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(j0-20);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0) {            /* raise inexact flag */
+               if(i0<0) {
+                   if(j0==20) i0+=1;
+                   else {
+                       j = i1+(1<<(52-j0));
+                       if(j<i1) i0 +=1 ;       /* got a carry */
+                       i1=j;
+                   }
+               }
+               i1 &= (~i);
+           }
+       }
+       INSERT_WORDS(x,i0,i1);
+       return x;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(floor, floorl);
+#endif
diff --git a/src/s_floorf.c b/src/s_floorf.c
new file mode 100644 (file)
index 0000000..07efe04
--- /dev/null
@@ -0,0 +1,62 @@
+/* s_floorf.c -- float version of s_floor.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_floorf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+OLM_DLLEXPORT float
+floorf(float x)
+{
+       int32_t i0,j0;
+       u_int32_t i;
+       GET_FLOAT_WORD(i0,x);
+       j0 = ((i0>>23)&0xff)-0x7f;
+       if(j0<23) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0>=0) {i0=0;}
+                   else if((i0&0x7fffffff)!=0)
+                       { i0=0xbf800000;}
+               }
+           } else {
+               i = (0x007fffff)>>j0;
+               if((i0&i)==0) return x; /* x is integral */
+               if(huge+x>(float)0.0) { /* raise inexact flag */
+                   if(i0<0) i0 += (0x00800000)>>j0;
+                   i0 &= (~i);
+               }
+           }
+       } else {
+           if(j0==0x80) return x+x;    /* inf or NaN */
+           else return x;              /* x is integral */
+       }
+       SET_FLOAT_WORD(x,i0);
+       return x;
+}
diff --git a/src/s_floorl.c b/src/s_floorl.c
new file mode 100644 (file)
index 0000000..8427edb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_floorl.c,v 1.8 2008/02/14 15:10:34 bde Exp $");
+
+/*
+ * floorl(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floorl(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define        MANH_SIZE       (LDBL_MANH_SIZE + 1)
+#define        INC_MANH(u, c)  do {                                    \
+       uint64_t o = u.bits.manh;                               \
+       u.bits.manh += (c);                                     \
+       if (u.bits.manh < o)                                    \
+               u.bits.exp++;                                   \
+} while (0)
+#else
+#define        MANH_SIZE       LDBL_MANH_SIZE
+#define        INC_MANH(u, c)  do {                                    \
+       uint64_t o = u.bits.manh;                               \
+       u.bits.manh += (c);                                     \
+       if (u.bits.manh < o) {                                  \
+               u.bits.exp++;                                   \
+               u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1);    \
+       }                                                       \
+} while (0)
+#endif
+
+static const long double huge = 1.0e300;
+
+OLM_DLLEXPORT long double
+floorl(long double x)
+{
+       union IEEEl2bits u = { .e = x };
+       int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+       if (e < MANH_SIZE - 1) {
+               if (e < 0) {                    /* raise inexact if x != 0 */
+                       if (huge + x > 0.0)
+                               if (u.bits.exp > 0 ||
+                                   (u.bits.manh | u.bits.manl) != 0)
+                                       u.e = u.bits.sign ? -1.0 : 0.0;
+               } else {
+                       uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+                       if (((u.bits.manh & m) | u.bits.manl) == 0)
+                               return (x);     /* x is integral */
+                       if (u.bits.sign) {
+#ifdef LDBL_IMPLICIT_NBIT
+                               if (e == 0)
+                                       u.bits.exp++;
+                               else
+#endif
+                               INC_MANH(u, 1llu << (MANH_SIZE - e - 1));
+                       }
+                       if (huge + x > 0.0) {   /* raise inexact flag */
+                               u.bits.manh &= ~m;
+                               u.bits.manl = 0;
+                       }
+               }
+       } else if (e < LDBL_MANT_DIG - 1) {
+               uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+               if ((u.bits.manl & m) == 0)
+                       return (x);     /* x is integral */
+               if (u.bits.sign) {
+                       if (e == MANH_SIZE - 1)
+                               INC_MANH(u, 1);
+                       else {
+                               uint64_t o = u.bits.manl;
+                               u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1);
+                               if (u.bits.manl < o)    /* got a carry */
+                                       INC_MANH(u, 1);
+                       }
+               }
+               if (huge + x > 0.0)             /* raise inexact flag */
+                       u.bits.manl &= ~m;
+       }
+       return (u.e);
+}
diff --git a/src/s_fma.c b/src/s_fma.c
new file mode 100644 (file)
index 0000000..798e426
--- /dev/null
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (c) 2005-2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fma.c,v 1.8 2011/10/21 06:30:43 das Exp $");
+
+#include <float.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * A struct dd represents a floating-point number with twice the precision
+ * of a double.  We maintain the invariant that "hi" stores the 53 high-order
+ * bits of the result.
+ */
+struct dd {
+       double hi;
+       double lo;
+};
+
+/*
+ * Compute a+b exactly, returning the exact result in a struct dd.  We assume
+ * that both a and b are finite, but make no assumptions about their relative
+ * magnitudes.
+ */
+static inline struct dd
+dd_add(double a, double b)
+{
+       struct dd ret;
+       double s;
+
+       ret.hi = a + b;
+       s = ret.hi - a;
+       ret.lo = (a - (ret.hi - s)) + (b - s);
+       return (ret);
+}
+
+/*
+ * Compute a+b, with a small tweak:  The least significant bit of the
+ * result is adjusted into a sticky bit summarizing all the bits that
+ * were lost to rounding.  This adjustment negates the effects of double
+ * rounding when the result is added to another number with a higher
+ * exponent.  For an explanation of round and sticky bits, see any reference
+ * on FPU design, e.g.,
+ *
+ *     J. Coonen.  An Implementation Guide to a Proposed Standard for
+ *     Floating-Point Arithmetic.  Computer, vol. 13, no. 1, Jan 1980.
+ */
+static inline double
+add_adjusted(double a, double b)
+{
+       struct dd sum;
+       u_int64_t hibits, lobits;
+
+       sum = dd_add(a, b);
+       if (sum.lo != 0) {
+               EXTRACT_WORD64(hibits, sum.hi);
+               if ((hibits & 1) == 0) {
+                       /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */
+                       EXTRACT_WORD64(lobits, sum.lo);
+                       hibits += 1 - ((hibits ^ lobits) >> 62);
+                       INSERT_WORD64(sum.hi, hibits);
+               }
+       }
+       return (sum.hi);
+}
+
+/*
+ * Compute ldexp(a+b, scale) with a single rounding error. It is assumed
+ * that the result will be subnormal, and care is taken to ensure that
+ * double rounding does not occur.
+ */
+static inline double
+add_and_denormalize(double a, double b, int scale)
+{
+       struct dd sum;
+       u_int64_t hibits, lobits;
+       int bits_lost;
+
+       sum = dd_add(a, b);
+
+       /*
+        * If we are losing at least two bits of accuracy to denormalization,
+        * then the first lost bit becomes a round bit, and we adjust the
+        * lowest bit of sum.hi to make it a sticky bit summarizing all the
+        * bits in sum.lo. With the sticky bit adjusted, the hardware will
+        * break any ties in the correct direction.
+        *
+        * If we are losing only one bit to denormalization, however, we must
+        * break the ties manually.
+        */
+       if (sum.lo != 0) {
+               EXTRACT_WORD64(hibits, sum.hi);
+               bits_lost = -((int)(hibits >> 52) & 0x7ff) - scale + 1;
+               if ((bits_lost != 1) ^ (int)(hibits & 1)) {
+                       /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */
+                       EXTRACT_WORD64(lobits, sum.lo);
+                       hibits += 1 - (((hibits ^ lobits) >> 62) & 2);
+                       INSERT_WORD64(sum.hi, hibits);
+               }
+       }
+       return (ldexp(sum.hi, scale));
+}
+
+/*
+ * Compute a*b exactly, returning the exact result in a struct dd.  We assume
+ * that both a and b are normalized, so no underflow or overflow will occur.
+ * The current rounding mode must be round-to-nearest.
+ */
+static inline struct dd
+dd_mul(double a, double b)
+{
+       static const double split = 0x1p27 + 1.0;
+       struct dd ret;
+       double ha, hb, la, lb, p, q;
+
+       p = a * split;
+       ha = a - p;
+       ha += p;
+       la = a - ha;
+
+       p = b * split;
+       hb = b - p;
+       hb += p;
+       lb = b - hb;
+
+       p = ha * hb;
+       q = ha * lb + la * hb;
+
+       ret.hi = p + q;
+       ret.lo = p - ret.hi + q + la * lb;
+       return (ret);
+}
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * We use scaling to avoid overflow/underflow, along with the
+ * canonical precision-doubling technique adapted from:
+ *
+ *     Dekker, T.  A Floating-Point Technique for Extending the
+ *     Available Precision.  Numer. Math. 18, 224-242 (1971).
+ *
+ * This algorithm is sensitive to the rounding precision.  FPUs such
+ * as the i387 must be set in double-precision mode if variables are
+ * to be stored in FP registers in order to avoid incorrect results.
+ * This is the default on FreeBSD, but not on many other systems.
+ *
+ * Hardware instructions should be used on architectures that support it,
+ * since this implementation will likely be several times slower.
+ */
+OLM_DLLEXPORT double
+fma(double x, double y, double z)
+{
+       double xs, ys, zs, adj;
+       struct dd xy, r;
+       int oround;
+       int ex, ey, ez;
+       int spread;
+
+       /*
+        * Handle special cases. The order of operations and the particular
+        * return values here are crucial in handling special cases involving
+        * infinities, NaNs, overflows, and signed zeroes correctly.
+        */
+       if (x == 0.0 || y == 0.0)
+               return (x * y + z);
+       if (z == 0.0)
+               return (x * y);
+       if (!isfinite(x) || !isfinite(y))
+               return (x * y + z);
+       if (!isfinite(z))
+               return (z);
+
+       xs = frexp(x, &ex);
+       ys = frexp(y, &ey);
+       zs = frexp(z, &ez);
+       oround = fegetround();
+       spread = ex + ey - ez;
+
+       /*
+        * If x * y and z are many orders of magnitude apart, the scaling
+        * will overflow, so we handle these cases specially.  Rounding
+        * modes other than FE_TONEAREST are painful.
+        */
+       if (spread < -DBL_MANT_DIG) {
+               feraiseexcept(FE_INEXACT);
+               if (!isnormal(z))
+                       feraiseexcept(FE_UNDERFLOW);
+               switch (oround) {
+               case FE_TONEAREST:
+                       return (z);
+               case FE_TOWARDZERO:
+                       if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0))
+                               return (z);
+                       else
+                               return (nextafter(z, 0));
+               case FE_DOWNWARD:
+                       if ((x > 0.0) ^ (y < 0.0))
+                               return (z);
+                       else
+                               return (nextafter(z, -INFINITY));
+               default:        /* FE_UPWARD */
+                       if ((x > 0.0) ^ (y < 0.0))
+                               return (nextafter(z, INFINITY));
+                       else
+                               return (z);
+               }
+       }
+       if (spread <= DBL_MANT_DIG * 2)
+               zs = ldexp(zs, -spread);
+       else
+               zs = copysign(DBL_MIN, zs);
+
+       fesetround(FE_TONEAREST);
+
+       /*
+        * Basic approach for round-to-nearest:
+        *
+        *     (xy.hi, xy.lo) = x * y           (exact)
+        *     (r.hi, r.lo)   = xy.hi + z       (exact)
+        *     adj = xy.lo + r.lo               (inexact; low bit is sticky)
+        *     result = r.hi + adj              (correctly rounded)
+        */
+       xy = dd_mul(xs, ys);
+       r = dd_add(xy.hi, zs);
+
+       spread = ex + ey;
+
+       if (r.hi == 0.0) {
+               /*
+                * When the addends cancel to 0, ensure that the result has
+                * the correct sign.
+                */
+               fesetround(oround);
+               volatile double vzs = zs; /* XXX gcc CSE bug workaround */
+               return (xy.hi + vzs + ldexp(xy.lo, spread));
+       }
+
+       if (oround != FE_TONEAREST) {
+               /*
+                * There is no need to worry about double rounding in directed
+                * rounding modes.
+                */
+               fesetround(oround);
+               adj = r.lo + xy.lo;
+               return (ldexp(r.hi + adj, spread));
+       }
+
+       adj = add_adjusted(r.lo, xy.lo);
+       if (spread + ilogb(r.hi) > -1023)
+               return (ldexp(r.hi + adj, spread));
+       else
+               return (add_and_denormalize(r.hi, adj, spread));
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fma, fmal);
+#endif
diff --git a/src/s_fmaf.c b/src/s_fmaf.c
new file mode 100644 (file)
index 0000000..b3c8efb
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2005-2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaf.c,v 1.3 2011/10/15 04:16:58 das Exp $");
+
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * A double has more than twice as much precision than a float, so
+ * direct double-precision arithmetic suffices, except where double
+ * rounding occurs.
+ */
+OLM_DLLEXPORT float
+fmaf(float x, float y, float z)
+{
+       double xy, result;
+       u_int32_t hr, lr;
+
+       xy = (double)x * y;
+       result = xy + z;
+       EXTRACT_WORDS(hr, lr, result);
+       /* Common case: The double precision result is fine. */
+       if ((lr & 0x1fffffff) != 0x10000000 ||  /* not a halfway case */
+           (hr & 0x7ff00000) == 0x7ff00000 ||  /* NaN */
+           result - xy == z ||                 /* exact */
+           fegetround() != FE_TONEAREST)       /* not round-to-nearest */
+               return (result);
+
+       /*
+        * If result is inexact, and exactly halfway between two float values,
+        * we need to adjust the low-order bit in the direction of the error.
+        */
+       fesetround(FE_TOWARDZERO);
+       volatile double vxy = xy;  /* XXX work around gcc CSE bug */
+       double adjusted_result = vxy + z;
+       fesetround(FE_TONEAREST);
+       if (result == adjusted_result)
+               SET_LOW_WORD(adjusted_result, lr + 1);
+       return (adjusted_result);
+}
diff --git a/src/s_fmal.c b/src/s_fmal.c
new file mode 100644 (file)
index 0000000..2fe30c6
--- /dev/null
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 2005-2011 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmal.c,v 1.7 2011/10/21 06:30:43 das Exp $");
+
+#include <float.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+/*
+ * A struct dd represents a floating-point number with twice the precision
+ * of a long double.  We maintain the invariant that "hi" stores the high-order
+ * bits of the result.
+ */
+struct dd {
+       long double hi;
+       long double lo;
+};
+
+/*
+ * Compute a+b exactly, returning the exact result in a struct dd.  We assume
+ * that both a and b are finite, but make no assumptions about their relative
+ * magnitudes.
+ */
+static inline struct dd
+dd_add(long double a, long double b)
+{
+       struct dd ret;
+       long double s;
+
+       ret.hi = a + b;
+       s = ret.hi - a;
+       ret.lo = (a - (ret.hi - s)) + (b - s);
+       return (ret);
+}
+
+/*
+ * Compute a+b, with a small tweak:  The least significant bit of the
+ * result is adjusted into a sticky bit summarizing all the bits that
+ * were lost to rounding.  This adjustment negates the effects of double
+ * rounding when the result is added to another number with a higher
+ * exponent.  For an explanation of round and sticky bits, see any reference
+ * on FPU design, e.g.,
+ *
+ *     J. Coonen.  An Implementation Guide to a Proposed Standard for
+ *     Floating-Point Arithmetic.  Computer, vol. 13, no. 1, Jan 1980.
+ */
+static inline long double
+add_adjusted(long double a, long double b)
+{
+       struct dd sum;
+       union IEEEl2bits u;
+
+       sum = dd_add(a, b);
+       if (sum.lo != 0) {
+               u.e = sum.hi;
+               if ((u.bits.manl & 1) == 0)
+                       sum.hi = nextafterl(sum.hi, INFINITY * sum.lo);
+       }
+       return (sum.hi);
+}
+
+/*
+ * Compute ldexp(a+b, scale) with a single rounding error. It is assumed
+ * that the result will be subnormal, and care is taken to ensure that
+ * double rounding does not occur.
+ */
+static inline long double
+add_and_denormalize(long double a, long double b, int scale)
+{
+       struct dd sum;
+       int bits_lost;
+       union IEEEl2bits u;
+
+       sum = dd_add(a, b);
+
+       /*
+        * If we are losing at least two bits of accuracy to denormalization,
+        * then the first lost bit becomes a round bit, and we adjust the
+        * lowest bit of sum.hi to make it a sticky bit summarizing all the
+        * bits in sum.lo. With the sticky bit adjusted, the hardware will
+        * break any ties in the correct direction.
+        *
+        * If we are losing only one bit to denormalization, however, we must
+        * break the ties manually.
+        */
+       if (sum.lo != 0) {
+               u.e = sum.hi;
+               bits_lost = -u.bits.exp - scale + 1;
+               if ((bits_lost != 1) ^ (int)(u.bits.manl & 1))
+                       sum.hi = nextafterl(sum.hi, INFINITY * sum.lo);
+       }
+       return (ldexp(sum.hi, scale));
+}
+
+/*
+ * Compute a*b exactly, returning the exact result in a struct dd.  We assume
+ * that both a and b are normalized, so no underflow or overflow will occur.
+ * The current rounding mode must be round-to-nearest.
+ */
+static inline struct dd
+dd_mul(long double a, long double b)
+{
+#if LDBL_MANT_DIG == 64
+       static const long double split = 0x1p32L + 1.0;
+#elif LDBL_MANT_DIG == 113
+       static const long double split = 0x1p57L + 1.0;
+#endif
+       struct dd ret;
+       long double ha, hb, la, lb, p, q;
+
+       p = a * split;
+       ha = a - p;
+       ha += p;
+       la = a - ha;
+
+       p = b * split;
+       hb = b - p;
+       hb += p;
+       lb = b - hb;
+
+       p = ha * hb;
+       q = ha * lb + la * hb;
+
+       ret.hi = p + q;
+       ret.lo = p - ret.hi + q + la * lb;
+       return (ret);
+}
+
+/*
+ * Fused multiply-add: Compute x * y + z with a single rounding error.
+ *
+ * We use scaling to avoid overflow/underflow, along with the
+ * canonical precision-doubling technique adapted from:
+ *
+ *     Dekker, T.  A Floating-Point Technique for Extending the
+ *     Available Precision.  Numer. Math. 18, 224-242 (1971).
+ */
+OLM_DLLEXPORT long double
+fmal(long double x, long double y, long double z)
+{
+       long double xs, ys, zs, adj;
+       struct dd xy, r;
+       int oround;
+       int ex, ey, ez;
+       int spread;
+
+       /*
+        * Handle special cases. The order of operations and the particular
+        * return values here are crucial in handling special cases involving
+        * infinities, NaNs, overflows, and signed zeroes correctly.
+        */
+       if (x == 0.0 || y == 0.0)
+               return (x * y + z);
+       if (z == 0.0)
+               return (x * y);
+       if (!isfinite(x) || !isfinite(y))
+               return (x * y + z);
+       if (!isfinite(z))
+               return (z);
+
+       xs = frexpl(x, &ex);
+       ys = frexpl(y, &ey);
+       zs = frexpl(z, &ez);
+       oround = fegetround();
+       spread = ex + ey - ez;
+
+       /*
+        * If x * y and z are many orders of magnitude apart, the scaling
+        * will overflow, so we handle these cases specially.  Rounding
+        * modes other than FE_TONEAREST are painful.
+        */
+       if (spread < -LDBL_MANT_DIG) {
+               feraiseexcept(FE_INEXACT);
+               if (!isnormal(z))
+                       feraiseexcept(FE_UNDERFLOW);
+               switch (oround) {
+               case FE_TONEAREST:
+                       return (z);
+               case FE_TOWARDZERO:
+                       if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0))
+                               return (z);
+                       else
+                               return (nextafterl(z, 0));
+               case FE_DOWNWARD:
+                       if ((x > 0.0) ^ (y < 0.0))
+                               return (z);
+                       else
+                               return (nextafterl(z, -INFINITY));
+               default:        /* FE_UPWARD */
+                       if ((x > 0.0) ^ (y < 0.0))
+                               return (nextafterl(z, INFINITY));
+                       else
+                               return (z);
+               }
+       }
+       if (spread <= LDBL_MANT_DIG * 2)
+               zs = ldexpl(zs, -spread);
+       else
+               zs = copysignl(LDBL_MIN, zs);
+
+       fesetround(FE_TONEAREST);
+
+       /*
+        * Basic approach for round-to-nearest:
+        *
+        *     (xy.hi, xy.lo) = x * y           (exact)
+        *     (r.hi, r.lo)   = xy.hi + z       (exact)
+        *     adj = xy.lo + r.lo               (inexact; low bit is sticky)
+        *     result = r.hi + adj              (correctly rounded)
+        */
+       xy = dd_mul(xs, ys);
+       r = dd_add(xy.hi, zs);
+
+       spread = ex + ey;
+
+       if (r.hi == 0.0) {
+               /*
+                * When the addends cancel to 0, ensure that the result has
+                * the correct sign.
+                */
+               fesetround(oround);
+               volatile long double vzs = zs; /* XXX gcc CSE bug workaround */
+               return (xy.hi + vzs + ldexpl(xy.lo, spread));
+       }
+
+       if (oround != FE_TONEAREST) {
+               /*
+                * There is no need to worry about double rounding in directed
+                * rounding modes.
+                */
+               fesetround(oround);
+               adj = r.lo + xy.lo;
+               return (ldexpl(r.hi + adj, spread));
+       }
+
+       adj = add_adjusted(r.lo, xy.lo);
+       if (spread + ilogbl(r.hi) > -16383)
+               return (ldexpl(r.hi + adj, spread));
+       else
+               return (add_and_denormalize(r.hi, adj, spread));
+}
diff --git a/src/s_fmax.c b/src/s_fmax.c
new file mode 100644 (file)
index 0000000..73919c6
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmax.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+fmax(double x, double y)
+{
+       union IEEEd2bits u[2];
+
+       u[0].d = x;
+       u[1].d = y;
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0)
+               return (y);
+       if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[u[0].bits.sign].d);
+
+       return (x > y ? x : y);
+}
diff --git a/src/s_fmaxf.c b/src/s_fmaxf.c
new file mode 100644 (file)
index 0000000..a803461
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaxf.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+fmaxf(float x, float y)
+{
+       union IEEEf2bits u[2];
+
+       u[0].f = x;
+       u[1].f = y;
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 255 && u[0].bits.man != 0)
+               return (y);
+       if (u[1].bits.exp == 255 && u[1].bits.man != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[u[0].bits.sign].f);
+
+       return (x > y ? x : y);
+}
diff --git a/src/s_fmaxl.c b/src/s_fmaxl.c
new file mode 100644 (file)
index 0000000..48de991
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaxl.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+fmaxl(long double x, long double y)
+{
+       union IEEEl2bits u[2];
+
+       u[0].e = x;
+       mask_nbit_l(u[0]);
+       u[1].e = y;
+       mask_nbit_l(u[1]);
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0)
+               return (y);
+       if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[0].bits.sign ? y : x);
+
+       return (x > y ? x : y);
+}
diff --git a/src/s_fmin.c b/src/s_fmin.c
new file mode 100644 (file)
index 0000000..9c52739
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmin.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+fmin(double x, double y)
+{
+       union IEEEd2bits u[2];
+
+       u[0].d = x;
+       u[1].d = y;
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0)
+               return (y);
+       if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[u[1].bits.sign].d);
+
+       return (x < y ? x : y);
+}
diff --git a/src/s_fminf.c b/src/s_fminf.c
new file mode 100644 (file)
index 0000000..cc4017f
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fminf.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+fminf(float x, float y)
+{
+       union IEEEf2bits u[2];
+
+       u[0].f = x;
+       u[1].f = y;
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 255 && u[0].bits.man != 0)
+               return (y);
+       if (u[1].bits.exp == 255 && u[1].bits.man != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[u[1].bits.sign].f);
+
+       return (x < y ? x : y);
+}
diff --git a/src/s_fminl.c b/src/s_fminl.c
new file mode 100644 (file)
index 0000000..043886d
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_fminl.c,v 1.1 2004/06/30 07:04:01 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+fminl(long double x, long double y)
+{
+       union IEEEl2bits u[2];
+
+       u[0].e = x;
+       mask_nbit_l(u[0]);
+       u[1].e = y;
+       mask_nbit_l(u[1]);
+
+       /* Check for NaNs to avoid raising spurious exceptions. */
+       if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0)
+               return (y);
+       if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+               return (x);
+
+       /* Handle comparisons of signed zeroes. */
+       if (u[0].bits.sign != u[1].bits.sign)
+               return (u[1].bits.sign ? y : x);
+
+       return (x < y ? x : y);
+}
diff --git a/src/s_fpclassify.c b/src/s_fpclassify.c
new file mode 100644 (file)
index 0000000..558fb55
--- /dev/null
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ */
+
+#include <openlibm_math.h>
+#include "math_private.h"
+#include "fpmath.h"
+
+OLM_DLLEXPORT int
+__fpclassifyd(double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       if (u.bits.exp == 2047) {
+               if (u.bits.manl == 0 && u.bits.manh == 0) {
+                       return FP_INFINITE;
+               } else {
+                       return FP_NAN;
+               }
+       } else if (u.bits.exp != 0) {
+               return FP_NORMAL;
+       } else if (u.bits.manl == 0 && u.bits.manh == 0) {
+               return FP_ZERO;
+       } else {
+               return FP_SUBNORMAL;
+       }
+}
+               
+
+OLM_DLLEXPORT int
+__fpclassifyf(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       if (u.bits.exp == 255) {
+          if (u.bits.man == 0) {
+                  return FP_INFINITE;
+          } else {
+                  return FP_NAN;
+          }
+       } else if (u.bits.exp != 0) {
+               return FP_NORMAL;
+       } else if (u.bits.man == 0) {
+               return FP_ZERO;
+       } else {
+               return FP_SUBNORMAL;
+       }
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__fpclassifyl(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       mask_nbit_l(u);
+       if (u.bits.exp == 32767) {
+               if (u.bits.manl == 0 && u.bits.manh == 0) {
+                       return FP_INFINITE;
+               } else {
+                       return FP_NAN;
+               }
+       } else if (u.bits.exp != 0) {
+               return FP_NORMAL;
+       } else if (u.bits.manl == 0 && u.bits.manh == 0) {
+               return FP_ZERO;
+       } else {
+               return FP_SUBNORMAL;
+       }
+}
+#endif
+
diff --git a/src/s_frexp.c b/src/s_frexp.c
new file mode 100644 (file)
index 0000000..46367a4
--- /dev/null
@@ -0,0 +1,56 @@
+/* @(#)s_frexp.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_frexp.c,v 1.11 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * for non-zero x
+ *     x = frexp(arg,&exp);
+ * return a double fp quantity x such that 0.5 <= |x| <1.0
+ * and the corresponding binary exponent "exp". That is
+ *     arg = x*2^exp.
+ * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
+ * with *exp=0.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+two54 =  1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
+
+OLM_DLLEXPORT double
+frexp(double x, int *eptr)
+{
+       int32_t hx, ix, lx;
+       EXTRACT_WORDS(hx,lx,x);
+       ix = 0x7fffffff&hx;
+       *eptr = 0;
+       if(ix>=0x7ff00000||((ix|lx)==0)) return x;      /* 0,inf,nan */
+       if (ix<0x00100000) {            /* subnormal */
+           x *= two54;
+           GET_HIGH_WORD(hx,x);
+           ix = hx&0x7fffffff;
+           *eptr = -54;
+       }
+       *eptr += (ix>>20)-1022;
+       hx = (hx&0x800fffff)|0x3fe00000;
+       SET_HIGH_WORD(x,hx);
+       return x;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(frexp, frexpl);
+#endif
diff --git a/src/s_frexpf.c b/src/s_frexpf.c
new file mode 100644 (file)
index 0000000..fe63046
--- /dev/null
@@ -0,0 +1,44 @@
+/* s_frexpf.c -- float version of s_frexp.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_frexpf.c,v 1.10 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+two25 =  3.3554432000e+07; /* 0x4c000000 */
+
+OLM_DLLEXPORT float
+frexpf(float x, int *eptr)
+{
+       int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = 0x7fffffff&hx;
+       *eptr = 0;
+       if(ix>=0x7f800000||(ix==0)) return x;   /* 0,inf,nan */
+       if (ix<0x00800000) {            /* subnormal */
+           x *= two25;
+           GET_FLOAT_WORD(hx,x);
+           ix = hx&0x7fffffff;
+           *eptr = -25;
+       }
+       *eptr += (ix>>23)-126;
+       hx = (hx&0x807fffff)|0x3f000000;
+       SET_FLOAT_WORD(x,hx);
+       return x;
+}
diff --git a/src/s_frexpl.c b/src/s_frexpl.c
new file mode 100644 (file)
index 0000000..ed2d28b
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2004-2005 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_frexpl.c,v 1.1 2005/03/07 04:54:51 das Exp $
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT long double
+frexpl(long double x, int *ex)
+{
+       union IEEEl2bits u;
+
+       u.e = x;
+       switch (u.bits.exp) {
+       case 0:         /* 0 or subnormal */
+               if ((u.bits.manl | u.bits.manh) == 0) {
+                       *ex = 0;
+               } else {
+                       u.e *= 0x1.0p514;
+                       *ex = u.bits.exp - 0x4200;
+                       u.bits.exp = 0x3ffe;
+               }
+               break;
+       case 0x7fff:    /* infinity or NaN; value of *ex is unspecified */
+               break;
+       default:        /* normal */
+               *ex = u.bits.exp - 0x3ffe;
+               u.bits.exp = 0x3ffe;
+               break;
+       }
+       return (u.e);
+}
diff --git a/src/s_ilogb.c b/src/s_ilogb.c
new file mode 100644 (file)
index 0000000..897e6d6
--- /dev/null
@@ -0,0 +1,49 @@
+/* @(#)s_ilogb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogb.c,v 1.10 2008/02/22 02:30:35 das Exp $");
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = FP_ILOGB0
+ * ilogb(NaN) = FP_ILOGBNAN (no signal is raised)
+ * ilogb(inf) = INT_MAX (no signal is raised)
+ */
+
+#include <limits.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+ilogb(double x)
+{
+       int32_t hx,lx,ix;
+
+       EXTRACT_WORDS(hx,lx,x);
+       hx &= 0x7fffffff;
+       if(hx<0x00100000) {
+           if((hx|lx)==0)
+               return FP_ILOGB0;
+           else                        /* subnormal x */
+               if(hx==0) {
+                   for (ix = -1043; lx>0; lx<<=1) ix -=1;
+               } else {
+                   for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+               }
+           return ix;
+       }
+       else if (hx<0x7ff00000) return (hx>>20)-1023;
+       else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN;
+       else return INT_MAX;
+}
diff --git a/src/s_ilogbf.c b/src/s_ilogbf.c
new file mode 100644 (file)
index 0000000..79e359d
--- /dev/null
@@ -0,0 +1,41 @@
+/* s_ilogbf.c -- float version of s_ilogb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogbf.c,v 1.8 2008/02/22 02:30:35 das Exp $");
+
+#include <limits.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+ilogbf(float x)
+{
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+       hx &= 0x7fffffff;
+       if(hx<0x00800000) {
+           if(hx==0)
+               return FP_ILOGB0;
+           else                        /* subnormal x */
+               for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1;
+           return ix;
+       }
+       else if (hx<0x7f800000) return (hx>>23)-127;
+       else if (hx>0x7f800000) return FP_ILOGBNAN;
+       else return INT_MAX;
+}
diff --git a/src/s_ilogbl.c b/src/s_ilogbl.c
new file mode 100644 (file)
index 0000000..d67eea8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * From: @(#)s_ilogb.c 5.1 93/09/24
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogbl.c,v 1.2 2008/02/22 02:30:35 das Exp $");
+
+#include <float.h>
+#include <limits.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+ilogbl(long double x)
+{
+       union IEEEl2bits u;
+       unsigned long m;
+       int b;
+
+       u.e = x;
+       if (u.bits.exp == 0) {
+               if ((u.bits.manl | u.bits.manh) == 0)
+                       return (FP_ILOGB0);
+               /* denormalized */
+               if (u.bits.manh == 0) {
+                       m = 1lu << (LDBL_MANL_SIZE - 1);
+                       for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1)
+                               b++;
+               } else {
+                       m = 1lu << (LDBL_MANH_SIZE - 1);
+                       for (b = 0; !(u.bits.manh & m); m >>= 1)
+                               b++;
+               }
+#ifdef LDBL_IMPLICIT_NBIT
+               b++;
+#endif
+               return (LDBL_MIN_EXP - b - 1);
+       } else if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1)
+               return (u.bits.exp - LDBL_MAX_EXP + 1);
+       else if (u.bits.manl != 0 || u.bits.manh != 0)
+               return (FP_ILOGBNAN);
+       else
+               return (INT_MAX);
+}
diff --git a/src/s_isfinite.c b/src/s_isfinite.c
new file mode 100644 (file)
index 0000000..504c2b8
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_isfinite.c,v 1.1 2004/07/09 03:32:39 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+__isfinite(double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       return (u.bits.exp != 2047);
+}
+
+OLM_DLLEXPORT int
+__isfinitef(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       return (u.bits.exp != 255);
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__isfinitel(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       return (u.bits.exp != 32767);
+}
+#endif
diff --git a/src/s_isinf.c b/src/s_isinf.c
new file mode 100644 (file)
index 0000000..c013c91
--- /dev/null
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+/* Provided by libc */
+#if 1
+OLM_DLLEXPORT int
+(isinf) (double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0);
+}
+#endif
+
+OLM_DLLEXPORT int
+__isinff(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       return (u.bits.exp == 255 && u.bits.man == 0);
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__isinfl(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       mask_nbit_l(u);
+       return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0);
+}
+#endif
+
+__weak_reference(__isinff, isinff);
diff --git a/src/s_isnan.c b/src/s_isnan.c
new file mode 100644 (file)
index 0000000..b68aa5b
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_isnan.c,v 1.9 2010/06/12 17:32:05 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+/* Provided by libc */
+#if 1
+OLM_DLLEXPORT int
+(isnan) (double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
+}
+#endif
+
+OLM_DLLEXPORT int
+__isnanf(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       return (u.bits.exp == 255 && u.bits.man != 0);
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__isnanl(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       mask_nbit_l(u);
+       return (u.bits.exp == 32767 && (u.bits.manl != 0 || u.bits.manh != 0));
+}
+#endif
+
+__weak_reference(__isnanf, isnanf);
diff --git a/src/s_isnormal.c b/src/s_isnormal.c
new file mode 100644 (file)
index 0000000..b6f6dd2
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2004 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_isnormal.c,v 1.1 2004/07/09 03:32:39 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+__isnormal(double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       return (u.bits.exp != 0 && u.bits.exp != 2047);
+}
+
+OLM_DLLEXPORT int
+__isnormalf(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       return (u.bits.exp != 0 && u.bits.exp != 255);
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__isnormall(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       return (u.bits.exp != 0 && u.bits.exp != 32767);
+}
+#endif
diff --git a/src/s_llrint.c b/src/s_llrint.c
new file mode 100644 (file)
index 0000000..dcd6aed
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrint.c,v 1.1 2005/01/11 23:12:55 das Exp $");
+
+#define type           double
+#define        roundit         rint
+#define dtype          long long
+#define        fn              llrint
+
+#include "s_lrint.c"
diff --git a/src/s_llrintf.c b/src/s_llrintf.c
new file mode 100644 (file)
index 0000000..81ae8f0
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrintf.c,v 1.1 2005/01/11 23:12:55 das Exp $");
+
+#define type           float
+#define        roundit         rintf
+#define dtype          long long
+#define        fn              llrintf
+
+#include "s_lrint.c"
diff --git a/src/s_llrintl.c b/src/s_llrintl.c
new file mode 100644 (file)
index 0000000..3b23238
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrintl.c,v 1.1 2008/01/14 02:12:06 das Exp $");
+
+#define type           long double
+#define        roundit         rintl
+#define dtype          long long
+#define        fn              llrintl
+
+#include "s_lrint.c"
diff --git a/src/s_llround.c b/src/s_llround.c
new file mode 100644 (file)
index 0000000..717ea96
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llround.c,v 1.2 2005/04/08 00:52:27 das Exp $");
+
+#define type           double
+#define        roundit         round
+#define dtype          long long
+#define        DTYPE_MIN       LLONG_MIN
+#define        DTYPE_MAX       LLONG_MAX
+#define        fn              llround
+
+#include "s_lround.c"
diff --git a/src/s_llroundf.c b/src/s_llroundf.c
new file mode 100644 (file)
index 0000000..9b8b8b8
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llroundf.c,v 1.2 2005/04/08 00:52:27 das Exp $");
+
+#define type           float
+#define        roundit         roundf
+#define dtype          long long
+#define        DTYPE_MIN       LLONG_MIN
+#define        DTYPE_MAX       LLONG_MAX
+#define        fn              llroundf
+
+#include "s_lround.c"
diff --git a/src/s_llroundl.c b/src/s_llroundl.c
new file mode 100644 (file)
index 0000000..7a00657
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_llroundl.c,v 1.1 2005/04/08 01:24:08 das Exp $");
+
+#define type           long double
+#define        roundit         roundl
+#define dtype          long long
+#define        DTYPE_MIN       LLONG_MIN
+#define        DTYPE_MAX       LLONG_MAX
+#define        fn              llroundl
+
+#include "s_lround.c"
diff --git a/src/s_log1p.c b/src/s_log1p.c
new file mode 100644 (file)
index 0000000..aa36fcd
--- /dev/null
@@ -0,0 +1,175 @@
+/* @(#)s_log1p.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_log1p.c,v 1.10 2008/03/29 16:37:59 das Exp $");
+
+/* double log1p(double x)
+ *
+ * Method :
+ *   1. Argument Reduction: find k and f such that
+ *                     1+x = 2^k * (1+f),
+ *        where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *      Note. If k=0, then f=x is exact. However, if k!=0, then f
+ *     may not be representable exactly. In that case, a correction
+ *     term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ *     log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ *     and add back the correction term c/u.
+ *     (Note: when x > 2**53, one can simply return log(x))
+ *
+ *   2. Approximation of log1p(f).
+ *     Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *              = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *              = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate
+ *     a polynomial of degree 14 to approximate R The maximum error
+ *     of this polynomial approximation is bounded by 2**-58.45. In
+ *     other words,
+ *                     2      4      6      8      10      12      14
+ *         R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+ *     (the values of Lp1 to Lp7 are listed in the program)
+ *     and
+ *         |      2          14          |     -58.45
+ *         | Lp1*s +...+Lp7*s    -  R(z) | <= 2
+ *         |                             |
+ *     Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *     In order to guarantee error in log below 1ulp, we compute log
+ *     by
+ *             log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ *     3. Finally, log1p(x) = k*ln2 + log1p(f).
+ *                          = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *        Here ln2 is split into two floating point number:
+ *                     ln2_hi + ln2_lo,
+ *        where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *     log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ *     log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ *     log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *     according to an error analysis, the error is always less than
+ *     1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ *      algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ *             u = 1+x;
+ *             if(u==1.0) return x ; else
+ *                        return log(u)*(x/(u-1.0));
+ *
+ *      See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero = 0.0;
+
+OLM_DLLEXPORT double
+log1p(double x)
+{
+       double hfsq,f,c,s,z,R,u;
+       int32_t k,hx,hu,ax;
+
+       GET_HIGH_WORD(hx,x);
+       ax = hx&0x7fffffff;
+
+       k = 1;
+       if (hx < 0x3FDA827A) {                  /* 1+x < sqrt(2)+ */
+           if(ax>=0x3ff00000) {                /* x <= -1.0 */
+               if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+               else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+           }
+           if(ax<0x3e200000) {                 /* |x| < 2**-29 */
+               if(two54+x>zero                 /* raise inexact */
+                   &&ax<0x3c900000)            /* |x| < 2**-54 */
+                   return x;
+               else
+                   return x - x*x*0.5;
+           }
+           if(hx>0||hx<=((int32_t)0xbfd2bec4)) {
+               k=0;f=x;hu=1;}          /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+       }
+       if (hx >= 0x7ff00000) return x+x;
+       if(k!=0) {
+           if(hx<0x43400000) {
+               STRICT_ASSIGN(double,u,1.0+x);
+               GET_HIGH_WORD(hu,u);
+               k  = (hu>>20)-1023;
+               c  = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+               c /= u;
+           } else {
+               u  = x;
+               GET_HIGH_WORD(hu,u);
+               k  = (hu>>20)-1023;
+               c  = 0;
+           }
+           hu &= 0x000fffff;
+           /*
+            * The approximation to sqrt(2) used in thresholds is not
+            * critical.  However, the ones used above must give less
+            * strict bounds than the one here so that the k==0 case is
+            * never reached from here, since here we have committed to
+            * using the correction term but don't use it if k==0.
+            */
+           if(hu<0x6a09e) {                    /* u ~< sqrt(2) */
+               SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */
+           } else {
+               k += 1;
+               SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */
+               hu = (0x00100000-hu)>>2;
+           }
+           f = u-1.0;
+       }
+       hfsq=0.5*f*f;
+       if(hu==0) {     /* |f| < 2**-20 */
+           if(f==zero) {
+               if(k==0) {
+                   return zero;
+               } else {
+                   c += k*ln2_lo;
+                   return k*ln2_hi+c;
+               }
+           }
+           R = hfsq*(1.0-0.66666666666666666*f);
+           if(k==0) return f-R; else
+                    return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+       }
+       s = f/(2.0+f);
+       z = s*s;
+       R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+       if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/s_log1pf.c b/src/s_log1pf.c
new file mode 100644 (file)
index 0000000..53c8f49
--- /dev/null
@@ -0,0 +1,114 @@
+/* s_log1pf.c -- float version of s_log1p.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_log1pf.c,v 1.12 2008/03/29 16:37:59 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,   /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,   /* 0x3717f7d1 */
+two25 =    3.355443200e+07,    /* 0x4c000000 */
+Lp1 = 6.6666668653e-01,        /* 3F2AAAAB */
+Lp2 = 4.0000000596e-01,        /* 3ECCCCCD */
+Lp3 = 2.8571429849e-01, /* 3E924925 */
+Lp4 = 2.2222198546e-01, /* 3E638E29 */
+Lp5 = 1.8183572590e-01, /* 3E3A3325 */
+Lp6 = 1.5313838422e-01, /* 3E1CD04F */
+Lp7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero = 0.0;
+
+OLM_DLLEXPORT float
+log1pf(float x)
+{
+       float hfsq,f,c,s,z,R,u;
+       int32_t k,hx,hu,ax;
+
+       GET_FLOAT_WORD(hx,x);
+       ax = hx&0x7fffffff;
+
+       k = 1;
+       if (hx < 0x3ed413d0) {                  /* 1+x < sqrt(2)+  */
+           if(ax>=0x3f800000) {                /* x <= -1.0 */
+               if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */
+               else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+           }
+           if(ax<0x38000000) {                 /* |x| < 2**-15 */
+               if(two25+x>zero                 /* raise inexact */
+                   &&ax<0x33800000)            /* |x| < 2**-24 */
+                   return x;
+               else
+                   return x - x*x*(float)0.5;
+           }
+           if(hx>0||hx<=((int32_t)0xbe95f619)) {
+               k=0;f=x;hu=1;}          /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+       }
+       if (hx >= 0x7f800000) return x+x;
+       if(k!=0) {
+           if(hx<0x5a000000) {
+               STRICT_ASSIGN(float,u,(float)1.0+x);
+               GET_FLOAT_WORD(hu,u);
+               k  = (hu>>23)-127;
+               /* correction term */
+               c  = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0);
+               c /= u;
+           } else {
+               u  = x;
+               GET_FLOAT_WORD(hu,u);
+               k  = (hu>>23)-127;
+               c  = 0;
+           }
+           hu &= 0x007fffff;
+           /*
+            * The approximation to sqrt(2) used in thresholds is not
+            * critical.  However, the ones used above must give less
+            * strict bounds than the one here so that the k==0 case is
+            * never reached from here, since here we have committed to
+            * using the correction term but don't use it if k==0.
+            */
+           if(hu<0x3504f4) {                   /* u < sqrt(2) */
+               SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */
+           } else {
+               k += 1;
+               SET_FLOAT_WORD(u,hu|0x3f000000);        /* normalize u/2 */
+               hu = (0x00800000-hu)>>2;
+           }
+           f = u-(float)1.0;
+       }
+       hfsq=(float)0.5*f*f;
+       if(hu==0) {     /* |f| < 2**-20 */
+           if(f==zero) {
+               if(k==0) {
+                   return zero;
+               } else {
+                   c += k*ln2_lo;
+                   return k*ln2_hi+c;
+               }
+           }
+           R = hfsq*((float)1.0-(float)0.66666666666666666*f);
+           if(k==0) return f-R; else
+                    return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+       }
+       s = f/((float)2.0+f);
+       z = s*s;
+       R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+       if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/s_logb.c b/src/s_logb.c
new file mode 100644 (file)
index 0000000..6395dd6
--- /dev/null
@@ -0,0 +1,49 @@
+/* @(#)s_logb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_logb.c,v 1.12 2008/02/08 01:22:13 bde Exp $");
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+two54 = 1.80143985094819840000e+16;    /* 43500000 00000000 */
+
+OLM_DLLEXPORT double
+logb(double x)
+{
+       int32_t lx,ix;
+       EXTRACT_WORDS(ix,lx,x);
+       ix &= 0x7fffffff;                       /* high |x| */
+       if((ix|lx)==0) return -1.0/fabs(x);
+       if(ix>=0x7ff00000) return x*x;
+       if(ix<0x00100000) {
+               x *= two54;              /* convert subnormal x to normal */
+               GET_HIGH_WORD(ix,x);
+               ix &= 0x7fffffff;
+               return (double) ((ix>>20)-1023-54);
+       } else
+               return (double) ((ix>>20)-1023);
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(logb, logbl);
+#endif
diff --git a/src/s_logbf.c b/src/s_logbf.c
new file mode 100644 (file)
index 0000000..8b1d117
--- /dev/null
@@ -0,0 +1,41 @@
+/* s_logbf.c -- float version of s_logb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_logbf.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+two25 = 3.355443200e+07;               /* 0x4c000000 */
+
+OLM_DLLEXPORT float
+logbf(float x)
+{
+       int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;                       /* high |x| */
+       if(ix==0) return (float)-1.0/fabsf(x);
+       if(ix>=0x7f800000) return x*x;
+       if(ix<0x00800000) {
+               x *= two25;              /* convert subnormal x to normal */
+               GET_FLOAT_WORD(ix,x);
+               ix &= 0x7fffffff;
+               return (float) ((ix>>23)-127-25);
+       } else
+               return (float) ((ix>>23)-127);
+}
diff --git a/src/s_logbl.c b/src/s_logbl.c
new file mode 100644 (file)
index 0000000..3c1336b
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * From: @(#)s_ilogb.c 5.1 93/09/24
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <float.h>
+#include <limits.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+logbl(long double x)
+{
+       union IEEEl2bits u;
+       unsigned long m;
+       int b;
+
+       u.e = x;
+       if (u.bits.exp == 0) {
+               if ((u.bits.manl | u.bits.manh) == 0) { /* x == 0 */
+                       u.bits.sign = 1;
+                       return (1.0L / u.e);
+               }
+               /* denormalized */
+               if (u.bits.manh == 0) {
+                       m = 1lu << (LDBL_MANL_SIZE - 1);
+                       for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1)
+                               b++;
+               } else {
+                       m = 1lu << (LDBL_MANH_SIZE - 1);
+                       for (b = 0; !(u.bits.manh & m); m >>= 1)
+                               b++;
+               }
+#ifdef LDBL_IMPLICIT_NBIT
+               b++;
+#endif
+               return ((long double)(LDBL_MIN_EXP - b - 1));
+       }
+       if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1)       /* normal */
+               return ((long double)(u.bits.exp - LDBL_MAX_EXP + 1));
+       else                                            /* +/- inf or nan */
+               return (x * x);
+}
diff --git a/src/s_lrint.c b/src/s_lrint.c
new file mode 100644 (file)
index 0000000..e1c5546
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#ifndef type
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrint.c,v 1.1 2005/01/11 23:12:55 das Exp $");
+#define type           double
+#define        roundit         rint
+#define dtype          long
+#define        fn              lrint
+#endif
+
+/*
+ * C99 says we should not raise a spurious inexact exception when an
+ * invalid exception is raised.  Unfortunately, the set of inputs
+ * that overflows depends on the rounding mode when 'dtype' has more
+ * significant bits than 'type'.  Hence, we bend over backwards for the
+ * sake of correctness; an MD implementation could be more efficient.
+ */
+OLM_DLLEXPORT dtype
+fn(type x)
+{
+       fenv_t env;
+       dtype d;
+
+       feholdexcept(&env);
+       d = (dtype)roundit(x);
+       if (fetestexcept(FE_INVALID))
+               feclearexcept(FE_INEXACT);
+       feupdateenv(&env);
+       return (d);
+}
diff --git a/src/s_lrintf.c b/src/s_lrintf.c
new file mode 100644 (file)
index 0000000..f29ad52
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrintf.c,v 1.1 2005/01/11 23:12:55 das Exp $");
+
+#define type           float
+#define        roundit         rintf
+#define dtype          long
+#define        fn              lrintf
+
+#include "s_lrint.c"
diff --git a/src/s_lrintl.c b/src/s_lrintl.c
new file mode 100644 (file)
index 0000000..b57c27d
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrintl.c,v 1.1 2008/01/14 02:12:06 das Exp $");
+
+#define type           long double
+#define        roundit         rintl
+#define dtype          long
+#define        fn              lrintl
+
+#include "s_lrint.c"
diff --git a/src/s_lround.c b/src/s_lround.c
new file mode 100644 (file)
index 0000000..76fa732
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2005 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.
+ */
+
+#include "cdefs-compat.h"
+
+#include <limits.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#ifndef type
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lround.c,v 1.2 2005/04/08 00:52:16 das Exp $");
+#define type           double
+#define        roundit         round
+#define dtype          long
+#define        DTYPE_MIN       LONG_MIN
+#define        DTYPE_MAX       LONG_MAX
+#define        fn              lround
+#endif
+
+/*
+ * If type has more precision than dtype, the endpoints dtype_(min|max) are
+ * of the form xxx.5; they are "out of range" because lround() rounds away
+ * from 0.  On the other hand, if type has less precision than dtype, then
+ * all values that are out of range are integral, so we might as well assume
+ * that everything is in range.  At compile time, INRANGE(x) should reduce to
+ * two floating-point comparisons in the former case, or TRUE otherwise.
+ */
+static const type dtype_min = DTYPE_MIN - 0.5;
+static const type dtype_max = DTYPE_MAX + 0.5;
+#define        INRANGE(x)      (dtype_max - DTYPE_MAX != 0.5 || \
+                        ((x) > dtype_min && (x) < dtype_max))
+
+OLM_DLLEXPORT dtype
+fn(type x)
+{
+
+       if (INRANGE(x)) {
+               x = roundit(x);
+               return ((dtype)x);
+       } else {
+               feraiseexcept(FE_INVALID);
+               return (DTYPE_MAX);
+       }
+}
diff --git a/src/s_lroundf.c b/src/s_lroundf.c
new file mode 100644 (file)
index 0000000..f526eef
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lroundf.c,v 1.2 2005/04/08 00:52:27 das Exp $");
+
+#define type           float
+#define        roundit         roundf
+#define dtype          long
+#define        DTYPE_MIN       LONG_MIN
+#define        DTYPE_MAX       LONG_MAX
+#define        fn              lroundf
+
+#include "s_lround.c"
diff --git a/src/s_lroundl.c b/src/s_lroundl.c
new file mode 100644 (file)
index 0000000..eb8997c
--- /dev/null
@@ -0,0 +1,11 @@
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_lroundl.c,v 1.1 2005/04/08 01:24:08 das Exp $");
+
+#define type           long double
+#define        roundit         roundl
+#define dtype          long
+#define        DTYPE_MIN       LONG_MIN
+#define        DTYPE_MAX       LONG_MAX
+#define        fn              lroundl
+
+#include "s_lround.c"
diff --git a/src/s_modf.c b/src/s_modf.c
new file mode 100644 (file)
index 0000000..e3b517b
--- /dev/null
@@ -0,0 +1,76 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *     Bit twiddling.
+ *
+ * Exception:
+ *     No exception.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0;
+
+OLM_DLLEXPORT double
+modf(double x, double *iptr)
+{
+       int32_t i0,i1,j0;
+       u_int32_t i;
+       EXTRACT_WORDS(i0,i1,x);
+       j0 = ((i0>>20)&0x7ff)-0x3ff;    /* exponent of x */
+       if(j0<20) {                     /* integer part in high x */
+           if(j0<0) {                  /* |x|<1 */
+               INSERT_WORDS(*iptr,i0&0x80000000,0);    /* *iptr = +-0 */
+               return x;
+           } else {
+               i = (0x000fffff)>>j0;
+               if(((i0&i)|i1)==0) {            /* x is integral */
+                   u_int32_t high;
+                   *iptr = x;
+                   GET_HIGH_WORD(high,x);
+                   INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+                   return x;
+               } else {
+                   INSERT_WORDS(*iptr,i0&(~i),0);
+                   return x - *iptr;
+               }
+           }
+       } else if (j0>51) {             /* no fraction part */
+           u_int32_t high;
+           if (j0 == 0x400) {          /* inf/NaN */
+               *iptr = x;
+               return 0.0 / x;
+           }
+           *iptr = x*one;
+           GET_HIGH_WORD(high,x);
+           INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+           return x;
+       } else {                        /* fraction part in low x */
+           i = ((u_int32_t)(0xffffffff))>>(j0-20);
+           if((i1&i)==0) {             /* x is integral */
+               u_int32_t high;
+               *iptr = x;
+               GET_HIGH_WORD(high,x);
+               INSERT_WORDS(x,high&0x80000000,0);      /* return +-0 */
+               return x;
+           } else {
+               INSERT_WORDS(*iptr,i0,i1&(~i));
+               return x - *iptr;
+           }
+       }
+}
diff --git a/src/s_modff.c b/src/s_modff.c
new file mode 100644 (file)
index 0000000..0a0c840
--- /dev/null
@@ -0,0 +1,58 @@
+/* s_modff.c -- float version of s_modf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_modff.c,v 1.9 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one = 1.0;
+
+OLM_DLLEXPORT float
+modff(float x, float *iptr)
+{
+       int32_t i0,j0;
+       u_int32_t i;
+       GET_FLOAT_WORD(i0,x);
+       j0 = ((i0>>23)&0xff)-0x7f;      /* exponent of x */
+       if(j0<23) {                     /* integer part in x */
+           if(j0<0) {                  /* |x|<1 */
+               SET_FLOAT_WORD(*iptr,i0&0x80000000);    /* *iptr = +-0 */
+               return x;
+           } else {
+               i = (0x007fffff)>>j0;
+               if((i0&i)==0) {                 /* x is integral */
+                   u_int32_t ix;
+                   *iptr = x;
+                   GET_FLOAT_WORD(ix,x);
+                   SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+                   return x;
+               } else {
+                   SET_FLOAT_WORD(*iptr,i0&(~i));
+                   return x - *iptr;
+               }
+           }
+       } else {                        /* no fraction part */
+           u_int32_t ix;
+           *iptr = x*one;
+           if (x != x)                 /* NaN */
+               return x;
+           GET_FLOAT_WORD(ix,x);
+           SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+           return x;
+       }
+}
diff --git a/src/s_modfl.c b/src/s_modfl.c
new file mode 100644 (file)
index 0000000..44a9363
--- /dev/null
@@ -0,0 +1,101 @@
+/*-
+ * 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.
+ *
+ * Derived from s_modf.c, which has the following Copyright:
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * $FreeBSD: src/lib/msun/src/s_modfl.c,v 1.1 2007/01/07 07:54:21 das Exp $
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#if LDBL_MANL_SIZE > 32
+#define        MASK    ((u_int64_t)-1)
+#else
+#define        MASK    ((u_int32_t)-1)
+#endif
+/* Return the last n bits of a word, representing the fractional part. */
+#define        GETFRAC(bits, n)        ((bits) & ~(MASK << (n)))
+/* The number of fraction bits in manh, not counting the integer bit */
+#define        HIBITS  (LDBL_MANT_DIG - LDBL_MANL_SIZE)
+
+static const long double zero[] = { 0.0L, -0.0L };
+
+OLM_DLLEXPORT long double
+modfl(long double x, long double *iptr)
+{
+       union IEEEl2bits ux;
+       int e;
+
+       ux.e = x;
+       e = ux.bits.exp - LDBL_MAX_EXP + 1;
+       if (e < HIBITS) {                       /* Integer part is in manh. */
+               if (e < 0) {                    /* |x|<1 */
+                       *iptr = zero[ux.bits.sign];
+                       return (x);
+               } else {
+                       if ((GETFRAC(ux.bits.manh, HIBITS - 1 - e) |
+                            ux.bits.manl) == 0) {      /* X is an integer. */
+                               *iptr = x;
+                               return (zero[ux.bits.sign]);
+                       } else {
+                               /* Clear all but the top e+1 bits. */
+                               ux.bits.manh >>= HIBITS - 1 - e;
+                               ux.bits.manh <<= HIBITS - 1 - e;
+                               ux.bits.manl = 0;
+                               *iptr = ux.e;
+                               return (x - ux.e);
+                       }
+               }
+       } else if (e >= LDBL_MANT_DIG - 1) {    /* x has no fraction part. */
+               *iptr = x;
+               if (x != x)                     /* Handle NaNs. */
+                       return (x);
+               return (zero[ux.bits.sign]);
+       } else {                                /* Fraction part is in manl. */
+               if (GETFRAC(ux.bits.manl, LDBL_MANT_DIG - 1 - e) == 0) {
+                       /* x is integral. */
+                       *iptr = x;
+                       return (zero[ux.bits.sign]);
+               } else {
+                       /* Clear all but the top e+1 bits. */
+                       ux.bits.manl >>= LDBL_MANT_DIG - 1 - e;
+                       ux.bits.manl <<= LDBL_MANT_DIG - 1 - e;
+                       *iptr = ux.e;
+                       return (x - ux.e);
+               }
+       }
+}
diff --git a/src/s_nan.c b/src/s_nan.c
new file mode 100644 (file)
index 0000000..3539a82
--- /dev/null
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2007 David Schultz
+ * 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 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 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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_nan.c,v 1.2 2007/12/18 23:46:32 das Exp $
+ */
+
+//VBS
+//#include <sys/endian.h>
+#include <ctype.h>
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+#include <string.h> //for memset
+
+#include "math_private.h"
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__DragonFly__)
+static __inline int digittoint(int c) {
+       if ('0' <= c && c <= '9')
+               return (c - '0');
+       else if ('A' <= c && c <= 'F')
+               return (c - 'A' + 10);
+       else if ('a' <= c && c <= 'f')
+               return (c - 'a' + 10);
+       return 0;
+}
+#endif
+
+
+/*
+ * Scan a string of hexadecimal digits (the format nan(3) expects) and
+ * make a bit array (using the local endianness). We stop when we
+ * encounter an invalid character, NUL, etc.  If we overflow, we do
+ * the same as gcc's __builtin_nan(), namely, discard the high order bits.
+ *
+ * The format this routine accepts needs to be compatible with what is used
+ * in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in
+ * __builtin_nan(). In fact, we're only 100% compatible for strings we
+ * consider valid, so we might be violating the C standard. But it's
+ * impossible to use nan(3) portably anyway, so this seems good enough.
+ */
+OLM_DLLEXPORT void
+__scan_nan(u_int32_t *words, int num_words, const char *s)
+{
+       int si;         /* index into s */
+       int bitpos;     /* index into words (in bits) */
+
+       memset(words, 0, num_words * sizeof(u_int32_t));
+
+       /* Allow a leading '0x'. (It's expected, but redundant.) */
+       if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+               s += 2;
+
+       /* Scan forwards in the string, looking for the end of the sequence. */
+       for (si = 0; isxdigit(s[si]); si++)
+               ;
+
+       /* Scan backwards, filling in the bits in words[] as we go. */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+       for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) {
+#else
+       for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) {
+#endif
+               if (--si < 0)
+                       break;
+               words[bitpos / 32] |= digittoint(s[si]) << (bitpos % 32);
+       }
+}
+
+OLM_DLLEXPORT double
+nan(const char *s)
+{
+       union {
+               double d;
+               u_int32_t bits[2];
+       } u;
+
+       __scan_nan(u.bits, 2, s);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+       u.bits[1] |= 0x7ff80000;
+#else
+       u.bits[0] |= 0x7ff80000;
+#endif
+       return (u.d);
+}
+
+OLM_DLLEXPORT float
+nanf(const char *s)
+{
+       union {
+               float f;
+               u_int32_t bits[1];
+       } u;
+
+       __scan_nan(u.bits, 1, s);
+       u.bits[0] |= 0x7fc00000;
+       return (u.f);
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(nan, nanl);
+#endif
diff --git a/src/s_nearbyint.c b/src/s_nearbyint.c
new file mode 100644 (file)
index 0000000..95162a5
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nearbyint.c,v 1.2 2008/01/14 02:12:06 das Exp $");
+
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * We save and restore the floating-point environment to avoid raising
+ * an inexact exception.  We can get away with using fesetenv()
+ * instead of feclearexcept()/feupdateenv() to restore the environment
+ * because the only exception defined for rint() is overflow, and
+ * rounding can't overflow as long as emax >= p.
+ */
+#define        DECL(type, fn, rint)    \
+OLM_DLLEXPORT type                             \
+fn(type x)                     \
+{                              \
+       type ret;               \
+       fenv_t env;             \
+                               \
+       fegetenv(&env);         \
+       ret = rint(x);          \
+       fesetenv(&env);         \
+       return (ret);           \
+}
+
+DECL(double, nearbyint, rint)
+DECL(float, nearbyintf, rintf)
diff --git a/src/s_nextafter.c b/src/s_nextafter.c
new file mode 100644 (file)
index 0000000..2fbf2ed
--- /dev/null
@@ -0,0 +1,83 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafter.c,v 1.12 2008/02/22 02:30:35 das Exp $");
+
+/* IEEE functions
+ *     nextafter(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+nextafter(double x, double y)
+{
+       volatile double t;
+       int32_t hx,hy,ix,iy;
+       u_int32_t lx,ly;
+
+       EXTRACT_WORDS(hx,lx,x);
+       EXTRACT_WORDS(hy,ly,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = hy&0x7fffffff;             /* |y| */
+
+       if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+          ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */
+          return x+y;
+       if(x==y) return y;              /* x=y, return y */
+       if((ix|lx)==0) {                        /* x == 0 */
+           INSERT_WORDS(x,hy&0x80000000,1);    /* return +-minsubnormal */
+           t = x*x;
+           if(t==x) return t; else return x;   /* raise underflow flag */
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if(hx>hy||((hx==hy)&&(lx>ly))) {    /* x > y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x < y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+               if(lx==0) hx -= 1;
+               lx -= 1;
+           } else {                            /* x > y, x += ulp */
+               lx += 1;
+               if(lx==0) hx += 1;
+           }
+       }
+       hy = hx&0x7ff00000;
+       if(hy>=0x7ff00000) return x+x;  /* overflow  */
+       if(hy<0x00100000) {             /* underflow */
+           t = x*x;
+           if(t!=x) {          /* raise underflow flag */
+               INSERT_WORDS(y,hx,lx);
+               return y;
+           }
+       }
+       INSERT_WORDS(x,hx,lx);
+       return x;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(nextafter, nexttoward);
+__weak_reference(nextafter, nexttowardl);
+__weak_reference(nextafter, nextafterl);
+#endif
diff --git a/src/s_nextafterf.c b/src/s_nextafterf.c
new file mode 100644 (file)
index 0000000..d4cd630
--- /dev/null
@@ -0,0 +1,67 @@
+/* s_nextafterf.c -- float version of s_nextafter.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafterf.c,v 1.11 2008/02/22 02:30:35 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+nextafterf(float x, float y)
+{
+       volatile float t;
+       int32_t hx,hy,ix,iy;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_FLOAT_WORD(hy,y);
+       ix = hx&0x7fffffff;             /* |x| */
+       iy = hy&0x7fffffff;             /* |y| */
+
+       if((ix>0x7f800000) ||   /* x is nan */
+          (iy>0x7f800000))     /* y is nan */
+          return x+y;
+       if(x==y) return y;              /* x=y, return y */
+       if(ix==0) {                             /* x == 0 */
+           SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */
+           t = x*x;
+           if(t==x) return t; else return x;   /* raise underflow flag */
+       }
+       if(hx>=0) {                             /* x > 0 */
+           if(hx>hy) {                         /* x > y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x < y, x += ulp */
+               hx += 1;
+           }
+       } else {                                /* x < 0 */
+           if(hy>=0||hx>hy){                   /* x < y, x -= ulp */
+               hx -= 1;
+           } else {                            /* x > y, x += ulp */
+               hx += 1;
+           }
+       }
+       hy = hx&0x7f800000;
+       if(hy>=0x7f800000) return x+x;  /* overflow  */
+       if(hy<0x00800000) {             /* underflow */
+           t = x*x;
+           if(t!=x) {          /* raise underflow flag */
+               SET_FLOAT_WORD(y,hx);
+               return y;
+           }
+       }
+       SET_FLOAT_WORD(x,hx);
+       return x;
+}
diff --git a/src/s_nextafterl.c b/src/s_nextafterl.c
new file mode 100644 (file)
index 0000000..d00cd65
--- /dev/null
@@ -0,0 +1,80 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafterl.c,v 1.2 2008/02/22 02:30:36 das Exp $");
+
+/* IEEE functions
+ *     nextafter(x,y)
+ *     return the next machine floating-point number of x in the
+ *     direction toward y.
+ *   Special cases:
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT long double
+nextafterl(long double x, long double y)
+{
+       volatile long double t;
+       union IEEEl2bits ux, uy;
+
+       ux.e = x;
+       uy.e = y;
+
+       if ((ux.bits.exp == 0x7fff &&
+            ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl) != 0) ||
+           (uy.bits.exp == 0x7fff &&
+            ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+          return x+y;  /* x or y is nan */
+       if(x==y) return y;              /* x=y, return y */
+       if(x==0.0) {
+           ux.bits.manh = 0;                   /* return +-minsubnormal */
+           ux.bits.manl = 1;
+           ux.bits.sign = uy.bits.sign;
+           t = ux.e*ux.e;
+           if(t==ux.e) return t; else return ux.e; /* raise underflow flag */
+       }
+       if((x>0.0) ^ (x<y)) {                   /* x -= ulp */
+           if(ux.bits.manl==0) {
+               if ((ux.bits.manh&~LDBL_NBIT)==0)
+                   ux.bits.exp -= 1;
+               ux.bits.manh = (ux.bits.manh - 1) | (ux.bits.manh & LDBL_NBIT);
+           }
+           ux.bits.manl -= 1;
+       } else {                                /* x += ulp */
+           ux.bits.manl += 1;
+           if(ux.bits.manl==0) {
+               ux.bits.manh = (ux.bits.manh + 1) | (ux.bits.manh & LDBL_NBIT);
+               if ((ux.bits.manh&~LDBL_NBIT)==0)
+                   ux.bits.exp += 1;
+           }
+       }
+       if(ux.bits.exp==0x7fff) return x+x;     /* overflow  */
+       if(ux.bits.exp==0) {                    /* underflow */
+           mask_nbit_l(ux);
+           t = ux.e * ux.e;
+           if(t!=ux.e)                 /* raise underflow flag */
+               return ux.e;
+       }
+       return ux.e;
+}
+
+__strong_reference(nextafterl, nexttowardl);
diff --git a/src/s_nexttoward.c b/src/s_nexttoward.c
new file mode 100644 (file)
index 0000000..8729c8f
--- /dev/null
@@ -0,0 +1,72 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nexttoward.c,v 1.3 2011/02/10 07:38:13 das Exp $");
+
+/*
+ * We assume that a long double has a 15-bit exponent.  On systems
+ * where long double is the same as double, nexttoward() is an alias
+ * for nextafter(), so we don't use this routine.
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT double
+nexttoward(double x, long double y)
+{
+       union IEEEl2bits uy;
+       volatile double t;
+       int32_t hx,ix;
+       u_int32_t lx;
+
+       EXTRACT_WORDS(hx,lx,x);
+       ix = hx&0x7fffffff;             /* |x| */
+       uy.e = y;
+
+       if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||
+           (uy.bits.exp == 0x7fff &&
+            ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+          return x+y;  /* x or y is nan */
+       if(x==y) return (double)y;              /* x=y, return y */
+       if(x==0.0) {
+           INSERT_WORDS(x,uy.bits.sign<<31,1); /* return +-minsubnormal */
+           t = x*x;
+           if(t==x) return t; else return x;   /* raise underflow flag */
+       }
+       if((hx>0.0) ^ (x < y)) {                        /* x -= ulp */
+           if(lx==0) hx -= 1;
+           lx -= 1;
+       } else {                                /* x += ulp */
+           lx += 1;
+           if(lx==0) hx += 1;
+       }
+       ix = hx&0x7ff00000;
+       if(ix>=0x7ff00000) return x+x;  /* overflow  */
+       if(ix<0x00100000) {             /* underflow */
+           t = x*x;
+           if(t!=x) {          /* raise underflow flag */
+               INSERT_WORDS(x,hx,lx);
+               return x;
+           }
+       }
+       INSERT_WORDS(x,hx,lx);
+       return x;
+}
diff --git a/src/s_nexttowardf.c b/src/s_nexttowardf.c
new file mode 100644 (file)
index 0000000..5676995
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_nexttowardf.c,v 1.3 2011/02/10 07:38:38 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#define        LDBL_INFNAN_EXP (LDBL_MAX_EXP * 2 - 1)
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT float
+nexttowardf(float x, long double y)
+{
+       union IEEEl2bits uy;
+       volatile float t;
+       int32_t hx,ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;             /* |x| */
+       uy.e = y;
+
+       if((ix>0x7f800000) ||
+          (uy.bits.exp == LDBL_INFNAN_EXP &&
+           ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0))
+          return x+y;  /* x or y is nan */
+       if(x==y) return (float)y;               /* x=y, return y */
+       if(ix==0) {                             /* x == 0 */
+           SET_FLOAT_WORD(x,(uy.bits.sign<<31)|1);/* return +-minsubnormal */
+           t = x*x;
+           if(t==x) return t; else return x;   /* raise underflow flag */
+       }
+       if((hx>=0) ^ (x < y))                   /* x -= ulp */
+           hx -= 1;
+       else                                    /* x += ulp */
+           hx += 1;
+       ix = hx&0x7f800000;
+       if(ix>=0x7f800000) return x+x;  /* overflow  */
+       if(ix<0x00800000) {             /* underflow */
+           t = x*x;
+           if(t!=x) {          /* raise underflow flag */
+               SET_FLOAT_WORD(x,hx);
+               return x;
+           }
+       }
+       SET_FLOAT_WORD(x,hx);
+       return x;
+}
+#endif
diff --git a/src/s_remquo.c b/src/s_remquo.c
new file mode 100644 (file)
index 0000000..13375c3
--- /dev/null
@@ -0,0 +1,158 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquo.c,v 1.2 2008/03/30 20:47:26 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+OLM_DLLEXPORT double
+remquo(double x, double y, int *quo)
+{
+       int32_t n,hx,hy,hz,ix,iy,sx,i;
+       u_int32_t lx,ly,lz,q,sxy;
+
+       EXTRACT_WORDS(hx,lx,x);
+       EXTRACT_WORDS(hy,ly,y);
+       sxy = (hx ^ hy) & 0x80000000;
+       sx = hx&0x80000000;             /* sign of x */
+       hx ^=sx;                /* |x| */
+       hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+       if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+         ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+           return (x*y)/(x*y);
+       if(hx<=hy) {
+           if((hx<hy)||(lx<ly)) {
+               q = 0;
+               goto fixup;     /* |x|<|y| return x or x-y */
+           }
+           if(lx==ly) {
+               *quo = 1;
+               return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if(hx<0x00100000) {     /* subnormal x */
+           if(hx==0) {
+               for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+           } else {
+               for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+           }
+       } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+       if(hy<0x00100000) {     /* subnormal y */
+           if(hy==0) {
+               for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+           } else {
+               for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+           }
+       } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       if(ix >= -1022) 
+           hx = 0x00100000|(0x000fffff&hx);
+       else {          /* subnormal x, shift x to normal */
+           n = -1022-ix;
+           if(n<=31) {
+               hx = (hx<<n)|(lx>>(32-n));
+               lx <<= n;
+           } else {
+               hx = lx<<(n-32);
+               lx = 0;
+           }
+       }
+       if(iy >= -1022) 
+           hy = 0x00100000|(0x000fffff&hy);
+       else {          /* subnormal y, shift y to normal */
+           n = -1022-iy;
+           if(n<=31) {
+               hy = (hy<<n)|(ly>>(32-n));
+               ly <<= n;
+           } else {
+               hy = ly<<(n-32);
+               ly = 0;
+           }
+       }
+
+    /* fix point fmod */
+       n = ix - iy;
+       q = 0;
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+           else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;}
+           q <<= 1;
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0) {                        /* return sign(x)*0 */
+           *quo = (sxy ? -q : q);
+           return Zero[(u_int32_t)sx>>31];
+       }
+       while(hx<0x00100000) {          /* normalize x */
+           hx = hx+hx+(lx>>31); lx = lx+lx;
+           iy -= 1;
+       }
+       if(iy>= -1022) {        /* normalize output */
+           hx = ((hx-0x00100000)|((iy+1023)<<20));
+       } else {                /* subnormal output */
+           n = -1022 - iy;
+           if(n<=20) {
+               lx = (lx>>n)|((u_int32_t)hx<<(32-n));
+               hx >>= n;
+           } else if (n<=31) {
+               lx = (hx<<(32-n))|(lx>>n); hx = sx;
+           } else {
+               lx = hx>>(n-32); hx = sx;
+           }
+       }
+fixup:
+       INSERT_WORDS(x,hx,lx);
+       y = fabs(y);
+       if (y < 0x1p-1021) {
+           if (x+x>y || (x+x==y && (q & 1))) {
+               q++;
+               x-=y;
+           }
+       } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+           q++;
+           x-=y;
+       }
+       GET_HIGH_WORD(hx,x);
+       SET_HIGH_WORD(x,hx^sx);
+       q &= 0x7fffffff;
+       *quo = (sxy ? -q : q);
+       return x;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(remquo, remquol);
+#endif
diff --git a/src/s_remquof.c b/src/s_remquof.c
new file mode 100644 (file)
index 0000000..7ef0f72
--- /dev/null
@@ -0,0 +1,122 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquof.c,v 1.1 2005/03/25 04:40:44 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+OLM_DLLEXPORT float
+remquof(float x, float y, int *quo)
+{
+       int32_t n,hx,hy,hz,ix,iy,sx,i;
+       u_int32_t q,sxy;
+
+       GET_FLOAT_WORD(hx,x);
+       GET_FLOAT_WORD(hy,y);
+       sxy = (hx ^ hy) & 0x80000000;
+       sx = hx&0x80000000;             /* sign of x */
+       hx ^=sx;                /* |x| */
+       hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+       if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */
+           return (x*y)/(x*y);
+       if(hx<hy) {
+           q = 0;
+           goto fixup; /* |x|<|y| return x or x-y */
+       } else if(hx==hy) {
+           *quo = 1;
+           return Zero[(u_int32_t)sx>>31];     /* |x|=|y| return x*0*/
+       }
+
+    /* determine ix = ilogb(x) */
+       if(hx<0x00800000) {     /* subnormal x */
+           for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+       } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+       if(hy<0x00800000) {     /* subnormal y */
+           for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1;
+       } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       if(ix >= -126)
+           hx = 0x00800000|(0x007fffff&hx);
+       else {          /* subnormal x, shift x to normal */
+           n = -126-ix;
+           hx <<= n;
+       }
+       if(iy >= -126)
+           hy = 0x00800000|(0x007fffff&hy);
+       else {          /* subnormal y, shift y to normal */
+           n = -126-iy;
+           hy <<= n;
+       }
+
+    /* fix point fmod */
+       n = ix - iy;
+       q = 0;
+       while(n--) {
+           hz=hx-hy;
+           if(hz<0) hx = hx << 1;
+           else {hx = hz << 1; q++;}
+           q <<= 1;
+       }
+       hz=hx-hy;
+       if(hz>=0) {hx=hz;q++;}
+
+    /* convert back to floating value and restore the sign */
+       if(hx==0) {                             /* return sign(x)*0 */
+           *quo = (sxy ? -q : q);
+           return Zero[(u_int32_t)sx>>31];
+       }
+       while(hx<0x00800000) {          /* normalize x */
+           hx <<= 1;
+           iy -= 1;
+       }
+       if(iy>= -126) {         /* normalize output */
+           hx = ((hx-0x00800000)|((iy+127)<<23));
+       } else {                /* subnormal output */
+           n = -126 - iy;
+           hx >>= n;
+       }
+fixup:
+       SET_FLOAT_WORD(x,hx);
+       y = fabsf(y);
+       if (y < 0x1p-125f) {
+           if (x+x>y || (x+x==y && (q & 1))) {
+               q++;
+               x-=y;
+           }
+       } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) {
+           q++;
+           x-=y;
+       }
+       GET_FLOAT_WORD(hx,x);
+       SET_FLOAT_WORD(x,hx^sx);
+       q &= 0x7fffffff;
+       *quo = (sxy ? -q : q);
+       return x;
+}
diff --git a/src/s_remquol.c b/src/s_remquol.c
new file mode 100644 (file)
index 0000000..ebde999
--- /dev/null
@@ -0,0 +1,177 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquol.c,v 1.2 2008/07/31 20:09:47 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#define        BIAS (LDBL_MAX_EXP - 1)
+
+#if LDBL_MANL_SIZE > 32
+typedef        u_int64_t manl_t;
+#else
+typedef        u_int32_t manl_t;
+#endif
+
+#if LDBL_MANH_SIZE > 32
+typedef        u_int64_t manh_t;
+#else
+typedef        u_int32_t manh_t;
+#endif
+
+/*
+ * These macros add and remove an explicit integer bit in front of the
+ * fractional mantissa, if the architecture doesn't have such a bit by
+ * default already.
+ */
+#ifdef LDBL_IMPLICIT_NBIT
+#define        SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
+#define        HFRAC_BITS      LDBL_MANH_SIZE
+#else
+#define        SET_NBIT(hx)    (hx)
+#define        HFRAC_BITS      (LDBL_MANH_SIZE - 1)
+#endif
+
+#define        MANL_SHIFT      (LDBL_MANL_SIZE - 1)
+
+static const long double Zero[] = {0.0L, -0.0L};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ *
+ * Assumptions:
+ * - The low part of the mantissa fits in a manl_t exactly.
+ * - The high part of the mantissa fits in an int64_t with enough room
+ *   for an explicit integer bit in front of the fractional bits.
+ */
+OLM_DLLEXPORT long double
+remquol(long double x, long double y, int *quo)
+{
+       union IEEEl2bits ux, uy;
+       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
+       manh_t hy;
+       manl_t lx,ly,lz;
+       int ix,iy,n,q,sx,sxy;
+
+       ux.e = x;
+       uy.e = y;
+       sx = ux.bits.sign;
+       sxy = sx ^ uy.bits.sign;
+       ux.bits.sign = 0;       /* |x| */
+       uy.bits.sign = 0;       /* |y| */
+       x = ux.e;
+
+    /* purge off exception values */
+       if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */
+          (ux.bits.exp == BIAS + LDBL_MAX_EXP) ||       /* or x not finite */
+          (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
+           ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */
+           return (x*y)/(x*y);
+       if(ux.bits.exp<=uy.bits.exp) {
+           if((ux.bits.exp<uy.bits.exp) ||
+              (ux.bits.manh<=uy.bits.manh &&
+               (ux.bits.manh<uy.bits.manh ||
+                ux.bits.manl<uy.bits.manl))) {
+               q = 0;
+               goto fixup;     /* |x|<|y| return x or x-y */
+           }
+           if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) {
+               *quo = 1;
+               return Zero[sx];        /* |x|=|y| return x*0*/
+           }
+       }
+
+    /* determine ix = ilogb(x) */
+       if(ux.bits.exp == 0) {  /* subnormal x */
+           ux.e *= 0x1.0p512;
+           ix = ux.bits.exp - (BIAS + 512);
+       } else {
+           ix = ux.bits.exp - BIAS;
+       }
+
+    /* determine iy = ilogb(y) */
+       if(uy.bits.exp == 0) {  /* subnormal y */
+           uy.e *= 0x1.0p512;
+           iy = uy.bits.exp - (BIAS + 512);
+       } else {
+           iy = uy.bits.exp - BIAS;
+       }
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+       hx = SET_NBIT(ux.bits.manh);
+       hy = SET_NBIT(uy.bits.manh);
+       lx = ux.bits.manl;
+       ly = uy.bits.manl;
+
+    /* fix point fmod */
+       n = ix - iy;
+       q = 0;
+
+       while(n--) {
+           hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+           if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;}
+           else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;}
+           q <<= 1;
+       }
+       hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+       if(hz>=0) {hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+       if((hx|lx)==0) {                        /* return sign(x)*0 */
+           *quo = (sxy ? -q : q);
+           return Zero[sx];
+       }
+       while(hx<(1ULL<<HFRAC_BITS)) {  /* normalize x */
+           hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;
+           iy -= 1;
+       }
+       ux.bits.manh = hx; /* The integer bit is truncated here if needed. */
+       ux.bits.manl = lx;
+       if (iy < LDBL_MIN_EXP) {
+           ux.bits.exp = iy + (BIAS + 512);
+           ux.e *= 0x1p-512;
+       } else {
+           ux.bits.exp = iy + BIAS;
+       }
+       ux.bits.sign = 0;
+       x = ux.e;
+fixup:
+       y = fabsl(y);
+       if (y < LDBL_MIN * 2) {
+           if (x+x>y || (x+x==y && (q & 1))) {
+               q++;
+               x-=y;
+           }
+       } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+           q++;
+           x-=y;
+       }
+
+       ux.e = x;
+       ux.bits.sign ^= sx;
+       x = ux.e;
+
+       q &= 0x7fffffff;
+       *quo = (sxy ? -q : q);
+       return x;
+}
diff --git a/src/s_rint.c b/src/s_rint.c
new file mode 100644 (file)
index 0000000..f2d8c0e
--- /dev/null
@@ -0,0 +1,92 @@
+/* @(#)s_rint.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_rint.c,v 1.16 2008/02/22 02:30:35 das Exp $");
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ *     Using floating addition.
+ * Exception:
+ *     Inexact flag raised if x not equal to rint(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+TWO52[2]={
+  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+OLM_DLLEXPORT double
+rint(double x)
+{
+       int32_t i0,j0,sx;
+       u_int32_t i,i1;
+       double w,t;
+       EXTRACT_WORDS(i0,i1,x);
+       sx = (i0>>31)&1;
+       j0 = ((i0>>20)&0x7ff)-0x3ff;
+       if(j0<20) {
+           if(j0<0) {
+               if(((i0&0x7fffffff)|i1)==0) return x;
+               i1 |= (i0&0x0fffff);
+               i0 &= 0xfffe0000;
+               i0 |= ((i1|-i1)>>12)&0x80000;
+               SET_HIGH_WORD(x,i0);
+               STRICT_ASSIGN(double,w,TWO52[sx]+x);
+               t =  w-TWO52[sx];
+               GET_HIGH_WORD(i0,t);
+               SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
+               return t;
+           } else {
+               i = (0x000fffff)>>j0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               i>>=1;
+               if(((i0&i)|i1)!=0) {
+                   /*
+                    * Some bit is set after the 0.5 bit.  To avoid the
+                    * possibility of errors from double rounding in
+                    * w = TWO52[sx]+x, adjust the 0.25 bit to a lower
+                    * guard bit.  We do this for all j0<=51.  The
+                    * adjustment is trickiest for j0==18 and j0==19
+                    * since then it spans the word boundary.
+                    */
+                   if(j0==19) i1 = 0x40000000; else
+                   if(j0==18) i1 = 0x80000000; else
+                   i0 = (i0&(~i))|((0x20000)>>j0);
+               }
+           }
+       } else if (j0>51) {
+           if(j0==0x400) return x+x;   /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(j0-20);
+           if((i1&i)==0) return x;     /* x is integral */
+           i>>=1;
+           if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+       }
+       INSERT_WORDS(x,i0,i1);
+       STRICT_ASSIGN(double,w,TWO52[sx]+x);
+       return w-TWO52[sx];
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(rint, rintl);
+#endif
diff --git a/src/s_rintf.c b/src/s_rintf.c
new file mode 100644 (file)
index 0000000..60cdb46
--- /dev/null
@@ -0,0 +1,53 @@
+/* s_rintf.c -- float version of s_rint.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_rintf.c,v 1.12 2008/02/22 02:30:35 das Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "math_private.h"
+
+static const float
+TWO23[2]={
+  8.3886080000e+06, /* 0x4b000000 */
+ -8.3886080000e+06, /* 0xcb000000 */
+};
+
+OLM_DLLEXPORT float
+rintf(float x)
+{
+       int32_t i0,j0,sx;
+       float w,t;
+       GET_FLOAT_WORD(i0,x);
+       sx = (i0>>31)&1;
+       j0 = ((i0>>23)&0xff)-0x7f;
+       if(j0<23) {
+           if(j0<0) {
+               if((i0&0x7fffffff)==0) return x;
+               STRICT_ASSIGN(float,w,TWO23[sx]+x);
+               t =  w-TWO23[sx];
+               GET_FLOAT_WORD(i0,t);
+               SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31));
+               return t;
+           }
+           STRICT_ASSIGN(float,w,TWO23[sx]+x);
+           return w-TWO23[sx];
+       }
+       if(j0==0x80) return x+x;        /* inf or NaN */
+       else return x;                  /* x is integral */
+}
diff --git a/src/s_rintl.c b/src/s_rintl.c
new file mode 100644 (file)
index 0000000..d20768e
--- /dev/null
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_rintl.c,v 1.5 2008/02/22 11:59:05 bde Exp $");
+
+#include <float.h>
+#include <openlibm_fenv.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+
+//VBS
+#include "math_private.h"
+
+
+#if LDBL_MAX_EXP != 0x4000
+/* We also require the usual bias, min exp and expsign packing. */
+#error "Unsupported long double format"
+#endif
+
+#define        BIAS    (LDBL_MAX_EXP - 1)
+
+static const float
+shift[2] = {
+#if LDBL_MANT_DIG == 64
+       0x1.0p63, -0x1.0p63
+#elif LDBL_MANT_DIG == 113
+       0x1.0p112, -0x1.0p112
+#else
+#error "Unsupported long double format"
+#endif
+};
+static const float zero[2] = { 0.0, -0.0 };
+
+OLM_DLLEXPORT long double
+rintl(long double x)
+{
+       union IEEEl2bits u;
+       u_int32_t expsign;
+       int ex, sign;
+
+       u.e = x;
+       expsign = u.xbits.expsign;
+       ex = expsign & 0x7fff;
+
+       if (ex >= BIAS + LDBL_MANT_DIG - 1) {
+               if (ex == BIAS + LDBL_MAX_EXP)
+                       return (x + x); /* Inf, NaN, or unsupported format */
+               return (x);             /* finite and already an integer */
+       }
+       sign = expsign >> 15;
+
+       /*
+        * The following code assumes that intermediate results are
+        * evaluated in long double precision. If they are evaluated in
+        * greater precision, double rounding may occur, and if they are
+        * evaluated in less precision (as on i386), results will be
+        * wildly incorrect.
+        */
+       x += shift[sign];
+       x -= shift[sign];
+
+       /*
+        * If the result is +-0, then it must have the same sign as x, but
+        * the above calculation doesn't always give this.  Fix up the sign.
+        */
+       if (ex < BIAS && x == 0.0L)
+               return (zero[sign]);
+
+       return (x);
+}
+
+/*
+ * We save and restore the floating-point environment to avoid raising
+ * an inexact exception.  We can get away with using fesetenv()
+ * instead of feclearexcept()/feupdateenv() to restore the environment
+ * because the only exception defined for rint() is overflow, and
+ * rounding can't overflow as long as emax >= p.
+ */
+#define        DECL(type, fn, rint)    \
+OLM_DLLEXPORT type                             \
+fn(type x)                     \
+{                              \
+       type ret;               \
+       fenv_t env;             \
+                               \
+       fegetenv(&env);         \
+       ret = rint(x);          \
+       fesetenv(&env);         \
+       return (ret);           \
+}
+DECL(long double, nearbyintl, rintl)
diff --git a/src/s_round.c b/src/s_round.c
new file mode 100644 (file)
index 0000000..a982ec3
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2003, 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_round.c,v 1.4 2005/12/02 13:45:06 bde Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+round(double x)
+{
+       double t;
+       uint32_t hx;
+
+       GET_HIGH_WORD(hx, x);
+       if ((hx & 0x7fffffff) == 0x7ff00000)
+               return (x + x);
+
+       if (!(hx & 0x80000000)) {
+               t = floor(x);
+               if (t - x <= -0.5)
+                       t += 1;
+               return (t);
+       } else {
+               t = floor(-x);
+               if (t + x <= -0.5)
+                       t += 1;
+               return (-t);
+       }
+}
diff --git a/src/s_roundf.c b/src/s_roundf.c
new file mode 100644 (file)
index 0000000..784a8a5
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003, 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_roundf.c,v 1.4 2005/12/02 13:45:06 bde Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+roundf(float x)
+{
+       float t;
+
+       if (!isfinite(x))
+               return (x);
+
+       if (x >= 0.0) {
+               t = floorf(x);
+               if (t - x <= -0.5)
+                       t += 1.0;
+               return (t);
+       } else {
+               t = floorf(-x);
+               if (t + x <= -0.5)
+                       t += 1.0;
+               return (-t);
+       }
+}
diff --git a/src/s_roundl.c b/src/s_roundl.c
new file mode 100644 (file)
index 0000000..dbcd651
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003, 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_roundl.c,v 1.2 2005/12/02 13:45:06 bde Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+roundl(long double x)
+{
+       long double t;
+
+       if (!isfinite(x))
+               return (x);
+
+       if (x >= 0.0) {
+               t = floorl(x);
+               if (t - x <= -0.5)
+                       t += 1.0;
+               return (t);
+       } else {
+               t = floorl(-x);
+               if (t + x <= -0.5)
+                       t += 1.0;
+               return (-t);
+       }
+}
diff --git a/src/s_scalbln.c b/src/s_scalbln.c
new file mode 100644 (file)
index 0000000..978b523
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2004 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_scalbln.c,v 1.2 2005/03/07 04:57:50 das Exp $");
+
+#include <limits.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+scalbln (double x, long n)
+{
+       int in;
+
+       in = (int)n;
+       if (in != n) {
+               if (n > 0)
+                       in = INT_MAX;
+               else
+                       in = INT_MIN;
+       }
+       return (scalbn(x, in));
+}
+
+OLM_DLLEXPORT float
+scalblnf (float x, long n)
+{
+       int in;
+
+       in = (int)n;
+       if (in != n) {
+               if (n > 0)
+                       in = INT_MAX;
+               else
+                       in = INT_MIN;
+       }
+       return (scalbnf(x, in));
+}
+
+OLM_DLLEXPORT long double
+scalblnl (long double x, long n)
+{
+       int in;
+
+       in = (int)n;
+       if (in != n) {
+               if (n > 0)
+                       in = INT_MAX;
+               else
+                       in = INT_MIN;
+       }
+       return (scalbnl(x, (int)n));
+}
diff --git a/src/s_scalbn.c b/src/s_scalbn.c
new file mode 100644 (file)
index 0000000..4ab59ca
--- /dev/null
@@ -0,0 +1,66 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n  computed by  exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include "cdefs-compat.h"
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double
+two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge   = 1.0e+300,
+tiny   = 1.0e-300;
+
+OLM_DLLEXPORT double
+scalbn (double x, int n)
+{
+       int32_t k,hx,lx;
+       EXTRACT_WORDS(hx,lx,x);
+        k = (hx&0x7ff00000)>>20;               /* extract exponent */
+        if (k==0) {                            /* 0 or subnormal x */
+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+           x *= two54;
+           GET_HIGH_WORD(hx,x);
+           k = ((hx&0x7ff00000)>>20) - 54;
+            if (n< -50000) return tiny*x;      /*underflow*/
+           }
+        if (k==0x7ff) return x+x;              /* NaN or Inf */
+        k = k+n;
+        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */
+        if (k > 0)                             /* normal result */
+           {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
+        if (k <= -54) {
+            if (n > 50000)     /* in case integer overflow in n+k */
+               return huge*copysign(huge,x);   /*overflow*/
+           else return tiny*copysign(tiny,x);  /*underflow*/
+        } 
+       k += 54;                                /* subnormal result */
+       SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
+        return x*twom54;
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(scalbn, ldexpl);
+__weak_reference(scalbn, scalbnl);
+#endif
+
+__strong_reference(scalbn, ldexp);
diff --git a/src/s_scalbnf.c b/src/s_scalbnf.c
new file mode 100644 (file)
index 0000000..3e8c471
--- /dev/null
@@ -0,0 +1,57 @@
+/* s_scalbnf.c -- float version of s_scalbn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+#include "cdefs-compat.h"
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float
+two25   =  3.355443200e+07,    /* 0x4c000000 */
+twom25  =  2.9802322388e-08,   /* 0x33000000 */
+huge   = 1.0e+30,
+tiny   = 1.0e-30;
+
+OLM_DLLEXPORT float
+scalbnf (float x, int n)
+{
+       int32_t k,ix;
+       GET_FLOAT_WORD(ix,x);
+        k = (ix&0x7f800000)>>23;               /* extract exponent */
+        if (k==0) {                            /* 0 or subnormal x */
+            if ((ix&0x7fffffff)==0) return x; /* +-0 */
+           x *= two25;
+           GET_FLOAT_WORD(ix,x);
+           k = ((ix&0x7f800000)>>23) - 25;
+            if (n< -50000) return tiny*x;      /*underflow*/
+           }
+        if (k==0xff) return x+x;               /* NaN or Inf */
+        k = k+n;
+        if (k >  0xfe) return huge*copysignf(huge,x); /* overflow  */
+        if (k > 0)                             /* normal result */
+           {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+        if (k <= -25) {
+            if (n > 50000)     /* in case integer overflow in n+k */
+               return huge*copysignf(huge,x);  /*overflow*/
+           else return tiny*copysignf(tiny,x); /*underflow*/
+        }
+       k += 25;                                /* subnormal result */
+       SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+        return x*twom25;
+}
+
+__strong_reference(scalbnf, ldexpf);
diff --git a/src/s_scalbnl.c b/src/s_scalbnl.c
new file mode 100644 (file)
index 0000000..d41cd02
--- /dev/null
@@ -0,0 +1,70 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbnl (long double x, int n)
+ * scalbnl(x,n) returns x* 2**n  computed by  exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+/*
+ * We assume that a long double has a 15-bit exponent.  On systems
+ * where long double is the same as double, scalbnl() is an alias
+ * for scalbn(), so we don't use this routine.
+ */
+
+#include "cdefs-compat.h"
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#if LDBL_MAX_EXP != 0x4000
+#error "Unsupported long double format"
+#endif
+
+static const long double
+huge = 0x1p16000L,
+tiny = 0x1p-16000L;
+
+OLM_DLLEXPORT long double
+scalbnl (long double x, int n)
+{
+       union IEEEl2bits u;
+       int k;
+       u.e = x;
+        k = u.bits.exp;                                /* extract exponent */
+        if (k==0) {                            /* 0 or subnormal x */
+            if ((u.bits.manh|u.bits.manl)==0) return x;        /* +-0 */
+           u.e *= 0x1p+128;
+           k = u.bits.exp - 128;
+            if (n< -50000) return tiny*x;      /*underflow*/
+           }
+        if (k==0x7fff) return x+x;             /* NaN or Inf */
+        k = k+n;
+        if (k >= 0x7fff) return huge*copysignl(huge,x); /* overflow  */
+        if (k > 0)                             /* normal result */
+           {u.bits.exp = k; return u.e;}
+        if (k <= -128) {
+            if (n > 50000)     /* in case integer overflow in n+k */
+               return huge*copysign(huge,x);   /*overflow*/
+           else return tiny*copysign(tiny,x);  /*underflow*/
+        }
+       k += 128;                               /* subnormal result */
+       u.bits.exp = k;
+        return u.e*0x1p-128;
+}
+
+__strong_reference(scalbnl, ldexpl);
diff --git a/src/s_signbit.c b/src/s_signbit.c
new file mode 100644 (file)
index 0000000..3954c41
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@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.
+ *
+ * $FreeBSD: src/lib/msun/src/s_signbit.c,v 1.1 2004/07/19 08:16:10 das Exp $
+ */
+
+#include <openlibm_math.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+OLM_DLLEXPORT int
+__signbit(double d)
+{
+       union IEEEd2bits u;
+
+       u.d = d;
+       return (u.bits.sign);
+}
+
+OLM_DLLEXPORT int
+__signbitf(float f)
+{
+       union IEEEf2bits u;
+
+       u.f = f;
+       return (u.bits.sign);
+}
+
+#ifdef LONG_DOUBLE
+OLM_DLLEXPORT int
+__signbitl(long double e)
+{
+       union IEEEl2bits u;
+
+       u.e = e;
+       return (u.bits.sign);
+}
+#endif
diff --git a/src/s_signgam.c b/src/s_signgam.c
new file mode 100644 (file)
index 0000000..ad72a73
--- /dev/null
@@ -0,0 +1,7 @@
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+#ifndef OPENLIBM_ONLY_THREAD_SAFE
+int signgam = 0;
+#endif
diff --git a/src/s_sin.c b/src/s_sin.c
new file mode 100644 (file)
index 0000000..3eb0c4a
--- /dev/null
@@ -0,0 +1,89 @@
+/* @(#)s_sin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_sin.c,v 1.13 2011/02/10 07:37:50 das Exp $");
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ *     __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *     __kernel_cos            ... cose function on [-pi/4,pi/4]
+ *     __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *     [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *     in [-pi/4 , +pi/4], and let n = k mod 4.
+ *     We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *         0          S           C             T
+ *         1          C          -S            -1/T
+ *         2         -S          -C             T
+ *         3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *     TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define INLINE_REM_PIO2
+#include "math_private.h"
+//#include "e_rem_pio2.c"
+
+OLM_DLLEXPORT double
+sin(double x)
+{
+       double y[2],z=0.0;
+       int32_t n, ix;
+
+    /* High word of x. */
+       GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+       ix &= 0x7fffffff;
+       if(ix <= 0x3fe921fb) {
+           if(ix<0x3e500000)                   /* |x| < 2**-26 */
+              {if((int)x==0) return x;}        /* generate inexact */
+           return __kernel_sin(x,z,0);
+       }
+
+    /* sin(Inf or NaN) is NaN */
+       else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2(x,y);
+           switch(n&3) {
+               case 0: return  __kernel_sin(y[0],y[1],1);
+               case 1: return  __kernel_cos(y[0],y[1]);
+               case 2: return -__kernel_sin(y[0],y[1],1);
+               default:
+                       return -__kernel_cos(y[0],y[1]);
+           }
+       }
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(sin, sinl);
+#endif
diff --git a/src/s_sincos.c b/src/s_sincos.c
new file mode 100644 (file)
index 0000000..229d967
--- /dev/null
@@ -0,0 +1,150 @@
+/* @(#)s_sincos.c 5.1 13/07/15 */
+/*
+ * ====================================================
+ * Copyright (C) 2013 Elliot Saba. All rights reserved.
+ *
+ * Developed at the University of Washington.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+ #include "cdefs-compat.h"
+
+/* sincos(x, s, c)
+ * Several applications need sine and cosine of the same
+ * angle x. This function computes both at the same time,
+ * and stores the results in *sin and *cos.
+ *
+ * kernel function:
+ *     __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *     __kernel_cos            ... cose function on [-pi/4,pi/4]
+ *     __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Borrow liberally from s_sin.c and s_cos.c, merging
+ *  efforts where applicable and returning their values in
+ * appropriate variables, thereby slightly reducing the
+ * amount of work relative to just calling sin/cos(x) 
+ * separately
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      sincos(+-INF, s, c)  is NaN, with signals;
+ *      sincos(NaN, s, c)    is that NaN;
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define INLINE_REM_PIO2
+#include "math_private.h"
+//#include "e_rem_pio2.c"
+
+/* Constants used in polynomial approximation of sin/cos */
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6  =  1.58969099521155010221e-10, /* 0x3DE5D93A, 0x5ACFD57C */
+C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+static void
+__kernel_sincos( double x, double y, int iy, double * k_s, double * k_c )
+{
+    /* Inline calculation of sin/cos, as we can save
+    some work, and we will always need to calculate
+    both values, no matter the result of switch */
+    double z, w, r, v, hz;
+    z   = x*x;
+    w   = z*z;
+
+    /* cos-specific computation; equivalent to calling
+     __kernel_cos(x,y) and storing in k_c*/
+    r   = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
+    hz  = 0.5*z;
+    v   = one-hz;
+
+    *k_c = v + (((one-v)-hz) + (z*r-x*y));
+
+    /* sin-specific computation; equivalent to calling
+    __kernel_sin(x,y,1) and storing in k_s*/
+    r   = S2+z*(S3+z*S4) + z*w*(S5+z*S6);
+    v   = z*x;
+    if(iy == 0)
+        *k_s = x+v*(S1+z*r);
+    else
+        *k_s = x-((z*(half*y-v*r)-y)-v*S1);
+}
+
+OLM_DLLEXPORT void
+sincos(double x, double * s, double * c)
+{
+    double y[2];
+    int32_t ix;
+
+    /* Store high word of x in ix */
+    GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+    ix &= 0x7fffffff;
+    if(ix <= 0x3fe921fb) {
+        /* Check for small x for sin and cos */
+        if(ix<0x3e46a09e) {
+            /* Check for exact zero */
+            if( (int)x==0 ) {
+                *s = x;
+                *c = 1.0;
+                return;
+            }
+        }
+        /* Call kernel function with 0 extra */
+        __kernel_sincos(x,0.0,0, s, c);
+    } else if( ix >= 0x7ff00000 ) {
+        /* sincos(Inf or NaN) is NaN */
+        *s = x-x;
+        *c = x-x;
+    }
+
+    /*argument reduction needed*/
+    else {
+        double k_c, k_s;
+
+        /* Calculate remainer, then sub out to kernel */
+        int32_t n = __ieee754_rem_pio2(x,y);
+        __kernel_sincos( y[0], y[1], 1, &k_s, &k_c );
+
+        /* Figure out permutation of sin/cos outputs to true outputs */
+        switch(n&3) {
+            case 0:
+                *c =  k_c;
+                *s =  k_s;
+                break;
+            case 1:
+                *c = -k_s;
+                *s =  k_c;
+                break;
+            case 2:
+                *c = -k_c;
+                *s = -k_s;
+                break;
+            default:
+                *c =  k_s;
+                *s = -k_c;
+                break;
+        }
+    }
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(sincos, sincosl);
+#endif
diff --git a/src/s_sincosf.c b/src/s_sincosf.c
new file mode 100644 (file)
index 0000000..09f35af
--- /dev/null
@@ -0,0 +1,163 @@
+/* s_sincosf.c -- float version of s_sincos.c
+ *
+ * Copyright (C) 2013 Elliot Saba
+ * Developed at the University of Washington
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+*/
+
+#include "cdefs-compat.h"
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define      INLINE_KERNEL_COSDF
+//#define      INLINE_KERNEL_SINDF
+//#define INLINE_REM_PIO2F
+#include "math_private.h"
+//#include "e_rem_pio2f.c"
+//#include "k_cosf.c"
+//#include "k_sinf.c"
+
+
+/* Constants used in shortcircuits in sincosf */
+static const double
+sc1pio2 = 1*M_PI_2,                    /* 0x3FF921FB, 0x54442D18 */
+sc2pio2 = 2*M_PI_2,                    /* 0x400921FB, 0x54442D18 */
+sc3pio2 = 3*M_PI_2,                    /* 0x4012D97C, 0x7F3321D2 */
+sc4pio2 = 4*M_PI_2,                    /* 0x401921FB, 0x54442D18 */
+
+/* Constants used in polynomial approximation of sin/cos */
+one =  1.0,
+S1 = -0x15555554cbac77.0p-55,  /* -0.166666666416265235595 */
+S2 =  0x111110896efbb2.0p-59,  /*  0.0083333293858894631756 */
+S3 = -0x1a00f9e2cae774.0p-65,  /* -0.000198393348360966317347 */
+S4 =  0x16cd878c3b46a7.0p-71,  /*  0.0000027183114939898219064 */
+C0  = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */
+C1  =  0x155553e1053a42.0p-57, /*  0.0416666233237390631894 */
+C2  = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */
+C3  =  0x199342e0ee5069.0p-68; /*  0.0000243904487962774090654 */
+
+static void
+__kernel_sincosdf( double x, float * s, float * c )
+{
+       double r, w, z, v;
+       z = x*x;
+       w = z*z;
+
+       /* cos-specific computation; equivalent to calling
+     __kernel_cos(x,y) and storing in k_c*/
+       r = C2+z*C3;
+       double k_c = ((one+z*C0) + w*C1) + (w*z)*r;
+
+       /* sin-specific computation; equivalent to calling
+    __kernel_sin(x,y,1) and storing in k_s*/
+       r = S3+z*S4;
+       v = z*x;
+       double k_s = (x + v*(S1+z*S2)) + v*w*r;
+
+       *c = k_c;
+       *s = k_s;
+}
+
+OLM_DLLEXPORT void
+sincosf(float x, float * s, float * c) {
+       // Worst approximation of sin and cos NA
+       *s = x;
+       *c = x;
+
+       double y;
+       float k_c, k_s;
+       int32_t n, hx, ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx & 0x7fffffff;
+
+       if(ix <= 0x3f490fda) {          /* |x| ~<= pi/4 */
+           if(ix<0x39800000) {         /* |x| < 2**-12 */
+                       /* Check if x is exactly zero */
+                       if(((int)x)==0) {
+                               *s = x;
+                               *c = 1.0f;
+                               return;
+                       }
+               }
+               __kernel_sincosdf(x, s, c);
+               return;
+       }
+       /* |x| ~<= 5*pi/4 */
+       if (ix<=0x407b53d1) {
+               /* |x| ~<= 3pi/4 */
+           if(ix<=0x4016cbe3) {
+                       if(hx>0) {
+                               __kernel_sincosdf( sc1pio2 - x, c, s );
+                       }
+                       else {
+                               __kernel_sincosdf( sc1pio2 + x, c, &k_s );
+                               *s = -k_s;
+                   }
+               } else {
+
+                       if(hx>0) {
+                               __kernel_sincosdf( sc2pio2 - x, s, &k_c );
+                               *c = -k_c;
+                       } else  {
+                               __kernel_sincosdf( -sc2pio2 - x, s, &k_c );
+                               *c = -k_c;
+                       }
+               }
+               return;
+       }
+
+       /* |x| ~<= 9*pi/4 */
+       if(ix<=0x40e231d5) {
+               /* |x|  ~> 7*pi/4 */
+           if(ix<=0x40afeddf) {        
+                       if(hx>0) {
+                               __kernel_sincosdf( x - sc3pio2, c, &k_s );
+                               *s = -k_s;
+                       } else {
+                               __kernel_sincosdf( x + sc3pio2, &k_c, s );
+                               *c = -k_c;
+                   } 
+               }
+               else {
+               if( hx > 0 ) {
+                       __kernel_sincosdf( x - sc4pio2, s, c );
+               } else {
+                       __kernel_sincosdf( x + sc4pio2, s, c );
+               }
+           }
+               return;
+       }
+
+       /* cos(Inf or NaN) is NaN */
+       else if(ix>=0x7f800000) {
+               *c = *s = x-x;
+       } else {
+               /* general argument reduction needed */
+               n = __ieee754_rem_pio2f(x,&y);
+
+               switch(n&3) {
+                       case 0:
+                               __kernel_sincosdf( y, s, c );
+                               break;
+                       case 1:
+                               __kernel_sincosdf( -y, c, s );
+                               break;
+                       case 2: 
+                               __kernel_sincosdf( -y, s, &k_c);
+                               *c = -k_c;
+                               break;
+                       default:
+                               __kernel_sincosdf( -y, &k_c, &k_s );
+                               *c = -k_c;
+                               *s = -k_s;
+                               break;
+           }
+       }
+
+}
diff --git a/src/s_sincosl.c b/src/s_sincosl.c
new file mode 100644 (file)
index 0000000..e2d3a34
--- /dev/null
@@ -0,0 +1,31 @@
+/* s_sincosl.c -- long double version of s_sincos.c
+ *
+ * Copyright (C) 2013 Elliot Saba
+ * Developed at the University of Washington
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+*/
+
+#include "cdefs-compat.h"
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#if LDBL_MANT_DIG == 64
+#include "../ld80/e_rem_pio2l.h"
+#elif LDBL_MANT_DIG == 113
+#include "../ld128/e_rem_pio2l.h"
+#else
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT void
+sincosl( long double x, long double * s, long double * c )
+{
+    *s = sinl( x );
+    *c = cosl( x );
+}
diff --git a/src/s_sinf.c b/src/s_sinf.c
new file mode 100644 (file)
index 0000000..d987369
--- /dev/null
@@ -0,0 +1,85 @@
+/* s_sinf.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_sinf.c,v 1.17 2008/02/25 22:19:17 bde Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define      INLINE_KERNEL_COSDF
+//#define      INLINE_KERNEL_SINDF
+//#define INLINE_REM_PIO2F
+#include "math_private.h"
+//#include "e_rem_pio2f.c"
+//#include "k_cosf.c"
+//#include "k_sinf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+s1pio2 = 1*M_PI_2,                     /* 0x3FF921FB, 0x54442D18 */
+s2pio2 = 2*M_PI_2,                     /* 0x400921FB, 0x54442D18 */
+s3pio2 = 3*M_PI_2,                     /* 0x4012D97C, 0x7F3321D2 */
+s4pio2 = 4*M_PI_2;                     /* 0x401921FB, 0x54442D18 */
+
+OLM_DLLEXPORT float
+sinf(float x)
+{
+       double y;
+       int32_t n, hx, ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx & 0x7fffffff;
+
+       if(ix <= 0x3f490fda) {          /* |x| ~<= pi/4 */
+           if(ix<0x39800000)           /* |x| < 2**-12 */
+               if(((int)x)==0) return x;       /* x with inexact if x != 0 */
+           return __kernel_sindf(x);
+       }
+       if(ix<=0x407b53d1) {            /* |x| ~<= 5*pi/4 */
+           if(ix<=0x4016cbe3) {        /* |x| ~<= 3pi/4 */
+               if(hx>0)
+                   return __kernel_cosdf(x - s1pio2);
+               else
+                   return -__kernel_cosdf(x + s1pio2);
+           } else
+                       return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x);
+       }
+       if(ix<=0x40e231d5) {            /* |x| ~<= 9*pi/4 */
+           if(ix<=0x40afeddf) {        /* |x| ~<= 7*pi/4 */
+               if(hx>0)
+                   return -__kernel_cosdf(x - s3pio2);
+               else
+                   return __kernel_cosdf(x + s3pio2);
+           } else
+                       return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2));
+       }
+
+    /* sin(Inf or NaN) is NaN */
+       else if (ix>=0x7f800000) return x-x;
+
+    /* general argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2f(x,&y);
+           switch(n&3) {
+               case 0: return  __kernel_sindf(y);
+               case 1: return  __kernel_cosdf(y);
+               case 2: return  __kernel_sindf(-y);
+               default:
+                               return -__kernel_cosdf(y);
+           }
+       }
+}
diff --git a/src/s_sinl.c b/src/s_sinl.c
new file mode 100644 (file)
index 0000000..7304fc7
--- /dev/null
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2007 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_sinl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#if LDBL_MANT_DIG == 64
+#include "../ld80/e_rem_pio2l.h"
+#elif LDBL_MANT_DIG == 113
+#include "../ld128/e_rem_pio2l.h"
+#else
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT long double
+sinl(long double x)
+{
+       union IEEEl2bits z;
+       int e0, s;
+       long double y[2];
+       long double hi, lo;
+
+       z.e = x;
+       s = z.bits.sign;
+       z.bits.sign = 0;
+
+       /* If x = +-0 or x is a subnormal number, then sin(x) = x */
+       if (z.bits.exp == 0)
+               return (x);
+
+       /* If x = NaN or Inf, then sin(x) = NaN. */
+       if (z.bits.exp == 32767)
+               return ((x - x) / (x - x));
+
+       /* Optimize the case where x is already within range. */
+       if (z.e < M_PI_4) {
+               hi = __kernel_sinl(z.e, 0, 0);
+               return  (s ? -hi : hi);
+       }
+
+       e0 = __ieee754_rem_pio2l(x, y);
+       hi = y[0];
+       lo = y[1];
+
+       switch (e0 & 3) {
+       case 0:
+           hi = __kernel_sinl(hi, lo, 1);
+           break;
+       case 1:
+           hi = __kernel_cosl(hi, lo);
+           break;
+       case 2:
+           hi = - __kernel_sinl(hi, lo, 1);
+           break;
+       case 3:
+           hi = - __kernel_cosl(hi, lo);
+           break;
+       }
+       
+       return (hi);
+}
diff --git a/src/s_tan.c b/src/s_tan.c
new file mode 100644 (file)
index 0000000..07f2244
--- /dev/null
@@ -0,0 +1,83 @@
+/* @(#)s_tan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tan.c,v 1.13 2011/02/10 07:37:50 das Exp $");
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ *     __kernel_tan            ... tangent function on [-pi/4,pi/4]
+ *     __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *     [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *     in [-pi/4 , +pi/4], and let n = k mod 4.
+ *     We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *         0          S           C             T
+ *         1          C          -S            -1/T
+ *         2         -S          -C             T
+ *         3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *     TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define INLINE_REM_PIO2
+#include "math_private.h"
+//#include "e_rem_pio2.c"
+
+OLM_DLLEXPORT double
+tan(double x)
+{
+       double y[2],z=0.0;
+       int32_t n, ix;
+
+    /* High word of x. */
+       GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+       ix &= 0x7fffffff;
+       if(ix <= 0x3fe921fb) {
+           if(ix<0x3e400000)                   /* x < 2**-27 */
+               if((int)x==0) return x;         /* generate inexact */
+           return __kernel_tan(x,z,1);
+       }
+
+    /* tan(Inf or NaN) is NaN */
+       else if (ix>=0x7ff00000) return x-x;            /* NaN */
+
+    /* argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2(x,y);
+           return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+                                                       -1 -- n odd */
+       }
+}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(tan, tanl);
+#endif
diff --git a/src/s_tanf.c b/src/s_tanf.c
new file mode 100644 (file)
index 0000000..7ffe193
--- /dev/null
@@ -0,0 +1,72 @@
+/* s_tanf.c -- float version of s_tan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanf.c,v 1.17 2008/02/25 22:19:17 bde Exp $");
+
+#include <float.h>
+#include <openlibm_math.h>
+
+//#define      INLINE_KERNEL_TANDF
+//#define INLINE_REM_PIO2F
+#include "math_private.h"
+//#include "e_rem_pio2f.c"
+//#include "k_tanf.c"
+
+/* Small multiples of pi/2 rounded to double precision. */
+static const double
+t1pio2 = 1*M_PI_2,                     /* 0x3FF921FB, 0x54442D18 */
+t2pio2 = 2*M_PI_2,                     /* 0x400921FB, 0x54442D18 */
+t3pio2 = 3*M_PI_2,                     /* 0x4012D97C, 0x7F3321D2 */
+t4pio2 = 4*M_PI_2;                     /* 0x401921FB, 0x54442D18 */
+
+OLM_DLLEXPORT float
+tanf(float x)
+{
+       double y;
+       int32_t n, hx, ix;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx & 0x7fffffff;
+
+       if(ix <= 0x3f490fda) {          /* |x| ~<= pi/4 */
+           if(ix<0x39800000)           /* |x| < 2**-12 */
+               if(((int)x)==0) return x;       /* x with inexact if x != 0 */
+           return __kernel_tandf(x,1);
+       }
+       if(ix<=0x407b53d1) {            /* |x| ~<= 5*pi/4 */
+           if(ix<=0x4016cbe3)          /* |x| ~<= 3pi/4 */
+               return __kernel_tandf(x + (hx>0 ? -t1pio2 : t1pio2), -1);
+           else
+               return __kernel_tandf(x + (hx>0 ? -t2pio2 : t2pio2), 1);
+       }
+       if(ix<=0x40e231d5) {            /* |x| ~<= 9*pi/4 */
+           if(ix<=0x40afeddf)          /* |x| ~<= 7*pi/4 */
+               return __kernel_tandf(x + (hx>0 ? -t3pio2 : t3pio2), -1);
+           else
+               return __kernel_tandf(x + (hx>0 ? -t4pio2 : t4pio2), 1);
+       }
+
+    /* tan(Inf or NaN) is NaN */
+       else if (ix>=0x7f800000) return x-x;
+
+    /* general argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2f(x,&y);
+           /* integer parameter: 1 -- n even; -1 -- n odd */
+           return __kernel_tandf(y,1-((n&1)<<1));
+       }
+}
diff --git a/src/s_tanh.c b/src/s_tanh.c
new file mode 100644 (file)
index 0000000..a8d52da
--- /dev/null
@@ -0,0 +1,78 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanh.c,v 1.9 2008/02/22 02:30:36 das Exp $");
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *                                    x    -x
+ *                                   e  - e
+ *     0. tanh(x) is defined to be -----------
+ *                                    x    -x
+ *                                   e  + e
+ *     1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ *     2.  0      <= x <  2**-28 : tanh(x) := x with inexact if x != 0
+ *                                             -t
+ *         2**-28 <= x <  1      : tanh(x) := -----; t = expm1(-2x)
+ *                                            t + 2
+ *                                                  2
+ *         1      <= x <  22     : tanh(x) := 1 - -----; t = expm1(2x)
+ *                                                t + 2
+ *         22     <= x <= INF    : tanh(x) := 1.
+ *
+ * Special cases:
+ *     tanh(NaN) is NaN;
+ *     only tanh(0)=0 is exact for finite argument.
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300;
+
+OLM_DLLEXPORT double
+tanh(double x)
+{
+       double t,z;
+       int32_t jx,ix;
+
+       GET_HIGH_WORD(jx,x);
+       ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7ff00000) {
+           if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+           else       return one/x-one;    /* tanh(NaN) = NaN */
+       }
+
+    /* |x| < 22 */
+       if (ix < 0x40360000) {          /* |x|<22 */
+           if (ix<0x3e300000) {        /* |x|<2**-28 */
+               if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */
+           }
+           if (ix>=0x3ff00000) {       /* |x|>=1  */
+               t = expm1(two*fabs(x));
+               z = one - two/(t+two);
+           } else {
+               t = expm1(-two*fabs(x));
+               z= -t/(t+two);
+           }
+    /* |x| >= 22, return +-1 */
+       } else {
+           z = one - tiny;             /* raise inexact flag */
+       }
+       return (jx>=0)? z: -z;
+}
diff --git a/src/s_tanhf.c b/src/s_tanhf.c
new file mode 100644 (file)
index 0000000..cd77e4e
--- /dev/null
@@ -0,0 +1,56 @@
+/* s_tanhf.c -- float version of s_tanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanhf.c,v 1.9 2008/02/22 02:30:36 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float one=1.0, two=2.0, tiny = 1.0e-30, huge = 1.0e30;
+OLM_DLLEXPORT float
+tanhf(float x)
+{
+       float t,z;
+       int32_t jx,ix;
+
+       GET_FLOAT_WORD(jx,x);
+       ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+       if(ix>=0x7f800000) {
+           if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+           else       return one/x-one;    /* tanh(NaN) = NaN */
+       }
+
+    /* |x| < 9 */
+       if (ix < 0x41100000) {          /* |x|<9 */
+           if (ix<0x39800000) {        /* |x|<2**-12 */
+               if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */
+           }
+           if (ix>=0x3f800000) {       /* |x|>=1  */
+               t = expm1f(two*fabsf(x));
+               z = one - two/(t+two);
+           } else {
+               t = expm1f(-two*fabsf(x));
+               z= -t/(t+two);
+           }
+    /* |x| >= 9, return +-1 */
+       } else {
+           z = one - tiny;             /* raise inexact flag */
+       }
+       return (jx>=0)? z: -z;
+}
diff --git a/src/s_tanl.c b/src/s_tanl.c
new file mode 100644 (file)
index 0000000..0370e6b
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2007 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $");
+
+/*
+ * Limited testing on pseudorandom numbers drawn within [0:4e8] shows
+ * an accuracy of <= 1.5 ULP where 247024 values of x out of 40 million
+ * possibles resulted in tan(x) that exceeded 0.5 ULP (ie., 0.6%).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+#if LDBL_MANT_DIG == 64
+#include "../ld80/e_rem_pio2l.h"
+#elif LDBL_MANT_DIG == 113
+#include "../ld128/e_rem_pio2l.h"
+#else
+#error "Unsupported long double format"
+#endif
+
+OLM_DLLEXPORT long double
+tanl(long double x)
+{
+       union IEEEl2bits z;
+       int e0, s;
+       long double y[2];
+       long double hi, lo;
+
+       z.e = x;
+       s = z.bits.sign;
+       z.bits.sign = 0;
+
+       /* If x = +-0 or x is subnormal, then tan(x) = x. */
+       if (z.bits.exp == 0)
+               return (x);
+
+       /* If x = NaN or Inf, then tan(x) = NaN. */
+       if (z.bits.exp == 32767)
+               return ((x - x) / (x - x));
+
+       /* Optimize the case where x is already within range. */
+       if (z.e < M_PI_4) {
+               hi = __kernel_tanl(z.e, 0, 0);
+               return (s ? -hi : hi);
+       }
+
+       e0 = __ieee754_rem_pio2l(x, y);
+       hi = y[0];
+       lo = y[1];
+
+       switch (e0 & 3) {
+       case 0:
+       case 2:
+           hi = __kernel_tanl(hi, lo, 0);
+           break;
+       case 1:
+       case 3:
+           hi = __kernel_tanl(hi, lo, 1);
+           break;
+       }
+
+       return (hi);
+}
diff --git a/src/s_tgammaf.c b/src/s_tgammaf.c
new file mode 100644 (file)
index 0000000..fbfa3fe
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_tgammaf.c,v 1.1 2008/02/18 17:27:10 das Exp $");
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+/*
+ * We simply call tgamma() rather than bloating the math library with
+ * a float-optimized version of it. The reason is that tgammaf() is
+ * essentially useless, since the function is superexponential and
+ * floats have very limited range.
+ */
+OLM_DLLEXPORT float
+tgammaf(float x)
+{
+
+       return (tgamma(x));
+}
diff --git a/src/s_trunc.c b/src/s_trunc.c
new file mode 100644 (file)
index 0000000..b01bfef
--- /dev/null
@@ -0,0 +1,67 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_trunc.c,v 1.4 2008/02/22 02:27:34 das Exp $");
+
+/*
+ * trunc(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to trunc(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+OLM_DLLEXPORT double
+trunc(double x)
+{
+       int32_t i0,i1,j0;
+       u_int32_t i;
+       EXTRACT_WORDS(i0,i1,x);
+       j0 = ((i0>>20)&0x7ff)-0x3ff;
+       if(j0<20) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */
+                   i0 &= 0x80000000U;
+                   i1 = 0;
+               }
+           } else {
+               i = (0x000fffff)>>j0;
+               if(((i0&i)|i1)==0) return x; /* x is integral */
+               if(huge+x>0.0) {        /* raise inexact flag */
+                   i0 &= (~i); i1=0;
+               }
+           }
+       } else if (j0>51) {
+           if(j0==0x400) return x+x;   /* inf or NaN */
+           else return x;              /* x is integral */
+       } else {
+           i = ((u_int32_t)(0xffffffff))>>(j0-20);
+           if((i1&i)==0) return x;     /* x is integral */
+           if(huge+x>0.0)              /* raise inexact flag */
+               i1 &= (~i);
+       }
+       INSERT_WORDS(x,i0,i1);
+       return x;
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(trunc, truncl);
+#endif
diff --git a/src/s_truncf.c b/src/s_truncf.c
new file mode 100644 (file)
index 0000000..d9fc62e
--- /dev/null
@@ -0,0 +1,54 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_truncf.c,v 1.1 2004/06/20 09:25:43 das Exp $");
+
+/*
+ * truncf(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to truncf(x).
+ */
+
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+static const float huge = 1.0e30F;
+
+OLM_DLLEXPORT float
+truncf(float x)
+{
+       int32_t i0,j0;
+       u_int32_t i;
+       GET_FLOAT_WORD(i0,x);
+       j0 = ((i0>>23)&0xff)-0x7f;
+       if(j0<23) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>0.0F)         /* |x|<1, so return 0*sign(x) */
+                   i0 &= 0x80000000;
+           } else {
+               i = (0x007fffff)>>j0;
+               if((i0&i)==0) return x; /* x is integral */
+               if(huge+x>0.0F)         /* raise inexact flag */
+                   i0 &= (~i);
+           }
+       } else {
+           if(j0==0x80) return x+x;    /* inf or NaN */
+           else return x;              /* x is integral */
+       }
+       SET_FLOAT_WORD(x,i0);
+       return x;
+}
diff --git a/src/s_truncl.c b/src/s_truncl.c
new file mode 100644 (file)
index 0000000..34d7b65
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ * From: @(#)s_floor.c 5.1 93/09/24
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/s_truncl.c,v 1.9 2008/02/14 15:10:34 bde Exp $");
+
+/*
+ * truncl(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to truncl(x).
+ */
+
+#include <float.h>
+#include <openlibm_math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+#include "math_private.h"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define        MANH_SIZE       (LDBL_MANH_SIZE + 1)
+#else
+#define        MANH_SIZE       LDBL_MANH_SIZE
+#endif
+
+static const long double huge = 1.0e300;
+static const float zero[] = { 0.0, -0.0 };
+
+OLM_DLLEXPORT long double
+truncl(long double x)
+{
+       union IEEEl2bits u = { .e = x };
+       int e = u.bits.exp - LDBL_MAX_EXP + 1;
+
+       if (e < MANH_SIZE - 1) {
+               if (e < 0) {                    /* raise inexact if x != 0 */
+                       if (huge + x > 0.0)
+                               u.e = zero[u.bits.sign];
+               } else {
+                       uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1);
+                       if (((u.bits.manh & m) | u.bits.manl) == 0)
+                               return (x);     /* x is integral */
+                       if (huge + x > 0.0) {   /* raise inexact flag */
+                               u.bits.manh &= ~m;
+                               u.bits.manl = 0;
+                       }
+               }
+       } else if (e < LDBL_MANT_DIG - 1) {
+               uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1);
+               if ((u.bits.manl & m) == 0)
+                       return (x);     /* x is integral */
+               if (huge + x > 0.0)             /* raise inexact flag */
+                       u.bits.manl &= ~m;
+       }
+       return (u.e);
+}
diff --git a/src/types-compat.h b/src/types-compat.h
new file mode 100644 (file)
index 0000000..b20b5ae
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _TYPES_COMPAT_H_
+#define        _TYPES_COMPAT_H_
+
+#include <stdint.h>
+#include <limits.h>
+
+typedef uint8_t               u_int8_t;
+typedef uint16_t              u_int16_t;
+typedef uint32_t              u_int32_t;
+typedef uint64_t              u_int64_t;
+
+
+#endif
diff --git a/src/w_cabs.c b/src/w_cabs.c
new file mode 100644 (file)
index 0000000..6b53a60
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * cabs() wrapper for hypot().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/w_cabs.c,v 1.7 2008/03/30 20:03:06 das Exp $");
+
+#include <float.h>
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT double
+cabs(double complex z)
+{
+       return hypot(creal(z), cimag(z));
+}
+
+#if LDBL_MANT_DIG == 53
+__weak_reference(cabs, cabsl);
+#endif
diff --git a/src/w_cabsf.c b/src/w_cabsf.c
new file mode 100644 (file)
index 0000000..f14c71a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * cabsf() wrapper for hypotf().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ */
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT float
+cabsf(z)
+       float complex z;
+{
+
+       return hypotf(crealf(z), cimagf(z));
+}
diff --git a/src/w_cabsl.c b/src/w_cabsl.c
new file mode 100644 (file)
index 0000000..c10f1d4
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * cabs() wrapper for hypot().
+ *
+ * Written by J.T. Conklin, <jtc@wimsey.com>
+ * Placed into the Public Domain, 1994.
+ *
+ * Modified by Steven G. Kargl for the long double type.
+ */
+
+#include "cdefs-compat.h"
+//__FBSDID("$FreeBSD: src/lib/msun/src/w_cabsl.c,v 1.1 2008/03/30 20:02:03 das Exp $");
+
+#include <openlibm_complex.h>
+#include <openlibm_math.h>
+
+#include "math_private.h"
+
+OLM_DLLEXPORT long double
+cabsl(long double complex z)
+{
+       return hypotl(creall(z), cimagl(z));
+}
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644 (file)
index 0000000..2d85b23
--- /dev/null
@@ -0,0 +1,9 @@
+/test-float
+/test-float-system
+/test-float.dSYM
+/test-double
+/test-double-system
+/test-double.dSYM
+/bench-openlibm
+/bench-syslibm
+/*.exe
diff --git a/test/Makefile b/test/Makefile
new file mode 100644 (file)
index 0000000..a7f7cb9
--- /dev/null
@@ -0,0 +1,35 @@
+OPENLIBM_HOME=$(abspath ..)
+include ../Make.inc
+
+# Set rpath of tests to builddir for loading shared library
+OPENLIBM_LIB = -L.. -lopenlibm
+ifneq ($(OS),WINNT)
+ifneq ($(OS),Darwin)
+OPENLIBM_LIB += -Wl,-rpath=$(OPENLIBM_HOME)
+endif
+endif
+
+all: test-double test-float # test-double-system test-float-system
+
+bench: bench-syslibm bench-openlibm
+
+test-double: test-double.c libm-test.c libm-test-ulps.h
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $@.c -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -o $@
+
+test-float: test-float.c libm-test.c libm-test-ulps.h
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $@.c -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -o $@
+
+test-double-system: test-double.c libm-test.c libm-test-ulps.h
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -DSYS_MATH_H -lm -o $@
+
+test-float-system: test-float.c libm-test.c libm-test-ulps.h
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -DSYS_MATH_H -lm -o $@
+
+bench-openlibm: libm-bench.cpp
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< $(OPENLIBM_LIB) -o $@
+
+bench-syslibm: libm-bench.cpp
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -lm -o $@
+
+clean:
+       rm -fr test-double test-float test-double-system test-float-system bench-openlibm bench-syslibm *.dSYM
diff --git a/test/inf_torture.c b/test/inf_torture.c
new file mode 100644 (file)
index 0000000..f2b0124
--- /dev/null
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <math.h>
+
+int main();
+int main2();
+int main3();
+int main4();
+
+int main() {
+        printf("+inf:\n");
+        float fx = (float)INFINITY; unsigned int *fxi = (unsigned int*)&fx;
+        double dx = (double)INFINITY; long unsigned long int *dxi = (long unsigned long int*)&dx;
+        long double ldx = (long double)INFINITY; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]);
+        printf("\t\tf d ld\n");
+        printf("correct:\t%x %x %x\n", isinf(fx), isinf(dx), isinf(ldx));
+        printf("as floats:\t%x %x %x\n", isinf(*(float*)fxi), isinf(*(float*)dxi), isinf(*(float*)ldxi1));
+        printf("as double:\t%x %x %x\n", isinf(*(double*)fxi), isinf(*(double*)dxi), isinf(*(double*)ldxi1));
+        printf("as long double:\t%x %x %x\n", isinf(*(long double*)fxi), isinf(*(long double*)dxi), isinf(*(long double*)ldxi1));
+        printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx));
+        printf("sizes:\t%d %d %d\n", (int)sizeof(*fxi), (int)sizeof(*dxi), (int)sizeof(*ldxi1)*2);
+        printf("bit repr:\n  f: %x\n  d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1);
+        printf("\n");
+        main2();
+        return 0;
+}
+
+int main2() {
+        printf("-inf:\n");
+        float fx = (float)-INFINITY; unsigned int *fxi = (unsigned int*)&fx;
+        double dx = (double)-INFINITY; long unsigned long int *dxi = (long unsigned long int*)&dx;
+        long double ldx = (long double)-INFINITY; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]);
+        printf("\t\tf d ld\n");
+        printf("correct:\t%x %x %x\n", isinf(fx), isinf(dx), isinf(ldx));
+        printf("as floats:\t%x %x %x\n", isinf(*(float*)fxi), isinf(*(float*)dxi), isinf(*(float*)ldxi1));
+        printf("as double:\t%x %x %x\n", isinf(*(double*)fxi), isinf(*(double*)dxi), isinf(*(double*)ldxi1));
+        printf("as long double:\t%x %x %x\n", isinf(*(long double*)fxi), isinf(*(long double*)dxi), isinf(*(long double*)ldxi1));
+        printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx));
+        printf("bit repr:\n  f: %x\n  d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1);
+        printf("\n");
+               main3();
+        return 0;
+}
+
+int main3() {
+        printf("+NaN:\n");
+        float fx = (float)NAN; unsigned int *fxi = (unsigned int*)&fx;
+        double dx = (double)NAN; long unsigned long int *dxi = (long unsigned long int*)&dx;
+        long double ldx = (long double)NAN; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]);
+        printf("\t\tf d ld\n");
+        printf("correct:\t%x %x %x\n", isnan(fx), isnan(dx), isnan(ldx));
+        printf("as floats:\t%x %x %x\n", isnan(*(float*)fxi), isnan(*(float*)dxi), isnan(*(float*)ldxi1));
+        printf("as double:\t%x %x %x\n", isnan(*(double*)fxi), isnan(*(double*)dxi), isnan(*(double*)ldxi1));
+        printf("as long double:\t%x %x %x\n", isnan(*(long double*)fxi), isnan(*(long double*)dxi), isnan(*(long double*)ldxi1));
+        printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx));
+        printf("sizes:\t%d %d %d\n", (int)sizeof(*fxi), (int)sizeof(*dxi), (int)sizeof(*ldxi1)*2);
+        printf("bit repr:\n  f: %x\n  d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1);
+        printf("\n");
+        main4();
+        return 0;
+}
+
+int main4() {
+        printf("-NaN:\n");
+        float fx = (float)-NAN; unsigned int *fxi = (unsigned int*)&fx;
+        double dx = (double)-NAN; long unsigned long int *dxi = (long unsigned long int*)&dx;
+        long double ldx = (long double)-NAN; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]);
+        printf("\t\tf d ld\n");
+        printf("correct:\t%x %x %x\n", isnan(fx), isnan(dx), isnan(ldx));
+        printf("as floats:\t%x %x %x\n", isnan(*(float*)fxi), isnan(*(float*)dxi), isnan(*(float*)ldxi1));
+        printf("as double:\t%x %x %x\n", isnan(*(double*)fxi), isnan(*(double*)dxi), isnan(*(double*)ldxi1));
+        printf("as long double:\t%x %x %x\n", isnan(*(long double*)fxi), isnan(*(long double*)dxi), isnan(*(long double*)ldxi1));
+        printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx));
+        printf("bit repr:\n  f: %x\n  d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1);
+        printf("\n");
+        return 0;
+}
diff --git a/test/libm-bench.cpp b/test/libm-bench.cpp
new file mode 100644 (file)
index 0000000..04876de
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright (C) Dahua Lin, 2014. Provided under the MIT license.
+
+// Benchmark on libm functions
+
+#include <math.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+// Timing facilities
+
+#ifdef __MACH__
+
+#include <mach/mach_time.h>
+
+class stimer
+{
+public:
+    typedef uint64_t time_type;
+
+    stimer()
+    {
+        ::mach_timebase_info(&m_baseinfo);
+    }
+
+    time_type current() const
+    {
+        return ::mach_absolute_time();
+    }
+
+    double span(const time_type& t0, const time_type& t1) const
+    {
+        uint64_t d = (m_baseinfo.numer * (t1 - t0)) / m_baseinfo.denom;
+        return static_cast<double>(d) / 1.0e9;
+    }
+
+private:
+    mach_timebase_info_data_t m_baseinfo;
+};
+
+#else
+
+class stimer
+{
+public:
+    typedef timespec time_type;
+
+    time_type current() const
+    {
+        time_type t;
+        ::clock_gettime(CLOCK_REALTIME, &t);
+        return t;
+    }
+
+    double span(const time_type& t0, const time_type& t1) const
+    {
+        return double(t1.tv_sec - t0.tv_sec) +
+            double(t1.tv_nsec - t0.tv_nsec) * 1.0e-9;
+    }
+};
+
+#endif
+
+
+inline double sec2mps(double s, long n)
+{
+    return n / (s * 1e6);
+}
+
+
+const long ARR_LEN = 1024;
+
+double a[ARR_LEN];
+double b[ARR_LEN];
+double r[ARR_LEN];
+
+#define TFUN1(FNAME) \
+    void test_##FNAME(long n) { \
+        for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j]); \
+        stimer tm; \
+        stimer::time_type t0 = tm.current(); \
+        for(int i = 0; i < n; ++i) { \
+            for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j]); \
+        } \
+        double s = tm.span(t0, tm.current()); \
+        double mps = sec2mps(s, n * ARR_LEN); \
+        printf("  %-8s:  %7.4f MPS\n", #FNAME, mps); }
+
+#define TFUN2(FNAME) \
+    void test_##FNAME(long n) { \
+        for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j], b[j]); \
+        stimer tm; \
+        stimer::time_type t0 = tm.current(); \
+        for(int i = 0; i < n; ++i) { \
+            for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j], b[j]); \
+        } \
+        double s = tm.span(t0, tm.current()); \
+        double mps = sec2mps(s, n * ARR_LEN); \
+        printf("  %-8s:  %7.4f MPS\n", #FNAME, mps); }
+
+
+#define TCALL(FNAME) test_##FNAME(20000)
+
+// define benchmark functions
+
+TFUN2(pow)
+TFUN2(hypot)
+
+TFUN1(exp)
+TFUN1(log)
+TFUN1(log10)
+TFUN1(sin)
+TFUN1(cos)
+TFUN1(tan)
+TFUN1(asin)
+TFUN1(acos)
+TFUN1(atan)
+TFUN2(atan2)
+
+int main(int argc, char *argv[])
+{
+    // initialize array contents
+    for (int i = 0; i < ARR_LEN; ++i)
+    {
+      a[i] = rand() / (double) RAND_MAX;
+      b[i] = rand() / (double) RAND_MAX;
+    }
+
+    TCALL(pow);
+    TCALL(hypot);
+    TCALL(exp);
+    TCALL(log);
+    TCALL(log10);
+    TCALL(sin);
+    TCALL(cos);
+    TCALL(tan);
+    TCALL(asin);
+    TCALL(acos);
+    TCALL(atan);
+    TCALL(atan2);
+
+    return 0;
+}
diff --git a/test/libm-test-ulps.h b/test/libm-test-ulps.h
new file mode 100644 (file)
index 0000000..4752bc3
--- /dev/null
@@ -0,0 +1,254 @@
+/* This file is automatically generated
+   from libm-test-ulps with gen-libm-test.pl.
+   Don't change it - change instead the master files.  */
+
+
+/* Maximal error of functions.  */
+#define DELTAacos CHOOSE(1150, 1, 1, 1150, 0, 0)       /* acos  */
+#define DELTAacosh CHOOSE(1, 0, 0, 1, 0, 0)    /* acosh  */
+#define DELTAasin CHOOSE(1, 1, 0, 1, 0, 0)     /* asin  */
+#define DELTAasinh CHOOSE(656, 0, 0, 656, 0, 0)        /* asinh  */
+#define DELTAatan CHOOSE(549, 0, 0, 549, 0, 0) /* atan  */
+#define DELTAatanh CHOOSE(1605, 1, 0, 1605, 1, 0)      /* atanh  */
+#define DELTAatan2 CHOOSE(549, 0, 0, 549, 0, 0)        /* atan2  */
+#define DELTAcabs CHOOSE(560, 1, 1, 560, 1, 1) /* cabs  */
+#define DELTAcacos CHOOSE(BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2), BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2))  /* cacos  */
+#define DELTAcacosh CHOOSE(BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4), BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4)) /* cacosh  */
+#define DELTAcasin CHOOSE(BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2), BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2))  /* casin  */
+#define DELTAcasinh CHOOSE(BUILD_COMPLEX (892, 12), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6), BUILD_COMPLEX (892, 12), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6))   /* casinh  */
+#define DELTAcatan CHOOSE(BUILD_COMPLEX (251, 474), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (251, 474), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* catan  */
+#define DELTAcatanh CHOOSE(BUILD_COMPLEX (66, 447), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (66, 447), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0))   /* catanh  */
+#define DELTAcbrt CHOOSE(716, 1, 0, 716, 1, 0) /* cbrt  */
+#define DELTAccos CHOOSE(BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1))     /* ccos  */
+#define DELTAccosh CHOOSE(BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1))      /* ccosh  */
+#define DELTAcexp CHOOSE(BUILD_COMPLEX (940, 1067), 0, BUILD_COMPLEX (1, 0), BUILD_COMPLEX (940, 1067), 0, BUILD_COMPLEX (1, 0))       /* cexp  */
+#define DELTAclog CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0)       /* clog  */
+#define DELTAclog10 CHOOSE(BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 1))       /* clog10  */
+#define DELTAcos CHOOSE(529, 2, 1, 529, 2, 1)  /* cos  */
+#define DELTAcosh CHOOSE(309, 0, 0, 309, 0, 0) /* cosh  */
+#define DELTAcpow CHOOSE(BUILD_COMPLEX (2, 9), BUILD_COMPLEX (1, 1.104), BUILD_COMPLEX (4, 2.5333), BUILD_COMPLEX (2, 9), BUILD_COMPLEX (1, 1.104), BUILD_COMPLEX (4, 2.5333)) /* cpow  */
+#define DELTAcsin CHOOSE(BUILD_COMPLEX (966, 168), 0, 0, BUILD_COMPLEX (966, 168), 0, 0)       /* csin  */
+#define DELTAcsinh CHOOSE(BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1))  /* csinh  */
+#define DELTAcsqrt CHOOSE(BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0)        /* csqrt  */
+#define DELTActan CHOOSE(BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1))   /* ctan  */
+#define DELTActanh CHOOSE(BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 1))        /* ctanh  */
+#define DELTAerfc CHOOSE(36, 24, 12, 36, 24, 12)       /* erfc  */
+#define DELTAexp CHOOSE(754, 0, 0, 754, 0, 0)  /* exp  */
+#define DELTAexp10 CHOOSE(1182, 1, 0, 1182, 1, 0)      /* exp10  */
+#define DELTAexp2 CHOOSE(462, 0, 0, 462, 0, 0) /* exp2  */
+#define DELTAexpm1 CHOOSE(825, 1, 1, 825, 0, 0)        /* expm1  */
+#define DELTAfmod CHOOSE(4096, 2, 1, 4096, 2, 1)       /* fmod  */
+#define DELTAgamma CHOOSE(1, 1, 0, 1, 1, 0)    /* gamma  */
+#define DELTAhypot CHOOSE(560, 1, 1, 560, 0, 0)        /* hypot  */
+#define DELTAj0 CHOOSE(0, 2, 2, 0, 2, 1)       /* j0  */
+#define DELTAj1 CHOOSE(2, 2, 2, 2, 2, 1)       /* j1  */
+#define DELTAjn CHOOSE(2, 6, 4, 2, 5, 2)       /* jn  */
+#define DELTAlgamma CHOOSE(1, 1, 2, 1, 1, 2)   /* lgamma  */
+#define DELTAlog CHOOSE(2341, 1, 1, 2341, 1, 1)        /* log  */
+#define DELTAlog10 CHOOSE(2033, 1, 1, 2033, 1, 1)      /* log10  */
+#define DELTAlog1p CHOOSE(585, 1, 1, 585, 1, 1)        /* log1p  */
+#define DELTAlog2 CHOOSE(1688, 1, 1, 1688, 1, 1)       /* log2  */
+#define DELTApow CHOOSE(725, 0, 0, 725, 0, 0)  /* pow  */
+#define DELTAsin CHOOSE(627, 0, 0, 627, 0, 0)  /* sin  */
+#define DELTAsincos CHOOSE(627, 1, 1, 627, 1, 1)       /* sincos  */
+#define DELTAsinh CHOOSE(1029, 1, 1, 1028, 0, 1)       /* sinh  */
+#define DELTAsqrt CHOOSE(489, 0, 0, 489, 0, 0) /* sqrt  */
+#define DELTAtan CHOOSE(1401, 1, 1, 1401, 0.5, 0)      /* tan  */
+#define DELTAtanh CHOOSE(521, 1, 1, 521, 0, 0) /* tanh  */
+#define DELTAtgamma CHOOSE(2, 2, 1, 2, 2, 1)   /* tgamma  */
+#define DELTAy0 CHOOSE(2, 3, 1, 2, 3, 1)       /* y0  */
+#define DELTAy1 CHOOSE(2, 3, 2, 2, 3, 2)       /* y1  */
+#define DELTAyn CHOOSE(7, 6, 3, 7, 6, 3)       /* yn  */
+
+/* Error of single function calls.  */
+#define DELTA16 CHOOSE(1, 0, 0, 1, 0, 0)       /* acosh (7) == 2.633915793849633417250092694615937  */
+#define DELTA24 CHOOSE(1, 1, 0, 1, 0, 0)       /* asin (0.5) == pi/6  */
+#define DELTA25 CHOOSE(1, 1, 0, 1, 0, 0)       /* asin (-0.5) == -pi/6  */
+#define DELTA26 CHOOSE(1, 0, 0, 1, 0, 0)       /* asin (1.0) == pi/2  */
+#define DELTA27 CHOOSE(1, 0, 0, 1, 0, 0)       /* asin (-1.0) == -pi/2  */
+#define DELTA28 CHOOSE(1, 1, 0, 1, 0, 0)       /* asin (0.7) == 0.77539749661075306374035335271498708  */
+#define DELTA34 CHOOSE(656, 1, 0, 656, 0, 0)   /* asinh (0.7) == 0.652666566082355786  */
+#define DELTA42 CHOOSE(549, 0, 0, 549, 0, 0)   /* atan (0.7) == 0.61072596438920861654375887649023613  */
+#define DELTA50 CHOOSE(1605, 1, 0, 1605, 1, 0) /* atanh (0.7) == 0.8673005276940531944  */
+#define DELTA74 CHOOSE(549, 0, 0, 549, 0, 0)   /* atan2 (0.7, 1) == 0.61072596438920861654375887649023613  */
+#define DELTA78 CHOOSE(1, 0, 0, 1, 0, 0)       /* atan2 (0.4, 0.0003) == 1.5700463269355215717704032607580829  */
+#define DELTA85 CHOOSE(0, 0, 1, 0, 0, 1)       /* cabs (0.7 + 12.4 i) == 12.419742348374220601176836866763271  */
+#define DELTA86 CHOOSE(0, 0, 1, 0, 0, 1)       /* cabs (-12.4 + 0.7 i) == 12.419742348374220601176836866763271  */
+#define DELTA87 CHOOSE(0, 0, 1, 0, 0, 1)       /* cabs (-0.7 + 12.4 i) == 12.419742348374220601176836866763271  */
+#define DELTA88 CHOOSE(0, 0, 1, 0, 0, 1)       /* cabs (-12.4 - 0.7 i) == 12.419742348374220601176836866763271  */
+#define DELTA89 CHOOSE(0, 0, 1, 0, 0, 1)       /* cabs (-0.7 - 12.4 i) == 12.419742348374220601176836866763271  */
+#define DELTA96 CHOOSE(560, 1, 0, 560, 1, 0)   /* cabs (0.7 + 1.2 i) == 1.3892443989449804508432547041028554  */
+#define DELTA130 CHOOSE(BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2), BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2))    /* cacos (0.7 + 1.2 i) == 1.1351827477151551088992008271819053 - 1.0927647857577371459105272080819308 i  */
+#define DELTA131 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0)        /* cacos (-2 - 3 i) == 2.1414491111159960199416055713254211 + 1.9833870299165354323470769028940395 i  */
+#define DELTA165 CHOOSE(BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 0), 0)  /* cacosh (0.7 + 1.2 i) == 1.0927647857577371459105272080819308 + 1.1351827477151551088992008271819053 i  */
+#define DELTA166 CHOOSE(BUILD_COMPLEX (6, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4), BUILD_COMPLEX (6, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4))    /* cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i  */
+#define DELTA225 CHOOSE(BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2), BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2))    /* casin (0.7 + 1.2 i) == 0.4356135790797415103321208644578462 + 1.0927647857577371459105272080819308 i  */
+#define DELTA226 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0)        /* casin (-2 - 3 i) == -0.57065278432109940071028387968566963 - 1.9833870299165354323470769028940395 i  */
+#define DELTA262 CHOOSE(BUILD_COMPLEX (892, 12), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (892, 12), 0, BUILD_COMPLEX (0, 1))    /* casinh (0.7 + 1.2 i) == 0.97865459559367387689317593222160964 + 0.91135418953156011567903546856170941 i  */
+#define DELTA263 CHOOSE(BUILD_COMPLEX (6, 6), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6), BUILD_COMPLEX (6, 6), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6))    /* casinh (-2 - 3 i) == -1.9686379257930962917886650952454982 - 0.96465850440760279204541105949953237 i  */
+#define DELTA301 CHOOSE(BUILD_COMPLEX (251, 474), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (251, 474), 0, BUILD_COMPLEX (0, 1))  /* catan (0.7 + 1.2 i) == 1.0785743834118921877443707996386368 + 0.57705737765343067644394541889341712 i  */
+#define DELTA302 CHOOSE(BUILD_COMPLEX (0, 7), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 7), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))    /* catan (-2 - 3 i) == -1.4099210495965755225306193844604208 - 0.22907268296853876629588180294200276 i  */
+#define DELTA340 CHOOSE(BUILD_COMPLEX (66, 447), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (66, 447), BUILD_COMPLEX (1, 0), 0)    /* catanh (0.7 + 1.2 i) == 0.2600749516525135959200648705635915 + 0.97024030779509898497385130162655963 i  */
+#define DELTA341 CHOOSE(BUILD_COMPLEX (6, 0), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (6, 0), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0))    /* catanh (-2 - 3 i) == -0.14694666622552975204743278515471595 - 1.3389725222944935611241935759091443 i  */
+#define DELTA347 CHOOSE(716, 0, 0, 716, 0, 0)  /* cbrt (-0.001) == -0.1  */
+#define DELTA349 CHOOSE(1, 0, 0, 1, 0, 0)      /* cbrt (-27.0) == -3.0  */
+#define DELTA350 CHOOSE(306, 0, 0, 306, 0, 0)  /* cbrt (0.970299) == 0.99  */
+#define DELTA351 CHOOSE(346, 1, 0, 346, 1, 0)  /* cbrt (0.7) == 0.8879040017426007084  */
+#define DELTA389 CHOOSE(BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0))      /* ccos (0.7 + 1.2 i) == 1.3848657645312111080 - 0.97242170335830028619 i  */
+#define DELTA390 CHOOSE(BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1))  /* ccos (-2 - 3 i) == -4.1896256909688072301 - 9.1092278937553365979 i  */
+#define DELTA428 CHOOSE(BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0))        /* ccosh (0.7 + 1.2 i) == 0.4548202223691477654 + 0.7070296600921537682 i  */
+#define DELTA429 CHOOSE(BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))    /* ccosh (-2 - 3 i) == -3.7245455049153225654 + 0.5118225699873846088 i  */
+#define DELTA469 CHOOSE(BUILD_COMPLEX (940, 0), 0, BUILD_COMPLEX (1, 0), BUILD_COMPLEX (940, 0), 0, BUILD_COMPLEX (1, 0))      /* cexp (0.7 + 1.2 i) == 0.72969890915032360123451688642930727 + 1.8768962328348102821139467908203072 i  */
+#define DELTA470 CHOOSE(BUILD_COMPLEX (4, 18), 0, 0, BUILD_COMPLEX (4, 18), 0, 0)      /* cexp (-2.0 - 3.0 i) == -0.13398091492954261346140525546115575 - 0.019098516261135196432576240858800925 i  */
+#define DELTA515 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0)        /* clog (-2 - 3 i) == 1.2824746787307683680267437207826593 - 2.1587989303424641704769327722648368 i  */
+#define DELTA520 CHOOSE(0, BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0)        /* clog10 (-inf + inf i) == inf + 3/4 pi*log10(e) i  */
+#define DELTA521 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (inf + inf i) == inf + pi/4*log10(e) i  */
+#define DELTA522 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (inf - inf i) == inf - pi/4*log10(e) i  */
+#define DELTA523 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (0 + inf i) == inf + pi/2*log10(e) i  */
+#define DELTA524 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (3 + inf i) == inf + pi/2*log10(e) i  */
+#define DELTA525 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-0 + inf i) == inf + pi/2*log10(e) i  */
+#define DELTA526 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-3 + inf i) == inf + pi/2*log10(e) i  */
+#define DELTA527 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (0 - inf i) == inf - pi/2*log10(e) i  */
+#define DELTA528 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (3 - inf i) == inf - pi/2*log10(e) i  */
+#define DELTA529 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-0 - inf i) == inf - pi/2*log10(e) i  */
+#define DELTA530 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-3 - inf i) == inf - pi/2*log10(e) i  */
+#define DELTA531 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-inf + 0 i) == inf + pi*log10(e) i  */
+#define DELTA532 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-inf + 1 i) == inf + pi*log10(e) i  */
+#define DELTA533 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-inf - 0 i) == inf - pi*log10(e) i  */
+#define DELTA534 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1))  /* clog10 (-inf - 1 i) == inf - pi*log10(e) i  */
+#define DELTA552 CHOOSE(BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 0))  /* clog10 (0.7 + 1.2 i) == 0.1427786545038868803 + 0.4528483579352493248 i  */
+#define DELTA553 CHOOSE(BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0)  /* clog10 (-2 - 3 i) == 0.5569716761534183846 - 0.9375544629863747085 i  */
+#define DELTA582 CHOOSE(0, 1, 0.5, 0, 1, 0.5)  /* cos (M_PI_6l * 2.0) == 0.5  */
+#define DELTA583 CHOOSE(0.5, 2, 1, 0.5, 2, 1)  /* cos (M_PI_6l * 4.0) == -0.5  */
+#define DELTA584 CHOOSE(0.25, 0.2758, 0.3667, 0.25, 0.2758, 0.3667)    /* cos (pi/2) == 0  */
+#define DELTA585 CHOOSE(529, 1, 0, 529, 1, 0)  /* cos (0.7) == 0.76484218728448842625585999019186495  */
+#define DELTA591 CHOOSE(309, 0, 0, 309, 0, 0)  /* cosh (0.7) == 1.255169005630943018  */
+#define DELTA594 CHOOSE(BUILD_COMPLEX (0, 9), BUILD_COMPLEX (0, 1.104), BUILD_COMPLEX (0, 2.5333), BUILD_COMPLEX (0, 9), BUILD_COMPLEX (0, 1.104), BUILD_COMPLEX (0, 2.5333))  /* cpow (e + 0 i, 0 + 2 * M_PIl i) == 1.0 + 0.0 i  */
+#define DELTA595 CHOOSE(BUILD_COMPLEX (2, 5), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (4, 1), BUILD_COMPLEX (2, 5), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (4, 1))    /* cpow (2 + 3 i, 4 + 0 i) == -119.0 - 120.0 i  */
+#define DELTA652 CHOOSE(BUILD_COMPLEX (966, 168), 0, 0, BUILD_COMPLEX (966, 168), 0, 0)        /* csin (0.7 + 1.2 i) == 1.1664563419657581376 + 1.1544997246948547371 i  */
+#define DELTA691 CHOOSE(BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0))    /* csinh (0.7 + 1.2 i) == 0.27487868678117583582 + 1.1698665727426565139 i  */
+#define DELTA692 CHOOSE(BUILD_COMPLEX (0, 2), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 2), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (0, 1))    /* csinh (-2 - 3 i) == 3.5905645899857799520 - 0.5309210862485198052 i  */
+#define DELTA732 CHOOSE(BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0)  /* csqrt (0.7 + 1.2 i) == 1.022067610030026450706487883081139 + 0.58704531296356521154977678719838035 i  */
+#define DELTA733 CHOOSE(BUILD_COMPLEX (1, 0), 0, 0, BUILD_COMPLEX (1, 0), 0, 0)        /* csqrt (-2 - 3 i) == 0.89597747612983812471573375529004348 - 1.6741492280355400404480393008490519 i  */
+#define DELTA734 CHOOSE(BUILD_COMPLEX (1, 0), 0, 0, BUILD_COMPLEX (1, 0), 0, 0)        /* csqrt (-2 + 3 i) == 0.89597747612983812471573375529004348 + 1.6741492280355400404480393008490519 i  */
+#define DELTA766 CHOOSE(BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0))    /* ctan (0.7 + 1.2 i) == 0.1720734197630349001 + 0.9544807059989405538 i  */
+#define DELTA767 CHOOSE(BUILD_COMPLEX (439, 2), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (439, 2), 0, BUILD_COMPLEX (0, 1))      /* ctan (-2 - 3 i) == 0.0037640256415042482 - 1.0032386273536098014 i  */
+#define DELTA799 CHOOSE(0, BUILD_COMPLEX (0, 0.5), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 0.5), BUILD_COMPLEX (0, 1))      /* ctanh (0 + pi/4 i) == 0.0 + 1.0 i  */
+#define DELTA800 CHOOSE(BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 0))  /* ctanh (0.7 + 1.2 i) == 1.3472197399061191630 + 0.4778641038326365540 i  */
+#define DELTA801 CHOOSE(BUILD_COMPLEX (5, 25), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (5, 25), 0, BUILD_COMPLEX (0, 1))        /* ctanh (-2 - 3 i) == -0.9653858790221331242 + 0.0098843750383224937 i  */
+#define DELTA817 CHOOSE(1, 1, 0, 1, 1, 0)      /* erfc (0.7) == 0.32219880616258152702  */
+#define DELTA818 CHOOSE(3, 1, 2, 3, 1, 2)      /* erfc (1.2) == 0.089686021770364619762  */
+#define DELTA819 CHOOSE(0, 1, 1, 0, 1, 0)      /* erfc (2.0) == 0.0046777349810472658379  */
+#define DELTA820 CHOOSE(12, 24, 12, 12, 24, 12)        /* erfc (4.1) == 0.67000276540848983727e-8  */
+#define DELTA821 CHOOSE(36, 0, 0, 36, 0, 0)    /* erfc (9) == 0.41370317465138102381e-36  */
+#define DELTA830 CHOOSE(412, 0, 0, 412, 0, 0)  /* exp (0.7) == 2.0137527074704765216  */
+#define DELTA831 CHOOSE(16, 0, 0, 16, 0, 0)    /* exp (50.0) == 5184705528587072464087.45332293348538  */
+#define DELTA832 CHOOSE(754, 0, 0, 754, 0, 0)  /* exp (1000.0) == 0.197007111401704699388887935224332313e435  */
+#define DELTA838 CHOOSE(8, 0, 0, 8, 0, 0)      /* exp10 (3) == 1000  */
+#define DELTA839 CHOOSE(818, 0, 0, 818, 0, 0)  /* exp10 (-1) == 0.1  */
+#define DELTA842 CHOOSE(1182, 1, 0, 1182, 1, 0)        /* exp10 (0.7) == 5.0118723362727228500155418688494574  */
+#define DELTA852 CHOOSE(462, 0, 0, 462, 0, 0)  /* exp2 (0.7) == 1.6245047927124710452  */
+#define DELTA859 CHOOSE(825, 0, 0, 825, 0, 0)  /* expm1 (0.7) == 1.0137527074704765216  */
+#define DELTA972 CHOOSE(4096, 2, 1, 4096, 2, 1)        /* fmod (6.5, 2.3) == 1.9  */
+#define DELTA973 CHOOSE(4096, 2, 1, 4096, 2, 1)        /* fmod (-6.5, 2.3) == -1.9  */
+#define DELTA974 CHOOSE(4096, 2, 1, 4096, 2, 1)        /* fmod (6.5, -2.3) == 1.9  */
+#define DELTA975 CHOOSE(4096, 2, 1, 4096, 2, 1)        /* fmod (-6.5, -2.3) == -1.9  */
+#define DELTA1004 CHOOSE(1, 1, 0, 1, 1, 0)     /* gamma (-0.5) == log(2*sqrt(pi))  */
+#define DELTA1013 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (0.7, 12.4) == 12.419742348374220601176836866763271  */
+#define DELTA1014 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-0.7, 12.4) == 12.419742348374220601176836866763271  */
+#define DELTA1015 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (0.7, -12.4) == 12.419742348374220601176836866763271  */
+#define DELTA1016 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-0.7, -12.4) == 12.419742348374220601176836866763271  */
+#define DELTA1017 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (12.4, 0.7) == 12.419742348374220601176836866763271  */
+#define DELTA1018 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-12.4, 0.7) == 12.419742348374220601176836866763271  */
+#define DELTA1019 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (12.4, -0.7) == 12.419742348374220601176836866763271  */
+#define DELTA1020 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-12.4, -0.7) == 12.419742348374220601176836866763271  */
+#define DELTA1024 CHOOSE(560, 1, 0, 560, 0, 0) /* hypot (0.7, 1.2) == 1.3892443989449804508432547041028554  */
+#define DELTA1053 CHOOSE(0, 2, 2, 0, 1, 1)     /* j0 (2.0) == 0.22389077914123566805  */
+#define DELTA1054 CHOOSE(0, 0, 1, 0, 0, 1)     /* j0 (8.0) == 0.17165080713755390609  */
+#define DELTA1055 CHOOSE(0, 2, 2, 0, 2, 1)     /* j0 (10.0) == -0.24593576445134833520  */
+#define DELTA1064 CHOOSE(0, 1, 0, 0, 1, 0)     /* j1 (2.0) == 0.57672480775687338720  */
+#define DELTA1065 CHOOSE(1, 1, 1, 1, 0, 1)     /* j1 (8.0) == 0.23463634685391462438  */
+#define DELTA1066 CHOOSE(2, 2, 2, 2, 2, 1)     /* j1 (10.0) == 0.043472746168861436670  */
+#define DELTA1075 CHOOSE(0, 2, 2, 0, 1, 1)     /* jn (0, 2.0) == 0.22389077914123566805  */
+#define DELTA1076 CHOOSE(1, 0, 1, 1, 0, 1)     /* jn (0, 8.0) == 0.17165080713755390609  */
+#define DELTA1077 CHOOSE(2, 2, 1, 2, 2, 1)     /* jn (0, 10.0) == -0.24593576445134833520  */
+#define DELTA1086 CHOOSE(0, 1, 0, 0, 1, 0)     /* jn (1, 2.0) == 0.57672480775687338720  */
+#define DELTA1087 CHOOSE(1, 1, 1, 1, 0, 1)     /* jn (1, 8.0) == 0.23463634685391462438  */
+#define DELTA1088 CHOOSE(2, 2, 2, 2, 2, 1)     /* jn (1, 10.0) == 0.043472746168861436670  */
+#define DELTA1091 CHOOSE(1, 0, 0, 1, 0, 0)     /* jn (3, -1.0) == -0.019563353982668405919  */
+#define DELTA1093 CHOOSE(1, 1, 0, 1, 1, 0)     /* jn (3, 0.1) == 0.000020820315754756261429  */
+#define DELTA1094 CHOOSE(0, 2, 1, 0, 2, 0)     /* jn (3, 0.7) == 0.0069296548267508408077  */
+#define DELTA1095 CHOOSE(1, 0, 0, 1, 0, 0)     /* jn (3, 1.0) == 0.019563353982668405919  */
+#define DELTA1096 CHOOSE(0, 1, 1, 0, 1, 1)     /* jn (3, 2.0) == 0.12894324947440205110  */
+#define DELTA1097 CHOOSE(1, 3, 1, 1, 3, 1)     /* jn (3, 10.0) == 0.058379379305186812343  */
+#define DELTA1100 CHOOSE(1, 1, 1, 1, 1, 1)     /* jn (10, -1.0) == 0.26306151236874532070e-9  */
+#define DELTA1102 CHOOSE(1, 6, 4, 1, 5, 2)     /* jn (10, 0.1) == 0.26905328954342155795e-19  */
+#define DELTA1103 CHOOSE(2, 4, 1, 2, 4, 1)     /* jn (10, 0.7) == 0.75175911502153953928e-11  */
+#define DELTA1104 CHOOSE(1, 1, 1, 1, 1, 1)     /* jn (10, 1.0) == 0.26306151236874532070e-9  */
+#define DELTA1105 CHOOSE(1, 2, 2, 1, 2, 1)     /* jn (10, 2.0) == 0.25153862827167367096e-6  */
+#define DELTA1106 CHOOSE(2, 4, 3, 2, 4, 2)     /* jn (10, 10.0) == 0.20748610663335885770  */
+#define DELTA1126 CHOOSE(1, 1, 0, 1, 1, 0)     /* lgamma (-0.5) == log(2*sqrt(pi))  */
+#define DELTA1128 CHOOSE(0, 1, 1, 0, 1, 1)     /* lgamma (0.7) == 0.26086724653166651439  */
+#define DELTA1130 CHOOSE(1, 1, 2, 1, 1, 2)     /* lgamma (1.2) == -0.853740900033158497197e-1  */
+#define DELTA1163 CHOOSE(1, 0, 0.5, 1, 0, 0.5) /* log (e) == 1  */
+#define DELTA1164 CHOOSE(1, 0, 0, 1, 0, 0)     /* log (1.0 / M_El) == -1  */
+#define DELTA1167 CHOOSE(2341, 1, 1, 2341, 1, 1)       /* log (0.7) == -0.35667494393873237891263871124118447  */
+#define DELTA1178 CHOOSE(1, 0, 1, 1, 0, 1)     /* log10 (e) == log10(e)  */
+#define DELTA1179 CHOOSE(2033, 1, 0, 2033, 1, 0)       /* log10 (0.7) == -0.15490195998574316929  */
+#define DELTA1186 CHOOSE(1, 0, 0, 1, 0, 0)     /* log1p (M_El - 1.0) == 1  */
+#define DELTA1187 CHOOSE(585, 1, 1, 585, 1, 1) /* log1p (-0.3) == -0.35667494393873237891263871124118447  */
+#define DELTA1198 CHOOSE(1688, 1, 1, 1688, 1, 1)       /* log2 (0.7) == -0.51457317282975824043  */
+#define DELTA1398 CHOOSE(725, 0, 0, 725, 0, 0) /* pow (0.7, 1.2) == 0.65180494056638638188  */
+#define DELTA1524 CHOOSE(627, 0, 0, 627, 0, 0) /* sin (0.7) == 0.64421768723769105367261435139872014  */
+#define DELTA1536 CHOOSE(0.25, 0.2758, 0.3667, 0.25, 0.2758, 0.3667)   /* sincos (pi/2, &sin_res, &cos_res) puts 0 in cos_res  */
+#define DELTA1539 CHOOSE(1, 1, 1, 1, 1, 1)     /* sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in sin_res  */
+#define DELTA1540 CHOOSE(0, 1, 0.5, 0, 1, 0.5) /* sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.5 in cos_res  */
+#define DELTA1541 CHOOSE(627, 0, 0, 627, 0, 0) /* sincos (0.7, &sin_res, &cos_res) puts 0.64421768723769105367261435139872014 in sin_res  */
+#define DELTA1542 CHOOSE(528, 1, 0, 528, 1, 0) /* sincos (0.7, &sin_res, &cos_res) puts 0.76484218728448842625585999019186495 in cos_res  */
+#define DELTA1548 CHOOSE(1029, 1, 1, 1028, 0, 1)       /* sinh (0.7) == 0.75858370183953350346  */
+#define DELTA1562 CHOOSE(325, 0, 0, 325, 0, 0) /* sqrt (15239.9025) == 123.45  */
+#define DELTA1569 CHOOSE(0, 0.5, 0, 0, 0.5, 0) /* tan (pi/4) == 1  */
+#define DELTA1570 CHOOSE(1401, 1, 1, 1401, 0, 0)       /* tan (0.7) == 0.84228838046307944812813500221293775  */
+#define DELTA1576 CHOOSE(521, 1, 1, 521, 0, 0) /* tanh (0.7) == 0.60436777711716349631  */
+#define DELTA1577 CHOOSE(1, 1, 1, 1, 0, 0)     /* tanh (-0.7) == -0.60436777711716349631  */
+#define DELTA1587 CHOOSE(0, 0, 1, 0, 0, 1)     /* tgamma (0.5) == sqrt (pi)  */
+#define DELTA1588 CHOOSE(2, 2, 1, 2, 2, 1)     /* tgamma (-0.5) == -2 sqrt (pi)  */
+#define DELTA1590 CHOOSE(2, 0, 0, 2, 0, 0)     /* tgamma (4) == 6  */
+#define DELTA1591 CHOOSE(0, 1, 1, 0, 1, 1)     /* tgamma (0.7) == 1.29805533264755778568  */
+#define DELTA1614 CHOOSE(0, 1, 1, 0, 1, 1)     /* y0 (0.1) == -1.5342386513503668441  */
+#define DELTA1615 CHOOSE(2, 3, 1, 2, 3, 1)     /* y0 (0.7) == -0.19066492933739506743  */
+#define DELTA1616 CHOOSE(0, 2, 1, 0, 2, 1)     /* y0 (1.0) == 0.088256964215676957983  */
+#define DELTA1617 CHOOSE(0, 1, 1, 0, 1, 1)     /* y0 (1.5) == 0.38244892379775884396  */
+#define DELTA1618 CHOOSE(0, 1, 0, 0, 1, 0)     /* y0 (2.0) == 0.51037567264974511960  */
+#define DELTA1619 CHOOSE(1, 1, 1, 1, 1, 1)     /* y0 (8.0) == 0.22352148938756622053  */
+#define DELTA1620 CHOOSE(1, 2, 1, 2, 2, 1)     /* y0 (10.0) == 0.055671167283599391424  */
+#define DELTA1625 CHOOSE(1, 1, 1, 1, 1, 1)     /* y1 (0.1) == -6.4589510947020269877  */
+#define DELTA1626 CHOOSE(0, 1, 1, 0, 1, 0)     /* y1 (0.7) == -1.1032498719076333697  */
+#define DELTA1627 CHOOSE(0, 1, 0, 0, 1, 0)     /* y1 (1.0) == -0.78121282130028871655  */
+#define DELTA1628 CHOOSE(0, 0, 1, 0, 0, 1)     /* y1 (1.5) == -0.41230862697391129595  */
+#define DELTA1629 CHOOSE(1, 1, 2, 1, 1, 2)     /* y1 (2.0) == -0.10703243154093754689  */
+#define DELTA1630 CHOOSE(2, 1, 2, 2, 0, 2)     /* y1 (8.0) == -0.15806046173124749426  */
+#define DELTA1631 CHOOSE(0, 3, 2, 0, 3, 2)     /* y1 (10.0) == 0.24901542420695388392  */
+#define DELTA1636 CHOOSE(0, 1, 1, 0, 1, 1)     /* yn (0, 0.1) == -1.5342386513503668441  */
+#define DELTA1637 CHOOSE(2, 3, 1, 2, 3, 1)     /* yn (0, 0.7) == -0.19066492933739506743  */
+#define DELTA1638 CHOOSE(0, 2, 1, 0, 2, 1)     /* yn (0, 1.0) == 0.088256964215676957983  */
+#define DELTA1639 CHOOSE(0, 1, 1, 0, 1, 1)     /* yn (0, 1.5) == 0.38244892379775884396  */
+#define DELTA1640 CHOOSE(0, 1, 0, 0, 1, 0)     /* yn (0, 2.0) == 0.51037567264974511960  */
+#define DELTA1641 CHOOSE(1, 1, 1, 1, 1, 1)     /* yn (0, 8.0) == 0.22352148938756622053  */
+#define DELTA1642 CHOOSE(1, 2, 1, 1, 2, 1)     /* yn (0, 10.0) == 0.055671167283599391424  */
+#define DELTA1647 CHOOSE(1, 1, 1, 1, 1, 1)     /* yn (1, 0.1) == -6.4589510947020269877  */
+#define DELTA1648 CHOOSE(0, 1, 1, 0, 1, 0)     /* yn (1, 0.7) == -1.1032498719076333697  */
+#define DELTA1649 CHOOSE(0, 1, 0, 0, 1, 0)     /* yn (1, 1.0) == -0.78121282130028871655  */
+#define DELTA1650 CHOOSE(0, 0, 1, 0, 0, 1)     /* yn (1, 1.5) == -0.41230862697391129595  */
+#define DELTA1651 CHOOSE(1, 1, 2, 1, 1, 2)     /* yn (1, 2.0) == -0.10703243154093754689  */
+#define DELTA1652 CHOOSE(2, 1, 2, 2, 0, 2)     /* yn (1, 8.0) == -0.15806046173124749426  */
+#define DELTA1653 CHOOSE(0, 3, 2, 0, 3, 2)     /* yn (1, 10.0) == 0.24901542420695388392  */
+#define DELTA1656 CHOOSE(2, 1, 2, 2, 1, 1)     /* yn (3, 0.1) == -5099.3323786129048894  */
+#define DELTA1657 CHOOSE(2, 3, 1, 2, 3, 1)     /* yn (3, 0.7) == -15.819479052819633505  */
+#define DELTA1659 CHOOSE(0, 1, 1, 0, 1, 1)     /* yn (3, 2.0) == -1.1277837768404277861  */
+#define DELTA1660 CHOOSE(0, 1, 1, 0, 1, 1)     /* yn (3, 10.0) == -0.25136265718383732978  */
+#define DELTA1663 CHOOSE(2, 2, 2, 2, 2, 1)     /* yn (10, 0.1) == -0.11831335132045197885e19  */
+#define DELTA1664 CHOOSE(7, 6, 3, 7, 6, 3)     /* yn (10, 0.7) == -0.42447194260703866924e10  */
+#define DELTA1665 CHOOSE(0, 1, 2, 0, 1, 1)     /* yn (10, 1.0) == -0.12161801427868918929e9  */
+#define DELTA1666 CHOOSE(1, 3, 1, 1, 2, 1)     /* yn (10, 2.0) == -129184.54220803928264  */
+#define DELTA1667 CHOOSE(0, 2, 1, 0, 2, 1)     /* yn (10, 10.0) == -0.35981415218340272205  */
diff --git a/test/libm-test.c b/test/libm-test.c
new file mode 100644 (file)
index 0000000..0cef025
--- /dev/null
@@ -0,0 +1,4537 @@
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Part of testsuite for libm.
+
+   This file is processed by a perl script.  The resulting file has to
+   be included by a master file that defines:
+
+   Makros:
+   FUNC(function): converts general function name (like cos) to
+   name with correct suffix (e.g. cosl or cosf)
+   MATHCONST(x):   like FUNC but for constants (e.g convert 0.0 to 0.0L)
+   FLOAT:         floating point type to test
+   - TEST_MSG:    informal message to be displayed
+   CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat):
+   chooses one of the parameters as delta for testing
+   equality
+   PRINTF_EXPR    Floating point conversion specification to print a variable
+   of type FLOAT with printf.  PRINTF_EXPR just contains
+   the specifier, not the percent and width arguments,
+   e.g. "f".
+   PRINTF_XEXPR           Like PRINTF_EXPR, but print in hexadecimal format.
+   PRINTF_NEXPR Like PRINTF_EXPR, but print nice.  */
+
+/* This testsuite has currently tests for:
+   acos, acosh, asin, asinh, atan, atan2, atanh,
+   cbrt, ceil, copysign, cos, cosh, erf, erfc, exp, exp10, exp2, expm1,
+   fabs, fdim, floor, fma, fmax, fmin, fmod, fpclassify,
+   frexp, gamma, hypot,
+   ilogb, isfinite, isinf, isnan, isnormal,
+   isless, islessequal, isgreater, isgreaterequal, islessgreater, isunordered,
+   j0, j1, jn,
+   ldexp, lgamma, log, log10, log1p, log2, logb,
+   modf, nearbyint, nextafter,
+   pow, remainder, remquo, rint, lrint, llrint,
+   round, lround, llround,
+   scalb, scalbn, scalbln, signbit, sin, sincos, sinh, sqrt, tan, tanh, tgamma, trunc,
+   y0, y1, yn
+
+   and for the following complex math functions:
+   cabs, cacos, cacosh, carg, casin, casinh, catan, catanh,
+   ccos, ccosh, cexp, clog, cpow, cproj, csin, csinh, csqrt, ctan, ctanh.
+
+   At the moment the following functions aren't tested:
+   drem, significand, nan
+
+   Parameter handling is primitive in the moment:
+   --verbose=[0..3] for different levels of output:
+   0: only error count
+   1: basic report on failed tests (default)
+   2: full report on all tests
+   -v for full output (equals --verbose=3)
+   -u for generation of an ULPs file
+ */
+
+/* "Philosophy":
+
+   This suite tests some aspects of the correct implementation of
+   mathematical functions in libm.  Some simple, specific parameters
+   are tested for correctness but there's no exhaustive
+   testing.  Handling of specific inputs (e.g. infinity, not-a-number)
+   is also tested.  Correct handling of exceptions is checked
+   against.  These implemented tests should check all cases that are
+   specified in ISO C99.
+
+   Exception testing: At the moment only divide-by-zero and invalid
+   exceptions are tested.  Overflow/underflow and inexact exceptions
+   aren't checked at the moment.
+
+   NaN values: There exist signalling and quiet NaNs.  This implementation
+   only uses signalling NaN as parameter but does not differenciate
+   between the two kinds of NaNs as result.
+
+   Inline functions: Inlining functions should give an improvement in
+   speed - but not in precission.  The inlined functions return
+   reasonable values for a reasonable range of input values.  The
+   result is not necessarily correct for all values and exceptions are
+   not correctly raised in all cases.  Problematic input and return
+   values are infinity, not-a-number and minus zero.  This suite
+   therefore does not check these specific inputs and the exception
+   handling for inlined mathematical functions - just the "reasonable"
+   values are checked.
+
+   Beware: The tests might fail for any of the following reasons:
+   - Tests are wrong
+   - Functions are wrong
+   - Floating Point Unit not working properly
+   - Compiler has errors
+
+   With e.g. gcc 2.7.2.2 the test for cexp fails because of a compiler error.
+
+
+   To Do: All parameter should be numbers that can be represented as
+   exact floating point values.  Currently some values cannot be represented
+   exactly and therefore the result is not the expected result.
+*/
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include "libm-test-ulps.h"
+#include <float.h>
+#ifdef SYS_MATH_H
+#include <math.h>
+#include <fenv.h>
+#else
+#include <openlibm.h>
+#endif
+
+#if 0 /* XXX scp XXX */
+#define FE_INEXACT FE_INEXACT
+#define FE_DIVBYZERO FE_DIVBYZERO
+#define FE_UNDERFLOW FE_UNDERFLOW
+#define FE_OVERFLOW FE_OVERFLOW
+#define FE_INVALID FE_INVALID
+#endif
+
+#include <limits.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if 0 /* XXX scp XXX */
+#include <argp.h>
+#endif
+
+// Some native libm implementations don't have sincos defined, so we have to do it ourselves
+void FUNC(sincos) (FLOAT x, FLOAT * s, FLOAT * c);
+
+#ifdef __APPLE__
+#ifdef SYS_MATH_H
+void sincos(FLOAT x, FLOAT * s, FLOAT * c)
+{
+    *s = sin(x);
+    *c = cos(x);
+}
+#endif
+#endif
+
+/* Possible exceptions */
+#define NO_EXCEPTION                   0x0
+#define INVALID_EXCEPTION              0x1
+#define DIVIDE_BY_ZERO_EXCEPTION       0x2
+/* The next flags signals that those exceptions are allowed but not required.   */
+#define INVALID_EXCEPTION_OK           0x4
+#define DIVIDE_BY_ZERO_EXCEPTION_OK    0x8
+#define EXCEPTIONS_OK INVALID_EXCEPTION_OK+DIVIDE_BY_ZERO_EXCEPTION_OK
+/* Some special test flags, passed togther with exceptions.  */
+#define IGNORE_ZERO_INF_SIGN           0x10
+
+/* Various constants (we must supply them precalculated for accuracy).  */
+#define M_PI_6l                        .52359877559829887307710723054658383L
+#define M_E2l                  7.389056098930650227230427460575008L
+#define M_E3l                  20.085536923187667740928529654581719L
+#define M_2_SQRT_PIl           3.5449077018110320545963349666822903L   /* 2 sqrt (M_PIl)  */
+#define M_SQRT_PIl             1.7724538509055160272981674833411451L   /* sqrt (M_PIl)  */
+#define M_LOG_SQRT_PIl         0.57236494292470008707171367567652933L  /* log(sqrt(M_PIl))  */
+#define M_LOG_2_SQRT_PIl       1.265512123484645396488945797134706L    /* log(2*sqrt(M_PIl))  */
+#define M_PI_34l               (M_PIl - M_PI_4l)               /* 3*pi/4 */
+#define M_PI_34_LOG10El                (M_PIl - M_PI_4l) * M_LOG10El
+#define M_PI2_LOG10El          M_PI_2l * M_LOG10El
+#define M_PI4_LOG10El          M_PI_4l * M_LOG10El
+#define M_PI_LOG10El           M_PIl * M_LOG10El
+
+#if 1 /* XXX scp XXX */
+# define M_El          2.7182818284590452353602874713526625L  /* e */
+# define M_LOG2El      1.4426950408889634073599246810018922L  /* log_2 e */
+# define M_LOG10El     0.4342944819032518276511289189166051L  /* log_10 e */
+# define M_LN2l                0.6931471805599453094172321214581766L  /* log_e 2 */
+# define M_LN10l       2.3025850929940456840179914546843642L  /* log_e 10 */
+# define M_PIl         3.1415926535897932384626433832795029L  /* pi */
+# define M_PI_2l       1.5707963267948966192313216916397514L  /* pi/2 */
+# define M_PI_4l       0.7853981633974483096156608458198757L  /* pi/4 */
+# define M_1_PIl       0.3183098861837906715377675267450287L  /* 1/pi */
+# define M_2_PIl       0.6366197723675813430755350534900574L  /* 2/pi */
+# define M_2_SQRTPIl   1.1283791670955125738961589031215452L  /* 2/sqrt(pi) */
+# define M_SQRT2l      1.4142135623730950488016887242096981L  /* sqrt(2) */
+# define M_SQRT1_2l    0.7071067811865475244008443621048490L  /* 1/sqrt(2) */
+#endif
+
+static FILE *ulps_file;        /* File to document difference.  */
+static int output_ulps;        /* Should ulps printed?  */
+
+static int noErrors;   /* number of errors */
+static int noTests;    /* number of tests (without testing exceptions) */
+static int noExcTests; /* number of tests for exception flags */
+static int noXFails;   /* number of expected failures.  */
+static int noXPasses;  /* number of unexpected passes.  */
+
+static int verbose;
+static int output_max_error;   /* Should the maximal errors printed?  */
+static int output_points;      /* Should the single function results printed?  */
+static int ignore_max_ulp;     /* Should we ignore max_ulp?  */
+
+static FLOAT minus_zero, plus_zero;
+static FLOAT plus_infty, minus_infty, nan_value;
+
+static FLOAT max_error, real_max_error, imag_max_error;
+
+
+#if 0 /* XXX scp XXX */
+#define BUILD_COMPLEX(real, imag) \
+  ({ __complex__ FLOAT __retval;                                             \
+     __real__ __retval = (real);                                             \
+     __imag__ __retval = (imag);                                             \
+     __retval; })
+
+#define BUILD_COMPLEX_INT(real, imag) \
+  ({ __complex__ int __retval;                                               \
+     __real__ __retval = (real);                                             \
+     __imag__ __retval = (imag);                                             \
+     __retval; })
+#endif
+
+
+#define MANT_DIG CHOOSE ((LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1),  \
+                         (LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1))
+
+
+static void
+init_max_error (void)
+{
+  max_error = 0;
+  real_max_error = 0;
+  imag_max_error = 0;
+  feclearexcept (FE_ALL_EXCEPT);
+}
+
+static void
+set_max_error (FLOAT current, FLOAT *curr_max_error)
+{
+  if (current > *curr_max_error)
+    *curr_max_error = current;
+}
+
+
+/* Should the message print to screen?  This depends on the verbose flag,
+   and the test status.  */
+static int
+print_screen (int ok, int xfail)
+{
+  if (output_points
+      && (verbose > 1
+         || (verbose == 1 && ok == xfail)))
+    return 1;
+  return 0;
+}
+
+
+/* Should the message print to screen?  This depends on the verbose flag,
+   and the test status.  */
+static int
+print_screen_max_error (int ok, int xfail)
+{
+  if (output_max_error
+      && (verbose > 1
+         || ((verbose == 1) && (ok == xfail))))
+    return 1;
+  return 0;
+}
+
+/* Update statistic counters.  */
+static void
+update_stats (int ok, int xfail)
+{
+  ++noTests;
+  if (ok && xfail)
+    ++noXPasses;
+  else if (!ok && xfail)
+    ++noXFails;
+  else if (!ok && !xfail)
+    ++noErrors;
+}
+
+static void
+print_ulps (const char *test_name, FLOAT ulp)
+{
+  if (output_ulps)
+    {
+      fprintf (ulps_file, "Test \"%s\":\n", test_name);
+      fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n",
+              CHOOSE("ldouble", "double", "float",
+                     "ildouble", "idouble", "ifloat"), ulp);
+    }
+}
+
+static void
+print_function_ulps (const char *function_name, FLOAT ulp)
+{
+  if (output_ulps)
+    {
+      fprintf (ulps_file, "Function: \"%s\":\n", function_name);
+      fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n",
+              CHOOSE("ldouble", "double", "float",
+                     "ildouble", "idouble", "ifloat"), ulp);
+    }
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+print_complex_function_ulps (const char *function_name, FLOAT real_ulp,
+                            FLOAT imag_ulp)
+{
+  if (output_ulps)
+    {
+      if (real_ulp != 0.0)
+       {
+         fprintf (ulps_file, "Function: Real part of \"%s\":\n", function_name);
+         fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n",
+                  CHOOSE("ldouble", "double", "float",
+                         "ildouble", "idouble", "ifloat"), real_ulp);
+       }
+      if (imag_ulp != 0.0)
+       {
+         fprintf (ulps_file, "Function: Imaginary part of \"%s\":\n", function_name);
+         fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n",
+                  CHOOSE("ldouble", "double", "float",
+                         "ildouble", "idouble", "ifloat"), imag_ulp);
+       }
+
+
+    }
+}
+#endif
+
+
+static void
+print_max_error (const char *func_name, FLOAT allowed, int xfail)
+{
+  int ok = 0;
+
+  if (max_error == 0.0 || (max_error <= allowed && !ignore_max_ulp))
+    {
+      ok = 1;
+    }
+
+  if (!ok)
+    print_function_ulps (func_name, max_error);
+
+
+  if (print_screen_max_error (ok, xfail))
+    {
+      printf ("Maximal error of `%s'\n", func_name);
+      printf (" is      : % .4" PRINTF_NEXPR " ulp\n", max_error);
+      printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", allowed);
+    }
+
+  update_stats (ok, xfail);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+print_complex_max_error (const char *func_name, __complex__ FLOAT allowed,
+                        __complex__ int xfail)
+{
+  int ok = 0;
+
+  if ((real_max_error <= __real__ allowed)
+      && (imag_max_error <= __imag__ allowed))
+    {
+      ok = 1;
+    }
+
+  if (!ok)
+    print_complex_function_ulps (func_name, real_max_error, imag_max_error);
+
+
+  if (print_screen_max_error (ok, xfail))
+    {
+      printf ("Maximal error of real part of: %s\n", func_name);
+      printf (" is      : % .4" PRINTF_NEXPR " ulp\n", real_max_error);
+      printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", __real__ allowed);
+      printf ("Maximal error of imaginary part of: %s\n", func_name);
+      printf (" is      : % .4" PRINTF_NEXPR " ulp\n", imag_max_error);
+      printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", __imag__ allowed);
+    }
+
+  update_stats (ok, xfail);
+}
+#endif
+
+
+/* Test whether a given exception was raised.  */
+static void
+test_single_exception (const char *test_name,
+                      int exception,
+                      int exc_flag,
+                      int fe_flag,
+                      const char *flag_name)
+{
+/* Don't perform these checks if we're compiling with clang, because clang
+   doesn't bother to set floating-point exceptions properly */
+#ifndef __clang__
+#ifndef TEST_INLINE
+  int ok = 1;
+  if (exception & exc_flag)
+    {
+      if (fetestexcept (fe_flag))
+       {
+         if (print_screen (1, 0))
+           printf ("Pass: %s: Exception \"%s\" set\n", test_name, flag_name);
+       }
+      else
+       {
+         ok = 0;
+         if (print_screen (0, 0))
+           printf ("Failure: %s: Exception \"%s\" not set\n",
+                   test_name, flag_name);
+       }
+    }
+  else
+    {
+      if (fetestexcept (fe_flag))
+       {
+         ok = 0;
+         if (print_screen (0, 0))
+           printf ("Failure: %s: Exception \"%s\" set\n",
+                   test_name, flag_name);
+       }
+      else
+       {
+         if (print_screen (1, 0))
+           printf ("%s: Exception \"%s\" not set\n", test_name,
+                   flag_name);
+       }
+    }
+  if (!ok)
+    ++noErrors;
+
+#endif
+#endif // __clang__
+}
+
+
+/* Test whether exceptions given by EXCEPTION are raised.  Ignore thereby
+   allowed but not required exceptions.
+*/
+static void
+test_exceptions (const char *test_name, int exception)
+{
+  ++noExcTests;
+#ifdef FE_DIVBYZERO
+  if ((exception & DIVIDE_BY_ZERO_EXCEPTION_OK) == 0)
+    test_single_exception (test_name, exception,
+                          DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO,
+                          "Divide by zero");
+#endif
+#ifdef FE_INVALID
+  if ((exception & INVALID_EXCEPTION_OK) == 0)
+    test_single_exception (test_name, exception, INVALID_EXCEPTION, FE_INVALID,
+                        "Invalid operation");
+#endif
+  feclearexcept (FE_ALL_EXCEPT);
+}
+
+
+static void
+check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
+                     FLOAT max_ulp, int xfail, int exceptions,
+                     FLOAT *curr_max_error)
+{
+  int ok = 0;
+  int print_diff = 0;
+  FLOAT diff = 0;
+  FLOAT ulp = 0;
+
+  test_exceptions (test_name, exceptions);
+  if (isnan (computed) && isnan (expected))
+    ok = 1;
+  else if (isinf (computed) && isinf (expected))
+    {
+      /* Test for sign of infinities.  */
+      if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0
+         && signbit (computed) != signbit (expected))
+       {
+         ok = 0;
+         printf ("infinity has wrong sign.\n");
+       }
+      else
+       ok = 1;
+    }
+  /* Don't calc ulp for NaNs or infinities.  */
+  else if (isinf (computed) || isnan (computed) || isinf (expected) || isnan (expected))
+    ok = 0;
+  else
+    {
+      diff = FUNC(fabs) (computed - expected);
+      /* ilogb (0) isn't allowed.  */
+      if (expected == 0.0)
+       ulp = diff / FUNC(ldexp) (1.0, - MANT_DIG);
+      else
+       ulp = diff / FUNC(ldexp) (1.0, FUNC(ilogb) (expected) - MANT_DIG);
+      set_max_error (ulp, curr_max_error);
+      print_diff = 1;
+      if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0
+         && computed == 0.0 && expected == 0.0
+         && signbit(computed) != signbit (expected))
+       ok = 0;
+      else if (ulp == 0.0 || (ulp <= max_ulp && !ignore_max_ulp))
+       ok = 1;
+      else
+       {
+         ok = 0;
+         print_ulps (test_name, ulp);
+       }
+
+    }
+  if (print_screen (ok, xfail))
+    {
+      if (!ok)
+       printf ("Failure: ");
+      printf ("Test: %s\n", test_name);
+      printf ("Result:\n");
+      printf (" is:         % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR "\n",
+             computed, computed);
+      printf (" should be:  % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR "\n",
+             expected, expected);
+      if (print_diff)
+       {
+         printf (" difference: % .20" PRINTF_EXPR "  % .20" PRINTF_XEXPR
+                 "\n", diff, diff);
+         printf (" ulp       : % .4" PRINTF_NEXPR "\n", ulp);
+         printf (" max.ulp   : % .4" PRINTF_NEXPR "\n", max_ulp);
+       }
+    }
+  update_stats (ok, xfail);
+}
+
+
+static void
+check_float (const char *test_name, FLOAT computed, FLOAT expected,
+            FLOAT max_ulp, int xfail, int exceptions)
+{
+  check_float_internal (test_name, computed, expected, max_ulp, xfail,
+                       exceptions, &max_error);
+}
+
+#if 0 /* XXX scp XXX */
+static void
+check_complex (const char *test_name, __complex__ FLOAT computed,
+              __complex__ FLOAT expected,
+              __complex__ FLOAT max_ulp, __complex__ int xfail,
+              int exception)
+{
+  FLOAT part_comp, part_exp, part_max_ulp;
+  int part_xfail;
+  char str[200];
+
+  sprintf (str, "Real part of: %s", test_name);
+  part_comp = __real__ computed;
+  part_exp = __real__ expected;
+  part_max_ulp = __real__ max_ulp;
+  part_xfail = __real__ xfail;
+
+  check_float_internal (str, part_comp, part_exp, part_max_ulp, part_xfail,
+                       exception, &real_max_error);
+
+  sprintf (str, "Imaginary part of: %s", test_name);
+  part_comp = __imag__ computed;
+  part_exp = __imag__ expected;
+  part_max_ulp = __imag__ max_ulp;
+  part_xfail = __imag__ xfail;
+
+  /* Don't check again for exceptions, just pass through the
+     zero/inf sign test.  */
+  check_float_internal (str, part_comp, part_exp, part_max_ulp, part_xfail,
+                       exception & IGNORE_ZERO_INF_SIGN,
+                       &imag_max_error);
+}
+#endif
+
+/* Check that computed and expected values are equal (int values).  */
+static void
+check_int (const char *test_name, int computed, int expected, int max_ulp,
+          int xfail, int exceptions)
+{
+  int diff = computed - expected;
+  int ok = 0;
+
+  test_exceptions (test_name, exceptions);
+  noTests++;
+  if (abs (diff) <= max_ulp)
+    ok = 1;
+
+  if (!ok)
+    print_ulps (test_name, diff);
+
+  if (print_screen (ok, xfail))
+    {
+      if (!ok)
+       printf ("Failure: ");
+      printf ("Test: %s\n", test_name);
+      printf ("Result:\n");
+      printf (" is:         %d\n", computed);
+      printf (" should be:  %d\n", expected);
+    }
+
+  update_stats (ok, xfail);
+}
+
+
+/* Check that computed and expected values are equal (long int values).  */
+static void
+check_long (const char *test_name, long int computed, long int expected,
+           long int max_ulp, int xfail, int exceptions)
+{
+  long int diff = computed - expected;
+  int ok = 0;
+
+  test_exceptions (test_name, exceptions);
+  noTests++;
+  if (labs (diff) <= max_ulp)
+    ok = 1;
+
+  if (!ok)
+    print_ulps (test_name, diff);
+
+  if (print_screen (ok, xfail))
+    {
+      if (!ok)
+       printf ("Failure: ");
+      printf ("Test: %s\n", test_name);
+      printf ("Result:\n");
+      printf (" is:         %ld\n", computed);
+      printf (" should be:  %ld\n", expected);
+    }
+
+  update_stats (ok, xfail);
+}
+
+
+/* Check that computed value is true/false.  */
+static void
+check_bool (const char *test_name, int computed, int expected,
+           long int max_ulp, int xfail, int exceptions)
+{
+  int ok = 0;
+
+  test_exceptions (test_name, exceptions);
+  noTests++;
+  if ((computed == 0) == (expected == 0))
+    ok = 1;
+
+  if (print_screen (ok, xfail))
+    {
+      if (!ok)
+       printf ("Failure: ");
+      printf ("Test: %s\n", test_name);
+      printf ("Result:\n");
+      printf (" is:         %d\n", computed);
+      printf (" should be:  %d\n", expected);
+    }
+
+  update_stats (ok, xfail);
+}
+
+
+/* check that computed and expected values are equal (long int values) */
+static void
+check_longlong (const char *test_name, long long int computed,
+               long long int expected,
+               long long int max_ulp, int xfail,
+               int exceptions)
+{
+  long long int diff = computed - expected;
+  int ok = 0;
+
+  test_exceptions (test_name, exceptions);
+  noTests++;
+  if (llabs (diff) <= max_ulp)
+    ok = 1;
+
+  if (!ok)
+    print_ulps (test_name, diff);
+
+  if (print_screen (ok, xfail))
+    {
+      if (!ok)
+       printf ("Failure:");
+      printf ("Test: %s\n", test_name);
+      printf ("Result:\n");
+      printf (" is:         %lld\n", computed);
+      printf (" should be:  %lld\n", expected);
+    }
+
+  update_stats (ok, xfail);
+}
+
+
+#if 0  /* XXX scp XXX */
+/* This is to prevent messages from the SVID libm emulation.  */
+int
+matherr (struct exception *x __attribute__ ((unused)))
+{
+  return 1;
+}
+#endif
+
+/****************************************************************************
+  Tests for single functions of libm.
+  Please keep them alphabetically sorted!
+****************************************************************************/
+
+static void
+acos_test (void)
+{
+  errno = 0;
+  FUNC(acos) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("acos (inf) == NaN plus invalid exception",  FUNC(acos) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("acos (-inf) == NaN plus invalid exception",  FUNC(acos) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("acos (NaN) == NaN",  FUNC(acos) (nan_value), nan_value, 0, 0, 0);
+
+  /* |x| > 1: */
+  check_float ("acos (1.1) == NaN plus invalid exception",  FUNC(acos) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("acos (-1.1) == NaN plus invalid exception",  FUNC(acos) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("acos (0) == pi/2",  FUNC(acos) (0), M_PI_2l, 0, 0, 0);
+  check_float ("acos (-0) == pi/2",  FUNC(acos) (minus_zero), M_PI_2l, 0, 0, 0);
+  check_float ("acos (1) == 0",  FUNC(acos) (1), 0, 0, 0, 0);
+  check_float ("acos (-1) == pi",  FUNC(acos) (-1), M_PIl, 0, 0, 0);
+  check_float ("acos (0.5) == M_PI_6l*2.0",  FUNC(acos) (0.5), M_PI_6l*2.0, 1, 0, 0);
+  check_float ("acos (-0.5) == M_PI_6l*4.0",  FUNC(acos) (-0.5), M_PI_6l*4.0, 0, 0, 0);
+  check_float ("acos (0.7) == 0.79539883018414355549096833892476432",  FUNC(acos) (0.7L), 0.79539883018414355549096833892476432L, 0, 0, 0);
+
+  print_max_error ("acos", DELTAacos, 0);
+}
+
+static void
+acosh_test (void)
+{
+  errno = 0;
+  FUNC(acosh) (7);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("acosh (inf) == inf",  FUNC(acosh) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("acosh (-inf) == NaN plus invalid exception",  FUNC(acosh) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  /* x < 1:  */
+  check_float ("acosh (-1.1) == NaN plus invalid exception",  FUNC(acosh) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("acosh (1) == 0",  FUNC(acosh) (1), 0, 0, 0, 0);
+  check_float ("acosh (7) == 2.633915793849633417250092694615937",  FUNC(acosh) (7), 2.633915793849633417250092694615937L, DELTA16, 0, 0);
+
+  print_max_error ("acosh", DELTAacosh, 0);
+}
+
+static void
+asin_test (void)
+{
+  errno = 0;
+  FUNC(asin) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("asin (inf) == NaN plus invalid exception",  FUNC(asin) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("asin (-inf) == NaN plus invalid exception",  FUNC(asin) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("asin (NaN) == NaN",  FUNC(asin) (nan_value), nan_value, 0, 0, 0);
+
+  /* asin x == NaN plus invalid exception for |x| > 1.  */
+  check_float ("asin (1.1) == NaN plus invalid exception",  FUNC(asin) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("asin (-1.1) == NaN plus invalid exception",  FUNC(asin) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("asin (0) == 0",  FUNC(asin) (0), 0, 0, 0, 0);
+  check_float ("asin (-0) == -0",  FUNC(asin) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("asin (0.5) == pi/6",  FUNC(asin) (0.5), M_PI_6l, DELTA24, 0, 0);
+  check_float ("asin (-0.5) == -pi/6",  FUNC(asin) (-0.5), -M_PI_6l, DELTA25, 0, 0);
+  check_float ("asin (1.0) == pi/2",  FUNC(asin) (1.0), M_PI_2l, DELTA26, 0, 0);
+  check_float ("asin (-1.0) == -pi/2",  FUNC(asin) (-1.0), -M_PI_2l, DELTA27, 0, 0);
+  check_float ("asin (0.7) == 0.77539749661075306374035335271498708",  FUNC(asin) (0.7L), 0.77539749661075306374035335271498708L, DELTA28, 0, 0);
+
+  print_max_error ("asin", DELTAasin, 0);
+}
+
+static void
+asinh_test (void)
+{
+  errno = 0;
+  FUNC(asinh) (0.7L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("asinh (0) == 0",  FUNC(asinh) (0), 0, 0, 0, 0);
+  check_float ("asinh (-0) == -0",  FUNC(asinh) (minus_zero), minus_zero, 0, 0, 0);
+#ifndef TEST_INLINE
+  check_float ("asinh (inf) == inf",  FUNC(asinh) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("asinh (-inf) == -inf",  FUNC(asinh) (minus_infty), minus_infty, 0, 0, 0);
+#endif
+  check_float ("asinh (NaN) == NaN",  FUNC(asinh) (nan_value), nan_value, 0, 0, 0);
+  check_float ("asinh (0.7) == 0.652666566082355786",  FUNC(asinh) (0.7L), 0.652666566082355786L, DELTA34, 0, 0);
+
+  print_max_error ("asinh", DELTAasinh, 0);
+}
+
+static void
+atan_test (void)
+{
+  errno = 0;
+  FUNC(atan) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("atan (0) == 0",  FUNC(atan) (0), 0, 0, 0, 0);
+  check_float ("atan (-0) == -0",  FUNC(atan) (minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("atan (inf) == pi/2",  FUNC(atan) (plus_infty), M_PI_2l, 0, 0, 0);
+  check_float ("atan (-inf) == -pi/2",  FUNC(atan) (minus_infty), -M_PI_2l, 0, 0, 0);
+  check_float ("atan (NaN) == NaN",  FUNC(atan) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("atan (1) == pi/4",  FUNC(atan) (1), M_PI_4l, 0, 0, 0);
+  check_float ("atan (-1) == -pi/4",  FUNC(atan) (-1), -M_PI_4l, 0, 0, 0);
+
+  check_float ("atan (0.7) == 0.61072596438920861654375887649023613",  FUNC(atan) (0.7L), 0.61072596438920861654375887649023613L, DELTA42, 0, 0);
+
+  print_max_error ("atan", DELTAatan, 0);
+}
+
+
+
+static void
+atanh_test (void)
+{
+  errno = 0;
+  FUNC(atanh) (0.7L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+
+  check_float ("atanh (0) == 0",  FUNC(atanh) (0), 0, 0, 0, 0);
+  check_float ("atanh (-0) == -0",  FUNC(atanh) (minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("atanh (1) == inf plus division by zero exception",  FUNC(atanh) (1), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("atanh (-1) == -inf plus division by zero exception",  FUNC(atanh) (-1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("atanh (NaN) == NaN",  FUNC(atanh) (nan_value), nan_value, 0, 0, 0);
+
+  /* atanh (x) == NaN plus invalid exception if |x| > 1.  */
+  check_float ("atanh (1.1) == NaN plus invalid exception",  FUNC(atanh) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("atanh (-1.1) == NaN plus invalid exception",  FUNC(atanh) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("atanh (0.7) == 0.8673005276940531944",  FUNC(atanh) (0.7L), 0.8673005276940531944L, DELTA50, 0, 0);
+
+  print_max_error ("atanh", DELTAatanh, 0);
+}
+
+static void
+atan2_test (void)
+{
+  errno = 0;
+  FUNC(atan2) (-0, 1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  /* atan2 (0,x) == 0 for x > 0.  */
+  check_float ("atan2 (0, 1) == 0",  FUNC(atan2) (0, 1), 0, 0, 0, 0);
+
+  /* atan2 (-0,x) == -0 for x > 0.  */
+  check_float ("atan2 (-0, 1) == -0",  FUNC(atan2) (minus_zero, 1), minus_zero, 0, 0, 0);
+
+  check_float ("atan2 (0, 0) == 0",  FUNC(atan2) (0, 0), 0, 0, 0, 0);
+  check_float ("atan2 (-0, 0) == -0",  FUNC(atan2) (minus_zero, 0), minus_zero, 0, 0, 0);
+
+  /* atan2 (+0,x) == +pi for x < 0.  */
+  check_float ("atan2 (0, -1) == pi",  FUNC(atan2) (0, -1), M_PIl, 0, 0, 0);
+
+  /* atan2 (-0,x) == -pi for x < 0.  */
+  check_float ("atan2 (-0, -1) == -pi",  FUNC(atan2) (minus_zero, -1), -M_PIl, 0, 0, 0);
+
+  check_float ("atan2 (0, -0) == pi",  FUNC(atan2) (0, minus_zero), M_PIl, 0, 0, 0);
+  check_float ("atan2 (-0, -0) == -pi",  FUNC(atan2) (minus_zero, minus_zero), -M_PIl, 0, 0, 0);
+
+  /* atan2 (y,+0) == pi/2 for y > 0.  */
+  check_float ("atan2 (1, 0) == pi/2",  FUNC(atan2) (1, 0), M_PI_2l, 0, 0, 0);
+
+  /* atan2 (y,-0) == pi/2 for y > 0.  */
+  check_float ("atan2 (1, -0) == pi/2",  FUNC(atan2) (1, minus_zero), M_PI_2l, 0, 0, 0);
+
+  /* atan2 (y,+0) == -pi/2 for y < 0.  */
+  check_float ("atan2 (-1, 0) == -pi/2",  FUNC(atan2) (-1, 0), -M_PI_2l, 0, 0, 0);
+
+  /* atan2 (y,-0) == -pi/2 for y < 0.  */
+  check_float ("atan2 (-1, -0) == -pi/2",  FUNC(atan2) (-1, minus_zero), -M_PI_2l, 0, 0, 0);
+
+  /* atan2 (y,inf) == +0 for finite y > 0.  */
+  check_float ("atan2 (1, inf) == 0",  FUNC(atan2) (1, plus_infty), 0, 0, 0, 0);
+
+  /* atan2 (y,inf) == -0 for finite y < 0.  */
+  check_float ("atan2 (-1, inf) == -0",  FUNC(atan2) (-1, plus_infty), minus_zero, 0, 0, 0);
+
+  /* atan2(+inf, x) == pi/2 for finite x.  */
+  check_float ("atan2 (inf, -1) == pi/2",  FUNC(atan2) (plus_infty, -1), M_PI_2l, 0, 0, 0);
+
+  /* atan2(-inf, x) == -pi/2 for finite x.  */
+  check_float ("atan2 (-inf, 1) == -pi/2",  FUNC(atan2) (minus_infty, 1), -M_PI_2l, 0, 0, 0);
+
+  /* atan2 (y,-inf) == +pi for finite y > 0.  */
+  check_float ("atan2 (1, -inf) == pi",  FUNC(atan2) (1, minus_infty), M_PIl, 0, 0, 0);
+
+  /* atan2 (y,-inf) == -pi for finite y < 0.  */
+  check_float ("atan2 (-1, -inf) == -pi",  FUNC(atan2) (-1, minus_infty), -M_PIl, 0, 0, 0);
+
+  check_float ("atan2 (inf, inf) == pi/4",  FUNC(atan2) (plus_infty, plus_infty), M_PI_4l, 0, 0, 0);
+  check_float ("atan2 (-inf, inf) == -pi/4",  FUNC(atan2) (minus_infty, plus_infty), -M_PI_4l, 0, 0, 0);
+  check_float ("atan2 (inf, -inf) == 3/4 pi",  FUNC(atan2) (plus_infty, minus_infty), M_PI_34l, 0, 0, 0);
+  check_float ("atan2 (-inf, -inf) == -3/4 pi",  FUNC(atan2) (minus_infty, minus_infty), -M_PI_34l, 0, 0, 0);
+  check_float ("atan2 (NaN, NaN) == NaN",  FUNC(atan2) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("atan2 (0.7, 1) == 0.61072596438920861654375887649023613",  FUNC(atan2) (0.7L, 1), 0.61072596438920861654375887649023613L, DELTA74, 0, 0);
+  check_float ("atan2 (-0.7, 1.0) == -0.61072596438920861654375887649023613",  FUNC(atan2) (-0.7L, 1.0L), -0.61072596438920861654375887649023613L, 0, 0, 0);
+  check_float ("atan2 (0.7, -1.0) == 2.530866689200584621918884506789267",  FUNC(atan2) (0.7L, -1.0L), 2.530866689200584621918884506789267L, 0, 0, 0);
+  check_float ("atan2 (-0.7, -1.0) == -2.530866689200584621918884506789267",  FUNC(atan2) (-0.7L, -1.0L), -2.530866689200584621918884506789267L, 0, 0, 0);
+  check_float ("atan2 (0.4, 0.0003) == 1.5700463269355215717704032607580829",  FUNC(atan2) (0.4L, 0.0003L), 1.5700463269355215717704032607580829L, DELTA78, 0, 0);
+  check_float ("atan2 (1.4, -0.93) == 2.1571487668237843754887415992772736",  FUNC(atan2) (1.4L, -0.93L), 2.1571487668237843754887415992772736L, 0, 0, 0);
+
+  print_max_error ("atan2", DELTAatan2, 0);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+cabs_test (void)
+{
+  errno = 0;
+  FUNC(cabs) (BUILD_COMPLEX (0.7L, 12.4L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  /* cabs (x + iy) is specified as hypot (x,y) */
+
+  /* cabs (+inf + i x) == +inf.  */
+  check_float ("cabs (inf + 1.0 i) == inf",  FUNC(cabs) (BUILD_COMPLEX (plus_infty, 1.0)), plus_infty, 0, 0, 0);
+  /* cabs (-inf + i x) == +inf.  */
+  check_float ("cabs (-inf + 1.0 i) == inf",  FUNC(cabs) (BUILD_COMPLEX (minus_infty, 1.0)), plus_infty, 0, 0, 0);
+
+  check_float ("cabs (-inf + NaN i) == inf",  FUNC(cabs) (BUILD_COMPLEX (minus_infty, nan_value)), plus_infty, 0, 0, 0);
+  check_float ("cabs (-inf + NaN i) == inf",  FUNC(cabs) (BUILD_COMPLEX (minus_infty, nan_value)), plus_infty, 0, 0, 0);
+
+  check_float ("cabs (NaN + NaN i) == NaN",  FUNC(cabs) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0);
+
+  /* cabs (x,y) == cabs (y,x).  */
+  check_float ("cabs (0.7 + 12.4 i) == 12.419742348374220601176836866763271",  FUNC(cabs) (BUILD_COMPLEX (0.7L, 12.4L)), 12.419742348374220601176836866763271L, DELTA85, 0, 0);
+  /* cabs (x,y) == cabs (-x,y).  */
+  check_float ("cabs (-12.4 + 0.7 i) == 12.419742348374220601176836866763271",  FUNC(cabs) (BUILD_COMPLEX (-12.4L, 0.7L)), 12.419742348374220601176836866763271L, DELTA86, 0, 0);
+  /* cabs (x,y) == cabs (-y,x).  */
+  check_float ("cabs (-0.7 + 12.4 i) == 12.419742348374220601176836866763271",  FUNC(cabs) (BUILD_COMPLEX (-0.7L, 12.4L)), 12.419742348374220601176836866763271L, DELTA87, 0, 0);
+  /* cabs (x,y) == cabs (-x,-y).  */
+  check_float ("cabs (-12.4 - 0.7 i) == 12.419742348374220601176836866763271",  FUNC(cabs) (BUILD_COMPLEX (-12.4L, -0.7L)), 12.419742348374220601176836866763271L, DELTA88, 0, 0);
+  /* cabs (x,y) == cabs (-y,-x).  */
+  check_float ("cabs (-0.7 - 12.4 i) == 12.419742348374220601176836866763271",  FUNC(cabs) (BUILD_COMPLEX (-0.7L, -12.4L)), 12.419742348374220601176836866763271L, DELTA89, 0, 0);
+  /* cabs (x,0) == fabs (x).  */
+  check_float ("cabs (-0.7 + 0 i) == 0.7",  FUNC(cabs) (BUILD_COMPLEX (-0.7L, 0)), 0.7L, 0, 0, 0);
+  check_float ("cabs (0.7 + 0 i) == 0.7",  FUNC(cabs) (BUILD_COMPLEX (0.7L, 0)), 0.7L, 0, 0, 0);
+  check_float ("cabs (-1.0 + 0 i) == 1.0",  FUNC(cabs) (BUILD_COMPLEX (-1.0L, 0)), 1.0L, 0, 0, 0);
+  check_float ("cabs (1.0 + 0 i) == 1.0",  FUNC(cabs) (BUILD_COMPLEX (1.0L, 0)), 1.0L, 0, 0, 0);
+  check_float ("cabs (-5.7e7 + 0 i) == 5.7e7",  FUNC(cabs) (BUILD_COMPLEX (-5.7e7L, 0)), 5.7e7L, 0, 0, 0);
+  check_float ("cabs (5.7e7 + 0 i) == 5.7e7",  FUNC(cabs) (BUILD_COMPLEX (5.7e7L, 0)), 5.7e7L, 0, 0, 0);
+
+  check_float ("cabs (0.7 + 1.2 i) == 1.3892443989449804508432547041028554",  FUNC(cabs) (BUILD_COMPLEX (0.7L, 1.2L)), 1.3892443989449804508432547041028554L, DELTA96, 0, 0);
+
+  print_max_error ("cabs", DELTAcabs, 0);
+}
+
+static void
+cacos_test (void)
+{
+  errno = 0;
+  FUNC(cacos) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+
+  check_complex ("cacos (0 + 0 i) == pi/2 - 0 i",  FUNC(cacos) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("cacos (-0 + 0 i) == pi/2 - 0 i",  FUNC(cacos) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("cacos (-0 - 0 i) == pi/2 + 0.0 i",  FUNC(cacos) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (M_PI_2l, 0.0), 0, 0, 0);
+  check_complex ("cacos (0 - 0 i) == pi/2 + 0.0 i",  FUNC(cacos) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (M_PI_2l, 0.0), 0, 0, 0);
+
+  check_complex ("cacos (-inf + inf i) == 3/4 pi - inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (M_PI_34l, minus_infty), 0, 0, 0);
+  check_complex ("cacos (-inf - inf i) == 3/4 pi + inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (M_PI_34l, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (inf + inf i) == pi/4 - inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_4l, minus_infty), 0, 0, 0);
+  check_complex ("cacos (inf - inf i) == pi/4 + inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_4l, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (-10.0 + inf i) == pi/2 - inf i",  FUNC(cacos) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0);
+  check_complex ("cacos (-10.0 - inf i) == pi/2 + inf i",  FUNC(cacos) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("cacos (0 + inf i) == pi/2 - inf i",  FUNC(cacos) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0);
+  check_complex ("cacos (0 - inf i) == pi/2 + inf i",  FUNC(cacos) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("cacos (0.1 + inf i) == pi/2 - inf i",  FUNC(cacos) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0);
+  check_complex ("cacos (0.1 - inf i) == pi/2 + inf i",  FUNC(cacos) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (-inf + 0 i) == pi - inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (M_PIl, minus_infty), 0, 0, 0);
+  check_complex ("cacos (-inf - 0 i) == pi + inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (M_PIl, plus_infty), 0, 0, 0);
+  check_complex ("cacos (-inf + 100 i) == pi - inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (M_PIl, minus_infty), 0, 0, 0);
+  check_complex ("cacos (-inf - 100 i) == pi + inf i",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (M_PIl, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (inf + 0 i) == 0.0 - inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+  check_complex ("cacos (inf - 0 i) == 0.0 + inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("cacos (inf + 0.5 i) == 0.0 - inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+  check_complex ("cacos (inf - 0.5 i) == 0.0 + inf i",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (inf + NaN i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(cacos) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("cacos (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(cacos) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("cacos (0 + NaN i) == pi/2 + NaN i",  FUNC(cacos) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (M_PI_2l, nan_value), 0, 0, 0);
+  check_complex ("cacos (-0 + NaN i) == pi/2 + NaN i",  FUNC(cacos) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (M_PI_2l, nan_value), 0, 0, 0);
+
+  check_complex ("cacos (NaN + inf i) == NaN - inf i",  FUNC(cacos) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, minus_infty), 0, 0, 0);
+  check_complex ("cacos (NaN - inf i) == NaN + inf i",  FUNC(cacos) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, 0);
+
+  check_complex ("cacos (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacos) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cacos (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacos) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("cacos (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacos) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cacos (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacos) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("cacos (NaN + NaN i) == NaN + NaN i",  FUNC(cacos) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("cacos (0.7 + 1.2 i) == 1.1351827477151551088992008271819053 - 1.0927647857577371459105272080819308 i",  FUNC(cacos) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.1351827477151551088992008271819053L, -1.0927647857577371459105272080819308L), DELTA130, 0, 0);
+  check_complex ("cacos (-2 - 3 i) == 2.1414491111159960199416055713254211 + 1.9833870299165354323470769028940395 i",  FUNC(cacos) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (2.1414491111159960199416055713254211L, 1.9833870299165354323470769028940395L), DELTA131, 0, 0);
+
+  print_complex_max_error ("cacos", DELTAcacos, 0);
+}
+
+
+static void
+cacosh_test (void)
+{
+  errno = 0;
+  FUNC(cacosh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+
+  check_complex ("cacosh (0 + 0 i) == 0.0 + pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (-0 + 0 i) == 0.0 + pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (0 - 0 i) == 0.0 - pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (-0 - 0 i) == 0.0 - pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (-inf + inf i) == inf + 3/4 pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34l), 0, 0, 0);
+  check_complex ("cacosh (-inf - inf i) == inf - 3/4 pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_34l), 0, 0, 0);
+
+  check_complex ("cacosh (inf + inf i) == inf + pi/4 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0);
+  check_complex ("cacosh (inf - inf i) == inf - pi/4 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0);
+
+  check_complex ("cacosh (-10.0 + inf i) == inf + pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (-10.0 - inf i) == inf - pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (0 + inf i) == inf + pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (0 - inf i) == inf - pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (0.1 + inf i) == inf + pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("cacosh (0.1 - inf i) == inf - pi/2 i",  FUNC(cacosh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("cacosh (-inf + 0 i) == inf + pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0);
+  check_complex ("cacosh (-inf - 0 i) == inf - pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0);
+  check_complex ("cacosh (-inf + 100 i) == inf + pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0);
+  check_complex ("cacosh (-inf - 100 i) == inf - pi i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0);
+
+  check_complex ("cacosh (inf + 0 i) == inf + 0.0 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("cacosh (inf - 0 i) == inf - 0 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("cacosh (inf + 0.5 i) == inf + 0.0 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("cacosh (inf - 0.5 i) == inf - 0 i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("cacosh (inf + NaN i) == inf + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("cacosh (-inf + NaN i) == inf + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("cacosh (0 + NaN i) == NaN + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+  check_complex ("cacosh (-0 + NaN i) == NaN + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("cacosh (NaN + inf i) == inf + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("cacosh (NaN - inf i) == inf + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("cacosh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacosh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cacosh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacosh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("cacosh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacosh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cacosh (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cacosh) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("cacosh (NaN + NaN i) == NaN + NaN i",  FUNC(cacosh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("cacosh (0.7 + 1.2 i) == 1.0927647857577371459105272080819308 + 1.1351827477151551088992008271819053 i",  FUNC(cacosh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.0927647857577371459105272080819308L, 1.1351827477151551088992008271819053L), DELTA165, 0, 0);
+  check_complex ("cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i",  FUNC(cacosh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.9833870299165354323470769028940395L, 2.1414491111159960199416055713254211L), DELTA166, 0, 0);
+
+  print_complex_max_error ("cacosh", DELTAcacosh, 0);
+}
+
+static void
+carg_test (void)
+{
+  init_max_error ();
+
+  /* carg (x + iy) is specified as atan2 (y, x) */
+
+  /* carg (x + i 0) == 0 for x > 0.  */
+  check_float ("carg (2.0 + 0 i) == 0",  FUNC(carg) (BUILD_COMPLEX (2.0, 0)), 0, 0, 0, 0);
+  /* carg (x - i 0) == -0 for x > 0.  */
+  check_float ("carg (2.0 - 0 i) == -0",  FUNC(carg) (BUILD_COMPLEX (2.0, minus_zero)), minus_zero, 0, 0, 0);
+
+  check_float ("carg (0 + 0 i) == 0",  FUNC(carg) (BUILD_COMPLEX (0, 0)), 0, 0, 0, 0);
+  check_float ("carg (0 - 0 i) == -0",  FUNC(carg) (BUILD_COMPLEX (0, minus_zero)), minus_zero, 0, 0, 0);
+
+  /* carg (x + i 0) == +pi for x < 0.  */
+  check_float ("carg (-2.0 + 0 i) == pi",  FUNC(carg) (BUILD_COMPLEX (-2.0, 0)), M_PIl, 0, 0, 0);
+
+  /* carg (x - i 0) == -pi for x < 0.  */
+  check_float ("carg (-2.0 - 0 i) == -pi",  FUNC(carg) (BUILD_COMPLEX (-2.0, minus_zero)), -M_PIl, 0, 0, 0);
+
+  check_float ("carg (-0 + 0 i) == pi",  FUNC(carg) (BUILD_COMPLEX (minus_zero, 0)), M_PIl, 0, 0, 0);
+  check_float ("carg (-0 - 0 i) == -pi",  FUNC(carg) (BUILD_COMPLEX (minus_zero, minus_zero)), -M_PIl, 0, 0, 0);
+
+  /* carg (+0 + i y) == pi/2 for y > 0.  */
+  check_float ("carg (0 + 2.0 i) == pi/2",  FUNC(carg) (BUILD_COMPLEX (0, 2.0)), M_PI_2l, 0, 0, 0);
+
+  /* carg (-0 + i y) == pi/2 for y > 0.  */
+  check_float ("carg (-0 + 2.0 i) == pi/2",  FUNC(carg) (BUILD_COMPLEX (minus_zero, 2.0)), M_PI_2l, 0, 0, 0);
+
+  /* carg (+0 + i y) == -pi/2 for y < 0.  */
+  check_float ("carg (0 - 2.0 i) == -pi/2",  FUNC(carg) (BUILD_COMPLEX (0, -2.0)), -M_PI_2l, 0, 0, 0);
+
+  /* carg (-0 + i y) == -pi/2 for y < 0.  */
+  check_float ("carg (-0 - 2.0 i) == -pi/2",  FUNC(carg) (BUILD_COMPLEX (minus_zero, -2.0)), -M_PI_2l, 0, 0, 0);
+
+  /* carg (inf + i y) == +0 for finite y > 0.  */
+  check_float ("carg (inf + 2.0 i) == 0",  FUNC(carg) (BUILD_COMPLEX (plus_infty, 2.0)), 0, 0, 0, 0);
+
+  /* carg (inf + i y) == -0 for finite y < 0.  */
+  check_float ("carg (inf - 2.0 i) == -0",  FUNC(carg) (BUILD_COMPLEX (plus_infty, -2.0)), minus_zero, 0, 0, 0);
+
+  /* carg(x + i inf) == pi/2 for finite x.  */
+  check_float ("carg (10.0 + inf i) == pi/2",  FUNC(carg) (BUILD_COMPLEX (10.0, plus_infty)), M_PI_2l, 0, 0, 0);
+
+  /* carg(x - i inf) == -pi/2 for finite x.  */
+  check_float ("carg (10.0 - inf i) == -pi/2",  FUNC(carg) (BUILD_COMPLEX (10.0, minus_infty)), -M_PI_2l, 0, 0, 0);
+
+  /* carg (-inf + i y) == +pi for finite y > 0.  */
+  check_float ("carg (-inf + 10.0 i) == pi",  FUNC(carg) (BUILD_COMPLEX (minus_infty, 10.0)), M_PIl, 0, 0, 0);
+
+  /* carg (-inf + i y) == -pi for finite y < 0.  */
+  check_float ("carg (-inf - 10.0 i) == -pi",  FUNC(carg) (BUILD_COMPLEX (minus_infty, -10.0)), -M_PIl, 0, 0, 0);
+
+  check_float ("carg (inf + inf i) == pi/4",  FUNC(carg) (BUILD_COMPLEX (plus_infty, plus_infty)), M_PI_4l, 0, 0, 0);
+
+  check_float ("carg (inf - inf i) == -pi/4",  FUNC(carg) (BUILD_COMPLEX (plus_infty, minus_infty)), -M_PI_4l, 0, 0, 0);
+
+  check_float ("carg (-inf + inf i) == 3 * M_PI_4l",  FUNC(carg) (BUILD_COMPLEX (minus_infty, plus_infty)), 3 * M_PI_4l, 0, 0, 0);
+
+  check_float ("carg (-inf - inf i) == -3 * M_PI_4l",  FUNC(carg) (BUILD_COMPLEX (minus_infty, minus_infty)), -3 * M_PI_4l, 0, 0, 0);
+
+  check_float ("carg (NaN + NaN i) == NaN",  FUNC(carg) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0);
+
+  print_max_error ("carg", 0, 0);
+}
+
+static void
+casin_test (void)
+{
+  errno = 0;
+  FUNC(casin) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("casin (0 + 0 i) == 0.0 + 0.0 i",  FUNC(casin) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("casin (-0 + 0 i) == -0 + 0.0 i",  FUNC(casin) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("casin (0 - 0 i) == 0.0 - 0 i",  FUNC(casin) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("casin (-0 - 0 i) == -0 - 0 i",  FUNC(casin) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("casin (inf + inf i) == pi/4 + inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_4l, plus_infty), 0, 0, 0);
+  check_complex ("casin (inf - inf i) == pi/4 - inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_4l, minus_infty), 0, 0, 0);
+  check_complex ("casin (-inf + inf i) == -pi/4 + inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (-M_PI_4l, plus_infty), 0, 0, 0);
+  check_complex ("casin (-inf - inf i) == -pi/4 - inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (-M_PI_4l, minus_infty), 0, 0, 0);
+
+  check_complex ("casin (-10.0 + inf i) == -0 + inf i",  FUNC(casin) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0);
+  check_complex ("casin (-10.0 - inf i) == -0 - inf i",  FUNC(casin) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0);
+  check_complex ("casin (0 + inf i) == 0.0 + inf i",  FUNC(casin) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("casin (0 - inf i) == 0.0 - inf i",  FUNC(casin) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+  check_complex ("casin (-0 + inf i) == -0 + inf i",  FUNC(casin) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0);
+  check_complex ("casin (-0 - inf i) == -0 - inf i",  FUNC(casin) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0);
+  check_complex ("casin (0.1 + inf i) == 0.0 + inf i",  FUNC(casin) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("casin (0.1 - inf i) == 0.0 - inf i",  FUNC(casin) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+
+  check_complex ("casin (-inf + 0 i) == -pi/2 + inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (-M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("casin (-inf - 0 i) == -pi/2 - inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-M_PI_2l, minus_infty), 0, 0, 0);
+  check_complex ("casin (-inf + 100 i) == -pi/2 + inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (-M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("casin (-inf - 100 i) == -pi/2 - inf i",  FUNC(casin) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (-M_PI_2l, minus_infty), 0, 0, 0);
+
+  check_complex ("casin (inf + 0 i) == pi/2 + inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("casin (inf - 0 i) == pi/2 - inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0);
+  check_complex ("casin (inf + 0.5 i) == pi/2 + inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0);
+  check_complex ("casin (inf - 0.5 i) == pi/2 - inf i",  FUNC(casin) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0);
+
+  check_complex ("casin (NaN + inf i) == NaN + inf i",  FUNC(casin) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, 0);
+  check_complex ("casin (NaN - inf i) == NaN - inf i",  FUNC(casin) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, minus_infty), 0, 0, 0);
+
+  check_complex ("casin (0.0 + NaN i) == 0.0 + NaN i",  FUNC(casin) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0);
+  check_complex ("casin (-0 + NaN i) == -0 + NaN i",  FUNC(casin) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0);
+
+  check_complex ("casin (inf + NaN i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(casin) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("casin (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(casin) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("casin (NaN + 10.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(casin) (BUILD_COMPLEX (nan_value, 10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("casin (NaN - 10.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(casin) (BUILD_COMPLEX (nan_value, -10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("casin (0.75 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(casin) (BUILD_COMPLEX (0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("casin (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(casin) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("casin (NaN + NaN i) == NaN + NaN i",  FUNC(casin) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("casin (0.7 + 1.2 i) == 0.4356135790797415103321208644578462 + 1.0927647857577371459105272080819308 i",  FUNC(casin) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.4356135790797415103321208644578462L, 1.0927647857577371459105272080819308L), DELTA225, 0, 0);
+  check_complex ("casin (-2 - 3 i) == -0.57065278432109940071028387968566963 - 1.9833870299165354323470769028940395 i",  FUNC(casin) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.57065278432109940071028387968566963L, -1.9833870299165354323470769028940395L), DELTA226, 0, 0);
+
+  print_complex_max_error ("casin", DELTAcasin, 0);
+}
+
+
+static void
+casinh_test (void)
+{
+  errno = 0;
+  FUNC(casinh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("casinh (0 + 0 i) == 0.0 + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("casinh (-0 + 0 i) == -0 + 0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0), 0, 0, 0);
+  check_complex ("casinh (0 - 0 i) == 0.0 - 0 i",  FUNC(casinh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("casinh (-0 - 0 i) == -0 - 0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("casinh (inf + inf i) == inf + pi/4 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0);
+  check_complex ("casinh (inf - inf i) == inf - pi/4 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0);
+  check_complex ("casinh (-inf + inf i) == -inf + pi/4 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_4l), 0, 0, 0);
+  check_complex ("casinh (-inf - inf i) == -inf - pi/4 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_4l), 0, 0, 0);
+
+  check_complex ("casinh (-10.0 + inf i) == -inf + pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (-10.0 - inf i) == -inf - pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (0 + inf i) == inf + pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (0 - inf i) == inf - pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (-0 + inf i) == -inf + pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (-0 - inf i) == -inf - pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (0.1 + inf i) == inf + pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("casinh (0.1 - inf i) == inf - pi/2 i",  FUNC(casinh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("casinh (-inf + 0 i) == -inf + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0);
+  check_complex ("casinh (-inf - 0 i) == -inf - 0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0);
+  check_complex ("casinh (-inf + 100 i) == -inf + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0);
+  check_complex ("casinh (-inf - 100 i) == -inf - 0 i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("casinh (inf + 0 i) == inf + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("casinh (inf - 0 i) == inf - 0 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("casinh (inf + 0.5 i) == inf + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("casinh (inf - 0.5 i) == inf - 0 i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("casinh (inf + NaN i) == inf + NaN i",  FUNC(casinh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("casinh (-inf + NaN i) == -inf + NaN i",  FUNC(casinh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (minus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("casinh (NaN + 0 i) == NaN + 0.0 i",  FUNC(casinh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0);
+  check_complex ("casinh (NaN - 0 i) == NaN - 0 i",  FUNC(casinh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0);
+
+  check_complex ("casinh (NaN + inf i) == inf + NaN i plus sign of zero/inf not specified",  FUNC(casinh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("casinh (NaN - inf i) == inf + NaN i plus sign of zero/inf not specified",  FUNC(casinh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("casinh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(casinh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("casinh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(casinh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("casinh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(casinh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("casinh (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(casinh) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("casinh (NaN + NaN i) == NaN + NaN i",  FUNC(casinh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("casinh (0.7 + 1.2 i) == 0.97865459559367387689317593222160964 + 0.91135418953156011567903546856170941 i",  FUNC(casinh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.97865459559367387689317593222160964L, 0.91135418953156011567903546856170941L), DELTA262, 0, 0);
+  check_complex ("casinh (-2 - 3 i) == -1.9686379257930962917886650952454982 - 0.96465850440760279204541105949953237 i",  FUNC(casinh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.9686379257930962917886650952454982L, -0.96465850440760279204541105949953237L), DELTA263, 0, 0);
+
+  print_complex_max_error ("casinh", DELTAcasinh, 0);
+}
+
+
+static void
+catan_test (void)
+{
+  errno = 0;
+  FUNC(catan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("catan (0 + 0 i) == 0 + 0 i",  FUNC(catan) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0, 0), 0, 0, 0);
+  check_complex ("catan (-0 + 0 i) == -0 + 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0), 0, 0, 0);
+  check_complex ("catan (0 - 0 i) == 0 - 0 i",  FUNC(catan) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0);
+  check_complex ("catan (-0 - 0 i) == -0 - 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("catan (inf + inf i) == pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (inf - inf i) == pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (-inf + inf i) == -pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (-inf - inf i) == -pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0);
+
+
+  check_complex ("catan (inf - 10.0 i) == pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, -10.0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (-inf - 10.0 i) == -pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, -10.0)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (inf - 0 i) == pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (-inf - 0 i) == -pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (inf + 0.0 i) == pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (-inf + 0.0 i) == -pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (inf + 0.1 i) == pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (plus_infty, 0.1L)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (-inf + 0.1 i) == -pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_infty, 0.1L)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0);
+
+  check_complex ("catan (0.0 - inf i) == pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (-0 - inf i) == -pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (100.0 - inf i) == pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (100.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0);
+  check_complex ("catan (-100.0 - inf i) == -pi/2 - 0 i",  FUNC(catan) (BUILD_COMPLEX (-100.0, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0);
+
+  check_complex ("catan (0.0 + inf i) == pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (-0 + inf i) == -pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (0.5 + inf i) == pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (0.5, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0);
+  check_complex ("catan (-0.5 + inf i) == -pi/2 + 0 i",  FUNC(catan) (BUILD_COMPLEX (-0.5, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0);
+
+  check_complex ("catan (NaN + 0.0 i) == NaN + 0 i",  FUNC(catan) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0), 0, 0, 0);
+  check_complex ("catan (NaN - 0 i) == NaN - 0 i",  FUNC(catan) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0);
+
+  check_complex ("catan (NaN + inf i) == NaN + 0 i",  FUNC(catan) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, 0), 0, 0, 0);
+  check_complex ("catan (NaN - inf i) == NaN - 0 i",  FUNC(catan) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0);
+
+  check_complex ("catan (0.0 + NaN i) == NaN + NaN i",  FUNC(catan) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+  check_complex ("catan (-0 + NaN i) == NaN + NaN i",  FUNC(catan) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("catan (inf + NaN i) == pi/2 + 0 i plus sign of zero/inf not specified",  FUNC(catan) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("catan (-inf + NaN i) == -pi/2 + 0 i plus sign of zero/inf not specified",  FUNC(catan) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("catan (NaN + 10.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(catan) (BUILD_COMPLEX (nan_value, 10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("catan (NaN - 10.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(catan) (BUILD_COMPLEX (nan_value, -10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("catan (0.75 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(catan) (BUILD_COMPLEX (0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("catan (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(catan) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("catan (NaN + NaN i) == NaN + NaN i",  FUNC(catan) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("catan (0.7 + 1.2 i) == 1.0785743834118921877443707996386368 + 0.57705737765343067644394541889341712 i",  FUNC(catan) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.0785743834118921877443707996386368L, 0.57705737765343067644394541889341712L), DELTA301, 0, 0);
+
+  check_complex ("catan (-2 - 3 i) == -1.4099210495965755225306193844604208 - 0.22907268296853876629588180294200276 i",  FUNC(catan) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.4099210495965755225306193844604208L, -0.22907268296853876629588180294200276L), DELTA302, 0, 0);
+
+  print_complex_max_error ("catan", DELTAcatan, 0);
+}
+
+static void
+catanh_test (void)
+{
+  errno = 0;
+  FUNC(catanh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("catanh (0 + 0 i) == 0.0 + 0.0 i",  FUNC(catanh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("catanh (-0 + 0 i) == -0 + 0.0 i",  FUNC(catanh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("catanh (0 - 0 i) == 0.0 - 0 i",  FUNC(catanh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("catanh (-0 - 0 i) == -0 - 0 i",  FUNC(catanh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("catanh (inf + inf i) == 0.0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (inf - inf i) == 0.0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-inf + inf i) == -0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-inf - inf i) == -0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("catanh (-10.0 + inf i) == -0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-10.0 - inf i) == -0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-0 + inf i) == -0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-0 - inf i) == -0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (0 + inf i) == 0.0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (0 - inf i) == 0.0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (0.1 + inf i) == 0.0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (0.1 - inf i) == 0.0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("catanh (-inf + 0 i) == -0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-inf - 0 i) == -0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-inf + 100 i) == -0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (-inf - 100 i) == -0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("catanh (inf + 0 i) == 0.0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (inf - 0 i) == 0.0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (inf + 0.5 i) == 0.0 + pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0);
+  check_complex ("catanh (inf - 0.5 i) == 0.0 - pi/2 i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("catanh (0 + NaN i) == 0.0 + NaN i",  FUNC(catanh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0);
+  check_complex ("catanh (-0 + NaN i) == -0 + NaN i",  FUNC(catanh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0);
+
+  check_complex ("catanh (inf + NaN i) == 0.0 + NaN i",  FUNC(catanh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0);
+  check_complex ("catanh (-inf + NaN i) == -0 + NaN i",  FUNC(catanh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0);
+
+  check_complex ("catanh (NaN + 0 i) == NaN + NaN i",  FUNC(catanh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+  check_complex ("catanh (NaN - 0 i) == NaN + NaN i",  FUNC(catanh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("catanh (NaN + inf i) == 0.0 + pi/2 i plus sign of zero/inf not specified",  FUNC(catanh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("catanh (NaN - inf i) == 0.0 - pi/2 i plus sign of zero/inf not specified",  FUNC(catanh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("catanh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(catanh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("catanh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(catanh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("catanh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(catanh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("catanh (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed",  FUNC(catanh) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("catanh (NaN + NaN i) == NaN + NaN i",  FUNC(catanh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("catanh (0.7 + 1.2 i) == 0.2600749516525135959200648705635915 + 0.97024030779509898497385130162655963 i",  FUNC(catanh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.2600749516525135959200648705635915L, 0.97024030779509898497385130162655963L), DELTA340, 0, 0);
+  check_complex ("catanh (-2 - 3 i) == -0.14694666622552975204743278515471595 - 1.3389725222944935611241935759091443 i",  FUNC(catanh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.14694666622552975204743278515471595L, -1.3389725222944935611241935759091443L), DELTA341, 0, 0);
+
+  print_complex_max_error ("catanh", DELTAcatanh, 0);
+}
+#endif
+
+static void
+cbrt_test (void)
+{
+  errno = 0;
+  FUNC(cbrt) (8);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("cbrt (0.0) == 0.0",  FUNC(cbrt) (0.0), 0.0, 0, 0, 0);
+  check_float ("cbrt (-0) == -0",  FUNC(cbrt) (minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("cbrt (inf) == inf",  FUNC(cbrt) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("cbrt (-inf) == -inf",  FUNC(cbrt) (minus_infty), minus_infty, 0, 0, 0);
+  check_float ("cbrt (NaN) == NaN",  FUNC(cbrt) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("cbrt (-0.001) == -0.1",  FUNC(cbrt) (-0.001L), -0.1L, DELTA347, 0, 0);
+  check_float ("cbrt (8) == 2",  FUNC(cbrt) (8), 2, 0, 0, 0);
+  check_float ("cbrt (-27.0) == -3.0",  FUNC(cbrt) (-27.0), -3.0, DELTA349, 0, 0);
+  check_float ("cbrt (0.970299) == 0.99",  FUNC(cbrt) (0.970299L), 0.99L, DELTA350, 0, 0);
+  check_float ("cbrt (0.7) == 0.8879040017426007084",  FUNC(cbrt) (0.7L), 0.8879040017426007084L, DELTA351, 0, 0);
+
+  print_max_error ("cbrt", DELTAcbrt, 0);
+}
+
+#if 0 /* XXX scp XXX */
+static void
+ccos_test (void)
+{
+  errno = 0;
+  FUNC(ccos) (BUILD_COMPLEX (0, 0));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("ccos (0.0 + 0.0 i) == 1.0 - 0 i",  FUNC(ccos) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+  check_complex ("ccos (-0 + 0.0 i) == 1.0 + 0.0 i",  FUNC(ccos) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("ccos (0.0 - 0 i) == 1.0 + 0.0 i",  FUNC(ccos) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("ccos (-0 - 0 i) == 1.0 - 0 i",  FUNC(ccos) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+
+  check_complex ("ccos (inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccos (inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccos (-inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccos (-inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccos (0.0 + inf i) == inf - 0 i",  FUNC(ccos) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("ccos (0.0 - inf i) == inf + 0.0 i",  FUNC(ccos) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("ccos (-0 + inf i) == inf + 0.0 i",  FUNC(ccos) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("ccos (-0 - inf i) == inf - 0 i",  FUNC(ccos) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("ccos (inf + inf i) == inf + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (-inf + inf i) == inf + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (inf - inf i) == inf + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (-inf - inf i) == inf + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ccos (4.625 + inf i) == -inf + inf i",  FUNC(ccos) (BUILD_COMPLEX (4.625, plus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("ccos (4.625 - inf i) == -inf - inf i",  FUNC(ccos) (BUILD_COMPLEX (4.625, minus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+  check_complex ("ccos (-4.625 + inf i) == -inf - inf i",  FUNC(ccos) (BUILD_COMPLEX (-4.625, plus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+  check_complex ("ccos (-4.625 - inf i) == -inf + inf i",  FUNC(ccos) (BUILD_COMPLEX (-4.625, minus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+
+  check_complex ("ccos (inf + 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (inf - 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (-inf + 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccos (-inf - 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ccos (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccos (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccos (NaN + inf i) == inf + NaN i",  FUNC(ccos) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("ccos (NaN - inf i) == inf + NaN i",  FUNC(ccos) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("ccos (NaN + 9.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (nan_value, 9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccos (NaN - 9.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (nan_value, -9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccos (0.0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccos (-0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccos) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccos (10.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccos (-10.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (-10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccos (inf + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccos (-inf + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccos) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccos (NaN + NaN i) == NaN + NaN i",  FUNC(ccos) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("ccos (0.7 + 1.2 i) == 1.3848657645312111080 - 0.97242170335830028619 i",  FUNC(ccos) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.3848657645312111080L, -0.97242170335830028619L), DELTA389, 0, 0);
+
+  check_complex ("ccos (-2 - 3 i) == -4.1896256909688072301 - 9.1092278937553365979 i",  FUNC(ccos) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-4.1896256909688072301L, -9.1092278937553365979L), DELTA390, 0, 0);
+
+  print_complex_max_error ("ccos", DELTAccos, 0);
+}
+
+
+static void
+ccosh_test (void)
+{
+  errno = 0;
+  FUNC(ccosh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("ccosh (0.0 + 0.0 i) == 1.0 + 0.0 i",  FUNC(ccosh) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("ccosh (-0 + 0.0 i) == 1.0 - 0 i",  FUNC(ccosh) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+  check_complex ("ccosh (0.0 - 0 i) == 1.0 - 0 i",  FUNC(ccosh) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+  check_complex ("ccosh (-0 - 0 i) == 1.0 + 0.0 i",  FUNC(ccosh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+
+  check_complex ("ccosh (0.0 + inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccosh (-0 + inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccosh (0.0 - inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccosh (-0 - inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccosh (inf + 0.0 i) == inf + 0.0 i",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("ccosh (-inf + 0.0 i) == inf - 0 i",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("ccosh (inf - 0 i) == inf - 0 i",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("ccosh (-inf - 0 i) == inf + 0.0 i",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+
+  check_complex ("ccosh (inf + inf i) == inf + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (-inf + inf i) == inf + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (inf - inf i) == inf + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (-inf - inf i) == inf + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ccosh (inf + 4.625 i) == -inf - inf i",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, 4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+  check_complex ("ccosh (-inf + 4.625 i) == -inf + inf i",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, 4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("ccosh (inf - 4.625 i) == -inf + inf i",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, -4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("ccosh (-inf - 4.625 i) == -inf - inf i",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, -4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+
+  check_complex ("ccosh (6.75 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (-6.75 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (-6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (6.75 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ccosh (-6.75 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ccosh) (BUILD_COMPLEX (-6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ccosh (0.0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccosh (-0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccosh (inf + NaN i) == inf + NaN i",  FUNC(ccosh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("ccosh (-inf + NaN i) == inf + NaN i",  FUNC(ccosh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("ccosh (9.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccosh (-9.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (-9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccosh (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ccosh (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ccosh (NaN + 10.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, 10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccosh (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccosh (NaN + inf i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ccosh (NaN - inf i) == NaN + NaN i plus invalid exception allowed",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ccosh (NaN + NaN i) == NaN + NaN i",  FUNC(ccosh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("ccosh (0.7 + 1.2 i) == 0.4548202223691477654 + 0.7070296600921537682 i",  FUNC(ccosh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.4548202223691477654L, 0.7070296600921537682L), DELTA428, 0, 0);
+
+  check_complex ("ccosh (-2 - 3 i) == -3.7245455049153225654 + 0.5118225699873846088 i",  FUNC(ccosh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-3.7245455049153225654L, 0.5118225699873846088L), DELTA429, 0, 0);
+
+  print_complex_max_error ("ccosh", DELTAccosh, 0);
+}
+#endif
+
+
+static void
+ceil_test (void)
+{
+  init_max_error ();
+
+  check_float ("ceil (0.0) == 0.0",  FUNC(ceil) (0.0), 0.0, 0, 0, 0);
+  check_float ("ceil (-0) == -0",  FUNC(ceil) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("ceil (inf) == inf",  FUNC(ceil) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("ceil (-inf) == -inf",  FUNC(ceil) (minus_infty), minus_infty, 0, 0, 0);
+  check_float ("ceil (NaN) == NaN",  FUNC(ceil) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("ceil (pi) == 4.0",  FUNC(ceil) (M_PIl), 4.0, 0, 0, 0);
+  check_float ("ceil (-pi) == -3.0",  FUNC(ceil) (-M_PIl), -3.0, 0, 0, 0);
+
+  print_max_error ("ceil", 0, 0);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+cexp_test (void)
+{
+  errno = 0;
+  FUNC(cexp) (BUILD_COMPLEX (0, 0));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("cexp (+0 + +0 i) == 1 + 0.0 i",  FUNC(cexp) (BUILD_COMPLEX (plus_zero, plus_zero)), BUILD_COMPLEX (1, 0.0), 0, 0, 0);
+  check_complex ("cexp (-0 + +0 i) == 1 + 0.0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_zero, plus_zero)), BUILD_COMPLEX (1, 0.0), 0, 0, 0);
+  check_complex ("cexp (+0 - 0 i) == 1 - 0 i",  FUNC(cexp) (BUILD_COMPLEX (plus_zero, minus_zero)), BUILD_COMPLEX (1, minus_zero), 0, 0, 0);
+  check_complex ("cexp (-0 - 0 i) == 1 - 0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1, minus_zero), 0, 0, 0);
+
+  check_complex ("cexp (inf + +0 i) == inf + 0.0 i",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, plus_zero)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("cexp (inf - 0 i) == inf - 0 i",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("cexp (-inf + +0 i) == 0.0 + 0.0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, plus_zero)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("cexp (-inf - 0 i) == 0.0 - 0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+
+  check_complex ("cexp (0.0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("cexp (-0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("cexp (0.0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("cexp (-0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("cexp (100.0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (100.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("cexp (-100.0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (-100.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("cexp (100.0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (100.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("cexp (-100.0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(cexp) (BUILD_COMPLEX (-100.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("cexp (-inf + 2.0 i) == -0 + 0.0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, 2.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("cexp (-inf + 4.0 i) == -0 - 0 i",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, 4.0)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+  check_complex ("cexp (inf + 2.0 i) == -inf + inf i",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, 2.0)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("cexp (inf + 4.0 i) == -inf - inf i",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, 4.0)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+
+  check_complex ("cexp (inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("cexp (inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("cexp (-inf + inf i) == 0.0 + 0.0 i plus sign of zero/inf not specified",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (0.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("cexp (-inf - inf i) == 0.0 - 0 i plus sign of zero/inf not specified",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("cexp (-inf + NaN i) == 0 + 0 i plus sign of zero/inf not specified",  FUNC(cexp) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (0, 0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("cexp (inf + NaN i) == inf + NaN i",  FUNC(cexp) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("cexp (NaN + 0.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cexp) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cexp (NaN + 1.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(cexp) (BUILD_COMPLEX (nan_value, 1.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("cexp (NaN + inf i) == NaN + NaN i plus invalid exception allowed",  FUNC(cexp) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cexp (0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cexp) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cexp (1 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(cexp) (BUILD_COMPLEX (1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("cexp (NaN + NaN i) == NaN + NaN i",  FUNC(cexp) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("cexp (0.7 + 1.2 i) == 0.72969890915032360123451688642930727 + 1.8768962328348102821139467908203072 i",  FUNC(cexp) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.72969890915032360123451688642930727L, 1.8768962328348102821139467908203072L), DELTA469, 0, 0);
+  check_complex ("cexp (-2.0 - 3.0 i) == -0.13398091492954261346140525546115575 - 0.019098516261135196432576240858800925 i",  FUNC(cexp) (BUILD_COMPLEX (-2.0, -3.0)), BUILD_COMPLEX (-0.13398091492954261346140525546115575L, -0.019098516261135196432576240858800925L), DELTA470, 0, 0);
+
+  print_complex_max_error ("cexp", DELTAcexp, 0);
+}
+
+static void
+cimag_test (void)
+{
+  init_max_error ();
+  check_float ("cimag (1.0 + 0.0 i) == 0.0",  FUNC(cimag) (BUILD_COMPLEX (1.0, 0.0)), 0.0, 0, 0, 0);
+  check_float ("cimag (1.0 - 0 i) == -0",  FUNC(cimag) (BUILD_COMPLEX (1.0, minus_zero)), minus_zero, 0, 0, 0);
+  check_float ("cimag (1.0 + NaN i) == NaN",  FUNC(cimag) (BUILD_COMPLEX (1.0, nan_value)), nan_value, 0, 0, 0);
+  check_float ("cimag (NaN + NaN i) == NaN",  FUNC(cimag) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0);
+  check_float ("cimag (1.0 + inf i) == inf",  FUNC(cimag) (BUILD_COMPLEX (1.0, plus_infty)), plus_infty, 0, 0, 0);
+  check_float ("cimag (1.0 - inf i) == -inf",  FUNC(cimag) (BUILD_COMPLEX (1.0, minus_infty)), minus_infty, 0, 0, 0);
+  check_float ("cimag (2.0 + 3.0 i) == 3.0",  FUNC(cimag) (BUILD_COMPLEX (2.0, 3.0)), 3.0, 0, 0, 0);
+
+  print_max_error ("cimag", 0, 0);
+}
+
+static void
+clog_test (void)
+{
+  errno = 0;
+  FUNC(clog) (BUILD_COMPLEX (-2, -3));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("clog (-0 + 0 i) == -inf + pi i plus division by zero exception",  FUNC(clog) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_infty, M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_complex ("clog (-0 - 0 i) == -inf - pi i plus division by zero exception",  FUNC(clog) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_infty, -M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_complex ("clog (0 + 0 i) == -inf + 0.0 i plus division by zero exception",  FUNC(clog) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_complex ("clog (0 - 0 i) == -inf - 0 i plus division by zero exception",  FUNC(clog) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_complex ("clog (-inf + inf i) == inf + 3/4 pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34l), 0, 0, 0);
+  check_complex ("clog (-inf - inf i) == inf - 3/4 pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_34l), 0, 0, 0);
+
+  check_complex ("clog (inf + inf i) == inf + pi/4 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0);
+  check_complex ("clog (inf - inf i) == inf - pi/4 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0);
+
+  check_complex ("clog (0 + inf i) == inf + pi/2 i",  FUNC(clog) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("clog (3 + inf i) == inf + pi/2 i",  FUNC(clog) (BUILD_COMPLEX (3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("clog (-0 + inf i) == inf + pi/2 i",  FUNC(clog) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("clog (-3 + inf i) == inf + pi/2 i",  FUNC(clog) (BUILD_COMPLEX (-3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0);
+  check_complex ("clog (0 - inf i) == inf - pi/2 i",  FUNC(clog) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("clog (3 - inf i) == inf - pi/2 i",  FUNC(clog) (BUILD_COMPLEX (3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("clog (-0 - inf i) == inf - pi/2 i",  FUNC(clog) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+  check_complex ("clog (-3 - inf i) == inf - pi/2 i",  FUNC(clog) (BUILD_COMPLEX (-3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0);
+
+  check_complex ("clog (-inf + 0 i) == inf + pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0);
+  check_complex ("clog (-inf + 1 i) == inf + pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0);
+  check_complex ("clog (-inf - 0 i) == inf - pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0);
+  check_complex ("clog (-inf - 1 i) == inf - pi i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0);
+
+  check_complex ("clog (inf + 0 i) == inf + 0.0 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("clog (inf + 1 i) == inf + 0.0 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("clog (inf - 0 i) == inf - 0 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("clog (inf - 1 i) == inf - 0 i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("clog (inf + NaN i) == inf + NaN i",  FUNC(clog) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("clog (-inf + NaN i) == inf + NaN i",  FUNC(clog) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("clog (NaN + inf i) == inf + NaN i",  FUNC(clog) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("clog (NaN - inf i) == inf + NaN i",  FUNC(clog) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("clog (0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (3 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (-0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (-3 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (-3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("clog (NaN + 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (NaN + 5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (NaN - 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog (NaN - 5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog) (BUILD_COMPLEX (nan_value, -5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("clog (NaN + NaN i) == NaN + NaN i",  FUNC(clog) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+  check_complex ("clog (-2 - 3 i) == 1.2824746787307683680267437207826593 - 2.1587989303424641704769327722648368 i",  FUNC(clog) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (1.2824746787307683680267437207826593L, -2.1587989303424641704769327722648368L), DELTA515, 0, 0);
+
+  print_complex_max_error ("clog", DELTAclog, 0);
+}
+
+
+static void
+clog10_test (void)
+{
+  errno = 0;
+  FUNC(clog10) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("clog10 (-0 + 0 i) == -inf + pi i plus division by zero exception",  FUNC(clog10) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_infty, M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_complex ("clog10 (-0 - 0 i) == -inf - pi i plus division by zero exception",  FUNC(clog10) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_infty, -M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_complex ("clog10 (0 + 0 i) == -inf + 0.0 i plus division by zero exception",  FUNC(clog10) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_complex ("clog10 (0 - 0 i) == -inf - 0 i plus division by zero exception",  FUNC(clog10) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_complex ("clog10 (-inf + inf i) == inf + 3/4 pi*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34_LOG10El), DELTA520, 0, 0);
+
+  check_complex ("clog10 (inf + inf i) == inf + pi/4*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI4_LOG10El), DELTA521, 0, 0);
+  check_complex ("clog10 (inf - inf i) == inf - pi/4*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI4_LOG10El), DELTA522, 0, 0);
+
+  check_complex ("clog10 (0 + inf i) == inf + pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA523, 0, 0);
+  check_complex ("clog10 (3 + inf i) == inf + pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA524, 0, 0);
+  check_complex ("clog10 (-0 + inf i) == inf + pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA525, 0, 0);
+  check_complex ("clog10 (-3 + inf i) == inf + pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (-3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA526, 0, 0);
+  check_complex ("clog10 (0 - inf i) == inf - pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA527, 0, 0);
+  check_complex ("clog10 (3 - inf i) == inf - pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA528, 0, 0);
+  check_complex ("clog10 (-0 - inf i) == inf - pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA529, 0, 0);
+  check_complex ("clog10 (-3 - inf i) == inf - pi/2*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (-3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA530, 0, 0);
+
+  check_complex ("clog10 (-inf + 0 i) == inf + pi*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PI_LOG10El), DELTA531, 0, 0);
+  check_complex ("clog10 (-inf + 1 i) == inf + pi*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (plus_infty, M_PI_LOG10El), DELTA532, 0, 0);
+  check_complex ("clog10 (-inf - 0 i) == inf - pi*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PI_LOG10El), DELTA533, 0, 0);
+  check_complex ("clog10 (-inf - 1 i) == inf - pi*log10(e) i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (plus_infty, -M_PI_LOG10El), DELTA534, 0, 0);
+
+  check_complex ("clog10 (inf + 0 i) == inf + 0.0 i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("clog10 (inf + 1 i) == inf + 0.0 i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("clog10 (inf - 0 i) == inf - 0 i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("clog10 (inf - 1 i) == inf - 0 i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("clog10 (inf + NaN i) == inf + NaN i",  FUNC(clog10) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("clog10 (-inf + NaN i) == inf + NaN i",  FUNC(clog10) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("clog10 (NaN + inf i) == inf + NaN i",  FUNC(clog10) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+  check_complex ("clog10 (NaN - inf i) == inf + NaN i",  FUNC(clog10) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("clog10 (0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (3 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (-0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (-3 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (-3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("clog10 (NaN + 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (NaN + 5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (NaN - 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("clog10 (NaN - 5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(clog10) (BUILD_COMPLEX (nan_value, -5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("clog10 (NaN + NaN i) == NaN + NaN i",  FUNC(clog10) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("clog10 (0.7 + 1.2 i) == 0.1427786545038868803 + 0.4528483579352493248 i",  FUNC(clog10) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.1427786545038868803L, 0.4528483579352493248L), DELTA552, 0, 0);
+  check_complex ("clog10 (-2 - 3 i) == 0.5569716761534183846 - 0.9375544629863747085 i",  FUNC(clog10) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.5569716761534183846L, -0.9375544629863747085L), DELTA553, 0, 0);
+
+  print_complex_max_error ("clog10", DELTAclog10, 0);
+}
+
+static void
+conj_test (void)
+{
+  init_max_error ();
+  check_complex ("conj (0.0 + 0.0 i) == 0.0 - 0 i",  FUNC(conj) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("conj (0.0 - 0 i) == 0.0 + 0.0 i",  FUNC(conj) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("conj (NaN + NaN i) == NaN + NaN i",  FUNC(conj) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+  check_complex ("conj (inf - inf i) == inf + inf i",  FUNC(conj) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("conj (inf + inf i) == inf - inf i",  FUNC(conj) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("conj (1.0 + 2.0 i) == 1.0 - 2.0 i",  FUNC(conj) (BUILD_COMPLEX (1.0, 2.0)), BUILD_COMPLEX (1.0, -2.0), 0, 0, 0);
+  check_complex ("conj (3.0 - 4.0 i) == 3.0 + 4.0 i",  FUNC(conj) (BUILD_COMPLEX (3.0, -4.0)), BUILD_COMPLEX (3.0, 4.0), 0, 0, 0);
+
+  print_complex_max_error ("conj", 0, 0);
+}
+#endif
+
+
+static void
+copysign_test (void)
+{
+  init_max_error ();
+
+  check_float ("copysign (0, 4) == 0",  FUNC(copysign) (0, 4), 0, 0, 0, 0);
+  check_float ("copysign (0, -4) == -0",  FUNC(copysign) (0, -4), minus_zero, 0, 0, 0);
+  check_float ("copysign (-0, 4) == 0",  FUNC(copysign) (minus_zero, 4), 0, 0, 0, 0);
+  check_float ("copysign (-0, -4) == -0",  FUNC(copysign) (minus_zero, -4), minus_zero, 0, 0, 0);
+
+  check_float ("copysign (inf, 0) == inf",  FUNC(copysign) (plus_infty, 0), plus_infty, 0, 0, 0);
+  check_float ("copysign (inf, -0) == -inf",  FUNC(copysign) (plus_infty, minus_zero), minus_infty, 0, 0, 0);
+  check_float ("copysign (-inf, 0) == inf",  FUNC(copysign) (minus_infty, 0), plus_infty, 0, 0, 0);
+  check_float ("copysign (-inf, -0) == -inf",  FUNC(copysign) (minus_infty, minus_zero), minus_infty, 0, 0, 0);
+
+  check_float ("copysign (0, inf) == 0",  FUNC(copysign) (0, plus_infty), 0, 0, 0, 0);
+  check_float ("copysign (0, -0) == -0",  FUNC(copysign) (0, minus_zero), minus_zero, 0, 0, 0);
+  check_float ("copysign (-0, inf) == 0",  FUNC(copysign) (minus_zero, plus_infty), 0, 0, 0, 0);
+  check_float ("copysign (-0, -0) == -0",  FUNC(copysign) (minus_zero, minus_zero), minus_zero, 0, 0, 0);
+
+  /* XXX More correctly we would have to check the sign of the NaN.  */
+  check_float ("copysign (NaN, 0) == NaN",  FUNC(copysign) (nan_value, 0), nan_value, 0, 0, 0);
+  check_float ("copysign (NaN, -0) == NaN",  FUNC(copysign) (nan_value, minus_zero), nan_value, 0, 0, 0);
+  check_float ("copysign (-NaN, 0) == NaN",  FUNC(copysign) (-nan_value, 0), nan_value, 0, 0, 0);
+  check_float ("copysign (-NaN, -0) == NaN",  FUNC(copysign) (-nan_value, minus_zero), nan_value, 0, 0, 0);
+
+  print_max_error ("copysign", 0, 0);
+}
+
+static void
+cos_test (void)
+{
+  errno = 0;
+  FUNC(cos) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("cos (0) == 1",  FUNC(cos) (0), 1, 0, 0, 0);
+  check_float ("cos (-0) == 1",  FUNC(cos) (minus_zero), 1, 0, 0, 0);
+  check_float ("cos (inf) == NaN plus invalid exception",  FUNC(cos) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("cos (-inf) == NaN plus invalid exception",  FUNC(cos) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("cos (NaN) == NaN",  FUNC(cos) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("cos (M_PI_6l * 2.0) == 0.5",  FUNC(cos) (M_PI_6l * 2.0), 0.5, DELTA582, 0, 0);
+  check_float ("cos (M_PI_6l * 4.0) == -0.5",  FUNC(cos) (M_PI_6l * 4.0), -0.5, DELTA583, 0, 0);
+  check_float ("cos (pi/2) == 0",  FUNC(cos) (M_PI_2l), 0, DELTA584, 0, 0);
+
+  check_float ("cos (0.7) == 0.76484218728448842625585999019186495",  FUNC(cos) (0.7L), 0.76484218728448842625585999019186495L, DELTA585, 0, 0);
+
+  print_max_error ("cos", DELTAcos, 0);
+}
+
+static void
+cosh_test (void)
+{
+  errno = 0;
+  FUNC(cosh) (0.7L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+  check_float ("cosh (0) == 1",  FUNC(cosh) (0), 1, 0, 0, 0);
+  check_float ("cosh (-0) == 1",  FUNC(cosh) (minus_zero), 1, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  check_float ("cosh (inf) == inf",  FUNC(cosh) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("cosh (-inf) == inf",  FUNC(cosh) (minus_infty), plus_infty, 0, 0, 0);
+#endif
+  check_float ("cosh (NaN) == NaN",  FUNC(cosh) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("cosh (0.7) == 1.255169005630943018",  FUNC(cosh) (0.7L), 1.255169005630943018L, DELTA591, 0, 0);
+  print_max_error ("cosh", DELTAcosh, 0);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+cpow_test (void)
+{
+  errno = 0;
+  FUNC(cpow) (BUILD_COMPLEX (1, 0), BUILD_COMPLEX (0, 0));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("cpow (1 + 0 i, 0 + 0 i) == 1.0 + 0.0 i",  FUNC(cpow) (BUILD_COMPLEX (1, 0), BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("cpow (2 + 0 i, 10 + 0 i) == 1024.0 + 0.0 i",  FUNC(cpow) (BUILD_COMPLEX (2, 0), BUILD_COMPLEX (10, 0)), BUILD_COMPLEX (1024.0, 0.0), 0, 0, 0);
+
+  check_complex ("cpow (e + 0 i, 0 + 2 * M_PIl i) == 1.0 + 0.0 i",  FUNC(cpow) (BUILD_COMPLEX (M_El, 0), BUILD_COMPLEX (0, 2 * M_PIl)), BUILD_COMPLEX (1.0, 0.0), DELTA594, 0, 0);
+  check_complex ("cpow (2 + 3 i, 4 + 0 i) == -119.0 - 120.0 i",  FUNC(cpow) (BUILD_COMPLEX (2, 3), BUILD_COMPLEX (4, 0)), BUILD_COMPLEX (-119.0, -120.0), DELTA595, 0, 0);
+
+  check_complex ("cpow (NaN + NaN i, NaN + NaN i) == NaN + NaN i",  FUNC(cpow) (BUILD_COMPLEX (nan_value, nan_value), BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  print_complex_max_error ("cpow", DELTAcpow, 0);
+}
+
+static void
+cproj_test (void)
+{
+  init_max_error ();
+  check_complex ("cproj (0.0 + 0.0 i) == 0.0 + 0.0 i",  FUNC(cproj) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("cproj (-0 - 0 i) == -0 - 0 i",  FUNC(cproj) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+  check_complex ("cproj (0.0 - 0 i) == 0.0 - 0 i",  FUNC(cproj) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("cproj (-0 + 0.0 i) == -0 + 0.0 i",  FUNC(cproj) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+
+  check_complex ("cproj (NaN + NaN i) == NaN + NaN i",  FUNC(cproj) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("cproj (inf + inf i) == inf + 0.0 i",  FUNC(cproj) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("cproj (inf - inf i) == inf - 0 i",  FUNC(cproj) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("cproj (-inf + inf i) == inf + 0.0 i",  FUNC(cproj) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("cproj (-inf - inf i) == inf - 0 i",  FUNC(cproj) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("cproj (1.0 + 0.0 i) == 1.0 + 0.0 i",  FUNC(cproj) (BUILD_COMPLEX (1.0, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("cproj (2.0 + 3.0 i) == 0.2857142857142857142857142857142857 + 0.42857142857142857142857142857142855 i",  FUNC(cproj) (BUILD_COMPLEX (2.0, 3.0)), BUILD_COMPLEX (0.2857142857142857142857142857142857L, 0.42857142857142857142857142857142855L), 0, 0, 0);
+
+  print_complex_max_error ("cproj", 0, 0);
+}
+
+static void
+creal_test (void)
+{
+  init_max_error ();
+  check_float ("creal (0.0 + 1.0 i) == 0.0",  FUNC(creal) (BUILD_COMPLEX (0.0, 1.0)), 0.0, 0, 0, 0);
+  check_float ("creal (-0 + 1.0 i) == -0",  FUNC(creal) (BUILD_COMPLEX (minus_zero, 1.0)), minus_zero, 0, 0, 0);
+  check_float ("creal (NaN + 1.0 i) == NaN",  FUNC(creal) (BUILD_COMPLEX (nan_value, 1.0)), nan_value, 0, 0, 0);
+  check_float ("creal (NaN + NaN i) == NaN",  FUNC(creal) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0);
+  check_float ("creal (inf + 1.0 i) == inf",  FUNC(creal) (BUILD_COMPLEX (plus_infty, 1.0)), plus_infty, 0, 0, 0);
+  check_float ("creal (-inf + 1.0 i) == -inf",  FUNC(creal) (BUILD_COMPLEX (minus_infty, 1.0)), minus_infty, 0, 0, 0);
+  check_float ("creal (2.0 + 3.0 i) == 2.0",  FUNC(creal) (BUILD_COMPLEX (2.0, 3.0)), 2.0, 0, 0, 0);
+
+  print_max_error ("creal", 0, 0);
+}
+
+static void
+csin_test (void)
+{
+  errno = 0;
+  FUNC(csin) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("csin (0.0 + 0.0 i) == 0.0 + 0.0 i",  FUNC(csin) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("csin (-0 + 0.0 i) == -0 + 0.0 i",  FUNC(csin) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("csin (0.0 - 0 i) == 0 - 0 i",  FUNC(csin) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0);
+  check_complex ("csin (-0 - 0 i) == -0 - 0 i",  FUNC(csin) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("csin (0.0 + inf i) == 0.0 + inf i",  FUNC(csin) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("csin (-0 + inf i) == -0 + inf i",  FUNC(csin) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0);
+  check_complex ("csin (0.0 - inf i) == 0.0 - inf i",  FUNC(csin) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+  check_complex ("csin (-0 - inf i) == -0 - inf i",  FUNC(csin) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0);
+
+  check_complex ("csin (inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (-inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (-inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csin (inf + inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (-inf + inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (inf - inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (-inf - inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csin (inf + 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(csin) (BUILD_COMPLEX (plus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csin (inf - 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(csin) (BUILD_COMPLEX (plus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csin (-inf + 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(csin) (BUILD_COMPLEX (minus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csin (-inf - 6.75 i) == NaN + NaN i plus invalid exception",  FUNC(csin) (BUILD_COMPLEX (minus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("csin (4.625 + inf i) == -inf - inf i",  FUNC(csin) (BUILD_COMPLEX (4.625, plus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csin (4.625 - inf i) == -inf + inf i",  FUNC(csin) (BUILD_COMPLEX (4.625, minus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csin (-4.625 + inf i) == inf - inf i",  FUNC(csin) (BUILD_COMPLEX (-4.625, plus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csin (-4.625 - inf i) == inf + inf i",  FUNC(csin) (BUILD_COMPLEX (-4.625, minus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+
+  check_complex ("csin (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csin (NaN + inf i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("csin (NaN - inf i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(csin) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csin (NaN + 9.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (nan_value, 9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csin (NaN - 9.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (nan_value, -9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csin (0.0 + NaN i) == 0.0 + NaN i",  FUNC(csin) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0);
+  check_complex ("csin (-0 + NaN i) == -0 + NaN i",  FUNC(csin) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0);
+
+  check_complex ("csin (10.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csin (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csin (inf + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csin (-inf + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csin) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csin (NaN + NaN i) == NaN + NaN i",  FUNC(csin) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("csin (0.7 + 1.2 i) == 1.1664563419657581376 + 1.1544997246948547371 i",  FUNC(csin) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.1664563419657581376L, 1.1544997246948547371L), DELTA652, 0, 0);
+
+  check_complex ("csin (-2 - 3 i) == -9.1544991469114295734 + 4.1689069599665643507 i",  FUNC(csin) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-9.1544991469114295734L, 4.1689069599665643507L), 0, 0, 0);
+
+  print_complex_max_error ("csin", DELTAcsin, 0);
+}
+
+
+static void
+csinh_test (void)
+{
+  errno = 0;
+  FUNC(csinh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("csinh (0.0 + 0.0 i) == 0.0 + 0.0 i",  FUNC(csinh) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("csinh (-0 + 0.0 i) == -0 + 0.0 i",  FUNC(csinh) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("csinh (0.0 - 0 i) == 0.0 - 0 i",  FUNC(csinh) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("csinh (-0 - 0 i) == -0 - 0 i",  FUNC(csinh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("csinh (0.0 + inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-0 + inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (0.0 - inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-0 - inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csinh (inf + 0.0 i) == inf + 0.0 i",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("csinh (-inf + 0.0 i) == -inf + 0.0 i",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0);
+  check_complex ("csinh (inf - 0 i) == inf - 0 i",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("csinh (-inf - 0 i) == -inf - 0 i",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("csinh (inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csinh (inf + 4.625 i) == -inf - inf i",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, 4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csinh (-inf + 4.625 i) == inf - inf i",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, 4.625)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csinh (inf - 4.625 i) == -inf + inf i",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, -4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csinh (-inf - 4.625 i) == inf + inf i",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, -4.625)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+
+  check_complex ("csinh (6.75 + inf i) == NaN + NaN i plus invalid exception",  FUNC(csinh) (BUILD_COMPLEX (6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csinh (-6.75 + inf i) == NaN + NaN i plus invalid exception",  FUNC(csinh) (BUILD_COMPLEX (-6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csinh (6.75 - inf i) == NaN + NaN i plus invalid exception",  FUNC(csinh) (BUILD_COMPLEX (6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("csinh (-6.75 - inf i) == NaN + NaN i plus invalid exception",  FUNC(csinh) (BUILD_COMPLEX (-6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("csinh (0.0 + NaN i) == 0.0 + NaN i plus sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-0 + NaN i) == 0.0 + NaN i plus sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csinh (inf + NaN i) == inf + NaN i plus sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("csinh (-inf + NaN i) == inf + NaN i plus sign of zero/inf not specified",  FUNC(csinh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csinh (9.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csinh (-9.0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (-9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csinh (NaN + 0.0 i) == NaN + 0.0 i",  FUNC(csinh) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0);
+  check_complex ("csinh (NaN - 0 i) == NaN - 0 i",  FUNC(csinh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0);
+
+  check_complex ("csinh (NaN + 10.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (nan_value, 10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csinh (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csinh (NaN + inf i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csinh (NaN - inf i) == NaN + NaN i plus invalid exception allowed",  FUNC(csinh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csinh (NaN + NaN i) == NaN + NaN i",  FUNC(csinh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("csinh (0.7 + 1.2 i) == 0.27487868678117583582 + 1.1698665727426565139 i",  FUNC(csinh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.27487868678117583582L, 1.1698665727426565139L), DELTA691, 0, 0);
+  check_complex ("csinh (-2 - 3 i) == 3.5905645899857799520 - 0.5309210862485198052 i",  FUNC(csinh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (3.5905645899857799520L, -0.5309210862485198052L), DELTA692, 0, 0);
+
+  print_complex_max_error ("csinh", DELTAcsinh, 0);
+}
+
+static void
+csqrt_test (void)
+{
+  errno = 0;
+  FUNC(csqrt) (BUILD_COMPLEX (-1, 0));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("csqrt (0 + 0 i) == 0.0 + 0.0 i",  FUNC(csqrt) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("csqrt (0 - 0 i) == 0 - 0 i",  FUNC(csqrt) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0);
+  check_complex ("csqrt (-0 + 0 i) == 0.0 + 0.0 i",  FUNC(csqrt) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("csqrt (-0 - 0 i) == 0.0 - 0 i",  FUNC(csqrt) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+
+  check_complex ("csqrt (-inf + 0 i) == 0.0 + inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (-inf + 6 i) == 0.0 + inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, 6)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (-inf - 0 i) == 0.0 - inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (-inf - 6 i) == 0.0 - inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, -6)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0);
+
+  check_complex ("csqrt (inf + 0 i) == inf + 0.0 i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("csqrt (inf + 6 i) == inf + 0.0 i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, 6)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0);
+  check_complex ("csqrt (inf - 0 i) == inf - 0 i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+  check_complex ("csqrt (inf - 6 i) == inf - 0 i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, -6)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0);
+
+  check_complex ("csqrt (0 + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (4 + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (4, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (inf + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (-0 + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (-4 + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (-4, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (-inf + inf i) == inf + inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0);
+  check_complex ("csqrt (0 - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (4 - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (4, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (inf - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (-0 - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (-4 - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (-4, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+  check_complex ("csqrt (-inf - inf i) == inf - inf i",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0);
+
+  check_complex ("csqrt (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified",  FUNC(csqrt) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("csqrt (inf + NaN i) == inf + NaN i",  FUNC(csqrt) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0);
+
+  check_complex ("csqrt (0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (1 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (-0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (-1 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (-1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csqrt (NaN + 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (NaN + 8 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (nan_value, 8)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (NaN - 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("csqrt (NaN - 8 i) == NaN + NaN i plus invalid exception allowed",  FUNC(csqrt) (BUILD_COMPLEX (nan_value, -8)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("csqrt (NaN + NaN i) == NaN + NaN i",  FUNC(csqrt) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("csqrt (16.0 - 30.0 i) == 5.0 - 3.0 i",  FUNC(csqrt) (BUILD_COMPLEX (16.0, -30.0)), BUILD_COMPLEX (5.0, -3.0), 0, 0, 0);
+  check_complex ("csqrt (-1 + 0 i) == 0.0 + 1.0 i",  FUNC(csqrt) (BUILD_COMPLEX (-1, 0)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0);
+  check_complex ("csqrt (0 + 2 i) == 1.0 + 1.0 i",  FUNC(csqrt) (BUILD_COMPLEX (0, 2)), BUILD_COMPLEX (1.0, 1.0), 0, 0, 0);
+  check_complex ("csqrt (119 + 120 i) == 12.0 + 5.0 i",  FUNC(csqrt) (BUILD_COMPLEX (119, 120)), BUILD_COMPLEX (12.0, 5.0), 0, 0, 0);
+  check_complex ("csqrt (0.7 + 1.2 i) == 1.022067610030026450706487883081139 + 0.58704531296356521154977678719838035 i",  FUNC(csqrt) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.022067610030026450706487883081139L, 0.58704531296356521154977678719838035L), DELTA732, 0, 0);
+  check_complex ("csqrt (-2 - 3 i) == 0.89597747612983812471573375529004348 - 1.6741492280355400404480393008490519 i",  FUNC(csqrt) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.89597747612983812471573375529004348L, -1.6741492280355400404480393008490519L), DELTA733, 0, 0);
+  check_complex ("csqrt (-2 + 3 i) == 0.89597747612983812471573375529004348 + 1.6741492280355400404480393008490519 i",  FUNC(csqrt) (BUILD_COMPLEX (-2, 3)), BUILD_COMPLEX (0.89597747612983812471573375529004348L, 1.6741492280355400404480393008490519L), DELTA734, 0, 0);
+
+  print_complex_max_error ("csqrt", DELTAcsqrt, 0);
+}
+
+static void
+ctan_test (void)
+{
+  errno = 0;
+  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("ctan (0 + 0 i) == 0.0 + 0.0 i",  FUNC(ctan) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("ctan (0 - 0 i) == 0.0 - 0 i",  FUNC(ctan) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("ctan (-0 + 0 i) == -0 + 0.0 i",  FUNC(ctan) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("ctan (-0 - 0 i) == -0 - 0 i",  FUNC(ctan) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("ctan (0 + inf i) == 0.0 + 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0);
+  check_complex ("ctan (1 + inf i) == 0.0 + 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (1, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0);
+  check_complex ("ctan (-0 + inf i) == -0 + 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, 1.0), 0, 0, 0);
+  check_complex ("ctan (-1 + inf i) == -0 + 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (-1, plus_infty)), BUILD_COMPLEX (minus_zero, 1.0), 0, 0, 0);
+
+  check_complex ("ctan (0 - inf i) == 0.0 - 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, 0);
+  check_complex ("ctan (1 - inf i) == 0.0 - 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (1, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, 0);
+  check_complex ("ctan (-0 - inf i) == -0 - 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, -1.0), 0, 0, 0);
+  check_complex ("ctan (-1 - inf i) == -0 - 1.0 i",  FUNC(ctan) (BUILD_COMPLEX (-1, minus_infty)), BUILD_COMPLEX (minus_zero, -1.0), 0, 0, 0);
+
+  check_complex ("ctan (inf + 0 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (inf + 2 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (plus_infty, 2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (-inf + 0 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (-inf + 2 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (minus_infty, 2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (inf - 0 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (inf - 2 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (plus_infty, -2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (-inf - 0 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctan (-inf - 2 i) == NaN + NaN i plus invalid exception",  FUNC(ctan) (BUILD_COMPLEX (minus_infty, -2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ctan (NaN + inf i) == 0.0 + 1.0 i plus sign of zero/inf not specified",  FUNC(ctan) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ctan (NaN - inf i) == 0.0 - 1.0 i plus sign of zero/inf not specified",  FUNC(ctan) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ctan (0 + NaN i) == 0.0 + NaN i",  FUNC(ctan) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0);
+  check_complex ("ctan (-0 + NaN i) == -0 + NaN i",  FUNC(ctan) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0);
+
+  check_complex ("ctan (0.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (0.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctan (-4.5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (-4.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ctan (NaN + 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctan (NaN + 5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctan (NaN - 0 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctan (NaN - 0.25 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctan) (BUILD_COMPLEX (nan_value, -0.25)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ctan (NaN + NaN i) == NaN + NaN i",  FUNC(ctan) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("ctan (0.7 + 1.2 i) == 0.1720734197630349001 + 0.9544807059989405538 i",  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.1720734197630349001L, 0.9544807059989405538L), DELTA766, 0, 0);
+  check_complex ("ctan (-2 - 3 i) == 0.0037640256415042482 - 1.0032386273536098014 i",  FUNC(ctan) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.0037640256415042482L, -1.0032386273536098014L), DELTA767, 0, 0);
+
+  print_complex_max_error ("ctan", DELTActan, 0);
+}
+
+
+static void
+ctanh_test (void)
+{
+  errno = 0;
+  FUNC(ctanh) (BUILD_COMPLEX (0, 0));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_complex ("ctanh (0 + 0 i) == 0.0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0);
+  check_complex ("ctanh (0 - 0 i) == 0.0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0);
+  check_complex ("ctanh (-0 + 0 i) == -0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0);
+  check_complex ("ctanh (-0 - 0 i) == -0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0);
+
+  check_complex ("ctanh (inf + 0 i) == 1.0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("ctanh (inf + 1 i) == 1.0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0);
+  check_complex ("ctanh (inf - 0 i) == 1.0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+  check_complex ("ctanh (inf - 1 i) == 1.0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0);
+  check_complex ("ctanh (-inf + 0 i) == -1.0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, 0);
+  check_complex ("ctanh (-inf + 1 i) == -1.0 + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, 0);
+  check_complex ("ctanh (-inf - 0 i) == -1.0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-1.0, minus_zero), 0, 0, 0);
+  check_complex ("ctanh (-inf - 1 i) == -1.0 - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (-1.0, minus_zero), 0, 0, 0);
+
+  check_complex ("ctanh (0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (2 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (2, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (2 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (2, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (-0 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (-2 + inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (-2, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (-0 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+  check_complex ("ctanh (-2 - inf i) == NaN + NaN i plus invalid exception",  FUNC(ctanh) (BUILD_COMPLEX (-2, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION);
+
+  check_complex ("ctanh (inf + NaN i) == 1.0 + 0.0 i plus sign of zero/inf not specified",  FUNC(ctanh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (1.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_complex ("ctanh (-inf + NaN i) == -1.0 + 0.0 i plus sign of zero/inf not specified",  FUNC(ctanh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN);
+
+  check_complex ("ctanh (NaN + 0 i) == NaN + 0.0 i",  FUNC(ctanh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0);
+  check_complex ("ctanh (NaN - 0 i) == NaN - 0 i",  FUNC(ctanh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0);
+
+  check_complex ("ctanh (NaN + 0.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (nan_value, 0.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctanh (NaN - 4.5 i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (nan_value, -4.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ctanh (0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctanh (5 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctanh (-0 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+  check_complex ("ctanh (-0.25 + NaN i) == NaN + NaN i plus invalid exception allowed",  FUNC(ctanh) (BUILD_COMPLEX (-0.25, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK);
+
+  check_complex ("ctanh (NaN + NaN i) == NaN + NaN i",  FUNC(ctanh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0);
+
+  check_complex ("ctanh (0 + pi/4 i) == 0.0 + 1.0 i",  FUNC(ctanh) (BUILD_COMPLEX (0, M_PI_4l)), BUILD_COMPLEX (0.0, 1.0), DELTA799, 0, 0);
+
+  check_complex ("ctanh (0.7 + 1.2 i) == 1.3472197399061191630 + 0.4778641038326365540 i",  FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.3472197399061191630L, 0.4778641038326365540L), DELTA800, 0, 0);
+  check_complex ("ctanh (-2 - 3 i) == -0.9653858790221331242 + 0.0098843750383224937 i",  FUNC(ctanh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.9653858790221331242L, 0.0098843750383224937L), DELTA801, 0, 0);
+
+  print_complex_max_error ("ctanh", DELTActanh, 0);
+}
+#endif
+
+static void
+erf_test (void)
+{
+  errno = 0;
+  FUNC(erf) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("erf (0) == 0",  FUNC(erf) (0), 0, 0, 0, 0);
+  check_float ("erf (-0) == -0",  FUNC(erf) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("erf (inf) == 1",  FUNC(erf) (plus_infty), 1, 0, 0, 0);
+  check_float ("erf (-inf) == -1",  FUNC(erf) (minus_infty), -1, 0, 0, 0);
+  check_float ("erf (NaN) == NaN",  FUNC(erf) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("erf (0.7) == 0.67780119383741847297",  FUNC(erf) (0.7L), 0.67780119383741847297L, 0, 0, 0);
+
+  check_float ("erf (1.2) == 0.91031397822963538024",  FUNC(erf) (1.2L), 0.91031397822963538024L, 0, 0, 0);
+  check_float ("erf (2.0) == 0.99532226501895273416",  FUNC(erf) (2.0), 0.99532226501895273416L, 0, 0, 0);
+  check_float ("erf (4.1) == 0.99999999329997234592",  FUNC(erf) (4.1L), 0.99999999329997234592L, 0, 0, 0);
+  check_float ("erf (27) == 1.0",  FUNC(erf) (27), 1.0L, 0, 0, 0);
+
+  print_max_error ("erf", 0, 0);
+}
+
+
+static void
+erfc_test (void)
+{
+  errno = 0;
+  FUNC(erfc) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("erfc (inf) == 0.0",  FUNC(erfc) (plus_infty), 0.0, 0, 0, 0);
+  check_float ("erfc (-inf) == 2.0",  FUNC(erfc) (minus_infty), 2.0, 0, 0, 0);
+  check_float ("erfc (0.0) == 1.0",  FUNC(erfc) (0.0), 1.0, 0, 0, 0);
+  check_float ("erfc (-0) == 1.0",  FUNC(erfc) (minus_zero), 1.0, 0, 0, 0);
+  check_float ("erfc (NaN) == NaN",  FUNC(erfc) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("erfc (0.7) == 0.32219880616258152702",  FUNC(erfc) (0.7L), 0.32219880616258152702L, DELTA817, 0, 0);
+
+  check_float ("erfc (1.2) == 0.089686021770364619762",  FUNC(erfc) (1.2L), 0.089686021770364619762L, DELTA818, 0, 0);
+  check_float ("erfc (2.0) == 0.0046777349810472658379",  FUNC(erfc) (2.0), 0.0046777349810472658379L, DELTA819, 0, 0);
+  check_float ("erfc (4.1) == 0.67000276540848983727e-8",  FUNC(erfc) (4.1L), 0.67000276540848983727e-8L, DELTA820, 0, 0);
+  check_float ("erfc (9) == 0.41370317465138102381e-36",  FUNC(erfc) (9), 0.41370317465138102381e-36L, DELTA821, 0, 0);
+
+  print_max_error ("erfc", DELTAerfc, 0);
+}
+
+static void
+exp_test (void)
+{
+  errno = 0;
+  FUNC(exp) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("exp (0) == 1",  FUNC(exp) (0), 1, 0, 0, 0);
+  check_float ("exp (-0) == 1",  FUNC(exp) (minus_zero), 1, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  check_float ("exp (inf) == inf",  FUNC(exp) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("exp (-inf) == 0",  FUNC(exp) (minus_infty), 0, 0, 0, 0);
+#endif
+  check_float ("exp (NaN) == NaN",  FUNC(exp) (nan_value), nan_value, 0, 0, 0);
+  check_float ("exp (1) == e",  FUNC(exp) (1), M_El, 0, 0, 0);
+
+  check_float ("exp (2) == e^2",  FUNC(exp) (2), M_E2l, 0, 0, 0);
+  check_float ("exp (3) == e^3",  FUNC(exp) (3), M_E3l, 0, 0, 0);
+  check_float ("exp (0.7) == 2.0137527074704765216",  FUNC(exp) (0.7L), 2.0137527074704765216L, DELTA830, 0, 0);
+  check_float ("exp (50.0) == 5184705528587072464087.45332293348538",  FUNC(exp) (50.0L), 5184705528587072464087.45332293348538L, DELTA831, 0, 0);
+#ifdef TEST_LDOUBLE
+  /* The result can only be represented in long double.  */
+  check_float ("exp (1000.0) == 0.197007111401704699388887935224332313e435",  FUNC(exp) (1000.0L), 0.197007111401704699388887935224332313e435L, DELTA832, 0, 0);
+#endif
+  print_max_error ("exp", DELTAexp, 0);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+exp10_test (void)
+{
+  errno = 0;
+  FUNC(exp10) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("exp10 (0) == 1",  FUNC(exp10) (0), 1, 0, 0, 0);
+  check_float ("exp10 (-0) == 1",  FUNC(exp10) (minus_zero), 1, 0, 0, 0);
+
+  check_float ("exp10 (inf) == inf",  FUNC(exp10) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("exp10 (-inf) == 0",  FUNC(exp10) (minus_infty), 0, 0, 0, 0);
+  check_float ("exp10 (NaN) == NaN",  FUNC(exp10) (nan_value), nan_value, 0, 0, 0);
+  check_float ("exp10 (3) == 1000",  FUNC(exp10) (3), 1000, DELTA838, 0, 0);
+  check_float ("exp10 (-1) == 0.1",  FUNC(exp10) (-1), 0.1L, DELTA839, 0, 0);
+  check_float ("exp10 (1e6) == inf",  FUNC(exp10) (1e6), plus_infty, 0, 0, 0);
+  check_float ("exp10 (-1e6) == 0",  FUNC(exp10) (-1e6), 0, 0, 0, 0);
+  check_float ("exp10 (0.7) == 5.0118723362727228500155418688494574",  FUNC(exp10) (0.7L), 5.0118723362727228500155418688494574L, DELTA842, 0, 0);
+
+  print_max_error ("exp10", DELTAexp10, 0);
+}
+#endif
+
+static void
+exp2_test (void)
+{
+  errno = 0;
+  FUNC(exp2) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("exp2 (0) == 1",  FUNC(exp2) (0), 1, 0, 0, 0);
+  check_float ("exp2 (-0) == 1",  FUNC(exp2) (minus_zero), 1, 0, 0, 0);
+  check_float ("exp2 (inf) == inf",  FUNC(exp2) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("exp2 (-inf) == 0",  FUNC(exp2) (minus_infty), 0, 0, 0, 0);
+  check_float ("exp2 (NaN) == NaN",  FUNC(exp2) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("exp2 (10) == 1024",  FUNC(exp2) (10), 1024, 0, 0, 0);
+  check_float ("exp2 (-1) == 0.5",  FUNC(exp2) (-1), 0.5, 0, 0, 0);
+  check_float ("exp2 (1e6) == inf",  FUNC(exp2) (1e6), plus_infty, 0, 0, 0);
+  check_float ("exp2 (-1e6) == 0",  FUNC(exp2) (-1e6), 0, 0, 0, 0);
+  check_float ("exp2 (0.7) == 1.6245047927124710452",  FUNC(exp2) (0.7L), 1.6245047927124710452L, DELTA852, 0, 0);
+
+  print_max_error ("exp2", DELTAexp2, 0);
+}
+
+static void
+expm1_test (void)
+{
+  errno = 0;
+  FUNC(expm1) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("expm1 (0) == 0",  FUNC(expm1) (0), 0, 0, 0, 0);
+  check_float ("expm1 (-0) == -0",  FUNC(expm1) (minus_zero), minus_zero, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  check_float ("expm1 (inf) == inf",  FUNC(expm1) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("expm1 (-inf) == -1",  FUNC(expm1) (minus_infty), -1, 0, 0, 0);
+#endif
+  check_float ("expm1 (NaN) == NaN",  FUNC(expm1) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("expm1 (1) == M_El - 1.0",  FUNC(expm1) (1), M_El - 1.0, 1, 0, 0);
+  check_float ("expm1 (0.7) == 1.0137527074704765216",  FUNC(expm1) (0.7L), 1.0137527074704765216L, DELTA859, 0, 0);
+
+  print_max_error ("expm1", DELTAexpm1, 0);
+}
+
+static void
+fabs_test (void)
+{
+  init_max_error ();
+
+  check_float ("fabs (0) == 0",  FUNC(fabs) ((FLOAT)0.0), 0, 0, 0, 0);
+  check_float ("fabs (-0) == 0",  FUNC(fabs) (minus_zero), 0, 0, 0, 0);
+
+  check_float ("fabs (inf) == inf",  FUNC(fabs) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("fabs (-inf) == inf",  FUNC(fabs) (minus_infty), plus_infty, 0, 0, 0);
+  check_float ("fabs (NaN) == NaN",  FUNC(fabs) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("fabs (38.0) == 38.0",  FUNC(fabs) ((FLOAT)38.0), 38.0, 0, 0, 0);
+  check_float ("fabs (-e) == e",  FUNC(fabs) ((FLOAT)-M_El), M_El, 0, 0, 0);
+
+  print_max_error ("fabs", 0, 0);
+}
+
+static void
+fdim_test (void)
+{
+  init_max_error ();
+
+  check_float ("fdim (0, 0) == 0",  FUNC(fdim) (0, 0), 0, 0, 0, 0);
+  check_float ("fdim (9, 0) == 9",  FUNC(fdim) (9, 0), 9, 0, 0, 0);
+  check_float ("fdim (0, 9) == 0",  FUNC(fdim) (0, 9), 0, 0, 0, 0);
+  check_float ("fdim (-9, 0) == 0",  FUNC(fdim) (-9, 0), 0, 0, 0, 0);
+  check_float ("fdim (0, -9) == 9",  FUNC(fdim) (0, -9), 9, 0, 0, 0);
+
+  check_float ("fdim (inf, 9) == inf",  FUNC(fdim) (plus_infty, 9), plus_infty, 0, 0, 0);
+  check_float ("fdim (inf, -9) == inf",  FUNC(fdim) (plus_infty, -9), plus_infty, 0, 0, 0);
+  check_float ("fdim (-inf, 9) == 0",  FUNC(fdim) (minus_infty, 9), 0, 0, 0, 0);
+  check_float ("fdim (-inf, -9) == 0",  FUNC(fdim) (minus_infty, -9), 0, 0, 0, 0);
+  check_float ("fdim (9, -inf) == inf",  FUNC(fdim) (9, minus_infty), plus_infty, 0, 0, 0);
+  check_float ("fdim (-9, -inf) == inf",  FUNC(fdim) (-9, minus_infty), plus_infty, 0, 0, 0);
+  check_float ("fdim (9, inf) == 0",  FUNC(fdim) (9, plus_infty), 0, 0, 0, 0);
+  check_float ("fdim (-9, inf) == 0",  FUNC(fdim) (-9, plus_infty), 0, 0, 0, 0);
+
+  check_float ("fdim (0, NaN) == NaN",  FUNC(fdim) (0, nan_value), nan_value, 0, 0, 0);
+  check_float ("fdim (9, NaN) == NaN",  FUNC(fdim) (9, nan_value), nan_value, 0, 0, 0);
+  check_float ("fdim (-9, NaN) == NaN",  FUNC(fdim) (-9, nan_value), nan_value, 0, 0, 0);
+  check_float ("fdim (NaN, 9) == NaN",  FUNC(fdim) (nan_value, 9), nan_value, 0, 0, 0);
+  check_float ("fdim (NaN, -9) == NaN",  FUNC(fdim) (nan_value, -9), nan_value, 0, 0, 0);
+  check_float ("fdim (inf, NaN) == NaN",  FUNC(fdim) (plus_infty, nan_value), nan_value, 0, 0, 0);
+  check_float ("fdim (-inf, NaN) == NaN",  FUNC(fdim) (minus_infty, nan_value), nan_value, 0, 0, 0);
+  check_float ("fdim (NaN, inf) == NaN",  FUNC(fdim) (nan_value, plus_infty), nan_value, 0, 0, 0);
+  check_float ("fdim (NaN, -inf) == NaN",  FUNC(fdim) (nan_value, minus_infty), nan_value, 0, 0, 0);
+  check_float ("fdim (NaN, NaN) == NaN",  FUNC(fdim) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  print_max_error ("fdim", 0, 0);
+}
+
+static void
+floor_test (void)
+{
+  init_max_error ();
+
+  check_float ("floor (0.0) == 0.0",  FUNC(floor) (0.0), 0.0, 0, 0, 0);
+  check_float ("floor (-0) == -0",  FUNC(floor) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("floor (inf) == inf",  FUNC(floor) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("floor (-inf) == -inf",  FUNC(floor) (minus_infty), minus_infty, 0, 0, 0);
+  check_float ("floor (NaN) == NaN",  FUNC(floor) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("floor (pi) == 3.0",  FUNC(floor) (M_PIl), 3.0, 0, 0, 0);
+  check_float ("floor (-pi) == -4.0",  FUNC(floor) (-M_PIl), -4.0, 0, 0, 0);
+
+  print_max_error ("floor", 0, 0);
+}
+
+static void
+fma_test (void)
+{
+  init_max_error ();
+
+  check_float ("fma (1.0, 2.0, 3.0) == 5.0",  FUNC(fma) (1.0, 2.0, 3.0), 5.0, 0, 0, 0);
+  check_float ("fma (NaN, 2.0, 3.0) == NaN",  FUNC(fma) (nan_value, 2.0, 3.0), nan_value, 0, 0, 0);
+  check_float ("fma (1.0, NaN, 3.0) == NaN",  FUNC(fma) (1.0, nan_value, 3.0), nan_value, 0, 0, 0);
+  check_float ("fma (1.0, 2.0, NaN) == NaN plus invalid exception allowed",  FUNC(fma) (1.0, 2.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK);
+  check_float ("fma (inf, 0.0, NaN) == NaN plus invalid exception allowed",  FUNC(fma) (plus_infty, 0.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK);
+  check_float ("fma (-inf, 0.0, NaN) == NaN plus invalid exception allowed",  FUNC(fma) (minus_infty, 0.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK);
+  check_float ("fma (0.0, inf, NaN) == NaN plus invalid exception allowed",  FUNC(fma) (0.0, plus_infty, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK);
+  check_float ("fma (0.0, -inf, NaN) == NaN plus invalid exception allowed",  FUNC(fma) (0.0, minus_infty, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK);
+  check_float ("fma (inf, 0.0, 1.0) == NaN plus invalid exception",  FUNC(fma) (plus_infty, 0.0, 1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (-inf, 0.0, 1.0) == NaN plus invalid exception",  FUNC(fma) (minus_infty, 0.0, 1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (0.0, inf, 1.0) == NaN plus invalid exception",  FUNC(fma) (0.0, plus_infty, 1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (0.0, -inf, 1.0) == NaN plus invalid exception",  FUNC(fma) (0.0, minus_infty, 1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("fma (inf, inf, -inf) == NaN plus invalid exception",  FUNC(fma) (plus_infty, plus_infty, minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (-inf, inf, inf) == NaN plus invalid exception",  FUNC(fma) (minus_infty, plus_infty, plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (inf, -inf, inf) == NaN plus invalid exception",  FUNC(fma) (plus_infty, minus_infty, plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("fma (-inf, -inf, -inf) == NaN plus invalid exception",  FUNC(fma) (minus_infty, minus_infty, minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  print_max_error ("fma", 0, 0);
+}
+
+
+static void
+fmax_test (void)
+{
+  init_max_error ();
+
+  check_float ("fmax (0, 0) == 0",  FUNC(fmax) (0, 0), 0, 0, 0, 0);
+  check_float ("fmax (-0, -0) == -0",  FUNC(fmax) (minus_zero, minus_zero), minus_zero, 0, 0, 0);
+  check_float ("fmax (9, 0) == 9",  FUNC(fmax) (9, 0), 9, 0, 0, 0);
+  check_float ("fmax (0, 9) == 9",  FUNC(fmax) (0, 9), 9, 0, 0, 0);
+  check_float ("fmax (-9, 0) == 0",  FUNC(fmax) (-9, 0), 0, 0, 0, 0);
+  check_float ("fmax (0, -9) == 0",  FUNC(fmax) (0, -9), 0, 0, 0, 0);
+
+  check_float ("fmax (inf, 9) == inf",  FUNC(fmax) (plus_infty, 9), plus_infty, 0, 0, 0);
+  check_float ("fmax (0, inf) == inf",  FUNC(fmax) (0, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("fmax (-9, inf) == inf",  FUNC(fmax) (-9, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("fmax (inf, -9) == inf",  FUNC(fmax) (plus_infty, -9), plus_infty, 0, 0, 0);
+
+  check_float ("fmax (-inf, 9) == 9",  FUNC(fmax) (minus_infty, 9), 9, 0, 0, 0);
+  check_float ("fmax (-inf, -9) == -9",  FUNC(fmax) (minus_infty, -9), -9, 0, 0, 0);
+  check_float ("fmax (9, -inf) == 9",  FUNC(fmax) (9, minus_infty), 9, 0, 0, 0);
+  check_float ("fmax (-9, -inf) == -9",  FUNC(fmax) (-9, minus_infty), -9, 0, 0, 0);
+
+  check_float ("fmax (0, NaN) == 0",  FUNC(fmax) (0, nan_value), 0, 0, 0, 0);
+  check_float ("fmax (9, NaN) == 9",  FUNC(fmax) (9, nan_value), 9, 0, 0, 0);
+  check_float ("fmax (-9, NaN) == -9",  FUNC(fmax) (-9, nan_value), -9, 0, 0, 0);
+  check_float ("fmax (NaN, 0) == 0",  FUNC(fmax) (nan_value, 0), 0, 0, 0, 0);
+  check_float ("fmax (NaN, 9) == 9",  FUNC(fmax) (nan_value, 9), 9, 0, 0, 0);
+  check_float ("fmax (NaN, -9) == -9",  FUNC(fmax) (nan_value, -9), -9, 0, 0, 0);
+  check_float ("fmax (inf, NaN) == inf",  FUNC(fmax) (plus_infty, nan_value), plus_infty, 0, 0, 0);
+  check_float ("fmax (-inf, NaN) == -inf",  FUNC(fmax) (minus_infty, nan_value), minus_infty, 0, 0, 0);
+  check_float ("fmax (NaN, inf) == inf",  FUNC(fmax) (nan_value, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("fmax (NaN, -inf) == -inf",  FUNC(fmax) (nan_value, minus_infty), minus_infty, 0, 0, 0);
+  check_float ("fmax (NaN, NaN) == NaN",  FUNC(fmax) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  print_max_error ("fmax", 0, 0);
+}
+
+
+static void
+fmin_test (void)
+{
+  init_max_error ();
+
+  check_float ("fmin (0, 0) == 0",  FUNC(fmin) (0, 0), 0, 0, 0, 0);
+  check_float ("fmin (-0, -0) == -0",  FUNC(fmin) (minus_zero, minus_zero), minus_zero, 0, 0, 0);
+  check_float ("fmin (9, 0) == 0",  FUNC(fmin) (9, 0), 0, 0, 0, 0);
+  check_float ("fmin (0, 9) == 0",  FUNC(fmin) (0, 9), 0, 0, 0, 0);
+  check_float ("fmin (-9, 0) == -9",  FUNC(fmin) (-9, 0), -9, 0, 0, 0);
+  check_float ("fmin (0, -9) == -9",  FUNC(fmin) (0, -9), -9, 0, 0, 0);
+
+  check_float ("fmin (inf, 9) == 9",  FUNC(fmin) (plus_infty, 9), 9, 0, 0, 0);
+  check_float ("fmin (9, inf) == 9",  FUNC(fmin) (9, plus_infty), 9, 0, 0, 0);
+  check_float ("fmin (inf, -9) == -9",  FUNC(fmin) (plus_infty, -9), -9, 0, 0, 0);
+  check_float ("fmin (-9, inf) == -9",  FUNC(fmin) (-9, plus_infty), -9, 0, 0, 0);
+  check_float ("fmin (-inf, 9) == -inf",  FUNC(fmin) (minus_infty, 9), minus_infty, 0, 0, 0);
+  check_float ("fmin (-inf, -9) == -inf",  FUNC(fmin) (minus_infty, -9), minus_infty, 0, 0, 0);
+  check_float ("fmin (9, -inf) == -inf",  FUNC(fmin) (9, minus_infty), minus_infty, 0, 0, 0);
+  check_float ("fmin (-9, -inf) == -inf",  FUNC(fmin) (-9, minus_infty), minus_infty, 0, 0, 0);
+
+  check_float ("fmin (0, NaN) == 0",  FUNC(fmin) (0, nan_value), 0, 0, 0, 0);
+  check_float ("fmin (9, NaN) == 9",  FUNC(fmin) (9, nan_value), 9, 0, 0, 0);
+  check_float ("fmin (-9, NaN) == -9",  FUNC(fmin) (-9, nan_value), -9, 0, 0, 0);
+  check_float ("fmin (NaN, 0) == 0",  FUNC(fmin) (nan_value, 0), 0, 0, 0, 0);
+  check_float ("fmin (NaN, 9) == 9",  FUNC(fmin) (nan_value, 9), 9, 0, 0, 0);
+  check_float ("fmin (NaN, -9) == -9",  FUNC(fmin) (nan_value, -9), -9, 0, 0, 0);
+  check_float ("fmin (inf, NaN) == inf",  FUNC(fmin) (plus_infty, nan_value), plus_infty, 0, 0, 0);
+  check_float ("fmin (-inf, NaN) == -inf",  FUNC(fmin) (minus_infty, nan_value), minus_infty, 0, 0, 0);
+  check_float ("fmin (NaN, inf) == inf",  FUNC(fmin) (nan_value, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("fmin (NaN, -inf) == -inf",  FUNC(fmin) (nan_value, minus_infty), minus_infty, 0, 0, 0);
+  check_float ("fmin (NaN, NaN) == NaN",  FUNC(fmin) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  print_max_error ("fmin", 0, 0);
+}
+
+
+static void
+fmod_test (void)
+{
+  errno = 0;
+  FUNC(fmod) (6.5, 2.3L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  /* fmod (+0, y) == +0 for y != 0.  */
+  check_float ("fmod (0, 3) == 0",  FUNC(fmod) (0, 3), 0, 0, 0, 0);
+
+  /* fmod (-0, y) == -0 for y != 0.  */
+  check_float ("fmod (-0, 3) == -0",  FUNC(fmod) (minus_zero, 3), minus_zero, 0, 0, 0);
+
+  /* fmod (+inf, y) == NaN plus invalid exception.  */
+  check_float ("fmod (inf, 3) == NaN plus invalid exception",  FUNC(fmod) (plus_infty, 3), nan_value, 0, 0, INVALID_EXCEPTION);
+  /* fmod (-inf, y) == NaN plus invalid exception.  */
+  check_float ("fmod (-inf, 3) == NaN plus invalid exception",  FUNC(fmod) (minus_infty, 3), nan_value, 0, 0, INVALID_EXCEPTION);
+  /* fmod (x, +0) == NaN plus invalid exception.  */
+  check_float ("fmod (3, 0) == NaN plus invalid exception",  FUNC(fmod) (3, 0), nan_value, 0, 0, INVALID_EXCEPTION);
+  /* fmod (x, -0) == NaN plus invalid exception.  */
+  check_float ("fmod (3, -0) == NaN plus invalid exception",  FUNC(fmod) (3, minus_zero), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  /* fmod (x, +inf) == x for x not infinite.  */
+  check_float ("fmod (3.0, inf) == 3.0",  FUNC(fmod) (3.0, plus_infty), 3.0, 0, 0, 0);
+  /* fmod (x, -inf) == x for x not infinite.  */
+  check_float ("fmod (3.0, -inf) == 3.0",  FUNC(fmod) (3.0, minus_infty), 3.0, 0, 0, 0);
+
+  check_float ("fmod (NaN, NaN) == NaN",  FUNC(fmod) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("fmod (6.5, 2.3) == 1.9",  FUNC(fmod) (6.5, 2.3L), 1.9L, DELTA972, 0, 0);
+  check_float ("fmod (-6.5, 2.3) == -1.9",  FUNC(fmod) (-6.5, 2.3L), -1.9L, DELTA973, 0, 0);
+  check_float ("fmod (6.5, -2.3) == 1.9",  FUNC(fmod) (6.5, -2.3L), 1.9L, DELTA974, 0, 0);
+  check_float ("fmod (-6.5, -2.3) == -1.9",  FUNC(fmod) (-6.5, -2.3L), -1.9L, DELTA975, 0, 0);
+
+  print_max_error ("fmod", DELTAfmod, 0);
+}
+
+static void
+fpclassify_test (void)
+{
+  init_max_error ();
+
+  check_int ("fpclassify (NaN) == FP_NAN", fpclassify (nan_value), FP_NAN, 0, 0, 0);
+  check_int ("fpclassify (inf) == FP_INFINITE", fpclassify (plus_infty), FP_INFINITE, 0, 0, 0);
+  check_int ("fpclassify (-inf) == FP_INFINITE", fpclassify (minus_infty), FP_INFINITE, 0, 0, 0);
+  check_int ("fpclassify (+0) == FP_ZERO", fpclassify (plus_zero), FP_ZERO, 0, 0, 0);
+  check_int ("fpclassify (-0) == FP_ZERO", fpclassify (minus_zero), FP_ZERO, 0, 0, 0);
+  check_int ("fpclassify (1000) == FP_NORMAL", fpclassify (1000.0), FP_NORMAL, 0, 0, 0);
+
+  print_max_error ("fpclassify", 0, 0);
+}
+
+
+static void
+frexp_test (void)
+{
+  int x;
+
+  init_max_error ();
+
+  check_float ("frexp (inf, &x) == inf",  FUNC(frexp) (plus_infty, &x), plus_infty, 0, 0, 0);
+  check_float ("frexp (-inf, &x) == -inf",  FUNC(frexp) (minus_infty, &x), minus_infty, 0, 0, 0);
+  check_float ("frexp (NaN, &x) == NaN",  FUNC(frexp) (nan_value, &x), nan_value, 0, 0, 0);
+
+  check_float ("frexp (0.0, &x) == 0.0",  FUNC(frexp) (0.0, &x), 0.0, 0, 0, 0);
+  check_int ("frexp (0.0, &x) sets x to 0.0", x, 0.0, 0, 0, 0);
+  check_float ("frexp (-0, &x) == -0",  FUNC(frexp) (minus_zero, &x), minus_zero, 0, 0, 0);
+  check_int ("frexp (-0, &x) sets x to 0.0", x, 0.0, 0, 0, 0);
+
+  check_float ("frexp (12.8, &x) == 0.8",  FUNC(frexp) (12.8L, &x), 0.8L, 0, 0, 0);
+  check_int ("frexp (12.8, &x) sets x to 4", x, 4, 0, 0, 0);
+  check_float ("frexp (-27.34, &x) == -0.854375",  FUNC(frexp) (-27.34L, &x), -0.854375L, 0, 0, 0);
+  check_int ("frexp (-27.34, &x) sets x to 5", x, 5, 0, 0, 0);
+
+  print_max_error ("frexp", 0, 0);
+}
+
+#define gamma lgamma /* XXX scp XXX */
+#define gammaf lgammaf /* XXX scp XXX */
+static void
+gamma_test (void)
+{
+  errno = 0;
+  FUNC(gamma) (1);
+
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+  feclearexcept (FE_ALL_EXCEPT);
+
+  init_max_error ();
+
+  signgam = 0;
+  check_float ("gamma (inf) == inf",  FUNC(gamma) (plus_infty), plus_infty, 0, 0, 0);
+  signgam = 0;
+  check_float ("gamma (0) == inf plus division by zero exception",  FUNC(gamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  signgam = 0;
+  check_float ("gamma (-3) == inf plus division by zero exception",  FUNC(gamma) (-3), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  signgam = 0;
+  check_float ("gamma (-inf) == inf",  FUNC(gamma) (minus_infty), plus_infty, 0, 0, 0);
+  signgam = 0;
+  check_float ("gamma (NaN) == NaN",  FUNC(gamma) (nan_value), nan_value, 0, 0, 0);
+
+  signgam = 0;
+  check_float ("gamma (1) == 0",  FUNC(gamma) (1), 0, 0, 0, 0);
+  check_int ("gamma (1) sets signgam to 1", signgam, 1, 0, 0, 0);
+  signgam = 0;
+  check_float ("gamma (3) == M_LN2l",  FUNC(gamma) (3), M_LN2l, 0, 0, 0);
+  check_int ("gamma (3) sets signgam to 1", signgam, 1, 0, 0, 0);
+
+  signgam = 0;
+  check_float ("gamma (0.5) == log(sqrt(pi))",  FUNC(gamma) (0.5), M_LOG_SQRT_PIl, 0, 0, 0);
+  check_int ("gamma (0.5) sets signgam to 1", signgam, 1, 0, 0, 0);
+  signgam = 0;
+  check_float ("gamma (-0.5) == log(2*sqrt(pi))",  FUNC(gamma) (-0.5), M_LOG_2_SQRT_PIl, DELTA1004, 0, 0);
+  check_int ("gamma (-0.5) sets signgam to -1", signgam, -1, 0, 0, 0);
+
+  print_max_error ("gamma", DELTAgamma, 0);
+}
+#undef gamma /* XXX scp XXX */
+#undef gammaf /* XXX scp XXX */
+
+static void
+hypot_test (void)
+{
+  errno = 0;
+  FUNC(hypot) (0.7L, 12.4L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("hypot (inf, 1) == inf plus sign of zero/inf not specified",  FUNC(hypot) (plus_infty, 1), plus_infty, 0, 0, IGNORE_ZERO_INF_SIGN);
+  check_float ("hypot (-inf, 1) == inf plus sign of zero/inf not specified",  FUNC(hypot) (minus_infty, 1), plus_infty, 0, 0, IGNORE_ZERO_INF_SIGN);
+
+#ifndef TEST_INLINE
+  check_float ("hypot (inf, NaN) == inf",  FUNC(hypot) (plus_infty, nan_value), plus_infty, 0, 0, 0);
+  check_float ("hypot (-inf, NaN) == inf",  FUNC(hypot) (minus_infty, nan_value), plus_infty, 0, 0, 0);
+  check_float ("hypot (NaN, inf) == inf",  FUNC(hypot) (nan_value, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("hypot (NaN, -inf) == inf",  FUNC(hypot) (nan_value, minus_infty), plus_infty, 0, 0, 0);
+#endif
+
+  check_float ("hypot (NaN, NaN) == NaN",  FUNC(hypot) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  /* hypot (x,y) == hypot (+-x, +-y)  */
+  check_float ("hypot (0.7, 12.4) == 12.419742348374220601176836866763271",  FUNC(hypot) (0.7L, 12.4L), 12.419742348374220601176836866763271L, DELTA1013, 0, 0);
+  check_float ("hypot (-0.7, 12.4) == 12.419742348374220601176836866763271",  FUNC(hypot) (-0.7L, 12.4L), 12.419742348374220601176836866763271L, DELTA1014, 0, 0);
+  check_float ("hypot (0.7, -12.4) == 12.419742348374220601176836866763271",  FUNC(hypot) (0.7L, -12.4L), 12.419742348374220601176836866763271L, DELTA1015, 0, 0);
+  check_float ("hypot (-0.7, -12.4) == 12.419742348374220601176836866763271",  FUNC(hypot) (-0.7L, -12.4L), 12.419742348374220601176836866763271L, DELTA1016, 0, 0);
+  check_float ("hypot (12.4, 0.7) == 12.419742348374220601176836866763271",  FUNC(hypot) (12.4L, 0.7L), 12.419742348374220601176836866763271L, DELTA1017, 0, 0);
+  check_float ("hypot (-12.4, 0.7) == 12.419742348374220601176836866763271",  FUNC(hypot) (-12.4L, 0.7L), 12.419742348374220601176836866763271L, DELTA1018, 0, 0);
+  check_float ("hypot (12.4, -0.7) == 12.419742348374220601176836866763271",  FUNC(hypot) (12.4L, -0.7L), 12.419742348374220601176836866763271L, DELTA1019, 0, 0);
+  check_float ("hypot (-12.4, -0.7) == 12.419742348374220601176836866763271",  FUNC(hypot) (-12.4L, -0.7L), 12.419742348374220601176836866763271L, DELTA1020, 0, 0);
+
+  /*  hypot (x,0) == fabs (x)  */
+  check_float ("hypot (0.7, 0) == 0.7",  FUNC(hypot) (0.7L, 0), 0.7L, 0, 0, 0);
+  check_float ("hypot (-0.7, 0) == 0.7",  FUNC(hypot) (-0.7L, 0), 0.7L, 0, 0, 0);
+  check_float ("hypot (-5.7e7, 0) == 5.7e7",  FUNC(hypot) (-5.7e7, 0), 5.7e7L, 0, 0, 0);
+
+  check_float ("hypot (0.7, 1.2) == 1.3892443989449804508432547041028554",  FUNC(hypot) (0.7L, 1.2L), 1.3892443989449804508432547041028554L, DELTA1024, 0, 0);
+
+  print_max_error ("hypot", DELTAhypot, 0);
+}
+
+
+static void
+ilogb_test (void)
+{
+  init_max_error ();
+
+  check_int ("ilogb (1) == 0",  FUNC(ilogb) (1), 0, 0, 0, 0);
+  check_int ("ilogb (e) == 1",  FUNC(ilogb) (M_El), 1, 0, 0, 0);
+  check_int ("ilogb (1024) == 10",  FUNC(ilogb) (1024), 10, 0, 0, 0);
+  check_int ("ilogb (-2000) == 10",  FUNC(ilogb) (-2000), 10, 0, 0, 0);
+
+  /* XXX We have a problem here: the standard does not tell us whether
+     exceptions are allowed/required.  ignore them for now.  */
+
+  check_int ("ilogb (0.0) == FP_ILOGB0 plus exceptions allowed",  FUNC(ilogb) (0.0), FP_ILOGB0, 0, 0, EXCEPTIONS_OK);
+  check_int ("ilogb (NaN) == FP_ILOGBNAN plus exceptions allowed",  FUNC(ilogb) (nan_value), FP_ILOGBNAN, 0, 0, EXCEPTIONS_OK);
+  check_int ("ilogb (inf) == INT_MAX plus exceptions allowed",  FUNC(ilogb) (plus_infty), INT_MAX, 0, 0, EXCEPTIONS_OK);
+  check_int ("ilogb (-inf) == INT_MAX plus exceptions allowed",  FUNC(ilogb) (minus_infty), INT_MAX, 0, 0, EXCEPTIONS_OK);
+
+  print_max_error ("ilogb", 0, 0);
+}
+
+static void
+isfinite_test (void)
+{
+  init_max_error ();
+
+  check_bool ("isfinite (0) == true", isfinite (0.0), 1, 0, 0, 0);
+  check_bool ("isfinite (-0) == true", isfinite (minus_zero), 1, 0, 0, 0);
+  check_bool ("isfinite (10) == true", isfinite (10.0), 1, 0, 0, 0);
+  check_bool ("isfinite (inf) == false", isfinite (plus_infty), 0, 0, 0, 0);
+  check_bool ("isfinite (-inf) == false", isfinite (minus_infty), 0, 0, 0, 0);
+  check_bool ("isfinite (NaN) == false", isfinite (nan_value), 0, 0, 0, 0);
+
+  print_max_error ("isfinite", 0, 0);
+}
+
+static void
+isnormal_test (void)
+{
+  init_max_error ();
+
+  check_bool ("isnormal (0) == false", isnormal (0.0), 0, 0, 0, 0);
+  check_bool ("isnormal (-0) == false", isnormal (minus_zero), 0, 0, 0, 0);
+  check_bool ("isnormal (10) == true", isnormal (10.0), 1, 0, 0, 0);
+  check_bool ("isnormal (inf) == false", isnormal (plus_infty), 0, 0, 0, 0);
+  check_bool ("isnormal (-inf) == false", isnormal (minus_infty), 0, 0, 0, 0);
+  check_bool ("isnormal (NaN) == false", isnormal (nan_value), 0, 0, 0, 0);
+
+  print_max_error ("isnormal", 0, 0);
+}
+
+static void
+j0_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(j0) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  /* j0 is the Bessel function of the first kind of order 0 */
+  check_float ("j0 (NaN) == NaN",  FUNC(j0) (nan_value), nan_value, 0, 0, 0);
+  check_float ("j0 (inf) == 0",  FUNC(j0) (plus_infty), 0, 0, 0, 0);
+  check_float ("j0 (-1.0) == 0.76519768655796655145",  FUNC(j0) (-1.0), 0.76519768655796655145L, 0, 0, 0);
+  check_float ("j0 (0.0) == 1.0",  FUNC(j0) (0.0), 1.0, 0, 0, 0);
+  check_float ("j0 (0.1) == 0.99750156206604003228",  FUNC(j0) (0.1L), 0.99750156206604003228L, 0, 0, 0);
+  check_float ("j0 (0.7) == 0.88120088860740528084",  FUNC(j0) (0.7L), 0.88120088860740528084L, 0, 0, 0);
+  check_float ("j0 (1.0) == 0.76519768655796655145",  FUNC(j0) (1.0), 0.76519768655796655145L, 0, 0, 0);
+  check_float ("j0 (1.5) == 0.51182767173591812875",  FUNC(j0) (1.5), 0.51182767173591812875L, 0, 0, 0);
+  check_float ("j0 (2.0) == 0.22389077914123566805",  FUNC(j0) (2.0), 0.22389077914123566805L, DELTA1053, 0, 0);
+  check_float ("j0 (8.0) == 0.17165080713755390609",  FUNC(j0) (8.0), 0.17165080713755390609L, DELTA1054, 0, 0);
+  check_float ("j0 (10.0) == -0.24593576445134833520",  FUNC(j0) (10.0), -0.24593576445134833520L, DELTA1055, 0, 0);
+
+  print_max_error ("j0", DELTAj0, 0);
+}
+
+
+static void
+j1_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(j1) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  /* j1 is the Bessel function of the first kind of order 1 */
+
+  init_max_error ();
+
+  check_float ("j1 (NaN) == NaN",  FUNC(j1) (nan_value), nan_value, 0, 0, 0);
+  check_float ("j1 (inf) == 0",  FUNC(j1) (plus_infty), 0, 0, 0, 0);
+
+  check_float ("j1 (-1.0) == -0.44005058574493351596",  FUNC(j1) (-1.0), -0.44005058574493351596L, 0, 0, 0);
+  check_float ("j1 (0.0) == 0.0",  FUNC(j1) (0.0), 0.0, 0, 0, 0);
+  check_float ("j1 (0.1) == 0.049937526036241997556",  FUNC(j1) (0.1L), 0.049937526036241997556L, 0, 0, 0);
+  check_float ("j1 (0.7) == 0.32899574154005894785",  FUNC(j1) (0.7L), 0.32899574154005894785L, 0, 0, 0);
+  check_float ("j1 (1.0) == 0.44005058574493351596",  FUNC(j1) (1.0), 0.44005058574493351596L, 0, 0, 0);
+  check_float ("j1 (1.5) == 0.55793650791009964199",  FUNC(j1) (1.5), 0.55793650791009964199L, 0, 0, 0);
+  check_float ("j1 (2.0) == 0.57672480775687338720",  FUNC(j1) (2.0), 0.57672480775687338720L, DELTA1064, 0, 0);
+  check_float ("j1 (8.0) == 0.23463634685391462438",  FUNC(j1) (8.0), 0.23463634685391462438L, DELTA1065, 0, 0);
+  check_float ("j1 (10.0) == 0.043472746168861436670",  FUNC(j1) (10.0), 0.043472746168861436670L, DELTA1066, 0, 0);
+
+  print_max_error ("j1", DELTAj1, 0);
+}
+
+static void
+jn_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(jn) (1, 1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  /* jn is the Bessel function of the first kind of order n.  */
+  init_max_error ();
+
+  /* jn (0, x) == j0 (x)  */
+  check_float ("jn (0, NaN) == NaN",  FUNC(jn) (0, nan_value), nan_value, 0, 0, 0);
+  check_float ("jn (0, inf) == 0",  FUNC(jn) (0, plus_infty), 0, 0, 0, 0);
+  check_float ("jn (0, -1.0) == 0.76519768655796655145",  FUNC(jn) (0, -1.0), 0.76519768655796655145L, 0, 0, 0);
+  check_float ("jn (0, 0.0) == 1.0",  FUNC(jn) (0, 0.0), 1.0, 0, 0, 0);
+  check_float ("jn (0, 0.1) == 0.99750156206604003228",  FUNC(jn) (0, 0.1L), 0.99750156206604003228L, 0, 0, 0);
+  check_float ("jn (0, 0.7) == 0.88120088860740528084",  FUNC(jn) (0, 0.7L), 0.88120088860740528084L, 0, 0, 0);
+  check_float ("jn (0, 1.0) == 0.76519768655796655145",  FUNC(jn) (0, 1.0), 0.76519768655796655145L, 0, 0, 0);
+  check_float ("jn (0, 1.5) == 0.51182767173591812875",  FUNC(jn) (0, 1.5), 0.51182767173591812875L, 0, 0, 0);
+  check_float ("jn (0, 2.0) == 0.22389077914123566805",  FUNC(jn) (0, 2.0), 0.22389077914123566805L, DELTA1075, 0, 0);
+  check_float ("jn (0, 8.0) == 0.17165080713755390609",  FUNC(jn) (0, 8.0), 0.17165080713755390609L, DELTA1076, 0, 0);
+  check_float ("jn (0, 10.0) == -0.24593576445134833520",  FUNC(jn) (0, 10.0), -0.24593576445134833520L, DELTA1077, 0, 0);
+
+  /* jn (1, x) == j1 (x)  */
+  check_float ("jn (1, NaN) == NaN",  FUNC(jn) (1, nan_value), nan_value, 0, 0, 0);
+  check_float ("jn (1, inf) == 0",  FUNC(jn) (1, plus_infty), 0, 0, 0, 0);
+
+  check_float ("jn (1, -1.0) == -0.44005058574493351596",  FUNC(jn) (1, -1.0), -0.44005058574493351596L, 0, 0, 0);
+  check_float ("jn (1, 0.0) == 0.0",  FUNC(jn) (1, 0.0), 0.0, 0, 0, 0);
+  check_float ("jn (1, 0.1) == 0.049937526036241997556",  FUNC(jn) (1, 0.1L), 0.049937526036241997556L, 0, 0, 0);
+  check_float ("jn (1, 0.7) == 0.32899574154005894785",  FUNC(jn) (1, 0.7L), 0.32899574154005894785L, 0, 0, 0);
+  check_float ("jn (1, 1.0) == 0.44005058574493351596",  FUNC(jn) (1, 1.0), 0.44005058574493351596L, 0, 0, 0);
+  check_float ("jn (1, 1.5) == 0.55793650791009964199",  FUNC(jn) (1, 1.5), 0.55793650791009964199L, 0, 0, 0);
+  check_float ("jn (1, 2.0) == 0.57672480775687338720",  FUNC(jn) (1, 2.0), 0.57672480775687338720L, DELTA1086, 0, 0);
+  check_float ("jn (1, 8.0) == 0.23463634685391462438",  FUNC(jn) (1, 8.0), 0.23463634685391462438L, DELTA1087, 0, 0);
+  check_float ("jn (1, 10.0) == 0.043472746168861436670",  FUNC(jn) (1, 10.0), 0.043472746168861436670L, DELTA1088, 0, 0);
+
+  /* jn (3, x)  */
+  check_float ("jn (3, NaN) == NaN",  FUNC(jn) (3, nan_value), nan_value, 0, 0, 0);
+  check_float ("jn (3, inf) == 0",  FUNC(jn) (3, plus_infty), 0, 0, 0, 0);
+
+  check_float ("jn (3, -1.0) == -0.019563353982668405919",  FUNC(jn) (3, -1.0), -0.019563353982668405919L, DELTA1091, 0, 0);
+  check_float ("jn (3, 0.0) == 0.0",  FUNC(jn) (3, 0.0), 0.0, 0, 0, 0);
+  check_float ("jn (3, 0.1) == 0.000020820315754756261429",  FUNC(jn) (3, 0.1L), 0.000020820315754756261429L, DELTA1093, 0, 0);
+  check_float ("jn (3, 0.7) == 0.0069296548267508408077",  FUNC(jn) (3, 0.7L), 0.0069296548267508408077L, DELTA1094, 0, 0);
+  check_float ("jn (3, 1.0) == 0.019563353982668405919",  FUNC(jn) (3, 1.0), 0.019563353982668405919L, DELTA1095, 0, 0);
+  check_float ("jn (3, 2.0) == 0.12894324947440205110",  FUNC(jn) (3, 2.0), 0.12894324947440205110L, DELTA1096, 0, 0);
+  check_float ("jn (3, 10.0) == 0.058379379305186812343",  FUNC(jn) (3, 10.0), 0.058379379305186812343L, DELTA1097, 0, 0);
+
+  /*  jn (10, x)  */
+  check_float ("jn (10, NaN) == NaN",  FUNC(jn) (10, nan_value), nan_value, 0, 0, 0);
+  check_float ("jn (10, inf) == 0",  FUNC(jn) (10, plus_infty), 0, 0, 0, 0);
+
+  check_float ("jn (10, -1.0) == 0.26306151236874532070e-9",  FUNC(jn) (10, -1.0), 0.26306151236874532070e-9L, DELTA1100, 0, 0);
+  check_float ("jn (10, 0.0) == 0.0",  FUNC(jn) (10, 0.0), 0.0, 0, 0, 0);
+  check_float ("jn (10, 0.1) == 0.26905328954342155795e-19",  FUNC(jn) (10, 0.1L), 0.26905328954342155795e-19L, DELTA1102, 0, 0);
+  check_float ("jn (10, 0.7) == 0.75175911502153953928e-11",  FUNC(jn) (10, 0.7L), 0.75175911502153953928e-11L, DELTA1103, 0, 0);
+  check_float ("jn (10, 1.0) == 0.26306151236874532070e-9",  FUNC(jn) (10, 1.0), 0.26306151236874532070e-9L, DELTA1104, 0, 0);
+  check_float ("jn (10, 2.0) == 0.25153862827167367096e-6",  FUNC(jn) (10, 2.0), 0.25153862827167367096e-6L, DELTA1105, 0, 0);
+  check_float ("jn (10, 10.0) == 0.20748610663335885770",  FUNC(jn) (10, 10.0), 0.20748610663335885770L, DELTA1106, 0, 0);
+
+  print_max_error ("jn", DELTAjn, 0);
+}
+
+
+static void
+ldexp_test (void)
+{
+  check_float ("ldexp (0, 0) == 0",  FUNC(ldexp) (0, 0), 0, 0, 0, 0);
+  check_float ("ldexp (-0, 0) == -0",  FUNC(ldexp) (minus_zero, 0), minus_zero, 0, 0, 0);
+
+  check_float ("ldexp (inf, 1) == inf",  FUNC(ldexp) (plus_infty, 1), plus_infty, 0, 0, 0);
+  check_float ("ldexp (-inf, 1) == -inf",  FUNC(ldexp) (minus_infty, 1), minus_infty, 0, 0, 0);
+  check_float ("ldexp (NaN, 1) == NaN",  FUNC(ldexp) (nan_value, 1), nan_value, 0, 0, 0);
+
+  check_float ("ldexp (0.8, 4) == 12.8",  FUNC(ldexp) (0.8L, 4), 12.8L, 0, 0, 0);
+  check_float ("ldexp (-0.854375, 5) == -27.34",  FUNC(ldexp) (-0.854375L, 5), -27.34L, 0, 0, 0);
+
+  /* ldexp (x, 0) == x.  */
+  check_float ("ldexp (1.0, 0) == 1.0",  FUNC(ldexp) (1.0L, 0L), 1.0L, 0, 0, 0);
+}
+
+static void
+lgamma_test (void)
+{
+  errno = 0;
+  FUNC(lgamma) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+  feclearexcept (FE_ALL_EXCEPT);
+
+  init_max_error ();
+
+  signgam = 0;
+  check_float ("lgamma (inf) == inf",  FUNC(lgamma) (plus_infty), plus_infty, 0, 0, 0);
+  signgam = 0;
+  check_float ("lgamma (0) == inf plus division by zero exception",  FUNC(lgamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  signgam = 0;
+  check_float ("lgamma (NaN) == NaN",  FUNC(lgamma) (nan_value), nan_value, 0, 0, 0);
+
+  /* lgamma (x) == +inf plus divide by zero exception for integer x <= 0.  */
+  signgam = 0;
+  check_float ("lgamma (-3) == inf plus division by zero exception",  FUNC(lgamma) (-3), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  signgam = 0;
+  check_float ("lgamma (-inf) == inf",  FUNC(lgamma) (minus_infty), plus_infty, 0, 0, 0);
+
+  signgam = 0;
+  check_float ("lgamma (1) == 0",  FUNC(lgamma) (1), 0, 0, 0, 0);
+  check_int ("lgamma (1) sets signgam to 1", signgam, 1, 0, 0, 0);
+
+  signgam = 0;
+  check_float ("lgamma (3) == M_LN2l",  FUNC(lgamma) (3), M_LN2l, 0, 0, 0);
+  check_int ("lgamma (3) sets signgam to 1", signgam, 1, 0, 0, 0);
+
+  signgam = 0;
+  check_float ("lgamma (0.5) == log(sqrt(pi))",  FUNC(lgamma) (0.5), M_LOG_SQRT_PIl, 0, 0, 0);
+  check_int ("lgamma (0.5) sets signgam to 1", signgam, 1, 0, 0, 0);
+  signgam = 0;
+  check_float ("lgamma (-0.5) == log(2*sqrt(pi))",  FUNC(lgamma) (-0.5), M_LOG_2_SQRT_PIl, DELTA1126, 0, 0);
+  check_int ("lgamma (-0.5) sets signgam to -1", signgam, -1, 0, 0, 0);
+  signgam = 0;
+  check_float ("lgamma (0.7) == 0.26086724653166651439",  FUNC(lgamma) (0.7L), 0.26086724653166651439L, DELTA1128, 0, 0);
+  check_int ("lgamma (0.7) sets signgam to 1", signgam, 1, 0, 0, 0);
+  signgam = 0;
+  check_float ("lgamma (1.2) == -0.853740900033158497197e-1",  FUNC(lgamma) (1.2L), -0.853740900033158497197e-1L, DELTA1130, 0, 0);
+  check_int ("lgamma (1.2) sets signgam to 1", signgam, 1, 0, 0, 0);
+
+  print_max_error ("lgamma", DELTAlgamma, 0);
+}
+
+static void
+lrint_test (void)
+{
+  /* XXX this test is incomplete.  We need to have a way to specifiy
+     the rounding method and test the critical cases.  So far, only
+     unproblematic numbers are tested.  */
+
+  init_max_error ();
+
+  check_long ("lrint (0.0) == 0",  FUNC(lrint) (0.0), 0, 0, 0, 0);
+  check_long ("lrint (-0) == 0",  FUNC(lrint) (minus_zero), 0, 0, 0, 0);
+  check_long ("lrint (0.2) == 0",  FUNC(lrint) (0.2L), 0, 0, 0, 0);
+  check_long ("lrint (-0.2) == 0",  FUNC(lrint) (-0.2L), 0, 0, 0, 0);
+
+  check_long ("lrint (1.4) == 1",  FUNC(lrint) (1.4L), 1, 0, 0, 0);
+  check_long ("lrint (-1.4) == -1",  FUNC(lrint) (-1.4L), -1, 0, 0, 0);
+
+  check_long ("lrint (8388600.3) == 8388600",  FUNC(lrint) (8388600.3L), 8388600, 0, 0, 0);
+  check_long ("lrint (-8388600.3) == -8388600",  FUNC(lrint) (-8388600.3L), -8388600, 0, 0, 0);
+
+  print_max_error ("lrint", 0, 0);
+}
+
+static void
+llrint_test (void)
+{
+  /* XXX this test is incomplete.  We need to have a way to specifiy
+     the rounding method and test the critical cases.  So far, only
+     unproblematic numbers are tested.  */
+
+  init_max_error ();
+
+  check_longlong ("llrint (0.0) == 0",  FUNC(llrint) (0.0), 0, 0, 0, 0);
+  check_longlong ("llrint (-0) == 0",  FUNC(llrint) (minus_zero), 0, 0, 0, 0);
+  check_longlong ("llrint (0.2) == 0",  FUNC(llrint) (0.2L), 0, 0, 0, 0);
+  check_longlong ("llrint (-0.2) == 0",  FUNC(llrint) (-0.2L), 0, 0, 0, 0);
+
+  check_longlong ("llrint (1.4) == 1",  FUNC(llrint) (1.4L), 1, 0, 0, 0);
+  check_longlong ("llrint (-1.4) == -1",  FUNC(llrint) (-1.4L), -1, 0, 0, 0);
+
+  check_longlong ("llrint (8388600.3) == 8388600",  FUNC(llrint) (8388600.3L), 8388600, 0, 0, 0);
+  check_longlong ("llrint (-8388600.3) == -8388600",  FUNC(llrint) (-8388600.3L), -8388600, 0, 0, 0);
+
+  /* Test boundary conditions.  */
+  /* 0x1FFFFF */
+  check_longlong ("llrint (2097151.0) == 2097151LL",  FUNC(llrint) (2097151.0), 2097151LL, 0, 0, 0);
+  /* 0x800000 */
+  check_longlong ("llrint (8388608.0) == 8388608LL",  FUNC(llrint) (8388608.0), 8388608LL, 0, 0, 0);
+  /* 0x1000000 */
+  check_longlong ("llrint (16777216.0) == 16777216LL",  FUNC(llrint) (16777216.0), 16777216LL, 0, 0, 0);
+  /* 0x20000000000 */
+  check_longlong ("llrint (2199023255552.0) == 2199023255552LL",  FUNC(llrint) (2199023255552.0), 2199023255552LL, 0, 0, 0);
+  /* 0x40000000000 */
+  check_longlong ("llrint (4398046511104.0) == 4398046511104LL",  FUNC(llrint) (4398046511104.0), 4398046511104LL, 0, 0, 0);
+  /* 0x10000000000000 */
+  check_longlong ("llrint (4503599627370496.0) == 4503599627370496LL",  FUNC(llrint) (4503599627370496.0), 4503599627370496LL, 0, 0, 0);
+  /* 0x10000080000000 */
+  check_longlong ("llrint (4503601774854144.0) == 4503601774854144LL",  FUNC(llrint) (4503601774854144.0), 4503601774854144LL, 0, 0, 0);
+  /* 0x20000000000000 */
+  check_longlong ("llrint (9007199254740992.0) == 9007199254740992LL",  FUNC(llrint) (9007199254740992.0), 9007199254740992LL, 0, 0, 0);
+  /* 0x80000000000000 */
+  check_longlong ("llrint (36028797018963968.0) == 36028797018963968LL",  FUNC(llrint) (36028797018963968.0), 36028797018963968LL, 0, 0, 0);
+  /* 0x100000000000000 */
+  check_longlong ("llrint (72057594037927936.0) == 72057594037927936LL",  FUNC(llrint) (72057594037927936.0), 72057594037927936LL, 0, 0, 0);
+
+  print_max_error ("llrint", 0, 0);
+}
+
+static void
+log_test (void)
+{
+  errno = 0;
+  FUNC(log) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+  init_max_error ();
+
+  check_float ("log (0) == -inf plus division by zero exception",  FUNC(log) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("log (-0) == -inf plus division by zero exception",  FUNC(log) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_float ("log (1) == 0",  FUNC(log) (1), 0, 0, 0, 0);
+
+  check_float ("log (-1) == NaN plus invalid exception",  FUNC(log) (-1), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("log (inf) == inf",  FUNC(log) (plus_infty), plus_infty, 0, 0, 0);
+
+  check_float ("log (e) == 1",  FUNC(log) (M_El), 1, DELTA1163, 0, 0);
+  check_float ("log (1.0 / M_El) == -1",  FUNC(log) (1.0 / M_El), -1, DELTA1164, 0, 0);
+  check_float ("log (2) == M_LN2l",  FUNC(log) (2), M_LN2l, 0, 0, 0);
+  check_float ("log (10) == M_LN10l",  FUNC(log) (10), M_LN10l, 0, 0, 0);
+  check_float ("log (0.7) == -0.35667494393873237891263871124118447",  FUNC(log) (0.7L), -0.35667494393873237891263871124118447L, DELTA1167, 0, 0);
+
+  print_max_error ("log", DELTAlog, 0);
+}
+
+
+static void
+log10_test (void)
+{
+  errno = 0;
+  FUNC(log10) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("log10 (0) == -inf plus division by zero exception",  FUNC(log10) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("log10 (-0) == -inf plus division by zero exception",  FUNC(log10) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_float ("log10 (1) == 0",  FUNC(log10) (1), 0, 0, 0, 0);
+
+  /* log10 (x) == NaN plus invalid exception if x < 0.  */
+  check_float ("log10 (-1) == NaN plus invalid exception",  FUNC(log10) (-1), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("log10 (inf) == inf",  FUNC(log10) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("log10 (NaN) == NaN",  FUNC(log10) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("log10 (0.1) == -1",  FUNC(log10) (0.1L), -1, 0, 0, 0);
+  check_float ("log10 (10.0) == 1",  FUNC(log10) (10.0), 1, 0, 0, 0);
+  check_float ("log10 (100.0) == 2",  FUNC(log10) (100.0), 2, 0, 0, 0);
+  check_float ("log10 (10000.0) == 4",  FUNC(log10) (10000.0), 4, 0, 0, 0);
+  check_float ("log10 (e) == log10(e)",  FUNC(log10) (M_El), M_LOG10El, DELTA1178, 0, 0);
+  check_float ("log10 (0.7) == -0.15490195998574316929",  FUNC(log10) (0.7L), -0.15490195998574316929L, DELTA1179, 0, 0);
+
+  print_max_error ("log10", DELTAlog10, 0);
+}
+
+
+static void
+log1p_test (void)
+{
+  errno = 0;
+  FUNC(log1p) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("log1p (0) == 0",  FUNC(log1p) (0), 0, 0, 0, 0);
+  check_float ("log1p (-0) == -0",  FUNC(log1p) (minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("log1p (-1) == -inf plus division by zero exception",  FUNC(log1p) (-1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("log1p (-2) == NaN plus invalid exception",  FUNC(log1p) (-2), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("log1p (inf) == inf",  FUNC(log1p) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("log1p (NaN) == NaN",  FUNC(log1p) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("log1p (M_El - 1.0) == 1",  FUNC(log1p) (M_El - 1.0), 1, DELTA1186, 0, 0);
+
+  check_float ("log1p (-0.3) == -0.35667494393873237891263871124118447",  FUNC(log1p) (-0.3L), -0.35667494393873237891263871124118447L, DELTA1187, 0, 0);
+
+  print_max_error ("log1p", DELTAlog1p, 0);
+}
+
+
+static void
+log2_test (void)
+{
+  errno = 0;
+  FUNC(log2) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("log2 (0) == -inf plus division by zero exception",  FUNC(log2) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("log2 (-0) == -inf plus division by zero exception",  FUNC(log2) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_float ("log2 (1) == 0",  FUNC(log2) (1), 0, 0, 0, 0);
+
+  check_float ("log2 (-1) == NaN plus invalid exception",  FUNC(log2) (-1), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("log2 (inf) == inf",  FUNC(log2) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("log2 (NaN) == NaN",  FUNC(log2) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("log2 (e) == M_LOG2El",  FUNC(log2) (M_El), M_LOG2El, 0, 0, 0);
+  check_float ("log2 (2.0) == 1",  FUNC(log2) (2.0), 1, 0, 0, 0);
+  check_float ("log2 (16.0) == 4",  FUNC(log2) (16.0), 4, 0, 0, 0);
+  check_float ("log2 (256.0) == 8",  FUNC(log2) (256.0), 8, 0, 0, 0);
+  check_float ("log2 (0.7) == -0.51457317282975824043",  FUNC(log2) (0.7L), -0.51457317282975824043L, DELTA1198, 0, 0);
+
+  print_max_error ("log2", DELTAlog2, 0);
+}
+
+
+static void
+logb_test (void)
+{
+  init_max_error ();
+
+  check_float ("logb (inf) == inf",  FUNC(logb) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("logb (-inf) == inf",  FUNC(logb) (minus_infty), plus_infty, 0, 0, 0);
+
+  check_float ("logb (0) == -inf plus division by zero exception",  FUNC(logb) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_float ("logb (-0) == -inf plus division by zero exception",  FUNC(logb) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("logb (NaN) == NaN",  FUNC(logb) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("logb (1) == 0",  FUNC(logb) (1), 0, 0, 0, 0);
+  check_float ("logb (e) == 1",  FUNC(logb) (M_El), 1, 0, 0, 0);
+  check_float ("logb (1024) == 10",  FUNC(logb) (1024), 10, 0, 0, 0);
+  check_float ("logb (-2000) == 10",  FUNC(logb) (-2000), 10, 0, 0, 0);
+
+  print_max_error ("logb", 0, 0);
+}
+
+static void
+lround_test (void)
+{
+  init_max_error ();
+
+  check_long ("lround (0) == 0",  FUNC(lround) (0), 0, 0, 0, 0);
+  check_long ("lround (-0) == 0",  FUNC(lround) (minus_zero), 0, 0, 0, 0);
+  check_long ("lround (0.2) == 0.0",  FUNC(lround) (0.2L), 0.0, 0, 0, 0);
+  check_long ("lround (-0.2) == 0",  FUNC(lround) (-0.2L), 0, 0, 0, 0);
+  check_long ("lround (0.5) == 1",  FUNC(lround) (0.5), 1, 0, 0, 0);
+  check_long ("lround (-0.5) == -1",  FUNC(lround) (-0.5), -1, 0, 0, 0);
+  check_long ("lround (0.8) == 1",  FUNC(lround) (0.8L), 1, 0, 0, 0);
+  check_long ("lround (-0.8) == -1",  FUNC(lround) (-0.8L), -1, 0, 0, 0);
+  check_long ("lround (1.5) == 2",  FUNC(lround) (1.5), 2, 0, 0, 0);
+  check_long ("lround (-1.5) == -2",  FUNC(lround) (-1.5), -2, 0, 0, 0);
+  check_long ("lround (22514.5) == 22515",  FUNC(lround) (22514.5), 22515, 0, 0, 0);
+  check_long ("lround (-22514.5) == -22515",  FUNC(lround) (-22514.5), -22515, 0, 0, 0);
+#ifndef TEST_FLOAT
+  check_long ("lround (2097152.5) == 2097153",  FUNC(lround) (2097152.5), 2097153, 0, 0, 0);
+  check_long ("lround (-2097152.5) == -2097153",  FUNC(lround) (-2097152.5), -2097153, 0, 0, 0);
+#endif
+  print_max_error ("lround", 0, 0);
+}
+
+
+static void
+llround_test (void)
+{
+  init_max_error ();
+
+  check_longlong ("llround (0) == 0",  FUNC(llround) (0), 0, 0, 0, 0);
+  check_longlong ("llround (-0) == 0",  FUNC(llround) (minus_zero), 0, 0, 0, 0);
+  check_longlong ("llround (0.2) == 0.0",  FUNC(llround) (0.2L), 0.0, 0, 0, 0);
+  check_longlong ("llround (-0.2) == 0",  FUNC(llround) (-0.2L), 0, 0, 0, 0);
+  check_longlong ("llround (0.5) == 1",  FUNC(llround) (0.5), 1, 0, 0, 0);
+  check_longlong ("llround (-0.5) == -1",  FUNC(llround) (-0.5), -1, 0, 0, 0);
+  check_longlong ("llround (0.8) == 1",  FUNC(llround) (0.8L), 1, 0, 0, 0);
+  check_longlong ("llround (-0.8) == -1",  FUNC(llround) (-0.8L), -1, 0, 0, 0);
+  check_longlong ("llround (1.5) == 2",  FUNC(llround) (1.5), 2, 0, 0, 0);
+  check_longlong ("llround (-1.5) == -2",  FUNC(llround) (-1.5), -2, 0, 0, 0);
+  check_longlong ("llround (22514.5) == 22515",  FUNC(llround) (22514.5), 22515, 0, 0, 0);
+  check_longlong ("llround (-22514.5) == -22515",  FUNC(llround) (-22514.5), -22515, 0, 0, 0);
+#ifndef TEST_FLOAT
+  check_longlong ("llround (2097152.5) == 2097153",  FUNC(llround) (2097152.5), 2097153, 0, 0, 0);
+  check_longlong ("llround (-2097152.5) == -2097153",  FUNC(llround) (-2097152.5), -2097153, 0, 0, 0);
+  check_longlong ("llround (34359738368.5) == 34359738369ll",  FUNC(llround) (34359738368.5), 34359738369ll, 0, 0, 0);
+  check_longlong ("llround (-34359738368.5) == -34359738369ll",  FUNC(llround) (-34359738368.5), -34359738369ll, 0, 0, 0);
+#endif
+
+  /* Test boundary conditions.  */
+  /* 0x1FFFFF */
+  check_longlong ("llround (2097151.0) == 2097151LL",  FUNC(llround) (2097151.0), 2097151LL, 0, 0, 0);
+  /* 0x800000 */
+  check_longlong ("llround (8388608.0) == 8388608LL",  FUNC(llround) (8388608.0), 8388608LL, 0, 0, 0);
+  /* 0x1000000 */
+  check_longlong ("llround (16777216.0) == 16777216LL",  FUNC(llround) (16777216.0), 16777216LL, 0, 0, 0);
+  /* 0x20000000000 */
+  check_longlong ("llround (2199023255552.0) == 2199023255552LL",  FUNC(llround) (2199023255552.0), 2199023255552LL, 0, 0, 0);
+  /* 0x40000000000 */
+  check_longlong ("llround (4398046511104.0) == 4398046511104LL",  FUNC(llround) (4398046511104.0), 4398046511104LL, 0, 0, 0);
+  /* 0x10000000000000 */
+  check_longlong ("llround (4503599627370496.0) == 4503599627370496LL",  FUNC(llround) (4503599627370496.0), 4503599627370496LL, 0, 0, 0);
+  /* 0x10000080000000 */
+  check_longlong ("llrint (4503601774854144.0) == 4503601774854144LL",  FUNC(llrint) (4503601774854144.0), 4503601774854144LL, 0, 0, 0);
+  /* 0x20000000000000 */
+  check_longlong ("llround (9007199254740992.0) == 9007199254740992LL",  FUNC(llround) (9007199254740992.0), 9007199254740992LL, 0, 0, 0);
+  /* 0x80000000000000 */
+  check_longlong ("llround (36028797018963968.0) == 36028797018963968LL",  FUNC(llround) (36028797018963968.0), 36028797018963968LL, 0, 0, 0);
+  /* 0x100000000000000 */
+  check_longlong ("llround (72057594037927936.0) == 72057594037927936LL",  FUNC(llround) (72057594037927936.0), 72057594037927936LL, 0, 0, 0);
+
+#ifndef TEST_FLOAT
+  /* 0x100000000 */
+  check_longlong ("llround (4294967295.5) == 4294967296LL",  FUNC(llround) (4294967295.5), 4294967296LL, 0, 0, 0);
+  /* 0x200000000 */
+  check_longlong ("llround (8589934591.5) == 8589934592LL",  FUNC(llround) (8589934591.5), 8589934592LL, 0, 0, 0);
+#endif
+
+  print_max_error ("llround", 0, 0);
+}
+
+static void
+modf_test (void)
+{
+  FLOAT x;
+
+  init_max_error ();
+
+  check_float ("modf (inf, &x) == 0",  FUNC(modf) (plus_infty, &x), 0, 0, 0, 0);
+  check_float ("modf (inf, &x) sets x to plus_infty", x, plus_infty, 0, 0, 0);
+  check_float ("modf (-inf, &x) == -0",  FUNC(modf) (minus_infty, &x), minus_zero, 0, 0, 0);
+  check_float ("modf (-inf, &x) sets x to minus_infty", x, minus_infty, 0, 0, 0);
+  check_float ("modf (NaN, &x) == NaN",  FUNC(modf) (nan_value, &x), nan_value, 0, 0, 0);
+  check_float ("modf (NaN, &x) sets x to nan_value", x, nan_value, 0, 0, 0);
+  check_float ("modf (0, &x) == 0",  FUNC(modf) (0, &x), 0, 0, 0, 0);
+  check_float ("modf (0, &x) sets x to 0", x, 0, 0, 0, 0);
+  check_float ("modf (1.5, &x) == 0.5",  FUNC(modf) (1.5, &x), 0.5, 0, 0, 0);
+  check_float ("modf (1.5, &x) sets x to 1", x, 1, 0, 0, 0);
+  check_float ("modf (2.5, &x) == 0.5",  FUNC(modf) (2.5, &x), 0.5, 0, 0, 0);
+  check_float ("modf (2.5, &x) sets x to 2", x, 2, 0, 0, 0);
+  check_float ("modf (-2.5, &x) == -0.5",  FUNC(modf) (-2.5, &x), -0.5, 0, 0, 0);
+  check_float ("modf (-2.5, &x) sets x to -2", x, -2, 0, 0, 0);
+  check_float ("modf (20, &x) == 0",  FUNC(modf) (20, &x), 0, 0, 0, 0);
+  check_float ("modf (20, &x) sets x to 20", x, 20, 0, 0, 0);
+  check_float ("modf (21, &x) == 0",  FUNC(modf) (21, &x), 0, 0, 0, 0);
+  check_float ("modf (21, &x) sets x to 21", x, 21, 0, 0, 0);
+  check_float ("modf (89.5, &x) == 0.5",  FUNC(modf) (89.5, &x), 0.5, 0, 0, 0);
+  check_float ("modf (89.5, &x) sets x to 89", x, 89, 0, 0, 0);
+
+  print_max_error ("modf", 0, 0);
+}
+
+static void
+nearbyint_test (void)
+{
+  init_max_error ();
+
+  check_float ("nearbyint (0.0) == 0.0",  FUNC(nearbyint) (0.0), 0.0, 0, 0, 0);
+  check_float ("nearbyint (-0) == -0",  FUNC(nearbyint) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("nearbyint (inf) == inf",  FUNC(nearbyint) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("nearbyint (-inf) == -inf",  FUNC(nearbyint) (minus_infty), minus_infty, 0, 0, 0);
+  check_float ("nearbyint (NaN) == NaN",  FUNC(nearbyint) (nan_value), nan_value, 0, 0, 0);
+
+  /* Default rounding mode is round to nearest.  */
+  check_float ("nearbyint (0.5) == 0.0",  FUNC(nearbyint) (0.5), 0.0, 0, 0, 0);
+  check_float ("nearbyint (1.5) == 2.0",  FUNC(nearbyint) (1.5), 2.0, 0, 0, 0);
+  check_float ("nearbyint (-0.5) == -0",  FUNC(nearbyint) (-0.5), minus_zero, 0, 0, 0);
+  check_float ("nearbyint (-1.5) == -2.0",  FUNC(nearbyint) (-1.5), -2.0, 0, 0, 0);
+
+  print_max_error ("nearbyint", 0, 0);
+}
+
+static void
+nextafter_test (void)
+{
+
+  init_max_error ();
+
+  check_float ("nextafter (0, 0) == 0",  FUNC(nextafter) (0, 0), 0, 0, 0, 0);
+  check_float ("nextafter (-0, 0) == 0",  FUNC(nextafter) (minus_zero, 0), 0, 0, 0, 0);
+  check_float ("nextafter (0, -0) == -0",  FUNC(nextafter) (0, minus_zero), minus_zero, 0, 0, 0);
+  check_float ("nextafter (-0, -0) == -0",  FUNC(nextafter) (minus_zero, minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("nextafter (9, 9) == 9",  FUNC(nextafter) (9, 9), 9, 0, 0, 0);
+  check_float ("nextafter (-9, -9) == -9",  FUNC(nextafter) (-9, -9), -9, 0, 0, 0);
+  check_float ("nextafter (inf, inf) == inf",  FUNC(nextafter) (plus_infty, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("nextafter (-inf, -inf) == -inf",  FUNC(nextafter) (minus_infty, minus_infty), minus_infty, 0, 0, 0);
+
+  check_float ("nextafter (NaN, 1.1) == NaN",  FUNC(nextafter) (nan_value, 1.1L), nan_value, 0, 0, 0);
+  check_float ("nextafter (1.1, NaN) == NaN",  FUNC(nextafter) (1.1L, nan_value), nan_value, 0, 0, 0);
+  check_float ("nextafter (NaN, NaN) == NaN",  FUNC(nextafter) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  /* XXX We need the hexadecimal FP number representation here for further
+     tests.  */
+
+  print_max_error ("nextafter", 0, 0);
+}
+
+
+#if 0 /* XXX scp XXX */
+static void
+nexttoward_test (void)
+{
+  init_max_error ();
+  check_float ("nexttoward (0, 0) == 0",  FUNC(nexttoward) (0, 0), 0, 0, 0, 0);
+  check_float ("nexttoward (-0, 0) == 0",  FUNC(nexttoward) (minus_zero, 0), 0, 0, 0, 0);
+  check_float ("nexttoward (0, -0) == -0",  FUNC(nexttoward) (0, minus_zero), minus_zero, 0, 0, 0);
+  check_float ("nexttoward (-0, -0) == -0",  FUNC(nexttoward) (minus_zero, minus_zero), minus_zero, 0, 0, 0);
+
+  check_float ("nexttoward (9, 9) == 9",  FUNC(nexttoward) (9, 9), 9, 0, 0, 0);
+  check_float ("nexttoward (-9, -9) == -9",  FUNC(nexttoward) (-9, -9), -9, 0, 0, 0);
+  check_float ("nexttoward (inf, inf) == inf",  FUNC(nexttoward) (plus_infty, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("nexttoward (-inf, -inf) == -inf",  FUNC(nexttoward) (minus_infty, minus_infty), minus_infty, 0, 0, 0);
+
+  check_float ("nexttoward (NaN, 1.1) == NaN",  FUNC(nexttoward) (nan_value, 1.1L), nan_value, 0, 0, 0);
+  check_float ("nexttoward (1.1, NaN) == NaN",  FUNC(nexttoward) (1.1L, nan_value), nan_value, 0, 0, 0);
+  check_float ("nexttoward (NaN, NaN) == NaN",  FUNC(nexttoward) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  /* XXX We need the hexadecimal FP number representation here for further
+     tests.  */
+
+  print_max_error ("nexttoward", 0, 0);
+}
+#endif
+
+
+static void
+pow_test (void)
+{
+
+  errno = 0;
+  FUNC(pow) (0, 0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("pow (0, 0) == 1",  FUNC(pow) (0, 0), 1, 0, 0, 0);
+  check_float ("pow (0, -0) == 1",  FUNC(pow) (0, minus_zero), 1, 0, 0, 0);
+  check_float ("pow (-0, 0) == 1",  FUNC(pow) (minus_zero, 0), 1, 0, 0, 0);
+  check_float ("pow (-0, -0) == 1",  FUNC(pow) (minus_zero, minus_zero), 1, 0, 0, 0);
+
+  check_float ("pow (10, 0) == 1",  FUNC(pow) (10, 0), 1, 0, 0, 0);
+  check_float ("pow (10, -0) == 1",  FUNC(pow) (10, minus_zero), 1, 0, 0, 0);
+  check_float ("pow (-10, 0) == 1",  FUNC(pow) (-10, 0), 1, 0, 0, 0);
+  check_float ("pow (-10, -0) == 1",  FUNC(pow) (-10, minus_zero), 1, 0, 0, 0);
+
+  check_float ("pow (NaN, 0) == 1",  FUNC(pow) (nan_value, 0), 1, 0, 0, 0);
+  check_float ("pow (NaN, -0) == 1",  FUNC(pow) (nan_value, minus_zero), 1, 0, 0, 0);
+
+
+#ifndef TEST_INLINE
+  check_float ("pow (1.1, inf) == inf",  FUNC(pow) (1.1L, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (inf, inf) == inf",  FUNC(pow) (plus_infty, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (-1.1, inf) == inf",  FUNC(pow) (-1.1L, plus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, inf) == inf",  FUNC(pow) (minus_infty, plus_infty), plus_infty, 0, 0, 0);
+
+  check_float ("pow (0.9, inf) == 0",  FUNC(pow) (0.9L, plus_infty), 0, 0, 0, 0);
+  check_float ("pow (1e-7, inf) == 0",  FUNC(pow) (1e-7L, plus_infty), 0, 0, 0, 0);
+  check_float ("pow (-0.9, inf) == 0",  FUNC(pow) (-0.9L, plus_infty), 0, 0, 0, 0);
+  check_float ("pow (-1e-7, inf) == 0",  FUNC(pow) (-1e-7L, plus_infty), 0, 0, 0, 0);
+
+  check_float ("pow (1.1, -inf) == 0",  FUNC(pow) (1.1L, minus_infty), 0, 0, 0, 0);
+  check_float ("pow (inf, -inf) == 0",  FUNC(pow) (plus_infty, minus_infty), 0, 0, 0, 0);
+  check_float ("pow (-1.1, -inf) == 0",  FUNC(pow) (-1.1L, minus_infty), 0, 0, 0, 0);
+  check_float ("pow (-inf, -inf) == 0",  FUNC(pow) (minus_infty, minus_infty), 0, 0, 0, 0);
+
+  check_float ("pow (0.9, -inf) == inf",  FUNC(pow) (0.9L, minus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (1e-7, -inf) == inf",  FUNC(pow) (1e-7L, minus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (-0.9, -inf) == inf",  FUNC(pow) (-0.9L, minus_infty), plus_infty, 0, 0, 0);
+  check_float ("pow (-1e-7, -inf) == inf",  FUNC(pow) (-1e-7L, minus_infty), plus_infty, 0, 0, 0);
+
+  check_float ("pow (inf, 1e-7) == inf",  FUNC(pow) (plus_infty, 1e-7L), plus_infty, 0, 0, 0);
+  check_float ("pow (inf, 1) == inf",  FUNC(pow) (plus_infty, 1), plus_infty, 0, 0, 0);
+  check_float ("pow (inf, 1e7) == inf",  FUNC(pow) (plus_infty, 1e7L), plus_infty, 0, 0, 0);
+
+  check_float ("pow (inf, -1e-7) == 0",  FUNC(pow) (plus_infty, -1e-7L), 0, 0, 0, 0);
+  check_float ("pow (inf, -1) == 0",  FUNC(pow) (plus_infty, -1), 0, 0, 0, 0);
+  check_float ("pow (inf, -1e7) == 0",  FUNC(pow) (plus_infty, -1e7L), 0, 0, 0, 0);
+
+  check_float ("pow (-inf, 1) == -inf",  FUNC(pow) (minus_infty, 1), minus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 11) == -inf",  FUNC(pow) (minus_infty, 11), minus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 1001) == -inf",  FUNC(pow) (minus_infty, 1001), minus_infty, 0, 0, 0);
+
+  check_float ("pow (-inf, 2) == inf",  FUNC(pow) (minus_infty, 2), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 12) == inf",  FUNC(pow) (minus_infty, 12), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 1002) == inf",  FUNC(pow) (minus_infty, 1002), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 0.1) == inf",  FUNC(pow) (minus_infty, 0.1L), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 1.1) == inf",  FUNC(pow) (minus_infty, 1.1L), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 11.1) == inf",  FUNC(pow) (minus_infty, 11.1L), plus_infty, 0, 0, 0);
+  check_float ("pow (-inf, 1001.1) == inf",  FUNC(pow) (minus_infty, 1001.1L), plus_infty, 0, 0, 0);
+
+  check_float ("pow (-inf, -1) == -0",  FUNC(pow) (minus_infty, -1), minus_zero, 0, 0, 0);
+  check_float ("pow (-inf, -11) == -0",  FUNC(pow) (minus_infty, -11), minus_zero, 0, 0, 0);
+  check_float ("pow (-inf, -1001) == -0",  FUNC(pow) (minus_infty, -1001), minus_zero, 0, 0, 0);
+
+  check_float ("pow (-inf, -2) == 0",  FUNC(pow) (minus_infty, -2), 0, 0, 0, 0);
+  check_float ("pow (-inf, -12) == 0",  FUNC(pow) (minus_infty, -12), 0, 0, 0, 0);
+  check_float ("pow (-inf, -1002) == 0",  FUNC(pow) (minus_infty, -1002), 0, 0, 0, 0);
+  check_float ("pow (-inf, -0.1) == 0",  FUNC(pow) (minus_infty, -0.1L), 0, 0, 0, 0);
+  check_float ("pow (-inf, -1.1) == 0",  FUNC(pow) (minus_infty, -1.1L), 0, 0, 0, 0);
+  check_float ("pow (-inf, -11.1) == 0",  FUNC(pow) (minus_infty, -11.1L), 0, 0, 0, 0);
+  check_float ("pow (-inf, -1001.1) == 0",  FUNC(pow) (minus_infty, -1001.1L), 0, 0, 0, 0);
+#endif
+
+  check_float ("pow (NaN, NaN) == NaN",  FUNC(pow) (nan_value, nan_value), nan_value, 0, 0, 0);
+  check_float ("pow (0, NaN) == NaN",  FUNC(pow) (0, nan_value), nan_value, 0, 0, 0);
+  check_float ("pow (1, NaN) == 1",  FUNC(pow) (1, nan_value), 1, 0, 0, 0);
+  check_float ("pow (-1, NaN) == NaN",  FUNC(pow) (-1, nan_value), nan_value, 0, 0, 0);
+  check_float ("pow (NaN, 1) == NaN",  FUNC(pow) (nan_value, 1), nan_value, 0, 0, 0);
+  check_float ("pow (NaN, -1) == NaN",  FUNC(pow) (nan_value, -1), nan_value, 0, 0, 0);
+
+  /* pow (x, NaN) == NaN.  */
+  check_float ("pow (3.0, NaN) == NaN",  FUNC(pow) (3.0, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("pow (1, inf) == 1",  FUNC(pow) (1, plus_infty), 1, 0, 0, 0);
+  check_float ("pow (-1, inf) == 1",  FUNC(pow) (-1, plus_infty), 1, 0, 0, 0);
+  check_float ("pow (1, -inf) == 1",  FUNC(pow) (1, minus_infty), 1, 0, 0, 0);
+  check_float ("pow (-1, -inf) == 1",  FUNC(pow) (-1, minus_infty), 1, 0, 0, 0);
+
+  check_float ("pow (-0.1, 1.1) == NaN plus invalid exception",  FUNC(pow) (-0.1L, 1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("pow (-0.1, -1.1) == NaN plus invalid exception",  FUNC(pow) (-0.1L, -1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("pow (-10.1, 1.1) == NaN plus invalid exception",  FUNC(pow) (-10.1L, 1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("pow (-10.1, -1.1) == NaN plus invalid exception",  FUNC(pow) (-10.1L, -1.1L), nan_value, 0, 0, INVALID_EXCEPTION);
+
+  check_float ("pow (0, -1) == inf plus division by zero exception",  FUNC(pow) (0, -1), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (0, -11) == inf plus division by zero exception",  FUNC(pow) (0, -11), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (-0, -1) == -inf plus division by zero exception",  FUNC(pow) (minus_zero, -1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (-0, -11) == -inf plus division by zero exception",  FUNC(pow) (minus_zero, -11), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+  check_float ("pow (0, -2) == inf plus division by zero exception",  FUNC(pow) (0, -2), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (0, -11.1) == inf plus division by zero exception",  FUNC(pow) (0, -11.1L), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (-0, -2) == inf plus division by zero exception",  FUNC(pow) (minus_zero, -2), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("pow (-0, -11.1) == inf plus division by zero exception",  FUNC(pow) (minus_zero, -11.1L), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+
+
+  check_float ("pow (0, 1) == 0",  FUNC(pow) (0, 1), 0, 0, 0, 0);
+  check_float ("pow (0, 11) == 0",  FUNC(pow) (0, 11), 0, 0, 0, 0);
+
+  check_float ("pow (-0, 1) == -0",  FUNC(pow) (minus_zero, 1), minus_zero, 0, 0, 0);
+  check_float ("pow (-0, 11) == -0",  FUNC(pow) (minus_zero, 11), minus_zero, 0, 0, 0);
+
+
+  check_float ("pow (0, 2) == 0",  FUNC(pow) (0, 2), 0, 0, 0, 0);
+  check_float ("pow (0, 11.1) == 0",  FUNC(pow) (0, 11.1L), 0, 0, 0, 0);
+
+
+  check_float ("pow (-0, 2) == 0",  FUNC(pow) (minus_zero, 2), 0, 0, 0, 0);
+  check_float ("pow (-0, 11.1) == 0",  FUNC(pow) (minus_zero, 11.1L), 0, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  /* pow (x, +inf) == +inf for |x| > 1.  */
+  check_float ("pow (1.5, inf) == inf",  FUNC(pow) (1.5, plus_infty), plus_infty, 0, 0, 0);
+
+  /* pow (x, +inf) == +0 for |x| < 1.  */
+  check_float ("pow (0.5, inf) == 0.0",  FUNC(pow) (0.5, plus_infty), 0.0, 0, 0, 0);
+
+  /* pow (x, -inf) == +0 for |x| > 1.  */
+  check_float ("pow (1.5, -inf) == 0.0",  FUNC(pow) (1.5, minus_infty), 0.0, 0, 0, 0);
+
+  /* pow (x, -inf) == +inf for |x| < 1.  */
+  check_float ("pow (0.5, -inf) == inf",  FUNC(pow) (0.5, minus_infty), plus_infty, 0, 0, 0);
+#endif
+
+  /* pow (+inf, y) == +inf for y > 0.  */
+  check_float ("pow (inf, 2) == inf",  FUNC(pow) (plus_infty, 2), plus_infty, 0, 0, 0);
+
+  /* pow (+inf, y) == +0 for y < 0.  */
+  check_float ("pow (inf, -1) == 0.0",  FUNC(pow) (plus_infty, -1), 0.0, 0, 0, 0);
+
+  /* pow (-inf, y) == -inf for y an odd integer > 0.  */
+  check_float ("pow (-inf, 27) == -inf",  FUNC(pow) (minus_infty, 27), minus_infty, 0, 0, 0);
+
+  /* pow (-inf, y) == +inf for y > 0 and not an odd integer.  */
+  check_float ("pow (-inf, 28) == inf",  FUNC(pow) (minus_infty, 28), plus_infty, 0, 0, 0);
+
+  /* pow (-inf, y) == -0 for y an odd integer < 0. */
+  check_float ("pow (-inf, -3) == -0",  FUNC(pow) (minus_infty, -3), minus_zero, 0, 0, 0);
+  /* pow (-inf, y) == +0 for y < 0 and not an odd integer.  */
+  check_float ("pow (-inf, -2.0) == 0.0",  FUNC(pow) (minus_infty, -2.0), 0.0, 0, 0, 0);
+
+  /* pow (+0, y) == +0 for y an odd integer > 0.  */
+  check_float ("pow (0.0, 27) == 0.0",  FUNC(pow) (0.0, 27), 0.0, 0, 0, 0);
+
+  /* pow (-0, y) == -0 for y an odd integer > 0.  */
+  check_float ("pow (-0, 27) == -0",  FUNC(pow) (minus_zero, 27), minus_zero, 0, 0, 0);
+
+  /* pow (+0, y) == +0 for y > 0 and not an odd integer.  */
+  check_float ("pow (0.0, 4) == 0.0",  FUNC(pow) (0.0, 4), 0.0, 0, 0, 0);
+
+  /* pow (-0, y) == +0 for y > 0 and not an odd integer.  */
+  check_float ("pow (-0, 4) == 0.0",  FUNC(pow) (minus_zero, 4), 0.0, 0, 0, 0);
+
+  check_float ("pow (0.7, 1.2) == 0.65180494056638638188",  FUNC(pow) (0.7L, 1.2L), 0.65180494056638638188L, DELTA1398, 0, 0);
+
+#if defined TEST_DOUBLE || defined TEST_LDOUBLE
+  check_float ("pow (-7.49321e+133, -9.80818e+16) == 0",  FUNC(pow) (-7.49321e+133, -9.80818e+16), 0, 0, 0, 0);
+#endif
+
+  print_max_error ("pow", DELTApow, 0);
+}
+
+static void
+remainder_test (void)
+{
+  errno = 0;
+  FUNC(remainder) (1.625, 1.0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("remainder (1, 0) == NaN plus invalid exception",  FUNC(remainder) (1, 0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remainder (1, -0) == NaN plus invalid exception",  FUNC(remainder) (1, minus_zero), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remainder (inf, 1) == NaN plus invalid exception",  FUNC(remainder) (plus_infty, 1), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remainder (-inf, 1) == NaN plus invalid exception",  FUNC(remainder) (minus_infty, 1), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remainder (NaN, NaN) == NaN",  FUNC(remainder) (nan_value, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("remainder (1.625, 1.0) == -0.375",  FUNC(remainder) (1.625, 1.0), -0.375, 0, 0, 0);
+  check_float ("remainder (-1.625, 1.0) == 0.375",  FUNC(remainder) (-1.625, 1.0), 0.375, 0, 0, 0);
+  check_float ("remainder (1.625, -1.0) == -0.375",  FUNC(remainder) (1.625, -1.0), -0.375, 0, 0, 0);
+  check_float ("remainder (-1.625, -1.0) == 0.375",  FUNC(remainder) (-1.625, -1.0), 0.375, 0, 0, 0);
+  check_float ("remainder (5.0, 2.0) == 1.0",  FUNC(remainder) (5.0, 2.0), 1.0, 0, 0, 0);
+  check_float ("remainder (3.0, 2.0) == -1.0",  FUNC(remainder) (3.0, 2.0), -1.0, 0, 0, 0);
+
+  print_max_error ("remainder", 0, 0);
+}
+
+static void
+remquo_test (void)
+{
+  /* x is needed.  */
+  int x;
+
+  errno = 0;
+  FUNC(remquo) (1.625, 1.0, &x);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("remquo (1, 0, &x) == NaN plus invalid exception",  FUNC(remquo) (1, 0, &x), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remquo (1, -0, &x) == NaN plus invalid exception",  FUNC(remquo) (1, minus_zero, &x), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remquo (inf, 1, &x) == NaN plus invalid exception",  FUNC(remquo) (plus_infty, 1, &x), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remquo (-inf, 1, &x) == NaN plus invalid exception",  FUNC(remquo) (minus_infty, 1, &x), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("remquo (NaN, NaN, &x) == NaN",  FUNC(remquo) (nan_value, nan_value, &x), nan_value, 0, 0, 0);
+
+  check_float ("remquo (1.625, 1.0, &x) == -0.375",  FUNC(remquo) (1.625, 1.0, &x), -0.375, 0, 0, 0);
+  check_int ("remquo (1.625, 1.0, &x) sets x to 2", x, 2, 0, 0, 0);
+  check_float ("remquo (-1.625, 1.0, &x) == 0.375",  FUNC(remquo) (-1.625, 1.0, &x), 0.375, 0, 0, 0);
+  check_int ("remquo (-1.625, 1.0, &x) sets x to -2", x, -2, 0, 0, 0);
+  check_float ("remquo (1.625, -1.0, &x) == -0.375",  FUNC(remquo) (1.625, -1.0, &x), -0.375, 0, 0, 0);
+  check_int ("remquo (1.625, -1.0, &x) sets x to -2", x, -2, 0, 0, 0);
+  check_float ("remquo (-1.625, -1.0, &x) == 0.375",  FUNC(remquo) (-1.625, -1.0, &x), 0.375, 0, 0, 0);
+  check_int ("remquo (-1.625, -1.0, &x) sets x to 2", x, 2, 0, 0, 0);
+
+  check_float ("remquo (5, 2, &x) == 1",  FUNC(remquo) (5, 2, &x), 1, 0, 0, 0);
+  check_int ("remquo (5, 2, &x) sets x to 2", x, 2, 0, 0, 0);
+  check_float ("remquo (3, 2, &x) == -1",  FUNC(remquo) (3, 2, &x), -1, 0, 0, 0);
+  check_int ("remquo (3, 2, &x) sets x to 2", x, 2, 0, 0, 0);
+
+  print_max_error ("remquo", 0, 0);
+}
+
+static void
+rint_test (void)
+{
+  init_max_error ();
+
+  check_float ("rint (0.0) == 0.0",  FUNC(rint) (0.0), 0.0, 0, 0, 0);
+  check_float ("rint (-0) == -0",  FUNC(rint) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("rint (inf) == inf",  FUNC(rint) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("rint (-inf) == -inf",  FUNC(rint) (minus_infty), minus_infty, 0, 0, 0);
+
+  /* Default rounding mode is round to even.  */
+  check_float ("rint (0.5) == 0.0",  FUNC(rint) (0.5), 0.0, 0, 0, 0);
+  check_float ("rint (1.5) == 2.0",  FUNC(rint) (1.5), 2.0, 0, 0, 0);
+  check_float ("rint (2.5) == 2.0",  FUNC(rint) (2.5), 2.0, 0, 0, 0);
+  check_float ("rint (3.5) == 4.0",  FUNC(rint) (3.5), 4.0, 0, 0, 0);
+  check_float ("rint (4.5) == 4.0",  FUNC(rint) (4.5), 4.0, 0, 0, 0);
+  check_float ("rint (-0.5) == -0.0",  FUNC(rint) (-0.5), -0.0, 0, 0, 0);
+  check_float ("rint (-1.5) == -2.0",  FUNC(rint) (-1.5), -2.0, 0, 0, 0);
+  check_float ("rint (-2.5) == -2.0",  FUNC(rint) (-2.5), -2.0, 0, 0, 0);
+  check_float ("rint (-3.5) == -4.0",  FUNC(rint) (-3.5), -4.0, 0, 0, 0);
+  check_float ("rint (-4.5) == -4.0",  FUNC(rint) (-4.5), -4.0, 0, 0, 0);
+
+  print_max_error ("rint", 0, 0);
+}
+
+static void
+round_test (void)
+{
+  init_max_error ();
+
+  check_float ("round (0) == 0",  FUNC(round) (0), 0, 0, 0, 0);
+  check_float ("round (-0) == -0",  FUNC(round) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("round (0.2) == 0.0",  FUNC(round) (0.2L), 0.0, 0, 0, 0);
+  check_float ("round (-0.2) == -0",  FUNC(round) (-0.2L), minus_zero, 0, 0, 0);
+  check_float ("round (0.5) == 1.0",  FUNC(round) (0.5), 1.0, 0, 0, 0);
+  check_float ("round (-0.5) == -1.0",  FUNC(round) (-0.5), -1.0, 0, 0, 0);
+  check_float ("round (0.8) == 1.0",  FUNC(round) (0.8L), 1.0, 0, 0, 0);
+  check_float ("round (-0.8) == -1.0",  FUNC(round) (-0.8L), -1.0, 0, 0, 0);
+  check_float ("round (1.5) == 2.0",  FUNC(round) (1.5), 2.0, 0, 0, 0);
+  check_float ("round (-1.5) == -2.0",  FUNC(round) (-1.5), -2.0, 0, 0, 0);
+  check_float ("round (2097152.5) == 2097153",  FUNC(round) (2097152.5), 2097153, 0, 0, 0);
+  check_float ("round (-2097152.5) == -2097153",  FUNC(round) (-2097152.5), -2097153, 0, 0, 0);
+
+  print_max_error ("round", 0, 0);
+}
+
+
+static void
+scalbn_test (void)
+{
+
+  init_max_error ();
+
+  check_float ("scalbn (0, 0) == 0",  FUNC(scalbn) (0, 0), 0, 0, 0, 0);
+  check_float ("scalbn (-0, 0) == -0",  FUNC(scalbn) (minus_zero, 0), minus_zero, 0, 0, 0);
+
+  check_float ("scalbn (inf, 1) == inf",  FUNC(scalbn) (plus_infty, 1), plus_infty, 0, 0, 0);
+  check_float ("scalbn (-inf, 1) == -inf",  FUNC(scalbn) (minus_infty, 1), minus_infty, 0, 0, 0);
+  check_float ("scalbn (NaN, 1) == NaN",  FUNC(scalbn) (nan_value, 1), nan_value, 0, 0, 0);
+
+  check_float ("scalbn (0.8, 4) == 12.8",  FUNC(scalbn) (0.8L, 4), 12.8L, 0, 0, 0);
+  check_float ("scalbn (-0.854375, 5) == -27.34",  FUNC(scalbn) (-0.854375L, 5), -27.34L, 0, 0, 0);
+
+  check_float ("scalbn (1, 0) == 1",  FUNC(scalbn) (1, 0L), 1, 0, 0, 0);
+
+  print_max_error ("scalbn", 0, 0);
+}
+
+static void
+scalbln_test (void)
+{
+
+  init_max_error ();
+
+  check_float ("scalbln (0, 0) == 0",  FUNC(scalbln) (0, 0), 0, 0, 0, 0);
+  check_float ("scalbln (-0, 0) == -0",  FUNC(scalbln) (minus_zero, 0), minus_zero, 0, 0, 0);
+
+  check_float ("scalbln (inf, 1) == inf",  FUNC(scalbln) (plus_infty, 1), plus_infty, 0, 0, 0);
+  check_float ("scalbln (-inf, 1) == -inf",  FUNC(scalbln) (minus_infty, 1), minus_infty, 0, 0, 0);
+  check_float ("scalbln (NaN, 1) == NaN",  FUNC(scalbln) (nan_value, 1), nan_value, 0, 0, 0);
+
+  check_float ("scalbln (0.8, 4) == 12.8",  FUNC(scalbln) (0.8L, 4), 12.8L, 0, 0, 0);
+  check_float ("scalbln (-0.854375, 5) == -27.34",  FUNC(scalbln) (-0.854375L, 5), -27.34L, 0, 0, 0);
+
+  check_float ("scalbln (1, 0) == 1",  FUNC(scalbln) (1, 0L), 1, 0, 0, 0);
+
+  print_max_error ("scalbn", 0, 0);
+}
+
+static void
+signbit_test (void)
+{
+
+  init_max_error ();
+
+  check_bool ("signbit (0) == false", signbit (0.0), 0, 0, 0, 0);
+  check_bool ("signbit (-0) == true", signbit (minus_zero), 1, 0, 0, 0);
+  check_bool ("signbit (inf) == false", signbit (plus_infty), 0, 0, 0, 0);
+  check_bool ("signbit (-inf) == true", signbit (minus_infty), 1, 0, 0, 0);
+
+  /* signbit (x) != 0 for x < 0.  */
+  check_bool ("signbit (-1) == true", signbit (-1.0), 1, 0, 0, 0);
+  /* signbit (x) == 0 for x >= 0.  */
+  check_bool ("signbit (1) == false", signbit (1.0), 0, 0, 0, 0);
+
+  print_max_error ("signbit", 0, 0);
+}
+
+static void
+sin_test (void)
+{
+  errno = 0;
+  FUNC(sin) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("sin (0) == 0",  FUNC(sin) (0), 0, 0, 0, 0);
+  check_float ("sin (-0) == -0",  FUNC(sin) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("sin (inf) == NaN plus invalid exception",  FUNC(sin) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sin (-inf) == NaN plus invalid exception",  FUNC(sin) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sin (NaN) == NaN",  FUNC(sin) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("sin (pi/6) == 0.5",  FUNC(sin) (M_PI_6l), 0.5, 0, 0, 0);
+  check_float ("sin (-pi/6) == -0.5",  FUNC(sin) (-M_PI_6l), -0.5, 0, 0, 0);
+  check_float ("sin (pi/2) == 1",  FUNC(sin) (M_PI_2l), 1, 0, 0, 0);
+  check_float ("sin (-pi/2) == -1",  FUNC(sin) (-M_PI_2l), -1, 0, 0, 0);
+  check_float ("sin (0.7) == 0.64421768723769105367261435139872014",  FUNC(sin) (0.7L), 0.64421768723769105367261435139872014L, DELTA1524, 0, 0);
+
+  print_max_error ("sin", DELTAsin, 0);
+
+}
+
+
+static void
+sincos_test (void)
+{
+  FLOAT sin_res, cos_res;
+
+  errno = 0;
+  FUNC(sincos) (0, &sin_res, &cos_res);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  /* sincos is treated differently because it returns void.  */
+  FUNC (sincos) (0, &sin_res, &cos_res);
+  check_float ("sincos (0, &sin_res, &cos_res) puts 0 in sin_res", sin_res, 0, 0, 0, 0);
+  check_float ("sincos (0, &sin_res, &cos_res) puts 1 in cos_res", cos_res, 1, 0, 0, 0);
+
+  FUNC (sincos) (minus_zero, &sin_res, &cos_res);
+  check_float ("sincos (-0, &sin_res, &cos_res) puts -0 in sin_res", sin_res, minus_zero, 0, 0, 0);
+  check_float ("sincos (-0, &sin_res, &cos_res) puts 1 in cos_res", cos_res, 1, 0, 0, 0);
+  FUNC (sincos) (plus_infty, &sin_res, &cos_res);
+  check_float ("sincos (inf, &sin_res, &cos_res) puts NaN in sin_res plus invalid exception", sin_res, nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sincos (inf, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0);
+  FUNC (sincos) (minus_infty, &sin_res, &cos_res);
+  check_float ("sincos (-inf, &sin_res, &cos_res) puts NaN in sin_res plus invalid exception", sin_res, nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sincos (-inf, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0);
+  FUNC (sincos) (nan_value, &sin_res, &cos_res);
+  check_float ("sincos (NaN, &sin_res, &cos_res) puts NaN in sin_res", sin_res, nan_value, 0, 0, 0);
+  check_float ("sincos (NaN, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0);
+
+  FUNC (sincos) (M_PI_2l, &sin_res, &cos_res);
+  check_float ("sincos (pi/2, &sin_res, &cos_res) puts 1 in sin_res", sin_res, 1, 0, 0, 0);
+  check_float ("sincos (pi/2, &sin_res, &cos_res) puts 0 in cos_res", cos_res, 0, DELTA1536, 0, 0);
+  FUNC (sincos) (M_PI_6l, &sin_res, &cos_res);
+  check_float ("sincos (pi/6, &sin_res, &cos_res) puts 0.5 in sin_res", sin_res, 0.5, 0, 0, 0);
+  check_float ("sincos (pi/6, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in cos_res", cos_res, 0.86602540378443864676372317075293616L, 0, 0, 0);
+  FUNC (sincos) (M_PI_6l*2.0, &sin_res, &cos_res);
+  check_float ("sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in sin_res", sin_res, 0.86602540378443864676372317075293616L, DELTA1539, 0, 0);
+  check_float ("sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.5 in cos_res", cos_res, 0.5, DELTA1540, 0, 0);
+  FUNC (sincos) (0.7L, &sin_res, &cos_res);
+  check_float ("sincos (0.7, &sin_res, &cos_res) puts 0.64421768723769105367261435139872014 in sin_res", sin_res, 0.64421768723769105367261435139872014L, DELTA1541, 0, 0);
+  check_float ("sincos (0.7, &sin_res, &cos_res) puts 0.76484218728448842625585999019186495 in cos_res", cos_res, 0.76484218728448842625585999019186495L, DELTA1542, 0, 0);
+
+  print_max_error ("sincos", DELTAsincos, 0);
+}
+
+static void
+sinh_test (void)
+{
+  errno = 0;
+  FUNC(sinh) (0.7L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+  check_float ("sinh (0) == 0",  FUNC(sinh) (0), 0, 0, 0, 0);
+  check_float ("sinh (-0) == -0",  FUNC(sinh) (minus_zero), minus_zero, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  check_float ("sinh (inf) == inf",  FUNC(sinh) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("sinh (-inf) == -inf",  FUNC(sinh) (minus_infty), minus_infty, 0, 0, 0);
+#endif
+  check_float ("sinh (NaN) == NaN",  FUNC(sinh) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("sinh (0.7) == 0.75858370183953350346",  FUNC(sinh) (0.7L), 0.75858370183953350346L, DELTA1548, 0, 0);
+#if 0  /* XXX scp XXX */
+  check_float ("sinh (0x8p-32) == 1.86264514923095703232705808926175479e-9",  FUNC(sinh) (0x8p-32L), 1.86264514923095703232705808926175479e-9L, 0, 0, 0);
+#endif
+
+  print_max_error ("sinh", DELTAsinh, 0);
+}
+
+static void
+sqrt_test (void)
+{
+  errno = 0;
+  FUNC(sqrt) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("sqrt (0) == 0",  FUNC(sqrt) (0), 0, 0, 0, 0);
+  check_float ("sqrt (NaN) == NaN",  FUNC(sqrt) (nan_value), nan_value, 0, 0, 0);
+  check_float ("sqrt (inf) == inf",  FUNC(sqrt) (plus_infty), plus_infty, 0, 0, 0);
+
+  check_float ("sqrt (-0) == -0",  FUNC(sqrt) (minus_zero), minus_zero, 0, 0, 0);
+
+  /* sqrt (x) == NaN plus invalid exception for x < 0.  */
+  check_float ("sqrt (-1) == NaN plus invalid exception",  FUNC(sqrt) (-1), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sqrt (-inf) == NaN plus invalid exception",  FUNC(sqrt) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("sqrt (NaN) == NaN",  FUNC(sqrt) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("sqrt (2209) == 47",  FUNC(sqrt) (2209), 47, 0, 0, 0);
+  check_float ("sqrt (4) == 2",  FUNC(sqrt) (4), 2, 0, 0, 0);
+  check_float ("sqrt (2) == M_SQRT2l",  FUNC(sqrt) (2), M_SQRT2l, 0, 0, 0);
+  check_float ("sqrt (0.25) == 0.5",  FUNC(sqrt) (0.25), 0.5, 0, 0, 0);
+  check_float ("sqrt (6642.25) == 81.5",  FUNC(sqrt) (6642.25), 81.5, 0, 0, 0);
+  check_float ("sqrt (15239.9025) == 123.45",  FUNC(sqrt) (15239.9025L), 123.45L, DELTA1562, 0, 0);
+  check_float ("sqrt (0.7) == 0.83666002653407554797817202578518747",  FUNC(sqrt) (0.7L), 0.83666002653407554797817202578518747L, 0, 0, 0);
+
+  print_max_error ("sqrt", DELTAsqrt, 0);
+}
+
+static void
+tan_test (void)
+{
+  errno = 0;
+  FUNC(tan) (0);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("tan (0) == 0",  FUNC(tan) (0), 0, 0, 0, 0);
+  check_float ("tan (-0) == -0",  FUNC(tan) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("tan (inf) == NaN plus invalid exception",  FUNC(tan) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("tan (-inf) == NaN plus invalid exception",  FUNC(tan) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("tan (NaN) == NaN",  FUNC(tan) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("tan (pi/4) == 1",  FUNC(tan) (M_PI_4l), 1, DELTA1569, 0, 0);
+  check_float ("tan (0.7) == 0.84228838046307944812813500221293775",  FUNC(tan) (0.7L), 0.84228838046307944812813500221293775L, DELTA1570, 0, 0);
+
+  print_max_error ("tan", DELTAtan, 0);
+}
+
+static void
+tanh_test (void)
+{
+  errno = 0;
+  FUNC(tanh) (0.7L);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  init_max_error ();
+
+  check_float ("tanh (0) == 0",  FUNC(tanh) (0), 0, 0, 0, 0);
+  check_float ("tanh (-0) == -0",  FUNC(tanh) (minus_zero), minus_zero, 0, 0, 0);
+
+#ifndef TEST_INLINE
+  check_float ("tanh (inf) == 1",  FUNC(tanh) (plus_infty), 1, 0, 0, 0);
+  check_float ("tanh (-inf) == -1",  FUNC(tanh) (minus_infty), -1, 0, 0, 0);
+#endif
+  check_float ("tanh (NaN) == NaN",  FUNC(tanh) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("tanh (0.7) == 0.60436777711716349631",  FUNC(tanh) (0.7L), 0.60436777711716349631L, DELTA1576, 0, 0);
+  check_float ("tanh (-0.7) == -0.60436777711716349631",  FUNC(tanh) (-0.7L), -0.60436777711716349631L, DELTA1577, 0, 0);
+
+  check_float ("tanh (1.0) == 0.7615941559557648881194582826047935904",  FUNC(tanh) (1.0L), 0.7615941559557648881194582826047935904L, 0, 0, 0);
+  check_float ("tanh (-1.0) == -0.7615941559557648881194582826047935904",  FUNC(tanh) (-1.0L), -0.7615941559557648881194582826047935904L, 0, 0, 0);
+
+  /* 2^-57  */
+  check_float ("tanh (6.938893903907228377647697925567626953125e-18) == 6.938893903907228377647697925567626953125e-18",  FUNC(tanh) (6.938893903907228377647697925567626953125e-18L), 6.938893903907228377647697925567626953125e-18L, 0, 0, 0);
+
+  print_max_error ("tanh", DELTAtanh, 0);
+}
+
+static void
+tgamma_test (void)
+{
+  errno = 0;
+  FUNC(tgamma) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+  feclearexcept (FE_ALL_EXCEPT);
+
+  init_max_error ();
+
+  check_float ("tgamma (inf) == inf",  FUNC(tgamma) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("tgamma (0) == inf plus divide-by-zero",  FUNC(tgamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("tgamma (-0) == inf plus divide-by-zero",  FUNC(tgamma) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  /* tgamma (x) == NaN plus invalid exception for integer x <= 0.  */
+  check_float ("tgamma (-2) == NaN plus invalid exception",  FUNC(tgamma) (-2), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("tgamma (-inf) == NaN plus invalid exception",  FUNC(tgamma) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("tgamma (NaN) == NaN",  FUNC(tgamma) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("tgamma (0.5) == sqrt (pi)",  FUNC(tgamma) (0.5), M_SQRT_PIl, DELTA1587, 0, 0);
+  check_float ("tgamma (-0.5) == -2 sqrt (pi)",  FUNC(tgamma) (-0.5), -M_2_SQRT_PIl, DELTA1588, 0, 0);
+
+  check_float ("tgamma (1) == 1",  FUNC(tgamma) (1), 1, 0, 0, 0);
+  check_float ("tgamma (4) == 6",  FUNC(tgamma) (4), 6, DELTA1590, 0, 0);
+
+  check_float ("tgamma (0.7) == 1.29805533264755778568",  FUNC(tgamma) (0.7L), 1.29805533264755778568L, DELTA1591, 0, 0);
+  check_float ("tgamma (1.2) == 0.91816874239976061064",  FUNC(tgamma) (1.2L), 0.91816874239976061064L, 0, 0, 0);
+
+  print_max_error ("tgamma", DELTAtgamma, 0);
+}
+
+static void
+trunc_test (void)
+{
+  init_max_error ();
+
+  check_float ("trunc (inf) == inf",  FUNC(trunc) (plus_infty), plus_infty, 0, 0, 0);
+  check_float ("trunc (-inf) == -inf",  FUNC(trunc) (minus_infty), minus_infty, 0, 0, 0);
+  check_float ("trunc (NaN) == NaN",  FUNC(trunc) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("trunc (0) == 0",  FUNC(trunc) (0), 0, 0, 0, 0);
+  check_float ("trunc (-0) == -0",  FUNC(trunc) (minus_zero), minus_zero, 0, 0, 0);
+  check_float ("trunc (0.625) == 0",  FUNC(trunc) (0.625), 0, 0, 0, 0);
+  check_float ("trunc (-0.625) == -0",  FUNC(trunc) (-0.625), minus_zero, 0, 0, 0);
+  check_float ("trunc (1) == 1",  FUNC(trunc) (1), 1, 0, 0, 0);
+  check_float ("trunc (-1) == -1",  FUNC(trunc) (-1), -1, 0, 0, 0);
+  check_float ("trunc (1.625) == 1",  FUNC(trunc) (1.625), 1, 0, 0, 0);
+  check_float ("trunc (-1.625) == -1",  FUNC(trunc) (-1.625), -1, 0, 0, 0);
+
+  check_float ("trunc (1048580.625) == 1048580",  FUNC(trunc) (1048580.625L), 1048580L, 0, 0, 0);
+  check_float ("trunc (-1048580.625) == -1048580",  FUNC(trunc) (-1048580.625L), -1048580L, 0, 0, 0);
+
+  check_float ("trunc (8388610.125) == 8388610.0",  FUNC(trunc) (8388610.125L), 8388610.0L, 0, 0, 0);
+  check_float ("trunc (-8388610.125) == -8388610.0",  FUNC(trunc) (-8388610.125L), -8388610.0L, 0, 0, 0);
+
+  check_float ("trunc (4294967296.625) == 4294967296.0",  FUNC(trunc) (4294967296.625L), 4294967296.0L, 0, 0, 0);
+  check_float ("trunc (-4294967296.625) == -4294967296.0",  FUNC(trunc) (-4294967296.625L), -4294967296.0L, 0, 0, 0);
+
+
+  print_max_error ("trunc", 0, 0);
+}
+
+static void
+y0_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(y0) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  /* y0 is the Bessel function of the second kind of order 0 */
+  init_max_error ();
+
+  check_float ("y0 (-1.0) == NaN",  FUNC(y0) (-1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("y0 (0.0) == -inf",  FUNC(y0) (0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("y0 (NaN) == NaN",  FUNC(y0) (nan_value), nan_value, 0, 0, 0);
+  check_float ("y0 (inf) == 0",  FUNC(y0) (plus_infty), 0, 0, 0, 0);
+
+  check_float ("y0 (0.1) == -1.5342386513503668441",  FUNC(y0) (0.1L), -1.5342386513503668441L, DELTA1614, 0, 0);
+  check_float ("y0 (0.7) == -0.19066492933739506743",  FUNC(y0) (0.7L), -0.19066492933739506743L, DELTA1615, 0, 0);
+  check_float ("y0 (1.0) == 0.088256964215676957983",  FUNC(y0) (1.0), 0.088256964215676957983L, DELTA1616, 0, 0);
+  check_float ("y0 (1.5) == 0.38244892379775884396",  FUNC(y0) (1.5), 0.38244892379775884396L, DELTA1617, 0, 0);
+  check_float ("y0 (2.0) == 0.51037567264974511960",  FUNC(y0) (2.0), 0.51037567264974511960L, DELTA1618, 0, 0);
+  check_float ("y0 (8.0) == 0.22352148938756622053",  FUNC(y0) (8.0), 0.22352148938756622053L, DELTA1619, 0, 0);
+  check_float ("y0 (10.0) == 0.055671167283599391424",  FUNC(y0) (10.0), 0.055671167283599391424L, DELTA1620, 0, 0);
+
+  print_max_error ("y0", DELTAy0, 0);
+}
+
+
+static void
+y1_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(y1) (1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  /* y1 is the Bessel function of the second kind of order 1 */
+  init_max_error ();
+
+  check_float ("y1 (-1.0) == NaN",  FUNC(y1) (-1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("y1 (0.0) == -inf",  FUNC(y1) (0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("y1 (inf) == 0",  FUNC(y1) (plus_infty), 0, 0, 0, 0);
+  check_float ("y1 (NaN) == NaN",  FUNC(y1) (nan_value), nan_value, 0, 0, 0);
+
+  check_float ("y1 (0.1) == -6.4589510947020269877",  FUNC(y1) (0.1L), -6.4589510947020269877L, DELTA1625, 0, 0);
+  check_float ("y1 (0.7) == -1.1032498719076333697",  FUNC(y1) (0.7L), -1.1032498719076333697L, DELTA1626, 0, 0);
+  check_float ("y1 (1.0) == -0.78121282130028871655",  FUNC(y1) (1.0), -0.78121282130028871655L, DELTA1627, 0, 0);
+  check_float ("y1 (1.5) == -0.41230862697391129595",  FUNC(y1) (1.5), -0.41230862697391129595L, DELTA1628, 0, 0);
+  check_float ("y1 (2.0) == -0.10703243154093754689",  FUNC(y1) (2.0), -0.10703243154093754689L, DELTA1629, 0, 0);
+  check_float ("y1 (8.0) == -0.15806046173124749426",  FUNC(y1) (8.0), -0.15806046173124749426L, DELTA1630, 0, 0);
+  check_float ("y1 (10.0) == 0.24901542420695388392",  FUNC(y1) (10.0), 0.24901542420695388392L, DELTA1631, 0, 0);
+
+  print_max_error ("y1", DELTAy1, 0);
+}
+
+static void
+yn_test (void)
+{
+  FLOAT s, c;
+  errno = 0;
+  FUNC (sincos) (0, &s, &c);
+  if (errno == ENOSYS)
+    /* Required function not implemented.  */
+    return;
+  FUNC(yn) (1, 1);
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  /* yn is the Bessel function of the second kind of order n */
+  init_max_error ();
+
+  /* yn (0, x) == y0 (x)  */
+  check_float ("yn (0, -1.0) == NaN",  FUNC(yn) (0, -1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("yn (0, 0.0) == -inf",  FUNC(yn) (0, 0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("yn (0, NaN) == NaN",  FUNC(yn) (0, nan_value), nan_value, 0, 0, 0);
+  check_float ("yn (0, inf) == 0",  FUNC(yn) (0, plus_infty), 0, 0, 0, 0);
+
+  check_float ("yn (0, 0.1) == -1.5342386513503668441",  FUNC(yn) (0, 0.1L), -1.5342386513503668441L, DELTA1636, 0, 0);
+  check_float ("yn (0, 0.7) == -0.19066492933739506743",  FUNC(yn) (0, 0.7L), -0.19066492933739506743L, DELTA1637, 0, 0);
+  check_float ("yn (0, 1.0) == 0.088256964215676957983",  FUNC(yn) (0, 1.0), 0.088256964215676957983L, DELTA1638, 0, 0);
+  check_float ("yn (0, 1.5) == 0.38244892379775884396",  FUNC(yn) (0, 1.5), 0.38244892379775884396L, DELTA1639, 0, 0);
+  check_float ("yn (0, 2.0) == 0.51037567264974511960",  FUNC(yn) (0, 2.0), 0.51037567264974511960L, DELTA1640, 0, 0);
+  check_float ("yn (0, 8.0) == 0.22352148938756622053",  FUNC(yn) (0, 8.0), 0.22352148938756622053L, DELTA1641, 0, 0);
+  check_float ("yn (0, 10.0) == 0.055671167283599391424",  FUNC(yn) (0, 10.0), 0.055671167283599391424L, DELTA1642, 0, 0);
+
+  /* yn (1, x) == y1 (x)  */
+  check_float ("yn (1, -1.0) == NaN",  FUNC(yn) (1, -1.0), nan_value, 0, 0, INVALID_EXCEPTION);
+  check_float ("yn (1, 0.0) == -inf",  FUNC(yn) (1, 0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION);
+  check_float ("yn (1, inf) == 0",  FUNC(yn) (1, plus_infty), 0, 0, 0, 0);
+  check_float ("yn (1, NaN) == NaN",  FUNC(yn) (1, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("yn (1, 0.1) == -6.4589510947020269877",  FUNC(yn) (1, 0.1L), -6.4589510947020269877L, DELTA1647, 0, 0);
+  check_float ("yn (1, 0.7) == -1.1032498719076333697",  FUNC(yn) (1, 0.7L), -1.1032498719076333697L, DELTA1648, 0, 0);
+  check_float ("yn (1, 1.0) == -0.78121282130028871655",  FUNC(yn) (1, 1.0), -0.78121282130028871655L, DELTA1649, 0, 0);
+  check_float ("yn (1, 1.5) == -0.41230862697391129595",  FUNC(yn) (1, 1.5), -0.41230862697391129595L, DELTA1650, 0, 0);
+  check_float ("yn (1, 2.0) == -0.10703243154093754689",  FUNC(yn) (1, 2.0), -0.10703243154093754689L, DELTA1651, 0, 0);
+  check_float ("yn (1, 8.0) == -0.15806046173124749426",  FUNC(yn) (1, 8.0), -0.15806046173124749426L, DELTA1652, 0, 0);
+  check_float ("yn (1, 10.0) == 0.24901542420695388392",  FUNC(yn) (1, 10.0), 0.24901542420695388392L, DELTA1653, 0, 0);
+
+  /* yn (3, x)  */
+  check_float ("yn (3, inf) == 0",  FUNC(yn) (3, plus_infty), 0, 0, 0, 0);
+  check_float ("yn (3, NaN) == NaN",  FUNC(yn) (3, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("yn (3, 0.1) == -5099.3323786129048894",  FUNC(yn) (3, 0.1L), -5099.3323786129048894L, DELTA1656, 0, 0);
+  check_float ("yn (3, 0.7) == -15.819479052819633505",  FUNC(yn) (3, 0.7L), -15.819479052819633505L, DELTA1657, 0, 0);
+  check_float ("yn (3, 1.0) == -5.8215176059647288478",  FUNC(yn) (3, 1.0), -5.8215176059647288478L, 0, 0, 0);
+  check_float ("yn (3, 2.0) == -1.1277837768404277861",  FUNC(yn) (3, 2.0), -1.1277837768404277861L, DELTA1659, 0, 0);
+  check_float ("yn (3, 10.0) == -0.25136265718383732978",  FUNC(yn) (3, 10.0), -0.25136265718383732978L, DELTA1660, 0, 0);
+
+  /* yn (10, x)  */
+  check_float ("yn (10, inf) == 0",  FUNC(yn) (10, plus_infty), 0, 0, 0, 0);
+  check_float ("yn (10, NaN) == NaN",  FUNC(yn) (10, nan_value), nan_value, 0, 0, 0);
+
+  check_float ("yn (10, 0.1) == -0.11831335132045197885e19",  FUNC(yn) (10, 0.1L), -0.11831335132045197885e19L, DELTA1663, 0, 0);
+  check_float ("yn (10, 0.7) == -0.42447194260703866924e10",  FUNC(yn) (10, 0.7L), -0.42447194260703866924e10L, DELTA1664, 0, 0);
+  check_float ("yn (10, 1.0) == -0.12161801427868918929e9",  FUNC(yn) (10, 1.0), -0.12161801427868918929e9L, DELTA1665, 0, 0);
+  check_float ("yn (10, 2.0) == -129184.54220803928264",  FUNC(yn) (10, 2.0), -129184.54220803928264L, DELTA1666, 0, 0);
+  check_float ("yn (10, 10.0) == -0.35981415218340272205",  FUNC(yn) (10, 10.0), -0.35981415218340272205L, DELTA1667, 0, 0);
+
+  print_max_error ("yn", DELTAyn, 0);
+
+}
+
+
+
+static void
+initialize (void)
+{
+  plus_zero = 0.0;
+  nan_value = plus_zero / plus_zero;   /* Suppress GCC warning */
+
+  minus_zero = FUNC(copysign) (0.0, -1.0);
+  plus_infty = CHOOSE (HUGE_VALL, HUGE_VAL, HUGE_VALF,
+                      HUGE_VALL, HUGE_VAL, HUGE_VALF);
+  minus_infty = CHOOSE (-HUGE_VALL, -HUGE_VAL, -HUGE_VALF,
+                       -HUGE_VALL, -HUGE_VAL, -HUGE_VALF);
+
+  (void) &plus_zero;
+  (void) &nan_value;
+  (void) &minus_zero;
+  (void) &plus_infty;
+  (void) &minus_infty;
+
+  /* Clear all exceptions.  From now on we must not get random exceptions.  */
+  feclearexcept (FE_ALL_EXCEPT);
+}
+
+#if 0 /* XXX scp XXX */
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { "verbose", 'v', "NUMBER", 0, "Level of verbosity (0..3)"},
+  { "ulps-file", 'u', NULL, 0, "Output ulps to file ULPs"},
+  { "no-max-error", 'f', NULL, 0,
+    "Don't output maximal errors of functions"},
+  { "no-points", 'p', NULL, 0,
+    "Don't output results of functions invocations"},
+  { "ignore-max-ulp", 'i', "yes/no", 0,
+    "Ignore given maximal errors"},
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program.  */
+static const char doc[] = "Math test suite: " TEST_MSG ;
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, NULL, doc,
+};
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'f':
+      output_max_error = 0;
+      break;
+    case 'i':
+      if (strcmp (arg, "yes") == 0)
+       ignore_max_ulp = 1;
+      else if (strcmp (arg, "no") == 0)
+       ignore_max_ulp = 0;
+      break;
+    case 'p':
+      output_points = 0;
+      break;
+    case 'u':
+      output_ulps = 1;
+      break;
+    case 'v':
+      if (optarg)
+       verbose = (unsigned int) strtoul (optarg, NULL, 0);
+      else
+       verbose = 3;
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+#endif
+
+#if 0
+/* function to check our ulp calculation.  */
+void
+check_ulp (void)
+{
+  int i;
+
+  FLOAT u, diff, ulp;
+  /* This gives one ulp.  */
+  u = FUNC(nextafter) (10, 20);
+  check_equal (10.0, u, 1, &diff, &ulp);
+  printf ("One ulp: % .4" PRINTF_NEXPR "\n", ulp);
+
+  /* This gives one more ulp.  */
+  u = FUNC(nextafter) (u, 20);
+  check_equal (10.0, u, 2, &diff, &ulp);
+  printf ("two ulp: % .4" PRINTF_NEXPR "\n", ulp);
+
+  /* And now calculate 100 ulp.  */
+  for (i = 2; i < 100; i++)
+    u = FUNC(nextafter) (u, 20);
+  check_equal (10.0, u, 100, &diff, &ulp);
+  printf ("100 ulp: % .4" PRINTF_NEXPR "\n", ulp);
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+#if 0 /* XXX scp XXX */
+  int remaining;
+#endif
+
+  verbose = 1;
+  output_ulps = 0;
+  output_max_error = 1;
+  output_points = 1;
+  /* XXX set to 0 for releases.  */
+  ignore_max_ulp = 0;
+
+#if 0 /* XXX scp XXX */
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if (remaining != argc)
+    {
+      fprintf (stderr, "wrong number of arguments");
+      argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
+      exit (EXIT_FAILURE);
+    }
+#endif
+
+  if (output_ulps)
+    {
+      ulps_file = fopen ("ULPs", "a");
+      if (ulps_file == NULL)
+       {
+         perror ("can't open file `ULPs' for writing: ");
+         exit (1);
+       }
+    }
+
+
+  initialize ();
+  printf (TEST_MSG);
+
+#if 0
+  check_ulp ();
+#endif
+
+  /* Keep the tests a wee bit ordered (according to ISO C99).  */
+  /* Classification macros:  */
+  fpclassify_test ();
+  isfinite_test ();
+  isnormal_test ();
+  signbit_test ();
+
+  /* Trigonometric functions:  */
+  acos_test ();
+  asin_test ();
+  atan_test ();
+  atan2_test ();
+  cos_test ();
+  sin_test ();
+  sincos_test ();
+  tan_test ();
+
+  /* Hyperbolic functions:  */
+  acosh_test ();
+  asinh_test ();
+  atanh_test ();
+  cosh_test ();
+  sinh_test ();
+  tanh_test ();
+
+  /* Exponential and logarithmic functions:  */
+  exp_test ();
+#if 0 /* XXX scp XXX */
+  exp10_test ();
+#endif
+  exp2_test ();
+  expm1_test ();
+  frexp_test ();
+  ldexp_test ();
+  log_test ();
+  log10_test ();
+  log1p_test ();
+  log2_test ();
+  logb_test ();
+  modf_test ();
+  ilogb_test ();
+  scalbn_test ();
+  scalbln_test ();
+
+  /* Power and absolute value functions:  */
+  cbrt_test ();
+  fabs_test ();
+  hypot_test ();
+  pow_test ();
+  sqrt_test ();
+
+  /* Error and gamma functions:  */
+  erf_test ();
+  erfc_test ();
+  gamma_test ();
+  lgamma_test ();
+  tgamma_test ();
+
+  /* Nearest integer functions:  */
+  ceil_test ();
+  floor_test ();
+  nearbyint_test ();
+  rint_test ();
+  lrint_test ();
+  llrint_test ();
+  round_test ();
+  lround_test ();
+  llround_test ();
+  trunc_test ();
+
+  /* Remainder functions:  */
+  fmod_test ();
+  remainder_test ();
+  remquo_test ();
+
+  /* Manipulation functions:  */
+  copysign_test ();
+  nextafter_test ();
+#if 0 /* XXX scp XXX */
+  nexttoward_test ();
+#endif
+
+  /* maximum, minimum and positive difference functions */
+  fdim_test ();
+  fmax_test ();
+  fmin_test ();
+
+  /* Multiply and add:  */
+  fma_test ();
+
+#if 0 /* XXX scp XXX */
+  /* Complex functions:  */
+  cabs_test ();
+  cacos_test ();
+  cacosh_test ();
+  carg_test ();
+  casin_test ();
+  casinh_test ();
+  catan_test ();
+  catanh_test ();
+  ccos_test ();
+  ccosh_test ();
+  cexp_test ();
+  cimag_test ();
+  clog10_test ();
+  clog_test ();
+  conj_test ();
+  cpow_test ();
+  cproj_test ();
+  creal_test ();
+  csin_test ();
+  csinh_test ();
+  csqrt_test ();
+  ctan_test ();
+  ctanh_test ();
+#endif
+
+  /* Bessel functions:  */
+  j0_test ();
+  j1_test ();
+  jn_test ();
+  y0_test ();
+  y1_test ();
+  yn_test ();
+
+  if (output_ulps)
+    fclose (ulps_file);
+
+  printf ("\nTest suite completed:\n");
+  printf ("  %d test cases plus %d tests for exception flags executed.\n",
+         noTests, noExcTests);
+  if (noXFails)
+    printf ("  %d expected failures occurred.\n", noXFails);
+  if (noXPasses)
+    printf ("  %d unexpected passes occurred.\n", noXPasses);
+  if (noErrors)
+    {
+      printf ("  %d errors occurred.\n", noErrors);
+      return 1;
+    }
+  printf ("  All tests passed successfully.\n");
+
+  return 0;
+}
+
+/*
+ * Local Variables:
+ * mode:c
+ * End:
+ */
diff --git a/test/test-double.c b/test/test-double.c
new file mode 100644 (file)
index 0000000..4d239a7
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FUNC(function) function
+#define FLOAT double
+#define TEST_MSG "testing double (without inline functions)\n"
+#define MATHCONST(x) x
+#define CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat) Cdouble
+#define PRINTF_EXPR "e"
+#define PRINTF_XEXPR "a"
+#define PRINTF_NEXPR "f"
+#define TEST_DOUBLE 1
+
+#ifndef __NO_MATH_INLINES
+# define __NO_MATH_INLINES
+#endif
+
+#include "libm-test.c"
diff --git a/test/test-float.c b/test/test-float.c
new file mode 100644 (file)
index 0000000..26a4213
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FUNC(function) function ## f
+#define FLOAT float
+#define TEST_MSG "testing float (without inline functions)\n"
+#define MATHCONST(x) x
+#define CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat) Cfloat
+#define PRINTF_EXPR "e"
+#define PRINTF_XEXPR "a"
+#define PRINTF_NEXPR "f"
+#define TEST_FLOAT 1
+
+#ifndef __NO_MATH_INLINES
+# define __NO_MATH_INLINES
+#endif
+
+#include "libm-test.c"