From 8e2ff164cc327aad8666333a1d75f86291858da0 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Tue, 25 Jan 2011 17:05:50 +0100 Subject: [PATCH] libm: Add nanf() and tgammaf() implementations. Requested by b/3370708 to export these through RenderScript. Change-Id: I1ae69f87a1ad4765b2dee8e4a6f2f3a6eb7c5ad4 --- libm/Android.mk | 2 + libm/include/math.h | 3 + libm/src/s_nan.c | 131 +++++++++++++++++++++++++++++++++++++++++++ libm/src/s_tgammaf.c | 43 ++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 libm/src/s_nan.c create mode 100644 libm/src/s_tgammaf.c diff --git a/libm/Android.mk b/libm/Android.mk index 28e8f334c..29c75a2bb 100644 --- a/libm/Android.mk +++ b/libm/Android.mk @@ -117,6 +117,7 @@ libm_common_src_files:= \ src/s_lroundf.c \ src/s_lroundl.c \ src/s_modff.c \ + src/s_nan.c \ src/s_nearbyint.c \ src/s_nextafter.c \ src/s_nextafterf.c \ @@ -138,6 +139,7 @@ libm_common_src_files:= \ src/s_tanf.c \ src/s_tanh.c \ src/s_tanhf.c \ + src/s_tgammaf.c \ src/s_trunc.c \ src/s_truncf.c \ src/s_truncl.c \ diff --git a/libm/include/math.h b/libm/include/math.h index 3b5660f30..a86a16fb6 100644 --- a/libm/include/math.h +++ b/libm/include/math.h @@ -251,6 +251,7 @@ double log1p(double); double logb(double); long lrint(double); long lround(double); +double nan(const char *) __pure2; double nextafter(double, double); double remainder(double, double); double remquo(double, double, int *); @@ -343,6 +344,7 @@ float erff(float); float erfcf(float); float hypotf(float, float); float lgammaf(float); +float tgammaf(float); float acoshf(float); float asinhf(float); @@ -354,6 +356,7 @@ long long llrintf(float); long long llroundf(float); long lrintf(float); long lroundf(float); +float nanf(const char *) __pure2; float nearbyintf(float); float nextafterf(float, float); float remainderf(float, float); diff --git a/libm/src/s_nan.c b/libm/src/s_nan.c new file mode 100644 index 000000000..e366e6b56 --- /dev/null +++ b/libm/src/s_nan.c @@ -0,0 +1,131 @@ +/*- + * 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$ + */ + +#include +#include +#include +#include +#include +#include + +#include "math_private.h" + +/* digittoint is in the FreeBSD C library, but not Bionic at this point */ +static int +digittoint(char ch) +{ + int d; + + d = ch - '0'; + if ((unsigned)d < 10) { + return d; + } + d = ch - 'a'; + if ((unsigned)d < 6) { + return d + 10; + } + d = ch - 'A'; + if ((unsigned)d < 6) { + return d + 10; + } + return -1; +} + +/* + * 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. + */ +void +_scan_nan(uint32_t *words, int num_words, const char *s) +{ + int si; /* index into s */ + int bitpos; /* index into words (in bits) */ + + bzero(words, num_words * sizeof(uint32_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 == _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); + } +} + +double +nan(const char *s) +{ + union { + double d; + uint32_t bits[2]; + } u; + + _scan_nan(u.bits, 2, s); +#if _BYTE_ORDER == _LITTLE_ENDIAN + u.bits[1] |= 0x7ff80000; +#else + u.bits[0] |= 0x7ff80000; +#endif + return (u.d); +} + +float +nanf(const char *s) +{ + union { + float f; + uint32_t bits[1]; + } u; + + _scan_nan(u.bits, 1, s); + u.bits[0] |= 0x7fc00000; + return (u.f); +} + +#if (LDBL_MANT_DIG == 53) +__weak_alias(nanl, nan); +#endif diff --git a/libm/src/s_tgammaf.c b/libm/src/s_tgammaf.c new file mode 100644 index 000000000..9993d91aa --- /dev/null +++ b/libm/src/s_tgammaf.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 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 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 +__FBSDID("$FreeBSD$"); + +#include + +/* + * 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. + */ +float +tgammaf(float x) +{ + + return (tgamma(x)); +}