diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
commit | 0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch) | |
tree | 6eaef0d8a720fa3da580de87b647fff796fe80b3 /src | |
download | musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz |
initial check-in, version 0.5.0v0.5.0
Diffstat (limited to 'src')
856 files changed, 33417 insertions, 0 deletions
diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c new file mode 100644 index 00000000..af7e4d3b --- /dev/null +++ b/src/conf/fpathconf.c @@ -0,0 +1,35 @@ +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +long fpathconf(int fd, int name) +{ + static const short values[] = { + [_PC_LINK_MAX] = _POSIX_LINK_MAX, + [_PC_MAX_CANON] = _POSIX_MAX_CANON, + [_PC_MAX_INPUT] = _POSIX_MAX_INPUT, + [_PC_NAME_MAX] = NAME_MAX, + [_PC_PATH_MAX] = PATH_MAX, + [_PC_PIPE_BUF] = PIPE_BUF, + [_PC_CHOWN_RESTRICTED] = 1, + [_PC_NO_TRUNC] = 1, + [_PC_VDISABLE] = 0, + [_PC_SYNC_IO] = 0, + [_PC_ASYNC_IO] = 0, + [_PC_PRIO_IO] = 0, + [_PC_SOCK_MAXBUF] = -1, + [_PC_FILESIZEBITS] = sizeof(off_t), + [_PC_REC_INCR_XFER_SIZE] = PAGE_SIZE, + [_PC_REC_MAX_XFER_SIZE] = PAGE_SIZE, + [_PC_REC_MIN_XFER_SIZE] = PAGE_SIZE, + [_PC_REC_XFER_ALIGN] = PAGE_SIZE, + [_PC_ALLOC_SIZE_MIN] = PAGE_SIZE, + [_PC_SYMLINK_MAX] = SYMLINK_MAX, + [_PC_2_SYMLINKS] = 1 + }; + if (name > sizeof(values)/sizeof(values[0])) { + errno = EINVAL; + return -1; + } + return values[name]; +} diff --git a/src/conf/pathconf.c b/src/conf/pathconf.c new file mode 100644 index 00000000..01e19c59 --- /dev/null +++ b/src/conf/pathconf.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +long pathconf(const char *path, int name) +{ + return fpathconf(-1, name); +} diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c new file mode 100644 index 00000000..cdaeb2a6 --- /dev/null +++ b/src/conf/sysconf.c @@ -0,0 +1,222 @@ +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +#define VER (-2) +#define OFLOW (-3) + +long sysconf(int name) +{ + static const short values[] = { + [_SC_ARG_MAX] = OFLOW, + [_SC_CHILD_MAX] = -1, + [_SC_CLK_TCK] = 100, + [_SC_NGROUPS_MAX] = 32, + [_SC_OPEN_MAX] = 1024, + [_SC_STREAM_MAX] = -1, + [_SC_TZNAME_MAX] = TZNAME_MAX, + [_SC_JOB_CONTROL] = 1, + [_SC_SAVED_IDS] = 1, + [_SC_REALTIME_SIGNALS] = 1, + [_SC_PRIORITY_SCHEDULING] = -1, + [_SC_TIMERS] = VER, + [_SC_ASYNCHRONOUS_IO] = VER, + [_SC_PRIORITIZED_IO] = -1, + [_SC_SYNCHRONIZED_IO] = -1, + [_SC_FSYNC] = -1, + [_SC_MAPPED_FILES] = VER, + [_SC_MEMLOCK] = VER, + [_SC_MEMLOCK_RANGE] = VER, + [_SC_MEMORY_PROTECTION] = VER, + [_SC_MESSAGE_PASSING] = -1, + [_SC_SEMAPHORES] = VER, + [_SC_SHARED_MEMORY_OBJECTS] = -1, + [_SC_AIO_LISTIO_MAX] = -1, + [_SC_AIO_MAX] = -1, + [_SC_AIO_PRIO_DELTA_MAX] = 0, /* ?? */ + [_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX, + [_SC_MQ_OPEN_MAX] = -1, + [_SC_MQ_PRIO_MAX] = _POSIX_MQ_PRIO_MAX, + [_SC_VERSION] = VER, + [_SC_PAGE_SIZE] = PAGE_SIZE, + [_SC_RTSIG_MAX] = 63, /* ?? */ + [_SC_SEM_NSEMS_MAX] = _POSIX_SEM_NSEMS_MAX, + [_SC_SEM_VALUE_MAX] = _POSIX_SEM_VALUE_MAX, + [_SC_SIGQUEUE_MAX] = -1, + [_SC_TIMER_MAX] = -1, + [_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX, + [_SC_BC_DIM_MAX] = _POSIX2_BC_DIM_MAX, + [_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX, + [_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX, + [_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX, + [_SC_EQUIV_CLASS_MAX] = -1, /* ?? */ + [_SC_EXPR_NEST_MAX] = -1, + [_SC_LINE_MAX] = -1, + [_SC_RE_DUP_MAX] = RE_DUP_MAX, + [_SC_CHARCLASS_NAME_MAX] = -1, /* ?? */ + [_SC_2_VERSION] = VER, + [_SC_2_C_BIND] = VER, + [_SC_2_C_DEV] = -1, + [_SC_2_FORT_DEV] = -1, + [_SC_2_FORT_RUN] = -1, + [_SC_2_SW_DEV] = -1, + [_SC_2_LOCALEDEF] = -1, + [_SC_PII] = -1, /* ????????? */ + [_SC_PII_XTI] = -1, + [_SC_PII_SOCKET] = -1, + [_SC_PII_INTERNET] = -1, + [_SC_PII_OSI] = -1, + [_SC_POLL] = 1, + [_SC_SELECT] = 1, + [_SC_IOV_MAX] = IOV_MAX, + [_SC_PII_INTERNET_STREAM] = -1, + [_SC_PII_INTERNET_DGRAM] = -1, + [_SC_PII_OSI_COTS] = -1, + [_SC_PII_OSI_CLTS] = -1, + [_SC_PII_OSI_M] = -1, + [_SC_T_IOV_MAX] = -1, + [_SC_THREADS] = VER, + [_SC_THREAD_SAFE_FUNCTIONS] = VER, + [_SC_GETGR_R_SIZE_MAX] = -1, + [_SC_GETPW_R_SIZE_MAX] = -1, + [_SC_LOGIN_NAME_MAX] = 256, + [_SC_TTY_NAME_MAX] = TTY_NAME_MAX, + [_SC_THREAD_DESTRUCTOR_ITERATIONS] = _POSIX_THREAD_DESTRUCTOR_ITERATIONS, + [_SC_THREAD_KEYS_MAX] = -1, + [_SC_THREAD_STACK_MIN] = 2*PAGE_SIZE, + [_SC_THREAD_THREADS_MAX] = -1, + [_SC_THREAD_ATTR_STACKADDR] = -1, + [_SC_THREAD_ATTR_STACKSIZE] = VER, + [_SC_THREAD_PRIORITY_SCHEDULING] = -1, + [_SC_THREAD_PRIO_INHERIT] = -1, + [_SC_THREAD_PRIO_PROTECT] = -1, + [_SC_THREAD_PROCESS_SHARED] = VER, + [_SC_NPROCESSORS_CONF] = -1, + [_SC_NPROCESSORS_ONLN] = -1, + [_SC_PHYS_PAGES] = -1, + [_SC_AVPHYS_PAGES] = -1, + [_SC_ATEXIT_MAX] = -1, + [_SC_PASS_MAX] = -1, + [_SC_XOPEN_VERSION] = _XOPEN_VERSION, + [_SC_XOPEN_XCU_VERSION] = _XOPEN_VERSION, + [_SC_XOPEN_UNIX] = -1, + [_SC_XOPEN_CRYPT] = -1, + [_SC_XOPEN_ENH_I18N] = 1, + [_SC_XOPEN_SHM] = 1, + [_SC_2_CHAR_TERM] = -1, + [_SC_2_C_VERSION] = -1, + [_SC_2_UPE] = -1, + [_SC_XOPEN_XPG2] = -1, + [_SC_XOPEN_XPG3] = -1, + [_SC_XOPEN_XPG4] = -1, + [_SC_CHAR_BIT] = -1, + [_SC_CHAR_MAX] = -1, + [_SC_CHAR_MIN] = -1, + [_SC_INT_MAX] = -1, + [_SC_INT_MIN] = -1, + [_SC_LONG_BIT] = -1, + [_SC_WORD_BIT] = -1, + [_SC_MB_LEN_MAX] = -1, + [_SC_NZERO] = NZERO, + [_SC_SSIZE_MAX] = -1, + [_SC_SCHAR_MAX] = -1, + [_SC_SCHAR_MIN] = -1, + [_SC_SHRT_MAX] = -1, + [_SC_SHRT_MIN] = -1, + [_SC_UCHAR_MAX] = -1, + [_SC_UINT_MAX] = -1, + [_SC_ULONG_MAX] = -1, + [_SC_USHRT_MAX] = -1, + [_SC_NL_ARGMAX] = -1, + [_SC_NL_LANGMAX] = -1, + [_SC_NL_MSGMAX] = -1, + [_SC_NL_NMAX] = -1, + [_SC_NL_SETMAX] = -1, + [_SC_NL_TEXTMAX] = -1, + [_SC_XBS5_ILP32_OFF32] = -1, + [_SC_XBS5_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, + [_SC_XBS5_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_XBS5_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, + [_SC_XOPEN_LEGACY] = -1, + [_SC_XOPEN_REALTIME] = -1, + [_SC_XOPEN_REALTIME_THREADS] = -1, + [_SC_ADVISORY_INFO] = -1, + [_SC_BARRIERS] = VER, + [_SC_BASE] = -1, + [_SC_C_LANG_SUPPORT] = -1, + [_SC_C_LANG_SUPPORT_R] = -1, + [_SC_CLOCK_SELECTION] = VER, + [_SC_CPUTIME] = VER, + [_SC_THREAD_CPUTIME] = -1, + [_SC_DEVICE_IO] = -1, + [_SC_DEVICE_SPECIFIC] = -1, + [_SC_DEVICE_SPECIFIC_R] = -1, + [_SC_FD_MGMT] = -1, + [_SC_FIFO] = -1, + [_SC_PIPE] = -1, + [_SC_FILE_ATTRIBUTES] = -1, + [_SC_FILE_LOCKING] = -1, + [_SC_FILE_SYSTEM] = -1, + [_SC_MONOTONIC_CLOCK] = VER, + [_SC_MULTI_PROCESS] = -1, + [_SC_SINGLE_PROCESS] = -1, + [_SC_NETWORKING] = -1, + [_SC_READER_WRITER_LOCKS] = VER, + [_SC_SPIN_LOCKS] = VER, + [_SC_REGEXP] = 1, + [_SC_REGEX_VERSION] = -1, + [_SC_SHELL] = 1, + [_SC_SIGNALS] = -1, + [_SC_SPAWN] = -1, + [_SC_SPORADIC_SERVER] = -1, + [_SC_THREAD_SPORADIC_SERVER] = -1, + [_SC_SYSTEM_DATABASE] = -1, + [_SC_SYSTEM_DATABASE_R] = -1, + [_SC_TIMEOUTS] = VER, + [_SC_TYPED_MEMORY_OBJECTS] = -1, + [_SC_USER_GROUPS] = -1, + [_SC_USER_GROUPS_R] = -1, + [_SC_2_PBS] = -1, + [_SC_2_PBS_ACCOUNTING] = -1, + [_SC_2_PBS_LOCATE] = -1, + [_SC_2_PBS_MESSAGE] = -1, + [_SC_2_PBS_TRACK] = -1, + [_SC_SYMLOOP_MAX] = SYMLOOP_MAX, + [_SC_STREAMS] = 0, + [_SC_2_PBS_CHECKPOINT] = -1, + [_SC_V6_ILP32_OFF32] = -1, + [_SC_V6_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, + [_SC_V6_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_V6_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, + [_SC_HOST_NAME_MAX] = HOST_NAME_MAX, + [_SC_TRACE] = -1, + [_SC_TRACE_EVENT_FILTER] = -1, + [_SC_TRACE_INHERIT] = -1, + [_SC_TRACE_LOG] = -1, + + [_SC_IPV6] = VER, + [_SC_RAW_SOCKETS] = VER, + [_SC_V7_ILP32_OFF32] = -1, + [_SC_V7_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, + [_SC_V7_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_V7_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, + [_SC_SS_REPL_MAX] = -1, + [_SC_TRACE_EVENT_NAME_MAX] = -1, + [_SC_TRACE_NAME_MAX] = -1, + [_SC_TRACE_SYS_MAX] = -1, + [_SC_TRACE_USER_EVENT_MAX] = -1, + [_SC_XOPEN_STREAMS] = 0, + [_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, + [_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, + }; + if (name > sizeof(values)/sizeof(values[0])) { + errno = EINVAL; + return -1; + } else if (values[name] == VER) { + return _POSIX_VERSION; + } else if (values[name] == OFLOW) { + return ARG_MAX; + } else { + return values[name]; + } +} diff --git a/src/ctype/__ctype_get_mb_cur_max.c b/src/ctype/__ctype_get_mb_cur_max.c new file mode 100644 index 00000000..42e4ee71 --- /dev/null +++ b/src/ctype/__ctype_get_mb_cur_max.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +size_t __ctype_get_mb_cur_max() +{ + return 4; +} diff --git a/src/ctype/isalnum.c b/src/ctype/isalnum.c new file mode 100644 index 00000000..e3d2cf0b --- /dev/null +++ b/src/ctype/isalnum.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} diff --git a/src/ctype/isalpha.c b/src/ctype/isalpha.c new file mode 100644 index 00000000..53e115c2 --- /dev/null +++ b/src/ctype/isalpha.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isalpha + +int isalpha(int c) +{ + return ((unsigned)c|32)-'a' < 26; +} diff --git a/src/ctype/isascii.c b/src/ctype/isascii.c new file mode 100644 index 00000000..3af0a10d --- /dev/null +++ b/src/ctype/isascii.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isascii(int c) +{ + return !(c&~0x7f); +} diff --git a/src/ctype/isblank.c b/src/ctype/isblank.c new file mode 100644 index 00000000..957400b2 --- /dev/null +++ b/src/ctype/isblank.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isblank(int c) +{ + return (c == ' ' || c == '\t'); +} diff --git a/src/ctype/iscntrl.c b/src/ctype/iscntrl.c new file mode 100644 index 00000000..92ed7f0e --- /dev/null +++ b/src/ctype/iscntrl.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int iscntrl(int c) +{ + return (unsigned)c < 0x20 || c == 0x7f; +} diff --git a/src/ctype/isdigit.c b/src/ctype/isdigit.c new file mode 100644 index 00000000..0bc82a6d --- /dev/null +++ b/src/ctype/isdigit.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isdigit + +int isdigit(int c) +{ + return (unsigned)c-'0' < 10; +} diff --git a/src/ctype/isgraph.c b/src/ctype/isgraph.c new file mode 100644 index 00000000..98979d1e --- /dev/null +++ b/src/ctype/isgraph.c @@ -0,0 +1,4 @@ +int isgraph(int c) +{ + return (unsigned)c-0x21 < 0x5e; +} diff --git a/src/ctype/islower.c b/src/ctype/islower.c new file mode 100644 index 00000000..d72fb212 --- /dev/null +++ b/src/ctype/islower.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef islower + +int islower(int c) +{ + return (unsigned)c-'a' < 26; +} diff --git a/src/ctype/isprint.c b/src/ctype/isprint.c new file mode 100644 index 00000000..504e66ed --- /dev/null +++ b/src/ctype/isprint.c @@ -0,0 +1,4 @@ +int isprint(int c) +{ + return (unsigned)c-0x20 < 0x5f; +} diff --git a/src/ctype/ispunct.c b/src/ctype/ispunct.c new file mode 100644 index 00000000..fc455352 --- /dev/null +++ b/src/ctype/ispunct.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); +} diff --git a/src/ctype/isspace.c b/src/ctype/isspace.c new file mode 100644 index 00000000..8e535aa1 --- /dev/null +++ b/src/ctype/isspace.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isspace(int c) +{ + return c == ' ' || (unsigned)c-'\t' < 5; +} diff --git a/src/ctype/isupper.c b/src/ctype/isupper.c new file mode 100644 index 00000000..f09d88c5 --- /dev/null +++ b/src/ctype/isupper.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isupper + +int isupper(int c) +{ + return (unsigned)c-'A' < 26; +} diff --git a/src/ctype/iswalnum.c b/src/ctype/iswalnum.c new file mode 100644 index 00000000..d3b56674 --- /dev/null +++ b/src/ctype/iswalnum.c @@ -0,0 +1,9 @@ +#include <wchar.h> +#include <wctype.h> + +#undef iswalnum + +int iswalnum(wint_t wc) +{ + return (unsigned)wc-'0' < 10 || iswalpha(wc); +} diff --git a/src/ctype/iswalpha.c b/src/ctype/iswalpha.c new file mode 100644 index 00000000..0f031eac --- /dev/null +++ b/src/ctype/iswalpha.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswalpha(wint_t wc) +{ + return (32U|wc)-'a'<26; +} diff --git a/src/ctype/iswblank.c b/src/ctype/iswblank.c new file mode 100644 index 00000000..bc6196f2 --- /dev/null +++ b/src/ctype/iswblank.c @@ -0,0 +1,8 @@ +#include <wchar.h> +#include <wctype.h> +#include <ctype.h> + +int iswblank(wint_t wc) +{ + return isblank(wc); +} diff --git a/src/ctype/iswcntrl.c b/src/ctype/iswcntrl.c new file mode 100644 index 00000000..93942b08 --- /dev/null +++ b/src/ctype/iswcntrl.c @@ -0,0 +1,10 @@ +#include <wchar.h> +#include <wctype.h> + +int iswcntrl(wint_t wc) +{ + return (unsigned)wc < 32 + || (unsigned)(wc-0x7f) < 33 + || (unsigned)(wc-0x2028) < 2 + || (unsigned)(wc-0xfff9) < 3; +} diff --git a/src/ctype/iswctype.c b/src/ctype/iswctype.c new file mode 100644 index 00000000..d917975b --- /dev/null +++ b/src/ctype/iswctype.c @@ -0,0 +1,63 @@ +#include <wchar.h> +#include <wctype.h> +#include <string.h> + +#define WCTYPE_ALNUM 1 +#define WCTYPE_ALPHA 2 +#define WCTYPE_BLANK 3 +#define WCTYPE_CNTRL 4 +#define WCTYPE_DIGIT 5 +#define WCTYPE_GRAPH 6 +#define WCTYPE_LOWER 7 +#define WCTYPE_PRINT 8 +#define WCTYPE_PUNCT 9 +#define WCTYPE_SPACE 10 +#define WCTYPE_UPPER 11 +#define WCTYPE_XDIGIT 12 + +int iswctype(wint_t wc, wctype_t type) +{ + switch (type) { + case WCTYPE_ALNUM: + return iswalnum(wc); + case WCTYPE_ALPHA: + return iswalpha(wc); + case WCTYPE_BLANK: + return iswblank(wc); + case WCTYPE_CNTRL: + return iswcntrl(wc); + case WCTYPE_DIGIT: + return iswdigit(wc); + case WCTYPE_GRAPH: + return iswgraph(wc); + case WCTYPE_LOWER: + return iswlower(wc); + case WCTYPE_PRINT: + return iswprint(wc); + case WCTYPE_PUNCT: + return iswpunct(wc); + case WCTYPE_SPACE: + return iswspace(wc); + case WCTYPE_UPPER: + return iswupper(wc); + case WCTYPE_XDIGIT: + return iswxdigit(wc); + } + return 0; +} + +wctype_t wctype(const char *s) +{ + int i; + const char *p; + /* order must match! */ + static const char names[] = + "alnum\0" "alpha\0" "blank\0" + "cntrl\0" "digit\0" "graph\0" + "lower\0" "print\0" "punct\0" + "space\0" "upper\0" "xdigit"; + for (i=1, p=names; *p; i++, p+=6) + if (*s == *p && !strcmp(s, p)) + return i; + return 0; +} diff --git a/src/ctype/iswdigit.c b/src/ctype/iswdigit.c new file mode 100644 index 00000000..0487145f --- /dev/null +++ b/src/ctype/iswdigit.c @@ -0,0 +1,9 @@ +#include <wchar.h> +#include <wctype.h> + +#undef iswdigit + +int iswdigit(wint_t wc) +{ + return (unsigned)wc-'0' < 10; +} diff --git a/src/ctype/iswgraph.c b/src/ctype/iswgraph.c new file mode 100644 index 00000000..fdc97853 --- /dev/null +++ b/src/ctype/iswgraph.c @@ -0,0 +1,7 @@ +#include <wctype.h> + +int iswgraph(wint_t wc) +{ + /* ISO C defines this function as: */ + return !iswspace(wc) && iswprint(wc); +} diff --git a/src/ctype/iswlower.c b/src/ctype/iswlower.c new file mode 100644 index 00000000..0a568e77 --- /dev/null +++ b/src/ctype/iswlower.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswlower(wint_t wc) +{ + return towupper(wc) != wc; +} diff --git a/src/ctype/iswprint.c b/src/ctype/iswprint.c new file mode 100644 index 00000000..7717671a --- /dev/null +++ b/src/ctype/iswprint.c @@ -0,0 +1,10 @@ +#include <wctype.h> + +int iswprint(wint_t wc) +{ + unsigned c = wc; + /* assume any non-control, non-illegal codepoint is printable */ + if (c>0x10ffff || c-0xd800<0x800 || (c&0xfffe)==0xfffe || iswcntrl(c)) + return 0; + return 1; +} diff --git a/src/ctype/iswpunct.c b/src/ctype/iswpunct.c new file mode 100644 index 00000000..1414c30c --- /dev/null +++ b/src/ctype/iswpunct.c @@ -0,0 +1,138 @@ +#include <wctype.h> +#include <inttypes.h> + +/* The below data is derived from classes (P.|Sm) plus Pattern_Syntax */ + +#define R(a,b) { (b), (b)-(a) } + +static const struct range { + uint32_t base:20; + uint32_t len:12; +} ranges[] = { +R(0x21, 0x2f), +R(0x3a, 0x40), +R(0x5b, 0x60), +R(0x7b, 0x7e), +R(0xa1, 0xa7), +R(0xa9, 0xa9), +R(0xab, 0xac), +R(0xae, 0xae), +R(0xb0, 0xb1), +R(0xb6, 0xb7), +R(0xbb, 0xbb), +R(0xbf, 0xbf), +R(0xd7, 0xd7), +R(0xf7, 0xf7), +R(0x37e, 0x37e), +R(0x387, 0x387), +R(0x3f6, 0x3f6), +R(0x55a, 0x55f), +R(0x589, 0x58a), +R(0x5be, 0x5be), +R(0x5c0, 0x5c0), +R(0x5c3, 0x5c3), +R(0x5c6, 0x5c6), +R(0x5f3, 0x5f4), +R(0x606, 0x60a), +R(0x60c, 0x60d), +R(0x61b, 0x61b), +R(0x61e, 0x61f), +R(0x66a, 0x66d), +R(0x6d4, 0x6d4), +R(0x700, 0x70d), +R(0x7f7, 0x7f9), +R(0x964, 0x965), +R(0x970, 0x970), +R(0xdf4, 0xdf4), +R(0xe4f, 0xe4f), +R(0xe5a, 0xe5b), +R(0xf04, 0xf12), +R(0xf3a, 0xf3d), +R(0xf85, 0xf85), +R(0xfd0, 0xfd4), +R(0x104a, 0x104f), +R(0x10fb, 0x10fb), +R(0x1361, 0x1368), +R(0x166d, 0x166e), +R(0x1680, 0x1680), +R(0x169b, 0x169c), +R(0x16eb, 0x16ed), +R(0x1735, 0x1736), +R(0x17d4, 0x17d6), +R(0x17d8, 0x17da), +R(0x1800, 0x180a), +R(0x180e, 0x180e), +R(0x1944, 0x1945), +R(0x19de, 0x19df), +R(0x1a1e, 0x1a1f), +R(0x1b5a, 0x1b60), +R(0x1c3b, 0x1c3f), +R(0x1c7e, 0x1c7f), +R(0x2010, 0x2027), +R(0x2030, 0x205e), +R(0x207a, 0x207e), +R(0x208a, 0x208e), +R(0x2140, 0x2144), +R(0x214b, 0x214b), +R(0x2190, 0x245f), +R(0x2500, 0x2775), +R(0x2794, 0x2bff), +R(0x2cf9, 0x2cfc), +R(0x2cfe, 0x2cff), +R(0x2e00, 0x2e7f), +R(0x3001, 0x3003), +R(0x3008, 0x3020), +R(0x3030, 0x3030), +R(0x303d, 0x303d), +R(0x30a0, 0x30a0), +R(0x30fb, 0x30fb), +R(0xa60d, 0xa60f), +R(0xa874, 0xa877), +R(0xa8ce, 0xa8cf), +R(0xa92e, 0xa92f), +R(0xa95f, 0xa95f), +R(0xfb29, 0xfb29), +R(0xfd3e, 0xfd3f), +R(0xfe10, 0xfe19), +R(0xfe30, 0xfe52), +R(0xfe54, 0xfe66), +R(0xfe68, 0xfe68), +R(0xfe6a, 0xfe6b), +R(0xff01, 0xff03), +R(0xff05, 0xff0f), +R(0xff1a, 0xff20), +R(0xff3b, 0xff3d), +R(0xff3f, 0xff3f), +R(0xff5b, 0xff65), +R(0xffe2, 0xffe2), +R(0xffe9, 0xffec), +R(0x10100, 0x10101), +R(0x1039f, 0x1039f), +R(0x103d0, 0x103d0), +R(0x1091f, 0x1091f), +R(0x1093f, 0x1093f), +R(0x10a50, 0x10a58), +R(0x12470, 0x12473), +R(0x1d6c1, 0x1d6c1), +R(0x1d6db, 0x1d6db), +R(0x1d6fb, 0x1d6fb), +R(0x1d715, 0x1d715), +R(0x1d735, 0x1d735), +R(0x1d74f, 0x1d74f), +R(0x1d76f, 0x1d76f), +R(0x1d789, 0x1d789), +R(0x1d7a9, 0x1d7a9), +R(0x1d7c3, 0x1d7c3), +}; + +int iswpunct(wint_t wc) +{ + unsigned c = wc; + int a = 0; + int n = sizeof ranges / sizeof ranges[0]; + do { + n >>= 1; + a += n+1 & (signed)(ranges[a+n].base-c)>>31; + } while (n); + return ranges[a].base-c <= ranges[a].len; +} diff --git a/src/ctype/iswspace.c b/src/ctype/iswspace.c new file mode 100644 index 00000000..68a17437 --- /dev/null +++ b/src/ctype/iswspace.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <wctype.h> +#include <ctype.h> + +int iswspace(wint_t wc) +{ + static const wchar_t spaces[] = { + ' ', '\t', '\n', '\r', 11, 12, 0x0085, + 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, + 0x2006, 0x2008, 0x2009, 0x200a, 0x200b, + 0x2028, 0x2029, 0x2050, 0x3000, 0 + }; + if (wcschr(spaces, wc)) return 1; + return 0; +} diff --git a/src/ctype/iswupper.c b/src/ctype/iswupper.c new file mode 100644 index 00000000..eae59a75 --- /dev/null +++ b/src/ctype/iswupper.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswupper(wint_t wc) +{ + return towlower(wc) != wc; +} diff --git a/src/ctype/iswxdigit.c b/src/ctype/iswxdigit.c new file mode 100644 index 00000000..229a469f --- /dev/null +++ b/src/ctype/iswxdigit.c @@ -0,0 +1,7 @@ +#include <wchar.h> +#include <wctype.h> + +int iswxdigit(wint_t wc) +{ + return (unsigned)(wc-'0') < 10 || (unsigned)((wc|32)-'a') < 6; +} diff --git a/src/ctype/isxdigit.c b/src/ctype/isxdigit.c new file mode 100644 index 00000000..ae68a3dc --- /dev/null +++ b/src/ctype/isxdigit.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isxdigit(int c) +{ + return isdigit(c) || ((unsigned)c|32)-'a' < 6; +} diff --git a/src/ctype/toascii.c b/src/ctype/toascii.c new file mode 100644 index 00000000..f0e48e8e --- /dev/null +++ b/src/ctype/toascii.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +/* nonsense function that should NEVER be used! */ +int toascii(int c) +{ + return c & 0x7f; +} diff --git a/src/ctype/tolower.c b/src/ctype/tolower.c new file mode 100644 index 00000000..b56f3c50 --- /dev/null +++ b/src/ctype/tolower.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int tolower(int c) +{ + if (isupper(c)) return c | 32; + return c; +} diff --git a/src/ctype/toupper.c b/src/ctype/toupper.c new file mode 100644 index 00000000..1799f030 --- /dev/null +++ b/src/ctype/toupper.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int toupper(int c) +{ + if (islower(c)) return c & 0x5f; + return c; +} diff --git a/src/ctype/towctrans.c b/src/ctype/towctrans.c new file mode 100644 index 00000000..0b1eed04 --- /dev/null +++ b/src/ctype/towctrans.c @@ -0,0 +1,246 @@ +#include <wchar.h> +#include <wctype.h> +#include <stdio.h> + +#define CASEMAP(u1,u2,l) { (u1), (l)-(u1), (u2)-(u1)+1 } +#define CASELACE(u1,u2) CASEMAP((u1),(u2),(u1)+1) + +static const struct { + unsigned short upper; + signed char lower; + unsigned char len; +} casemaps[] = { + CASEMAP('A','Z','a'), + CASEMAP(0xc0,0xde,0xe0), + + CASELACE(0x0100,0x012e), + CASELACE(0x0132,0x0136), + CASELACE(0x0139,0x0147), + CASELACE(0x014a,0x0176), + CASELACE(0x0179,0x017d), + + CASELACE(0x370,0x372), + CASEMAP(0x391,0x3a1,0x3b1), + CASEMAP(0x3a3,0x3ab,0x3c3), + CASEMAP(0x400,0x40f,0x450), + CASEMAP(0x410,0x42f,0x430), + + CASELACE(0x460,0x480), + CASELACE(0x48a,0x4be), + CASELACE(0x4c1,0x4cd), + CASELACE(0x4d0,0x50e), + + CASEMAP(0x531,0x556,0x561), + + CASELACE(0x01a0,0x01a4), + CASELACE(0x01b3,0x01b5), + CASELACE(0x01cd,0x01db), + CASELACE(0x01de,0x01ee), + CASELACE(0x01f8,0x021e), + CASELACE(0x0222,0x0232), + CASELACE(0x03d8,0x03ee), + + CASELACE(0x1e00,0x1e94), + CASELACE(0x1ea0,0x1efe), + + CASEMAP(0x1f08,0x1f0f,0x1f00), + CASEMAP(0x1f18,0x1f1d,0x1f10), + CASEMAP(0x1f28,0x1f2f,0x1f20), + CASEMAP(0x1f38,0x1f3f,0x1f30), + CASEMAP(0x1f48,0x1f4d,0x1f40), + + CASEMAP(0x1f68,0x1f6f,0x1f60), + CASEMAP(0x1f88,0x1f8f,0x1f80), + CASEMAP(0x1f98,0x1f9f,0x1f90), + CASEMAP(0x1fa8,0x1faf,0x1fa0), + CASEMAP(0x1fb8,0x1fb9,0x1fb0), + CASEMAP(0x1fba,0x1fbb,0x1f70), + CASEMAP(0x1fc8,0x1fcb,0x1f72), + CASEMAP(0x1fd8,0x1fd9,0x1fd0), + CASEMAP(0x1fda,0x1fdb,0x1f76), + CASEMAP(0x1fe8,0x1fe9,0x1fe0), + CASEMAP(0x1fea,0x1feb,0x1f7a), + CASEMAP(0x1ff8,0x1ff9,0x1f78), + CASEMAP(0x1ffa,0x1ffb,0x1f7c), + + CASELACE(0x246,0x24e), + CASELACE(0x510,0x512), + CASEMAP(0x2160,0x216f,0x2170), + CASEMAP(0x2c00,0x2c2e,0x2c30), + CASELACE(0x2c67,0x2c6b), + CASELACE(0x2c80,0x2ce2), + + CASELACE(0xa722,0xa72e), + CASELACE(0xa732,0xa76e), + CASELACE(0xa779,0xa77b), + CASELACE(0xa77e,0xa786), + + CASEMAP(0xff21,0xff3a,0xff41), + { 0,0,0 } +}; + +static const unsigned short pairs[][2] = { + { 'I', 0x0131 }, + { 'S', 0x017f }, + { 0x0130, 'i' }, + { 0x0178, 0x00ff }, + { 0x0181, 0x0253 }, + { 0x0182, 0x0183 }, + { 0x0184, 0x0185 }, + { 0x0186, 0x0254 }, + { 0x0187, 0x0188 }, + { 0x0189, 0x0256 }, + { 0x018a, 0x0257 }, + { 0x018b, 0x018c }, + { 0x018e, 0x01dd }, + { 0x018f, 0x0259 }, + { 0x0190, 0x025b }, + { 0x0191, 0x0192 }, + { 0x0193, 0x0260 }, + { 0x0194, 0x0263 }, + { 0x0196, 0x0269 }, + { 0x0197, 0x0268 }, + { 0x0198, 0x0199 }, + { 0x019c, 0x026f }, + { 0x019d, 0x0272 }, + { 0x019f, 0x0275 }, + { 0x01a6, 0x0280 }, + { 0x01a7, 0x01a8 }, + { 0x01a9, 0x0283 }, + { 0x01ac, 0x01ad }, + { 0x01ae, 0x0288 }, + { 0x01af, 0x01b0 }, + { 0x01b1, 0x028a }, + { 0x01b2, 0x028b }, + { 0x01b7, 0x0292 }, + { 0x01b8, 0x01b9 }, + { 0x01bc, 0x01bd }, + { 0x01c4, 0x01c6 }, + { 0x01c4, 0x01c5 }, + { 0x01c5, 0x01c6 }, + { 0x01c7, 0x01c9 }, + { 0x01c7, 0x01c8 }, + { 0x01c8, 0x01c9 }, + { 0x01ca, 0x01cc }, + { 0x01ca, 0x01cb }, + { 0x01cb, 0x01cc }, + { 0x01f1, 0x01f3 }, + { 0x01f1, 0x01f2 }, + { 0x01f2, 0x01f3 }, + { 0x01f4, 0x01f5 }, + { 0x01f6, 0x0195 }, + { 0x01f7, 0x01bf }, + { 0x0220, 0x019e }, + { 0x0386, 0x03ac }, + { 0x0388, 0x03ad }, + { 0x0389, 0x03ae }, + { 0x038a, 0x03af }, + { 0x038c, 0x03cc }, + { 0x038e, 0x03cd }, + { 0x038f, 0x03ce }, + { 0x0399, 0x0345 }, + { 0x0399, 0x1fbe }, + { 0x03a3, 0x03c2 }, + { 0x03f7, 0x03f8 }, + { 0x03fa, 0x03fb }, + { 0x1e60, 0x1e9b }, + + { 0x1f59, 0x1f51 }, + { 0x1f5b, 0x1f53 }, + { 0x1f5d, 0x1f55 }, + { 0x1f5f, 0x1f57 }, + { 0x1fbc, 0x1fb3 }, + { 0x1fcc, 0x1fc3 }, + { 0x1fec, 0x1fe5 }, + { 0x1ffc, 0x1ff3 }, + + { 0x23a, 0x2c65 }, + { 0x23b, 0x23c }, + { 0x23d, 0x19a }, + { 0x23e, 0x2c66 }, + { 0x241, 0x242 }, + { 0x243, 0x180 }, + { 0x244, 0x289 }, + { 0x245, 0x28c }, + { 0x3f4, 0x3b8 }, + { 0x3f9, 0x3f2 }, + { 0x3fd, 0x37b }, + { 0x3fe, 0x37c }, + { 0x3ff, 0x37d }, + { 0x4c0, 0x4cf }, + + { 0x2126, 0x3c9 }, + { 0x212a, 'k' }, + { 0x212b, 0xe5 }, + { 0x2132, 0x214e }, + { 0x2183, 0x2184 }, + { 0x2c60, 0x2c61 }, + { 0x2c62, 0x26b }, + { 0x2c63, 0x1d7d }, + { 0x2c64, 0x27d }, + { 0x2c6d, 0x251 }, + { 0x2c6e, 0x271 }, + { 0x2c6f, 0x250 }, + { 0x2c72, 0x2c73 }, + { 0x2c75, 0x2c76 }, + + { 0xa77d, 0x1d79 }, + + /* bogus greek 'symbol' letters */ + { 0x376, 0x377 }, + { 0x39c, 0xb5 }, + { 0x392, 0x3d0 }, + { 0x398, 0x3d1 }, + { 0x3a6, 0x3d5 }, + { 0x3a0, 0x3d6 }, + { 0x39a, 0x3f0 }, + { 0x3a1, 0x3f1 }, + { 0x395, 0x3f5 }, + { 0x3cf, 0x3d7 }, + + { 0,0 } +}; + + +static wchar_t __towcase(wchar_t wc, int lower) +{ + int i; + int lmul = 2*lower-1; + int lmask = lower-1; + if ((unsigned)wc - 0x10400 < 0x50) + return wc + lmul*0x28; + /* no letters with case in these large ranges */ + if (!iswalpha(wc) + || (unsigned)wc - 0x0600 <= 0x0fff-0x0600 + || (unsigned)wc - 0x2e00 <= 0xa6ff-0x2e00 + || (unsigned)wc - 0xa800 <= 0xfeff-0xa800) + return wc; + /* special case because the diff between upper/lower is too big */ + if ((unsigned)wc - 0x10a0 < 0x26 || (unsigned)wc - 0x2d00 < 0x26) + return wc + lmul*(0x2d00-0x10a0); + for (i=0; casemaps[i].len; i++) { + int base = casemaps[i].upper + (lmask & casemaps[i].lower); + if ((unsigned)wc-base < casemaps[i].len) { + if (casemaps[i].lower == 1) + return wc + lower - ((wc-casemaps[i].upper)&1); + return wc + lmul*casemaps[i].lower; + } + } + for (i=0; pairs[i][1-lower]; i++) { + if (pairs[i][1-lower] == wc) + return pairs[i][lower]; + } + if ((unsigned)wc - 0x10428 + (lower<<5) + (lower<<3) < 0x28) + return wc - 0x28 + (lower<<10) + (lower<<6); + return wc; +} + +wint_t towupper(wint_t wc) +{ + return __towcase(wc, 0); +} + +wint_t towlower(wint_t wc) +{ + return __towcase(wc, 1); +} diff --git a/src/ctype/wcswidth.c b/src/ctype/wcswidth.c new file mode 100644 index 00000000..5c8a5a4d --- /dev/null +++ b/src/ctype/wcswidth.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +int wcswidth(const wchar_t *wcs, size_t n) +{ + int l=0, k=0; + for (; n-- && *wcs && (k = wcwidth(*wcs)) >= 0; l+=k, wcs++); + return (k < 0) ? k : l; +} diff --git a/src/ctype/wctrans.c b/src/ctype/wctrans.c new file mode 100644 index 00000000..03e9fd6a --- /dev/null +++ b/src/ctype/wctrans.c @@ -0,0 +1,16 @@ +#include <wctype.h> +#include <string.h> + +wctrans_t wctrans(const char *class) +{ + if (!strcmp(class, "toupper")) return 1; + if (!strcmp(class, "tolower")) return 2; + return 0; +} + +wint_t towctrans(wint_t wc, wctrans_t trans) +{ + if (trans == 1) return towupper(wc); + if (trans == 2) return towlower(wc); + return wc; +} diff --git a/src/ctype/wcwidth.c b/src/ctype/wcwidth.c new file mode 100644 index 00000000..ebc560a5 --- /dev/null +++ b/src/ctype/wcwidth.c @@ -0,0 +1,185 @@ +#include <inttypes.h> +#include <wchar.h> + +#define R(a,b,w) { (b), (w)/2, (b)-(a) } + +static const struct range { + uint32_t base:20; + uint32_t width:1; + uint32_t len:11; +} ranges[] = { + R(0x0300, 0x036F, 0), + R(0x0483, 0x0486, 0), + R(0x0488, 0x0489, 0), + R(0x0591, 0x05BD, 0), + R(0x05BF, 0x05BF, 0), + R(0x05C1, 0x05C2, 0), + R(0x05C4, 0x05C5, 0), + R(0x05C7, 0x05C7, 0), + R(0x0600, 0x0603, 0), + R(0x0610, 0x0615, 0), + R(0x064B, 0x065E, 0), + R(0x0670, 0x0670, 0), + R(0x06D6, 0x06E4, 0), + R(0x06E7, 0x06E8, 0), + R(0x06EA, 0x06ED, 0), + R(0x070F, 0x070F, 0), + R(0x0711, 0x0711, 0), + R(0x0730, 0x074A, 0), + R(0x07A6, 0x07B0, 0), + R(0x07EB, 0x07F3, 0), + R(0x0901, 0x0902, 0), + R(0x093C, 0x093C, 0), + R(0x0941, 0x0948, 0), + R(0x094D, 0x094D, 0), + R(0x0951, 0x0954, 0), + R(0x0962, 0x0963, 0), + R(0x0981, 0x0981, 0), + R(0x09BC, 0x09BC, 0), + R(0x09C1, 0x09C4, 0), + R(0x09CD, 0x09CD, 0), + R(0x09E2, 0x09E3, 0), + R(0x0A01, 0x0A02, 0), + R(0x0A3C, 0x0A3C, 0), + R(0x0A41, 0x0A42, 0), + R(0x0A47, 0x0A48, 0), + R(0x0A4B, 0x0A4D, 0), + R(0x0A70, 0x0A71, 0), + R(0x0A81, 0x0A82, 0), + R(0x0ABC, 0x0ABC, 0), + R(0x0AC1, 0x0AC5, 0), + R(0x0AC7, 0x0AC8, 0), + R(0x0ACD, 0x0ACD, 0), + R(0x0AE2, 0x0AE3, 0), + R(0x0B01, 0x0B01, 0), + R(0x0B3C, 0x0B3C, 0), + R(0x0B3F, 0x0B3F, 0), + R(0x0B41, 0x0B43, 0), + R(0x0B4D, 0x0B4D, 0), + R(0x0B56, 0x0B56, 0), + R(0x0B82, 0x0B82, 0), + R(0x0BC0, 0x0BC0, 0), + R(0x0BCD, 0x0BCD, 0), + R(0x0C3E, 0x0C40, 0), + R(0x0C46, 0x0C48, 0), + R(0x0C4A, 0x0C4D, 0), + R(0x0C55, 0x0C56, 0), + R(0x0CBC, 0x0CBC, 0), + R(0x0CBF, 0x0CBF, 0), + R(0x0CC6, 0x0CC6, 0), + R(0x0CCC, 0x0CCD, 0), + R(0x0CE2, 0x0CE3, 0), + R(0x0D41, 0x0D43, 0), + R(0x0D4D, 0x0D4D, 0), + R(0x0DCA, 0x0DCA, 0), + R(0x0DD2, 0x0DD4, 0), + R(0x0DD6, 0x0DD6, 0), + R(0x0E31, 0x0E31, 0), + R(0x0E34, 0x0E3A, 0), + R(0x0E47, 0x0E4E, 0), + R(0x0EB1, 0x0EB1, 0), + R(0x0EB4, 0x0EB9, 0), + R(0x0EBB, 0x0EBC, 0), + R(0x0EC8, 0x0ECD, 0), + R(0x0F18, 0x0F19, 0), + R(0x0F35, 0x0F35, 0), + R(0x0F37, 0x0F37, 0), + R(0x0F39, 0x0F39, 0), + R(0x0F71, 0x0F7E, 0), + R(0x0F80, 0x0F84, 0), + R(0x0F86, 0x0F87, 0), + R(0x0F90, 0x0F97, 0), + R(0x0F99, 0x0FBC, 0), + R(0x0FC6, 0x0FC6, 0), + R(0x102D, 0x1030, 0), + R(0x1032, 0x1032, 0), + R(0x1036, 0x1037, 0), + R(0x1039, 0x1039, 0), + R(0x1058, 0x1059, 0), + R(0x1100, 0x115F, 2), + R(0x1160, 0x11FF, 0), + R(0x135F, 0x135F, 0), + R(0x1712, 0x1714, 0), + R(0x1732, 0x1734, 0), + R(0x1752, 0x1753, 0), + R(0x1772, 0x1773, 0), + R(0x17B4, 0x17B5, 0), + R(0x17B7, 0x17BD, 0), + R(0x17C6, 0x17C6, 0), + R(0x17C9, 0x17D3, 0), + R(0x17DD, 0x17DD, 0), + R(0x180B, 0x180D, 0), + R(0x18A9, 0x18A9, 0), + R(0x1920, 0x1922, 0), + R(0x1927, 0x1928, 0), + R(0x1932, 0x1932, 0), + R(0x1939, 0x193B, 0), + R(0x1A17, 0x1A18, 0), + R(0x1B00, 0x1B03, 0), + R(0x1B34, 0x1B34, 0), + R(0x1B36, 0x1B3A, 0), + R(0x1B3C, 0x1B3C, 0), + R(0x1B42, 0x1B42, 0), + R(0x1B6B, 0x1B73, 0), + R(0x1DC0, 0x1DCA, 0), + R(0x1DFE, 0x1DFF, 0), + R(0x200B, 0x200F, 0), + R(0x202A, 0x202E, 0), + R(0x2060, 0x2063, 0), + R(0x206A, 0x206F, 0), + R(0x20D0, 0x20EF, 0), + R(0x2329, 0x232A, 2), + R(0x2E80, 0x3029, 2), + R(0x302A, 0x302F, 0), + R(0x3030, 0x303E, 2), + R(0x3099, 0x309A, 0), + R(0xA806, 0xA806, 0), + R(0xA80B, 0xA80B, 0), + R(0xA825, 0xA826, 0), + R(0xF900, 0xFAFF, 2), + R(0xFB1E, 0xFB1E, 0), + R(0xFE00, 0xFE0F, 0), + R(0xFE20, 0xFE23, 0), + R(0xFE30, 0xFE6F, 2), + R(0xFEFF, 0xFEFF, 0), + R(0xFF00, 0xFF60, 2), + R(0xFFE0, 0xFFE6, 2), + R(0x10A01, 0x10A03, 0), + R(0x10A05, 0x10A06, 0), + R(0x10A0C, 0x10A0F, 0), + R(0x10A38, 0x10A3A, 0), + R(0x10A3F, 0x10A3F, 0), + R(0x1D167, 0x1D169, 0), + R(0x1D173, 0x1D182, 0), + R(0x1D185, 0x1D18B, 0), + R(0x1D1AA, 0x1D1AD, 0), + R(0x1D242, 0x1D244, 0), + R(0xE0001, 0xE0001, 0), + R(0xE0020, 0xE007F, 0), + R(0xE0100, 0xE01EF, 0), +}; + +/* Note: because the len field is only 10 bits, we must special-case + * the two huge ranges of full width characters and exclude them + * from the binary search table. */ + +int wcwidth(wchar_t wc) +{ + int a, n; + uint32_t c = wc; + + if (c-0x20 < 0x5f) return 1; + if (!iswprint(c)) return wc ? -1 : 0; + if (c-0x20000 < 0x20000) return 2; + + /* The following code is a branchless binary search. */ + a = 0; + n = sizeof ranges / sizeof ranges[0]; + do { + n >>= 1; + a += n+1 & (signed)(ranges[a+n].base-c)>>31; + } while (n); + if (ranges[a].base-c <= ranges[a].len) + return 2*ranges[a].width; + return 1 + (c-0x3040 < 0xd800-0x3040); +} diff --git a/src/dirent/__dirent.h b/src/dirent/__dirent.h new file mode 100644 index 00000000..07b3ee68 --- /dev/null +++ b/src/dirent/__dirent.h @@ -0,0 +1,9 @@ +struct __DIR_s +{ + int lock; + int fd; + off_t tell; + int buf_pos; + int buf_end; + char buf[2048]; +}; diff --git a/src/dirent/__getdents.c b/src/dirent/__getdents.c new file mode 100644 index 00000000..4195430b --- /dev/null +++ b/src/dirent/__getdents.c @@ -0,0 +1,12 @@ +#include <dirent.h> +#include "syscall.h" +#include "libc.h" + +int __getdents(int fd, struct dirent *buf, size_t len) +{ + return syscall3(__NR_getdents64, fd, (long)buf, len); +} + +weak_alias(__getdents, getdents); + +LFS64(getdents); diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c new file mode 100644 index 00000000..42050fb7 --- /dev/null +++ b/src/dirent/alphasort.c @@ -0,0 +1,10 @@ +#include <string.h> +#include <dirent.h> +#include "libc.h" + +int alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcoll((*a)->d_name, (*b)->d_name); +} + +LFS64(alphasort); diff --git a/src/dirent/closedir.c b/src/dirent/closedir.c new file mode 100644 index 00000000..81e9591c --- /dev/null +++ b/src/dirent/closedir.c @@ -0,0 +1,11 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +int closedir(DIR *dir) +{ + int ret = close(dir->fd); + free(dir); + return ret; +} diff --git a/src/dirent/dirfd.c b/src/dirent/dirfd.c new file mode 100644 index 00000000..6c860073 --- /dev/null +++ b/src/dirent/dirfd.c @@ -0,0 +1,7 @@ +#include <dirent.h> +#include "__dirent.h" + +int dirfd(DIR *d) +{ + return d->fd; +} diff --git a/src/dirent/fdopendir.c b/src/dirent/fdopendir.c new file mode 100644 index 00000000..c4b8e61d --- /dev/null +++ b/src/dirent/fdopendir.c @@ -0,0 +1,26 @@ +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "__dirent.h" + +DIR *fdopendir(int fd) +{ + DIR *dir; + struct stat st; + + if (fstat(fd, &st) < 0 || !S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return 0; + } + if (!(dir = calloc(1, sizeof *dir))) { + return 0; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + dir->fd = fd; + return dir; +} diff --git a/src/dirent/opendir.c b/src/dirent/opendir.c new file mode 100644 index 00000000..cefe6ce7 --- /dev/null +++ b/src/dirent/opendir.c @@ -0,0 +1,25 @@ +#define _GNU_SOURCE +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "__dirent.h" + +DIR *opendir(const char *name) +{ + int fd; + DIR *dir; + + if ((fd = open(name, O_RDONLY|O_DIRECTORY)) < 0) + return 0; + fcntl(fd, F_SETFD, FD_CLOEXEC); + if (!(dir = calloc(1, sizeof *dir))) { + close(fd); + return 0; + } + dir->fd = fd; + return dir; +} diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c new file mode 100644 index 00000000..1aeb25a5 --- /dev/null +++ b/src/dirent/readdir.c @@ -0,0 +1,32 @@ +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include "__dirent.h" +#include "syscall.h" +#include "libc.h" + +int __getdents(int, struct dirent *, size_t); + +struct dirent *readdir(DIR *dir) +{ + struct dirent *de; + + if (dir->buf_pos >= dir->buf_end) { + int len = __getdents(dir->fd, (void *)dir->buf, sizeof dir->buf); + if (len < 0) { + dir->lock = 0; + return NULL; + } else if (len == 0) return 0; + dir->buf_end = len; + dir->buf_pos = 0; + } + de = (void *)(dir->buf + dir->buf_pos); + dir->buf_pos += de->d_reclen; + dir->tell = de->d_off; + return de; +} + +LFS64(readdir); diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c new file mode 100644 index 00000000..58f60325 --- /dev/null +++ b/src/dirent/readdir_r.c @@ -0,0 +1,30 @@ +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "__dirent.h" +#include "libc.h" + +int readdir_r(DIR *dir, struct dirent *buf, struct dirent **result) +{ + struct dirent *de; + int errno_save = errno; + int ret; + + LOCK(&dir->lock); + errno = 0; + de = readdir(dir); + if ((ret = errno)) { + UNLOCK(&dir->lock); + return ret; + } + errno = errno_save; + if (de) memcpy(buf, de, de->d_reclen); + else buf = NULL; + + UNLOCK(&dir->lock); + *result = buf; + return 0; +} + +LFS64_2(readdir_r, readdir64_r); diff --git a/src/dirent/rewinddir.c b/src/dirent/rewinddir.c new file mode 100644 index 00000000..c6138f7c --- /dev/null +++ b/src/dirent/rewinddir.c @@ -0,0 +1,13 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +void rewinddir(DIR *dir) +{ + LOCK(&dir->lock); + lseek(dir->fd, 0, SEEK_SET); + dir->buf_pos = dir->buf_end = 0; + dir->tell = 0; + UNLOCK(&dir->lock); +} diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c new file mode 100644 index 00000000..6a0a9993 --- /dev/null +++ b/src/dirent/scandir.c @@ -0,0 +1,50 @@ +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <stddef.h> +#include <libc.h> + +int scandir(const char *path, struct dirent ***res, + int (*sel)(const struct dirent *), + int (*cmp)(const struct dirent **, const struct dirent **)) +{ + DIR *d = opendir(path); + struct dirent *de, **names=0, **tmp; + size_t cnt=0, len=0, size; + int old_errno = errno; + + if (!d) return -1; + + while ((errno=0), (de = readdir(d))) { + if (sel && !sel(de)) continue; + if (cnt >= len) { + len = 2*len+1; + if (len > SIZE_MAX/sizeof *names) break; + tmp = realloc(names, len * sizeof *names); + if (!tmp) break; + names = tmp; + } + size = offsetof(struct dirent,d_name) + strlen(de->d_name) + 1; + names[cnt] = malloc(size); + if (!names[cnt]) break; + memcpy(names[cnt++], de, size); + } + + closedir(d); + + if (errno) { + old_errno = errno; + if (names) while (cnt-->0) free(names[cnt]); + free(names); + errno = old_errno; + return -1; + } + + if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp); + *res = names; + return cnt; +} + +LFS64(scandir); diff --git a/src/dirent/seekdir.c b/src/dirent/seekdir.c new file mode 100644 index 00000000..81a0e331 --- /dev/null +++ b/src/dirent/seekdir.c @@ -0,0 +1,12 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +void seekdir(DIR *dir, long off) +{ + LOCK(&dir->lock); + dir->tell = lseek(dir->fd, off, SEEK_SET); + dir->buf_pos = dir->buf_end = 0; + UNLOCK(&dir->lock); +} diff --git a/src/dirent/telldir.c b/src/dirent/telldir.c new file mode 100644 index 00000000..cf25acff --- /dev/null +++ b/src/dirent/telldir.c @@ -0,0 +1,7 @@ +#include <dirent.h> +#include "__dirent.h" + +long telldir(DIR *dir) +{ + return dir->tell; +} diff --git a/src/env/__environ.c b/src/env/__environ.c new file mode 100644 index 00000000..d7bd5e50 --- /dev/null +++ b/src/env/__environ.c @@ -0,0 +1,7 @@ +#include "libc.h" + +#undef environ +char **___environ = 0; +weak_alias(___environ, __environ); +weak_alias(___environ, _environ); +weak_alias(___environ, environ); diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c new file mode 100644 index 00000000..70af77b5 --- /dev/null +++ b/src/env/__libc_start_main.c @@ -0,0 +1,26 @@ +#include "libc.h" + +/* Any use of __environ/environ will override this symbol. */ +char **__dummy_environ = (void *)-1; +weak_alias(__dummy_environ, ___environ); + +int __libc_start_main( + int (*main)(int, char **, char **), int argc, char **argv, + int (*init)(int, char **, char **), void (*fini)(void), + void (*ldso_fini)(void)) +{ + /* Save the environment if it may be used by libc/application */ + char **envp = argv+argc+1; + if (___environ != (void *)-1) ___environ = envp; + + /* Avoid writing 0 and triggering unnecessary COW */ + if (ldso_fini) libc.ldso_fini = ldso_fini; + if (fini) libc.fini = fini; + + /* Execute constructors (static) linked into the application */ + if (init) init(argc, argv, envp); + + /* Pass control to to application */ + exit(main(argc, argv, envp)); + return 0; +} diff --git a/src/env/clearenv.c b/src/env/clearenv.c new file mode 100644 index 00000000..a2475ce7 --- /dev/null +++ b/src/env/clearenv.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +extern char **__environ; + +int clearenv() +{ + __environ[0] = 0; + return 0; +} diff --git a/src/env/getenv.c b/src/env/getenv.c new file mode 100644 index 00000000..00c1bce0 --- /dev/null +++ b/src/env/getenv.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +char *getenv(const char *name) +{ + int i; + size_t l = strlen(name); + if (!__environ || !*name || strchr(name, '=')) return NULL; + for (i=0; __environ[i] && (strncmp(name, __environ[i], l) + || __environ[i][l] != '='); i++); + if (__environ[i]) return __environ[i] + l+1; + return NULL; +} diff --git a/src/env/putenv.c b/src/env/putenv.c new file mode 100644 index 00000000..181a4181 --- /dev/null +++ b/src/env/putenv.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +extern char **__environ; +char **__env_map; + +int __putenv(char *s, int a) +{ + int i=0, j=0; + char *end = strchr(s, '='); + size_t l = end-s+1; + char **newenv = 0; + char **newmap = 0; + static char **oldenv; + + if (!end || l == 1) return -1; + for (; __environ[i] && memcmp(s, __environ[i], l); i++); + if (a) { + if (!__env_map) { + __env_map = calloc(2, sizeof(char *)); + if (__env_map) __env_map[0] = s; + } else { + for (; __env_map[j] && __env_map[j] != __environ[i]; j++); + if (!__env_map[j]) { + newmap = realloc(__env_map, sizeof(char *)*(j+2)); + if (newmap) { + __env_map = newmap; + __env_map[j] = s; + __env_map[j+1] = NULL; + } + } else { + free(__env_map[j]); + } + } + } + if (!__environ[i]) { + newenv = malloc(sizeof(char *)*(i+2)); + if (!newenv) { + if (a && __env_map) __env_map[j] = 0; + return -1; + } + memcpy(newenv, __environ, sizeof(char *)*i); + newenv[i] = s; + newenv[i+1] = 0; + __environ = newenv; + free(oldenv); + oldenv = __environ; + } + + __environ[i] = s; + return 0; +} + +int putenv(char *s) +{ + return __putenv(s, 0); +} diff --git a/src/env/setenv.c b/src/env/setenv.c new file mode 100644 index 00000000..03e165c8 --- /dev/null +++ b/src/env/setenv.c @@ -0,0 +1,31 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int __putenv(char *s, int a); + +int setenv(const char *var, const char *value, int overwrite) +{ + char *s; + int l1, l2; + + if (strchr(var, '=')) { + errno = EINVAL; + return -1; + } + if (!overwrite && getenv(var)) return 0; + + l1 = strlen(var); + l2 = strlen(value); + s = malloc(l1+l2+2); + memcpy(s, var, l1); + s[l1] = '='; + memcpy(s+l1+1, value, l2); + s[l1+l2+1] = 0; + if (__putenv(s, 1)) { + free(s); + errno = ENOMEM; + return -1; + } + return 0; +} diff --git a/src/env/unsetenv.c b/src/env/unsetenv.c new file mode 100644 index 00000000..7493d970 --- /dev/null +++ b/src/env/unsetenv.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +extern char **__environ; +extern char **__env_map; + +int unsetenv(const char *name) +{ + int i, j; + size_t l = strlen(name); + + if (!*name || strchr(name, '=')) { + errno = EINVAL; + return -1; + } +again: + for (i=0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++); + if (__environ[i]) { + if (__env_map) { + for (j=0; __env_map[j] && __env_map[j] != __environ[i]; j++); + free (__env_map[j]); + for (; __env_map[j]; j++) + __env_map[j] = __env_map[j+1]; + } + for (; __environ[i]; i++) + __environ[i] = __environ[i+1]; + goto again; + } + return 0; +} diff --git a/src/errno/__errno_location.c b/src/errno/__errno_location.c new file mode 100644 index 00000000..0a220b63 --- /dev/null +++ b/src/errno/__errno_location.c @@ -0,0 +1,11 @@ +#include <errno.h> +#include "libc.h" + +#undef errno +int errno; + +int *__errno_location(void) +{ + if (libc.errno_location) return libc.errno_location(); + return &errno; +} diff --git a/src/errno/__strerror.h b/src/errno/__strerror.h new file mode 100644 index 00000000..00eaf938 --- /dev/null +++ b/src/errno/__strerror.h @@ -0,0 +1,101 @@ +/* This file is sorted such that 'errors' which represent exceptional + * conditions under which a correct program may fail come first, followed + * by messages that indicate an incorrect program or system failure. The + * macro E() along with double-inclusion is used to ensure that ordering + * of the strings remains synchronized. */ + +E(EILSEQ, "Illegal byte sequence") +E(EDOM, "Argument outside domain") +E(ERANGE, "Result not representable") + +E(ENOTTY, "Not a tty") +E(EACCES, "Permission denied") +E(EPERM, "Operation not permitted") +E(ENOENT, "No such file or directory") +E(ESRCH, "No such process") +E(EEXIST, "File exists") + +E(EOVERFLOW, "Value too large for defined data type") +E(ENOSPC, "No space left on device") +E(ENOMEM, "Out of memory") + +E(EBUSY, "Device or resource busy") +E(EINTR, "Interrupted system call") +E(EAGAIN, "Operation would block") +E(ESPIPE, "Illegal seek") + +E(EXDEV, "Cross-device link") +E(EROFS, "Read-only file system") +E(ENOTEMPTY, "Directory not empty") + +E(ECONNRESET, "Connection reset by peer") +E(ETIMEDOUT, "Connection timed out") +E(ECONNREFUSED, "Connection refused") +E(EHOSTDOWN, "Host is down") +E(EHOSTUNREACH, "No route to host") +E(EADDRINUSE, "Address already in use") + +E(EPIPE, "Broken pipe") +E(EIO, "I/O error") +E(ENXIO, "No such device or address") +E(ENOTBLK, "Block device required") +E(ENODEV, "No such device") +E(ENOTDIR, "Not a directory") +E(EISDIR, "Is a directory") +E(ETXTBSY, "Text file busy") +E(ENOEXEC, "Exec format error") + +E(EINVAL, "Invalid argument") + +E(E2BIG, "Argument list too long") +E(ELOOP, "Too many levels of symbolic links") +E(ENAMETOOLONG, "Filename too long") +E(ENFILE, "File table overflow") +E(EMFILE, "Too many open files") +E(EBADF, "Bad file number") +E(ECHILD, "No child processes") +E(EFAULT, "Bad address") +E(EFBIG, "File too large") +E(EMLINK, "Too many links") +E(ENOLCK, "No record locks available") + +E(EDEADLK, "Resource deadlock would occur") +E(ENOSYS, "Function not supported") +E(ENOMSG, "No message of desired type") +E(EIDRM, "Identifier removed") +E(ENOSTR, "Device not a stream") +E(ENODATA, "No data available") +E(ETIME, "Timer expired") +E(ENOSR, "Out of streams resources") +E(ENOLINK, "Link has been severed") +E(EPROTO, "Protocol error") +E(EBADMSG, "Not a data message") +E(EBADFD, "File descriptor in bad state") +E(ENOTSOCK, "Socket operation on non-socket") +E(EDESTADDRREQ, "Destination address required") +E(EMSGSIZE, "Message too long") +E(EPROTOTYPE, "Protocol wrong type for socket") +E(ENOPROTOOPT, "Protocol not available") +E(EPROTONOSUPPORT,"Protocol not supported") +E(ESOCKTNOSUPPORT,"Socket type not supported") +E(EOPNOTSUPP, "Operation not supported on socket") +E(EPFNOSUPPORT, "Protocol family not supported") +E(EAFNOSUPPORT, "Address family not supported by protocol") +E(EADDRNOTAVAIL,"Cannot assign requested address") +E(ENETDOWN, "Network is down") +E(ENETUNREACH, "Network is unreachable") +E(ENETRESET, "Network dropped connection because of reset") +E(ECONNABORTED, "Software caused connection abort") +E(ENOBUFS, "No buffer space available") +E(EISCONN, "Socket is connected") +E(ENOTCONN, "Socket is not connected") +E(ESHUTDOWN, "Cannot send after socket shutdown") +E(EALREADY, "Operation already in progress") +E(EINPROGRESS, "Operation now in progress") +E(ESTALE, "Stale NFS file handle") +E(EREMOTEIO, "Remote I/O error") +E(EDQUOT, "Quota exceeded") +E(ENOMEDIUM, "No medium found") +E(EMEDIUMTYPE, "Wrong medium type") + +E(0, "Invalid error number") diff --git a/src/errno/strerror.c b/src/errno/strerror.c new file mode 100644 index 00000000..b8fbc6db --- /dev/null +++ b/src/errno/strerror.c @@ -0,0 +1,22 @@ +#include <errno.h> +#include <string.h> + +#define E(a,b) a, +static const unsigned char errid[] = { +#include "__strerror.h" +}; + +#undef E +#define E(a,b) b "\0" +static const char errmsg[] = +#include "__strerror.h" +; + +char *strerror(int e) +{ + const char *s; + int i; + for (i=0; errid[i] && errid[i] != e; i++); + for (s=errmsg; i; s++, i--) for (; *s; s++); + return (char *)s; +} diff --git a/src/exit/_Exit.c b/src/exit/_Exit.c new file mode 100644 index 00000000..8ef85a8f --- /dev/null +++ b/src/exit/_Exit.c @@ -0,0 +1,9 @@ +#include <stdlib.h> +#define SYSCALL_NORETURN +#include "syscall.h" + +void _Exit(int ec) +{ + syscall1(__NR_exit_group, ec); + syscall1(__NR_exit, ec); +} diff --git a/src/exit/abort.c b/src/exit/abort.c new file mode 100644 index 00000000..9a1c3d40 --- /dev/null +++ b/src/exit/abort.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <signal.h> + +void abort(void) +{ + raise(SIGABRT); + for (;;); +} diff --git a/src/exit/assert.c b/src/exit/assert.c new file mode 100644 index 00000000..e87442a7 --- /dev/null +++ b/src/exit/assert.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <stdlib.h> + +void __assert_fail(const char *expr, const char *file, int line, const char *func) +{ + fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); + fflush(NULL); + abort(); +} diff --git a/src/exit/atexit.c b/src/exit/atexit.c new file mode 100644 index 00000000..49c060e6 --- /dev/null +++ b/src/exit/atexit.c @@ -0,0 +1,57 @@ +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> +#include "libc.h" + +/* Ensure that at least 32 atexit handlers can be registered without malloc */ +#define COUNT 32 + +static struct fl +{ + struct fl *next; + void (*f[COUNT])(void); +} builtin, *head; + +static int run_atexit_functions(void) +{ + int i; + for (; head; head=head->next) { + for (i=COUNT-1; i>=0 && !head->f[i]; i--); + for (; i>=0; i--) head->f[i](); + } + return 0; +} + +int (*const __funcs_on_exit)(void) = run_atexit_functions; + +int atexit(void (*func)(void)) +{ + static int lock; + int i; + + /* Hook for atexit extensions */ + if (libc.atexit) return libc.atexit(func); + + LOCK(&lock); + + /* Defer initialization of head so it can be in BSS */ + if (!head) head = &builtin; + + /* If the current function list is full, add a new one */ + if (head->f[COUNT-1]) { + struct fl *new_fl = calloc(sizeof(struct fl), 1); + if (!new_fl) { + UNLOCK(&lock); + return -1; + } + new_fl->next = head; + head = new_fl; + } + + /* Append function to the list. */ + for (i=0; i<COUNT && head->f[i]; i++); + head->f[i] = func; + + UNLOCK(&lock); + return 0; +} diff --git a/src/exit/exit.c b/src/exit/exit.c new file mode 100644 index 00000000..d0c1bfc1 --- /dev/null +++ b/src/exit/exit.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include "libc.h" + +/* __overflow.c and atexit.c override these */ +static int (*const dummy)() = 0; +weak_alias(dummy, __funcs_on_exit); +weak_alias(dummy, __fflush_on_exit); + +void exit(int code) +{ + static int lock; + + /* If more than one thread calls exit, hang until _Exit ends it all */ + LOCK(&lock); + + /* Only do atexit & stdio flush if they were actually used */ + if (__funcs_on_exit) __funcs_on_exit(); + if (__fflush_on_exit) __fflush_on_exit(0); + + /* Destructor s**t is kept separate from atexit to avoid bloat */ + if (libc.fini) libc.fini(); + if (libc.ldso_fini) libc.ldso_fini(); + + _Exit(code); + for(;;); +} diff --git a/src/fcntl/creat.c b/src/fcntl/creat.c new file mode 100644 index 00000000..be05faae --- /dev/null +++ b/src/fcntl/creat.c @@ -0,0 +1,9 @@ +#include <fcntl.h> +#include "libc.h" + +int creat(const char *filename, mode_t mode) +{ + return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode); +} + +LFS64(creat); diff --git a/src/fcntl/fcntl.c b/src/fcntl/fcntl.c new file mode 100644 index 00000000..464dbf00 --- /dev/null +++ b/src/fcntl/fcntl.c @@ -0,0 +1,22 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int fcntl(int fd, int cmd, ...) +{ + int r; + long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + if (cmd == F_SETFL) arg |= O_LARGEFILE; + if (cmd == F_SETLKW) CANCELPT_BEGIN; + r = __syscall_fcntl(fd, cmd, arg); + if (cmd == F_SETLKW) CANCELPT_END; + return r; +} + +LFS64(fcntl); diff --git a/src/fcntl/open.c b/src/fcntl/open.c new file mode 100644 index 00000000..4c1a591d --- /dev/null +++ b/src/fcntl/open.c @@ -0,0 +1,21 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int open(const char *filename, int flags, ...) +{ + int r; + mode_t mode; + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + CANCELPT_BEGIN; + r = __syscall_open(filename, flags, mode); + CANCELPT_END; + return r; +} + +LFS64(open); diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c new file mode 100644 index 00000000..eefa0901 --- /dev/null +++ b/src/fcntl/openat.c @@ -0,0 +1,21 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int openat(int fd, const char *filename, int flags, ...) +{ + int r; + mode_t mode; + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + CANCELPT_BEGIN; + r = syscall4(__NR_openat, fd, (long)filename, flags|O_LARGEFILE, mode); + CANCELPT_END; + return r; +} + +LFS64(openat); diff --git a/src/internal/atomic.h b/src/internal/atomic.h new file mode 100644 index 00000000..a15f8c2a --- /dev/null +++ b/src/internal/atomic.h @@ -0,0 +1,110 @@ +#ifndef _INTERNAA_ATOMIC_H +#define _INTERNAA_ATOMIC_H + +#include <stdint.h> + +static inline int a_ctz_64(uint64_t x) +{ + int r; + __asm__( "bsf %1,%0 ; jnz 1f ; bsf %2,%0 ; addl $32,%0\n1:" + : "=r"(r) : "r"((unsigned)x), "r"((unsigned)(x>>32)) ); + return r; +} + + +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ + __asm__( "lock ; andl %1, (%0) ; lock ; andl %2, 4(%0)" + : : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) ); +} + +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ + __asm__( "lock ; orl %1, (%0) ; lock ; orl %2, 4(%0)" + : : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) ); +} + +static inline void a_store_l(volatile void *p, long x) +{ + __asm__( "movl %1, %0" : "=m"(*(long *)p) : "r"(x) : "memory" ); +} + +static inline void a_or_l(volatile void *p, long v) +{ + __asm__( "lock ; orl %1, %0" + : "=m"(*(long *)p) : "r"(v) ); +} + +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + __asm__( "lock ; cmpxchg %3, %1" + : "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) ); + return t; +} + +static inline long a_cas_l(volatile void *p, long t, long s) +{ + __asm__( "lock ; cmpxchg %3, %1" + : "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) ); + return t; +} + +static inline void *a_swap_p(void *volatile *x, void *v) +{ + __asm__( "xchg %0, %1" : "=r"(v), "=m"(*(void **)x) : "0"(v) ); + return v; +} +static inline long a_swap_l(volatile void *x, long v) +{ + __asm__( "xchg %0, %1" : "=r"(v), "=m"(*(long *)x) : "0"(v) ); + return v; +} + +static inline void a_or(volatile void *p, int v) +{ + __asm__( "lock ; orl %1, %0" + : "=m"(*(int *)p) : "r"(v) ); +} + +static inline void a_and(volatile void *p, int v) +{ + __asm__( "lock ; andl %1, %0" + : "=m"(*(int *)p) : "r"(v) ); +} + +static inline int a_swap(volatile int *x, int v) +{ + __asm__( "xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) ); + return v; +} + +#define a_xchg a_swap + +static inline int a_fetch_add(volatile int *x, int v) +{ + __asm__( "lock ; xadd %0, %1" : "=r"(v), "=m"(*x) : "0"(v) ); + return v; +} + +static inline void a_inc(volatile int *x) +{ + __asm__( "lock ; incl %0" : "=m"(*x) : "m"(*x) ); +} + +static inline void a_dec(volatile int *x) +{ + __asm__( "lock ; decl %0" : "=m"(*x) : "m"(*x) ); +} + +static inline void a_store(volatile int *p, int x) +{ + __asm__( "movl %1, %0" : "=m"(*p) : "r"(x) : "memory" ); +} + +static inline void a_spin() +{ + __asm__ __volatile__( "pause" : : : "memory" ); +} + + +#endif diff --git a/src/internal/clone.h b/src/internal/clone.h new file mode 100644 index 00000000..cc84aeb4 --- /dev/null +++ b/src/internal/clone.h @@ -0,0 +1,22 @@ +#define CLONE_VM 0x00000100 +#define CLONE_FS 0x00000200 +#define CLONE_FILES 0x00000400 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_PTRACE 0x00002000 +#define CLONE_VFORK 0x00004000 +#define CLONE_PARENT 0x00008000 +#define CLONE_THREAD 0x00010000 +#define CLONE_NEWNS 0x00020000 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_SETTLS 0x00080000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWUTS 0x04000000 +#define CLONE_NEWIPC 0x08000000 +#define CLONE_NEWUSER 0x10000000 +#define CLONE_NEWPID 0x20000000 +#define CLONE_NEWNET 0x40000000 +#define CLONE_IO 0x80000000 diff --git a/src/internal/futex.h b/src/internal/futex.h new file mode 100644 index 00000000..c0453822 --- /dev/null +++ b/src/internal/futex.h @@ -0,0 +1,16 @@ +#ifndef _INTERNAL_FUTEX_H +#define _INTERNAL_FUTEX_H + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 + +int __futex(volatile int *, int, int, void *); + +#endif diff --git a/src/internal/libc.c b/src/internal/libc.c new file mode 100644 index 00000000..5e8e9d95 --- /dev/null +++ b/src/internal/libc.c @@ -0,0 +1,3 @@ +#include "libc.h" + +struct libc libc; diff --git a/src/internal/libc.h b/src/internal/libc.h new file mode 100644 index 00000000..e353f363 --- /dev/null +++ b/src/internal/libc.h @@ -0,0 +1,43 @@ +#ifndef LIBC_H +#define LIBC_H + +#include <stdlib.h> +#include <stdio.h> + +#define libc __libc +extern struct libc { + void (*lock)(volatile int *); + void (*cancelpt)(int); + int (*atexit)(void (*)(void)); + void (*fini)(void); + void (*ldso_fini)(void); + int *(*errno_location)(void); + volatile int threads_minus_1; + int (*rsyscall)(int, long, long, long, long, long, long); + void (**tsd_keys)(void *); +} libc; + + +/* Designed to avoid any overhead in non-threaded processes */ +void __lock(volatile int *); +#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1)) +#define UNLOCK(x) (*(x)=0) +#define CANCELPT(x) (libc.cancelpt ? libc.cancelpt((x)),0 : (void)(x),0) +#define CANCELPT_BEGIN CANCELPT(1) +#define CANCELPT_END CANCELPT(0) + +extern char **__environ; +#define environ __environ + +#undef weak_alias +#define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((weak, alias(#old))) + +#undef LFS64_2 +//#define LFS64_2(x, y) weak_alias(x, y) +#define LFS64_2(x, y) extern __typeof(x) y + +#undef LFS64 +#define LFS64(x) LFS64_2(x, x##64) + +#endif diff --git a/src/internal/locale_impl.h b/src/internal/locale_impl.h new file mode 100644 index 00000000..c268124f --- /dev/null +++ b/src/internal/locale_impl.h @@ -0,0 +1,5 @@ +#include <locale.h> + +struct __locale { + int dummy; +}; diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h new file mode 100644 index 00000000..b7892103 --- /dev/null +++ b/src/internal/pthread_impl.h @@ -0,0 +1,68 @@ +#ifndef _PTHREAD_IMPL_H +#define _PTHREAD_IMPL_H + +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <unistd.h> +#include <sys/mman.h> +#include <errno.h> +#include <limits.h> +#include <inttypes.h> +#include <setjmp.h> +#include <string.h> +#include <time.h> +#include "libc.h" +#include "syscall.h" +#include "atomic.h" +#include "futex.h" + +#define pthread __pthread + +struct pthread { + struct pthread *self, *join; + int errno_val; + pid_t tid, pid; + volatile int canceldisable, cancelasync, cancelpoint, cancel; + unsigned char *map_base; + size_t map_size; + void *start_arg; + void *(*start)(void *); + void *result; + jmp_buf exit_jmp_buf; + int detached; + int exitlock; + unsigned long tlsdesc[4]; + struct __ptcb *cancelbuf; + void **tsd; + int tsd_used; + pthread_attr_t attr; + int *errno_ptr; +}; + +static inline struct pthread *__pthread_self() +{ + struct pthread *self; + __asm__ ("movl %%gs:0,%0" : "=r" (self) ); + return self; +} + +#define SIGCANCEL 32 +#define SIGSYSCALL 33 +#define SIGTIMER 32 /* ?? */ + +int __set_thread_area(unsigned long *); +int __set_pthread_self(void *); +int __libc_sigaction(int, const struct sigaction *, struct sigaction *); +int __libc_sigprocmask(int, const sigset_t *, sigset_t *); +void __lock(volatile int *); +void __unmapself(void *, size_t); + +int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); +void __wait(volatile int *, volatile int *, int, int); +void __wake(volatile int *, int, int); + +#define DEFAULT_STACK_SIZE (16384-PAGE_SIZE) +#define DEFAULT_GUARD_SIZE PAGE_SIZE + +#endif diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h new file mode 100644 index 00000000..1e9159f6 --- /dev/null +++ b/src/internal/stdio_impl.h @@ -0,0 +1,100 @@ +#ifndef _STDIO_IMPL_H +#define _STDIO_IMPL_H + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <string.h> +#include <inttypes.h> +#include <wchar.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <errno.h> +#include <termios.h> +#include <sys/ioctl.h> +#include <ctype.h> +#include <sys/wait.h> +#include <math.h> +#include <float.h> +#include "syscall.h" +#include "libc.h" + +#define UNGET 4 + +#define FLOCK(f) LOCK(&f->lock) +#define FUNLOCK(f) UNLOCK(&f->lock) + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 + +struct __FILE_s { + unsigned flags; + unsigned char *rpos, *rstop; + unsigned char *rend, *wend; + unsigned char *wpos, *wstop; + unsigned char *wbase; + unsigned char *dummy01[3]; + unsigned char *buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long dummy2; + short dummy3; + char dummy4; + signed char lbf; + int lock; + int lockcount; + void *owner; + off_t off; + int (*flush)(FILE *); + void **wide_data; /* must be NULL */ + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + int mode; + int (*close)(FILE *); +}; + +size_t __stdio_read(FILE *, unsigned char *, size_t); +size_t __stdio_write(FILE *, const unsigned char *, size_t); +off_t __stdio_seek(FILE *, off_t, int); +int __stdio_close(FILE *); + +int __overflow(FILE *, int); +int __oflow(FILE *); +int __uflow(FILE *); +int __underflow(FILE *); + +int __fseeko(FILE *, off_t, int); +int __fseeko_unlocked(FILE *, off_t, int); +off_t __ftello(FILE *); +off_t __ftello_unlocked(FILE *); +size_t __fwritex(const unsigned char *, size_t, FILE *); +int __putc_unlocked(int, FILE *); + +FILE *__fdopen(int, const char *); + +extern struct ofl +{ + FILE *head; + int lock; +} __ofl; + +#define OFLLOCK() LOCK(&__ofl.lock) +#define OFLUNLOCK() UNLOCK(&__ofl.lock) +#define ofl_head (__ofl.head) + +#define feof(f) ((f)->flags & F_EOF) +#define ferror(f) ((f)->flags & F_ERR) + +/* Caller-allocated FILE * operations */ +FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t); +int __fclose_ca(FILE *); + +#endif diff --git a/src/internal/syscall.c b/src/internal/syscall.c new file mode 100644 index 00000000..4f159e0b --- /dev/null +++ b/src/internal/syscall.c @@ -0,0 +1,11 @@ +#include <errno.h> +#include <unistd.h> + +long __syscall_ret(unsigned long r) +{ + if (r >= (unsigned long)-1 - 4096) { + errno = -(long)r; + return -1; + } + return (long)r; +} diff --git a/src/internal/syscall.h b/src/internal/syscall.h new file mode 100644 index 00000000..4b3c0a73 --- /dev/null +++ b/src/internal/syscall.h @@ -0,0 +1,469 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define SYSCALL_LL(x) \ +((union { long long ll; long l[2]; }){ .ll = x }).l[0], \ +((union { long long ll; long l[2]; }){ .ll = x }).l[1] + +#define SYSCALL_SIGSET_SIZE 8 + +#if defined(SYSCALL_STANDALONE) +#include <errno.h> +static inline long __syscall_ret(unsigned long r) +{ + if (r >= (unsigned long)-1 - 4096) { + errno = -(long)r; + return -1; + } + return (long)r; +} +#elif defined(SYSCALL_NORETURN) +static inline long __syscall_ret(unsigned long r) +{ + for(;;); + return 0; +} +#elif defined(SYSCALL_RETURN_ERRNO) +static inline long __syscall_ret(unsigned long r) +{ + return -r; +} +#else +extern long __syscall_ret(unsigned long); +#endif + +#define SYSCALL0 "int $128" + +#ifdef __PIC__ +#define SYSCALL "xchgl %%ebx,%2\n\t" SYSCALL0 "\n\txchgl %%ebx,%2" +#define EBX "m" +#else +#define SYSCALL SYSCALL0 +#define EBX "b" +#endif + +static inline long syscall0(long n) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL0 : "=a"(ret) : "a"(n) : "memory"); + return __syscall_ret(ret); +} + +static inline long syscall1(long n, long a1) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1) : "memory"); + return __syscall_ret(ret); +} + +static inline long syscall2(long n, long a1, long a2) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2) : "memory"); + return __syscall_ret(ret); +} + +static inline long syscall3(long n, long a1, long a2, long a3) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3) : "memory"); + return __syscall_ret(ret); +} + +static inline long syscall4(long n, long a1, long a2, long a3, long a4) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); + return __syscall_ret(ret); +} + +static inline long syscall5(long n, long a1, long a2, long a3, long a4, long a5) +{ + unsigned long ret; + __asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); + return __syscall_ret(ret); +} + +#ifdef __PIC__ +/* note: it's probably only safe to use this when a6 is on the stack */ +static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + unsigned long ret; + __asm__ __volatile__ ("xchgl %%ebx,%2 ; pushl %1 ; pushl %%ebp ; movl %%eax,%%ebp ; movl 4(%%esp),%%eax ; int $128 ; popl %%ebp ; popl %%ecx ; xchgl %%ebx,%2" + : "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory"); + return __syscall_ret(ret); +} +#else +static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + unsigned long ret; + __asm__ __volatile__ ("pushl %%ebp ; mov %1, %%ebp ; xchg %%ebp, %7 ; int $128 ; popl %%ebp" + : "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory"); + return __syscall_ret(ret); +} +#endif + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_vm86 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 +#define __NR_putpmsg 189 +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_lchown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_mincore 218 +#define __NR_madvise 219 +#define __NR_madvise1 219 +#define __NR_getdents64 220 +#define __NR_fcntl64 221 +/* 223 is unused */ +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_fadvise64 250 +/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 +#define __NR_tgkill 270 +#define __NR_utimes 271 +#define __NR_fadvise64_64 272 +#define __NR_vserver 273 +#define __NR_mbind 274 +#define __NR_get_mempolicy 275 +#define __NR_set_mempolicy 276 +#define __NR_mq_open 277 +#define __NR_mq_unlink (__NR_mq_open+1) +#define __NR_mq_timedsend (__NR_mq_open+2) +#define __NR_mq_timedreceive (__NR_mq_open+3) +#define __NR_mq_notify (__NR_mq_open+4) +#define __NR_mq_getsetattr (__NR_mq_open+5) +#define __NR_kexec_load 283 +#define __NR_waitid 284 +/* #define __NR_sys_setaltroot 285 */ +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 +#define __NR_ioprio_set 289 +#define __NR_ioprio_get 290 +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 +#define __NR_set_robust_list 311 +#define __NR_get_robust_list 312 +#define __NR_splice 313 +#define __NR_sync_file_range 314 +#define __NR_tee 315 +#define __NR_vmsplice 316 +#define __NR_move_pages 317 +#define __NR_getcpu 318 +#define __NR_epoll_pwait 319 +#define __NR_utimensat 320 +#define __NR_signalfd 321 +#define __NR_timerfd_create 322 +#define __NR_eventfd 323 +#define __NR_fallocate 324 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 +#define __NR_signalfd4 327 +#define __NR_eventfd2 328 +#define __NR_epoll_create1 329 +#define __NR_dup3 330 +#define __NR_pipe2 331 +#define __NR_inotify_init1 332 +#define __NR_preadv 333 +#define __NR_pwritev 334 + + +#undef O_LARGEFILE +#define O_LARGEFILE 0100000 + +/* the following are needed for iso c functions to use */ +#define __syscall_open(filename, flags, mode) syscall3(__NR_open, (long)(filename), (flags)|O_LARGEFILE, (mode)) +#define __syscall_read(fd, buf, len) syscall3(__NR_read, (fd), (long)(buf), (len)) +#define __syscall_write(fd, buf, len) syscall3(__NR_write, (fd), (long)(buf), (len)) +#define __syscall_close(fd) syscall1(__NR_close, (fd)) +#define __syscall_fcntl(fd, cmd, arg) syscall3(__NR_fcntl64, (fd), (cmd), (long)(arg)) +#define __syscall_dup2(old, new) syscall2(__NR_dup2, (old), (new)) +#define __syscall_unlink(path) syscall1(__NR_unlink, (long)(path)) +#define __syscall_getpid() syscall0(__NR_getpid) +#define __syscall_kill(pid,sig) syscall2(__NR_kill, (pid), (sig)) +#define __syscall_sigaction(sig,new,old) syscall4(__NR_rt_sigaction, (sig), (long)(new), (long)(old), SYSCALL_SIGSET_SIZE) +#define __syscall_ioctl(fd,ioc,arg) syscall3(__NR_ioctl, (fd), (ioc), (long)(arg)) +#define __syscall_exit(code) syscall1(__NR_exit, code) + +#define __NEED_off_t +#include <bits/alltypes.h> + +static inline off_t __syscall_lseek(int fd, off_t offset, int whence) +{ + off_t result; + return syscall5(__NR__llseek, fd, offset>>32, offset, (long)&result, whence) ? -1 : result; +} + +#endif diff --git a/src/internal/util.h b/src/internal/util.h new file mode 100644 index 00000000..7c7c3a17 --- /dev/null +++ b/src/internal/util.h @@ -0,0 +1,5 @@ +#ifndef _INTERNAL_UTIL_H +#define _INTERNAL_UTIL_H + + +#endif diff --git a/src/ipc/ftok.c b/src/ipc/ftok.c new file mode 100644 index 00000000..cd6002ed --- /dev/null +++ b/src/ipc/ftok.c @@ -0,0 +1,10 @@ +#include <sys/ipc.h> +#include <sys/stat.h> + +key_t ftok(const char *path, int id) +{ + struct stat st; + if (stat(path, &st) < 0) return -1; + + return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xff) << 24)); +} diff --git a/src/ipc/ipc.h b/src/ipc/ipc.h new file mode 100644 index 00000000..9edd5ecf --- /dev/null +++ b/src/ipc/ipc.h @@ -0,0 +1,13 @@ +#define IPCOP_semop 1 +#define IPCOP_semget 2 +#define IPCOP_semctl 3 +#define IPCOP_msgsnd 11 +#define IPCOP_msgrcv 12 +#define IPCOP_msgget 13 +#define IPCOP_msgctl 14 +#define IPCOP_shmat 21 +#define IPCOP_shmdt 22 +#define IPCOP_shmget 23 +#define IPCOP_shmctl 24 + +#define IPC_MODERN 0x100 diff --git a/src/ipc/semctl.c b/src/ipc/semctl.c new file mode 100644 index 00000000..7ada116b --- /dev/null +++ b/src/ipc/semctl.c @@ -0,0 +1,18 @@ +#include <sys/sem.h> +#include <stdarg.h> +#include "syscall.h" +#include "ipc.h" + +int semctl(int id, int num, int cmd, ...) +{ + long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); +#ifdef __NR_semctl + return syscall4(__NR_semctl, id, num, cmd, arg); +#else + return syscall5(__NR_ipc, IPCOP_semctl, id, num, cmd | 0x100, (long)&arg); +#endif +} diff --git a/src/ipc/semget.c b/src/ipc/semget.c new file mode 100644 index 00000000..2dcf6eac --- /dev/null +++ b/src/ipc/semget.c @@ -0,0 +1,12 @@ +#include <sys/sem.h> +#include "syscall.h" +#include "ipc.h" + +int semget(key_t key, int n, int fl) +{ +#ifdef __NR_semget + return syscall3(__NR_semget, key, n, fl); +#else + return syscall4(__NR_ipc, IPCOP_semget, key, n, fl); +#endif +} diff --git a/src/ipc/semop.c b/src/ipc/semop.c new file mode 100644 index 00000000..48d8a654 --- /dev/null +++ b/src/ipc/semop.c @@ -0,0 +1,12 @@ +#include <sys/sem.h> +#include "syscall.h" +#include "ipc.h" + +int semop(int id, struct sembuf *buf, size_t n) +{ +#ifdef __NR_semop + return syscall3(__NR_semop, id, (long)buf, n); +#else + return syscall5(__NR_ipc, IPCOP_semop, id, n, 0, (long)buf); +#endif +} diff --git a/src/ipc/shmat.c b/src/ipc/shmat.c new file mode 100644 index 00000000..ff65b6a4 --- /dev/null +++ b/src/ipc/shmat.c @@ -0,0 +1,17 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +#ifdef __NR_shmat +void *shmat(int id, const void *addr, int flag) +{ + return syscall3(__NR_shmat, id, (long)addr, flag); +} +#else +void *shmat(int id, const void *addr, int flag) +{ + unsigned long ret; + ret = syscall5(__NR_ipc, IPCOP_shmat, id, flag, (long)&addr, (long)addr); + return (ret > -(unsigned long)SHMLBA) ? (void *)ret : (void *)addr; +} +#endif diff --git a/src/ipc/shmctl.c b/src/ipc/shmctl.c new file mode 100644 index 00000000..da357fa8 --- /dev/null +++ b/src/ipc/shmctl.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmctl(int id, int cmd, struct shmid_ds *buf) +{ +#ifdef __NR_shmctl + return syscall3(__NR_shmctl, id, cmd, (long)buf); +#else + return syscall4(__NR_ipc, IPCOP_shmctl, id, cmd | IPC_MODERN, (long)buf); +#endif +} diff --git a/src/ipc/shmdt.c b/src/ipc/shmdt.c new file mode 100644 index 00000000..e04188f9 --- /dev/null +++ b/src/ipc/shmdt.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmdt(const void *addr) +{ +#ifdef __NR_shmdt + return syscall1(__NR_shmdt, (long)addr); +#else + return syscall2(__NR_ipc, IPCOP_shmdt, (long)addr); +#endif +} diff --git a/src/ipc/shmget.c b/src/ipc/shmget.c new file mode 100644 index 00000000..86e254af --- /dev/null +++ b/src/ipc/shmget.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmget(key_t key, size_t size, int flag) +{ +#ifdef __NR_shmget + return syscall3(__NR_shmget, key, size, flag); +#else + return syscall4(__NR_ipc, IPCOP_shmget, key, size, flag); +#endif +} diff --git a/src/linux/brk.c b/src/linux/brk.c new file mode 100644 index 00000000..3c2982c6 --- /dev/null +++ b/src/linux/brk.c @@ -0,0 +1,6 @@ +#include "syscall.h" + +int brk(void *end) +{ + return -(syscall1(__NR_brk, (long)end) == -1); +} diff --git a/src/linux/chroot.c b/src/linux/chroot.c new file mode 100644 index 00000000..b5af62dc --- /dev/null +++ b/src/linux/chroot.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int chroot(const char *path) +{ + return syscall1(__NR_chroot, (long)path); +} diff --git a/src/linux/daemon.c b/src/linux/daemon.c new file mode 100644 index 00000000..632d1203 --- /dev/null +++ b/src/linux/daemon.c @@ -0,0 +1,31 @@ +#include <fcntl.h> +#include <unistd.h> + +int daemon(int nochdir, int noclose) +{ + int fd; + + switch(fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); + } + + if (setsid() < 0) return -1; + + switch(fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); + } + + if (!nochdir) chdir("/"); + if (!noclose && (fd = open("/dev/null", O_RDWR)) >= 0) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) close(fd); + } + + return 0; +} diff --git a/src/linux/epoll_create.c b/src/linux/epoll_create.c new file mode 100644 index 00000000..c9dea8ce --- /dev/null +++ b/src/linux/epoll_create.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_create(int size) +{ + return syscall1(__NR_epoll_create, size); +} diff --git a/src/linux/epoll_create1.c b/src/linux/epoll_create1.c new file mode 100644 index 00000000..2e82e995 --- /dev/null +++ b/src/linux/epoll_create1.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_create1(int flags) +{ + return syscall1(__NR_epoll_create1, flags); +} diff --git a/src/linux/epoll_ctl.c b/src/linux/epoll_ctl.c new file mode 100644 index 00000000..4214f407 --- /dev/null +++ b/src/linux/epoll_ctl.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) +{ + return syscall4(__NR_epoll_ctl, fd, op, fd2, (long)ev); +} diff --git a/src/linux/epoll_pwait.c b/src/linux/epoll_pwait.c new file mode 100644 index 00000000..5aaacba6 --- /dev/null +++ b/src/linux/epoll_pwait.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs) +{ + return syscall6(__NR_epoll_pwait, fd, (long)ev, cnt, to, (long)sigs, 8); +} diff --git a/src/linux/epoll_wait.c b/src/linux/epoll_wait.c new file mode 100644 index 00000000..8a68ebdd --- /dev/null +++ b/src/linux/epoll_wait.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) +{ + return syscall4(__NR_epoll_wait, fd, (long)ev, cnt, to); +} diff --git a/src/linux/getdtablesize.c b/src/linux/getdtablesize.c new file mode 100644 index 00000000..623a6af3 --- /dev/null +++ b/src/linux/getdtablesize.c @@ -0,0 +1,9 @@ +#include <limits.h> +#include <sys/resource.h> + +int getdtablesize(void) +{ + struct rlimit rl; + getrlimit(RLIMIT_NOFILE, &rl); + return rl.rlim_max < INT_MAX ? rl.rlim_max : INT_MAX; +} diff --git a/src/linux/gethostid.c b/src/linux/gethostid.c new file mode 100644 index 00000000..ea65611a --- /dev/null +++ b/src/linux/gethostid.c @@ -0,0 +1,4 @@ +long gethostid() +{ + return 0; +} diff --git a/src/linux/getopt_long.c b/src/linux/getopt_long.c new file mode 100644 index 00000000..d80cd1b6 --- /dev/null +++ b/src/linux/getopt_long.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include <stddef.h> +#include <getopt.h> +#include <stdio.h> + +static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ + if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1; + if ((longonly && argv[optind][1]) || + (argv[optind][1] == '-' && argv[optind][2])) + { + int i; + for (i=0; longopts[i].name; i++) { + const char *name = longopts[i].name; + char *opt = argv[optind]+1; + if (*opt == '-') opt++; + while (*name && *name++ == *opt++); + if (*name || (*opt && *opt != '=')) continue; + if (*opt == '=') { + if (!longopts[i].has_arg) continue; + optarg = opt+1; + } else { + if (longopts[i].has_arg == required_argument) { + if (!(optarg = argv[++optind])) + return ':'; + } else optarg = NULL; + } + optind++; + if (idx) *idx = i; + if (longopts[i].flag) { + *longopts[i].flag = longopts[i].val; + return 0; + } + return longopts[i].val; + } + if (argv[optind][1] == '-') { + optind++; + return '?'; + } + } + return getopt(argc, argv, optstring); +} + +int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ + return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/src/linux/getpagesize.c b/src/linux/getpagesize.c new file mode 100644 index 00000000..5ede652b --- /dev/null +++ b/src/linux/getpagesize.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <limits.h> + +int getpagesize(void) +{ + return PAGE_SIZE; +} diff --git a/src/linux/getpass.c b/src/linux/getpass.c new file mode 100644 index 00000000..d439a2a5 --- /dev/null +++ b/src/linux/getpass.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> + +char *getpass(const char *prompt) +{ + int fd; + struct termios s, t; + ssize_t l; + static char password[128]; + + if ((fd = open("/dev/tty", O_RDONLY|O_NOCTTY)) < 0) fd = 0; + + tcgetattr(fd, &t); + s = t; + t.c_lflag &= ~(ECHO|ISIG); + t.c_lflag |= ICANON; + t.c_iflag &= ~(INLCR|IGNCR); + t.c_iflag |= ICRNL; + tcsetattr(fd, TCSAFLUSH, &t); + tcdrain(fd); + + fputs(prompt, stderr); + fflush(stderr); + + l = read(fd, password, sizeof password); + if (l >= 0) { + if (l > 0 && password[l-1] == '\n') l--; + password[l] = 0; + } + + tcsetattr(fd, TCSAFLUSH, &s); + + if (fd > 2) close(fd); + + return password; +} diff --git a/src/linux/initgroups.c b/src/linux/initgroups.c new file mode 100644 index 00000000..ef9bc10a --- /dev/null +++ b/src/linux/initgroups.c @@ -0,0 +1,15 @@ +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> +#include <limits.h> + +int getgrouplist(const char *, gid_t, gid_t *, int *); +int setgroups(size_t, const gid_t *); + +int initgroups(const char *user, gid_t gid) +{ + gid_t groups[NGROUPS_MAX]; + int count; + if (getgrouplist(user, gid, groups, &count) < 0) return -1; + return setgroups(count, groups); +} diff --git a/src/linux/klogctl.c b/src/linux/klogctl.c new file mode 100644 index 00000000..6c288aff --- /dev/null +++ b/src/linux/klogctl.c @@ -0,0 +1,7 @@ +#define SYSCALL_STANDALONE +#include "syscall.h" + +int klogctl (int type, char *buf, int len) +{ + return syscall3(__NR_syslog, type, (long)buf, len); +} diff --git a/src/linux/mntent.c b/src/linux/mntent.c new file mode 100644 index 00000000..e3735666 --- /dev/null +++ b/src/linux/mntent.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <string.h> +#include <mntent.h> + +FILE *setmntent(const char *name, const char *mode) +{ + return fopen(name, mode); +} + +int endmntent(FILE *f) +{ + fclose(f); + return 1; +} + +struct mntent *getmntent(FILE *f) +{ + static char linebuf[256]; + static struct mntent mnt; + int cnt, n[8]; + + mnt.mnt_freq = 0; + mnt.mnt_passno = 0; + + do { + fgets(linebuf, sizeof linebuf, f); + if (feof(f)) return NULL; + cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, + &mnt.mnt_freq, &mnt.mnt_passno); + } while (cnt >= 8 && linebuf[n[0]] != '#'); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt.mnt_fsname = linebuf+n[0]; + mnt.mnt_dir = linebuf+n[2]; + mnt.mnt_type = linebuf+n[4]; + mnt.mnt_opts = linebuf+n[6]; + + return &mnt; +} + +int addmntent(FILE *f, const struct mntent *mnt) +{ + fseek(f, 0, SEEK_END); + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) +{ + return strstr(mnt->mnt_opts, opt); +} diff --git a/src/linux/mount.c b/src/linux/mount.c new file mode 100644 index 00000000..61299d48 --- /dev/null +++ b/src/linux/mount.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int mount(const char *special, const char *dir, const char *fstype, unsigned long flags, const void *data) +{ + return syscall5(__NR_mount, (long)special, (long)dir, (long)fstype, flags, (long)data); +} diff --git a/src/linux/prctl.c b/src/linux/prctl.c new file mode 100644 index 00000000..d5516830 --- /dev/null +++ b/src/linux/prctl.c @@ -0,0 +1,13 @@ +#include <sys/prctl.h> +#include <stdarg.h> +#include "syscall.h" + +int prctl(int op, ...) +{ + unsigned long x[4]; + int i; + va_list ap; + va_start(ap, op); + for (i=0; i<4; i++) x[i] = va_arg(ap, unsigned long); + return syscall5(__NR_prctl, op, x[0], x[1], x[2], x[3]); +} diff --git a/src/linux/reboot.c b/src/linux/reboot.c new file mode 100644 index 00000000..68830d8e --- /dev/null +++ b/src/linux/reboot.c @@ -0,0 +1,8 @@ +#include <sys/reboot.h> +#include <errno.h> + +int reboot(int type) +{ + errno = ENOSYS; + return -1; +} diff --git a/src/linux/sbrk.c b/src/linux/sbrk.c new file mode 100644 index 00000000..56f60d1b --- /dev/null +++ b/src/linux/sbrk.c @@ -0,0 +1,7 @@ +#include <stddef.h> +#include "syscall.h" + +void *sbrk(ptrdiff_t inc) +{ + return (void *)syscall1(__NR_brk, syscall1(__NR_brk, 0)+inc); +} diff --git a/src/linux/sendfile.c b/src/linux/sendfile.c new file mode 100644 index 00000000..bfbc40ae --- /dev/null +++ b/src/linux/sendfile.c @@ -0,0 +1,10 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count) +{ + return syscall4(__NR_sendfile, out_fd, in_fd, (long)ofs, count); +} + +LFS64(sendfile); diff --git a/src/linux/setgroups.c b/src/linux/setgroups.c new file mode 100644 index 00000000..2368aa0d --- /dev/null +++ b/src/linux/setgroups.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int setgroups(int count, const gid_t list[]) +{ + /* this depends on our gid_t being 32bit */ + return syscall2(__NR_setgroups32, count, (long)list); +} diff --git a/src/linux/sethostname.c b/src/linux/sethostname.c new file mode 100644 index 00000000..f61e0cb4 --- /dev/null +++ b/src/linux/sethostname.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int sethostname(const char *name, size_t len) +{ + return syscall2(__NR_sethostname, (long)name, len); +} diff --git a/src/linux/settimeofday.c b/src/linux/settimeofday.c new file mode 100644 index 00000000..bd7e4104 --- /dev/null +++ b/src/linux/settimeofday.c @@ -0,0 +1,7 @@ +#include <sys/time.h> +#include "syscall.h" + +int settimeofday(const struct timeval *tv, void *tz) +{ + return syscall2(__NR_settimeofday, (long)tv, 0); +} diff --git a/src/linux/signalfd.c b/src/linux/signalfd.c new file mode 100644 index 00000000..ecda263e --- /dev/null +++ b/src/linux/signalfd.c @@ -0,0 +1,7 @@ +#include <sys/signalfd.h> +#include "syscall.h" + +int signalfd(int fd, const sigset_t *sigs, int flags) +{ + return syscall3(__NR_signalfd, fd, (long)sigs, 8); +} diff --git a/src/linux/stime.c b/src/linux/stime.c new file mode 100644 index 00000000..ec3ba821 --- /dev/null +++ b/src/linux/stime.c @@ -0,0 +1,7 @@ +#include <sys/time.h> + +int stime(time_t *t) +{ + struct timeval tv = { .tv_sec = *t, .tv_usec = 0 }; + return settimeofday(&tv, (void *)0); +} diff --git a/src/linux/swapoff.c b/src/linux/swapoff.c new file mode 100644 index 00000000..f6fa794e --- /dev/null +++ b/src/linux/swapoff.c @@ -0,0 +1,8 @@ +#include <sys/swap.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int swapoff(const char *path) +{ + return syscall1(__NR_swapoff, (long)path); +} diff --git a/src/linux/swapon.c b/src/linux/swapon.c new file mode 100644 index 00000000..13d2876b --- /dev/null +++ b/src/linux/swapon.c @@ -0,0 +1,8 @@ +#include <sys/swap.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int swapon(const char *path, int flags) +{ + return syscall2(__NR_swapon, (long)path, flags); +} diff --git a/src/linux/sysinfo.c b/src/linux/sysinfo.c new file mode 100644 index 00000000..98669472 --- /dev/null +++ b/src/linux/sysinfo.c @@ -0,0 +1,9 @@ +#define SYSCALL_STANDALONE +#include "syscall.h" + +struct sysinfo; + +int sysinfo(struct sysinfo *info) +{ + return syscall1(__NR_sysinfo, (long)info); +} diff --git a/src/linux/umount.c b/src/linux/umount.c new file mode 100644 index 00000000..c35f994d --- /dev/null +++ b/src/linux/umount.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int umount(const char *special) +{ + return syscall1(__NR_umount, (long)special); +} diff --git a/src/linux/umount2.c b/src/linux/umount2.c new file mode 100644 index 00000000..cab93fd0 --- /dev/null +++ b/src/linux/umount2.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int umount2(const char *special, int flags) +{ + return syscall2(__NR_umount2, (long)special, flags); +} diff --git a/src/linux/utimes.c b/src/linux/utimes.c new file mode 100644 index 00000000..99a3b2b8 --- /dev/null +++ b/src/linux/utimes.c @@ -0,0 +1,13 @@ +#include <sys/time.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int utimes(const char *path, const struct timeval times[2]) +{ + long ktimes[2]; + if (times) { + ktimes[0] = times[0].tv_sec; + ktimes[1] = times[1].tv_sec; + } + return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0); +} diff --git a/src/linux/wait3.c b/src/linux/wait3.c new file mode 100644 index 00000000..dd63707c --- /dev/null +++ b/src/linux/wait3.c @@ -0,0 +1,11 @@ +#include <sys/wait.h> +#include <sys/resource.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +pid_t wait4(pid_t, int *, int, struct rusage *); + +pid_t wait3(int *status, int options, struct rusage *usage) +{ + return wait4(-1, status, options, usage); +} diff --git a/src/linux/wait4.c b/src/linux/wait4.c new file mode 100644 index 00000000..dda942d3 --- /dev/null +++ b/src/linux/wait4.c @@ -0,0 +1,19 @@ +#include <sys/wait.h> +#include <sys/resource.h> +#include <string.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage) +{ + pid_t ret = syscall4(__NR_wait4, pid, (long)status, options, (long)usage); + /* Fixup kernel time_t... */ + if (usage) { + long kusage[4]; + memcpy(kusage, usage, sizeof kusage); + memmove((struct timeval *)usage + 2, (long *)usage + 4, sizeof *usage - 2*sizeof(struct timeval)); + usage->ru_utime = (struct timeval){ kusage[0], kusage[1] }; + usage->ru_stime = (struct timeval){ kusage[2], kusage[3] }; + } + return ret; +} diff --git a/src/locale/catclose.c b/src/locale/catclose.c new file mode 100644 index 00000000..02cd3e5c --- /dev/null +++ b/src/locale/catclose.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +int catclose (nl_catd catd) +{ + return 0; +} diff --git a/src/locale/catgets.c b/src/locale/catgets.c new file mode 100644 index 00000000..bbee8986 --- /dev/null +++ b/src/locale/catgets.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +char *catgets (nl_catd catd, int set_id, int msg_id, const char *s) +{ + return (char *)s; +} diff --git a/src/locale/catopen.c b/src/locale/catopen.c new file mode 100644 index 00000000..4423c4d9 --- /dev/null +++ b/src/locale/catopen.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +nl_catd catopen (const char *name, int oflag) +{ + return (nl_catd)-1; +} diff --git a/src/locale/duplocale.c b/src/locale/duplocale.c new file mode 100644 index 00000000..dd445d46 --- /dev/null +++ b/src/locale/duplocale.c @@ -0,0 +1,11 @@ +#include <stdlib.h> +#include <string.h> +#include "locale_impl.h" + +locale_t duplocale(locale_t old) +{ + locale_t new; + new = calloc(1, sizeof *new); + if (new) memcpy(new, old, sizeof *new); + return new; +} diff --git a/src/locale/freelocale.c b/src/locale/freelocale.c new file mode 100644 index 00000000..4e089f22 --- /dev/null +++ b/src/locale/freelocale.c @@ -0,0 +1,7 @@ +#include <stdlib.h> +#include "locale_impl.h" + +void freelocale(locale_t l) +{ + free(l); +} diff --git a/src/locale/iconv.c b/src/locale/iconv.c new file mode 100644 index 00000000..4e46c7e4 --- /dev/null +++ b/src/locale/iconv.c @@ -0,0 +1,568 @@ +#include <iconv.h> +#include <errno.h> +#include <wchar.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <stdint.h> + +#define UTF_32BE 000 +#define UTF_16LE 001 +#define UTF_16BE 002 +#define UTF_32LE 003 +#define UCS2BE 004 +#define UCS2LE 005 +#define WCHAR_T 007 + +#define US_ASCII 021 +#define UTF_8 022 +#define LATIN_9 024 +#define TIS_620 025 +#define JIS_0201 026 + +#define EUC 031 +#define EUC_TW 032 +#define SHIFT_JIS 033 +#define BIG5 034 +#define GBK 035 + +/* FIXME: these are not implemented yet + * EUC: A1-FE A1-FE + * GBK: 81-FE 40-7E,80-FE + * Big5: A1-FE 40-7E,A1-FE + */ + +/* Definitions of charmaps. Each charmap consists of: + * 1. Empty-string-terminated list of null-terminated aliases. + * 2. Special type code or bits per character. + * 3. Number of elided entries (128 for specials). + * 4. Character table (size determined by fields 2 and 3). */ + +static const unsigned char charmaps[] = +"utf8\0\0\022\x80" +"wchart\0\0\007\x80" + +"ucs2\0ucs2be\0\0\004\x80" +"ucs2le\0\0\005\x80" + +"utf16\0utf16be\0\0\002\x80" +"utf16le\0\0\001\x80" + +"ucs4\0ucs4be\0utf32\0utf32be\0\0\000\x80" +"ucs4le\0utf32le\0\0\003\x80" + +"ascii\0iso646\0usascii\0\0\021\x80" +"latin1\0iso88591\0\0\x09\x80" +"latin9\0iso885915\0\0\024\x80" +"tis620\0iso885911\0\0\025\x80" +"jis0201\0\0\026\x80" + +"iso88592\0\0\x0a\x21" +"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a" +"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c" +"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e" +"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55" +"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43" +"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44" +"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56" +"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55" +"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43" +"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44" +"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56" +"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d" + +"iso88593\0\0\x0a\x21" +"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a" +"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c" +"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e" +"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30" +"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32" +"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00" +"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47" +"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38" +"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a" +"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00" +"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47" +"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d" + +"iso88594\0\0\x0a\x21" +"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a" +"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c" +"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e" +"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40" +"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43" +"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44" +"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36" +"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40" +"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43" +"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44" +"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e" +"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d" + +"iso88595\0\0\x0e\x21" +"\x01\x84\x00\x31\x40\x10\x10\x05\x84\x01" +"\x71\x40\x20\x10\x09\x84\x02\xb1\x40\x30" +"\x10\xad\x80\x03\xf1\x40\x40\x10\x11\x84" +"\x04\x31\x41\x50\x10\x15\x84\x05\x71\x41" +"\x60\x10\x19\x84\x06\xb1\x41\x70\x10\x1d" +"\x84\x07\xf1\x41\x80\x10\x21\x84\x08\x31" +"\x42\x90\x10\x25\x84\x09\x71\x42\xa0\x10" +"\x29\x84\x0a\xb1\x42\xb0\x10\x2d\x84\x0b" +"\xf1\x42\xc0\x10\x31\x84\x0c\x31\x43\xd0" +"\x10\x35\x84\x0d\x71\x43\xe0\x10\x39\x84" +"\x0e\xb1\x43\xf0\x10\x3d\x84\x0f\xf1\x43" +"\x00\x11\x41\x84\x10\x31\x44\x10\x11\x45" +"\x84\x11\x71\x44\x20\x11\x49\x84\x12\xb1" +"\x44\x30\x11\x4d\x84\x13\xf1\x44\x58\x84" +"\x51\x84\x14\x31\x45\x50\x11\x55\x84\x15" +"\x71\x45\x60\x11\x59\x84\x16\xb1\x45\x70" +"\x11\xa7\x80\x17\xf1\x45\x00" + +"iso88596\0\0\x0b\x21" +"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\xc0\x86\x01\x00\x00" +"\x00\x7c\x18\x00\x21\x16\xf1\x88\x49\x5c" +"\x62\x13\x9f\x18\xc5\x29\x56\xf1\x8a\x59" +"\xdc\x62\x17\xbf\x18\xc6\x31\x96\xf1\x8c" +"\x69\x5c\x63\x1b\xdf\x18\xc7\x39\xd6\x31" +"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16" +"\xf2\x90\x89\x5c\x64\x23\x1f\x19\xc9\x49" +"\x56\xf2\x92\x99\xdc\x64\x27\x3f\x19\xca" +"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00" + +"iso88597\0\0\x0e\x21" +"\x18\x60\x06\x38\x0a\xb0\x82\xaf\xa0\x29" +"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0" +"\x02\xad\x00\x00\x50\x01\xc2\x02\xb1\x80" +"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b" +"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd" +"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30" +"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e" +"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7" +"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90" +"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83" +"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a" +"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5" +"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0" +"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f" +"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1" +"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30" +"\x0f\xcd\x83\xf3\x00\x00\x00" + +"iso88598\0\0\x0e\x21" +"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29" +"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0" +"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80" +"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b" +"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01" +"\x42\x17\xd1\x85\x74\x31\x5d\x50\x17\xd5" +"\x85\x75\x71\x5d\x60\x17\xd9\x85\x76\xb1" +"\x5d\x70\x17\xdd\x85\x77\xf1\x5d\x80\x17" +"\xe1\x85\x78\x31\x5e\x90\x17\xe5\x85\x79" +"\x71\x5e\xa0\x17\xe9\x85\x7a\x01\x00\x00" +"\x00\x0e\xe0\x03\x08\x00\x00" + +"iso88599\0\0\x09\x50" +"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8" +"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2" +"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9" +"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b" +"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7" +"\x2f\xe6\xd7\x7f" + +"iso885910\0\0\x0e\x21" +"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d" +"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4" +"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1" +"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b" +"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15" +"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30" +"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04" +"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33" +"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50" +"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81" +"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d" +"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5" +"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0" +"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03" +"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d" +"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0" +"\x03\xfd\x80\x3f\x80\x13\x00" + +"iso885913\0\0\x0e\x21" +"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29" +"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0" +"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b" +"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60" +"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04" +"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a" +"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30" +"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81" +"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d" +"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5" +"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70" +"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05" +"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d" +"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0" +"\x03\x7c\x81\x5f\x90\x01\x02" + +"iso885914\0\0\x0d\x21" +"\x02\x7e\xc0\x8f\x02\x85\xb0\x10\x14\xfc" +"\x29\x00\xf4\xa9\x40\xd0\x2f\x78\x79\xdf" +"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84" +"\x04\x20\x1f\xe4\x6d\x81\x95\x0f\xf4\x57" +"\x7e\xd0\x83\xf9\x79\x4f\xe8\x0b\x7d\x98" +"\x07\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c" +"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03" +"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40" +"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc7" +"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec" +"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72" +"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d" +"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b" +"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1" +"\x9a\xc7\x07\xf9\x40\x1f\xec\x03\x7e\xd0" +"\x0f\xee\xc2\x3f\x00" + +"iso885916\0\0\x0e\x21" +"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58" +"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4" +"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00" +"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b" +"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53" +"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20" +"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03" +"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33" +"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50" +"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80" +"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d" +"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07" +"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0" +"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04" +"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d" +"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0" +"\x03\x19\xc1\x86\xf0\x0f\x00" + +"windows1252\0\0\x0e\x00" +"\xac\x20\x00\xa0\x01\x4a\x06\x1e\xa0\x09" +"\x08\x02\x86\x80\xc6\x02\x0c\x08\x16\xe4" +"\x80\x52\x01\x00\xd0\x17\x00\x00\x00\x00" +"\x06\x98\x01\x72\x80\x1d\xa0\x08\x38\x01" +"\x52\x80\xdc\x82\x48\x18\x16\xe8\x80\x53" +"\x01\x00\xe0\x17\xe0\x05\xa0\x40\x28\x20" +"\x0a\x8c\x02\xa4\x40\x29\x60\x0a\x9c\x02" +"\xa8\x40\x2a\xa0\x0a\xac\x02\xac\x40\x2b" +"\xe0\x0a\xbc\x02\xb0\x40\x2c\x20\x0b\xcc" +"\x02\xb4\x40\x2d\x60\x0b\xdc\x02\xb8\x40" +"\x2e\xa0\x0b\xec\x02\xbc\x40\x2f\xe0\x0b" +"\xfc\x02\xc0\x40\x30\x20\x0c\x0c\x03\xc4" +"\x40\x31\x60\x0c\x1c\x03\xc8\x40\x32\xa0" +"\x0c\x2c\x03\xcc\x40\x33\xe0\x0c\x3c\x03" +"\xd0\x40\x34\x20\x0d\x4c\x03\xd4\x40\x35" +"\x60\x0d\x5c\x03\xd8\x40\x36\xa0\x0d\x6c" +"\x03\xdc\x40\x37\xe0\x0d\x7c\x03\xe0\x40" +"\x38\x20\x0e\x8c\x03\xe4\x40\x39\x60\x0e" +"\x9c\x03\xe8\x40\x3a\xa0\x0e\xac\x03\xec" +"\x40\x3b\xe0\x0e\xbc\x03\xf0\x40\x3c\x20" +"\x0f\xcc\x03\xf4\x40\x3d\x60\x0f\xdc\x03" +"\xf8\x40\x3e\xa0\x0f\xec\x03\xfc\x40\x3f" +"\xe0\x0f\xfc\x03" +; + + + +static int fuzzycmp(const char *a, const char *b) +{ + for (; *a && *b; a++, b++) { + while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++; + if ((*a|32U) != *b) return 1; + } + return *a != *b; +} + +static int find_charmap(const char *name) +{ + const unsigned char *s; + for (s=charmaps; *s; ) { + if (!fuzzycmp(name, s)) { + for (; *s; s+=strlen(s)+1); + return s+1-charmaps; + } + s += strlen(s)+1; + if (!*s) s += ((128-s[2])*s[1]+7)/8 + 3; + } + return -1; +} + +iconv_t iconv_open(const char *to, const char *from) +{ + int f, t; + + if ((t = find_charmap(to)) < 0 || (f = find_charmap(from)) < 0) { + errno = EINVAL; + return (iconv_t)-1; + } + + return (void *)(f<<16 | t); +} + +int iconv_close(iconv_t cd) +{ + return 0; +} + +static unsigned get_16(const unsigned char *s, int e) +{ + e &= 1; + return s[e]<<8 | s[1-e]; +} + +static void put_16(unsigned char *s, unsigned c, int e) +{ + e &= 1; + s[e] = c>>8; + s[1-e] = c; +} + +static unsigned get_32(const unsigned char *s, int e) +{ + return s[e]+0U<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3]; +} + +static void put_32(unsigned char *s, unsigned c, int e) +{ + s[e^0] = c>>24; + s[e^1] = c>>16; + s[e^2] = c>>8; + s[e^3] = c; +} + + + +#define GET_MAPPING(m, i, n) ( (1<<(n))-1 & ( \ + (m)[(i)*(n)/8] >> ((n)%8*(i)%8) | \ + (m)[(i)*(n)/8+1] << 8-((n)%8*(i)%8) | \ + (m)[(i)*(n)/8+2] << 16-((n)%8*(i)%8) ) ) + +static unsigned get_mapping(const unsigned char *m, unsigned c, unsigned n) +{ + switch (n) { + default: + case 9: return m[c*9/8]>>c%8 | m[c*9/8+1]<<8-c%8 & (1<<n)-1; + case 10: return m[c*10/8]>>2*c%8 | m[c*10/8+1]<<8-2*c%8 & (1<<n)-1; + case 11: return GET_MAPPING(m, c, 11); + case 13: return GET_MAPPING(m, c, 13); + case 14: return GET_MAPPING(m, c, 14); + } +} + +/* Adapt as needed */ +#define mbrtowc_utf8 mbrtowc +#define wctomb_utf8 wctomb + +#include <stdio.h> +size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb) +{ + size_t x=0; + unsigned long cd = (unsigned long)cd0; + unsigned to = cd & 0xffff; + unsigned from = cd >> 16; + const unsigned char *map = charmaps+from+2; + const unsigned char *tomap = charmaps+to+2; + mbstate_t st = {0}; + wchar_t wc; + unsigned c, d; + size_t k, l; + int err; + unsigned elide = map[-1] + 128; + unsigned toelide = tomap[-1] + 128; + unsigned char type = map[-2]; + unsigned char totype = tomap[-2]; + + if (!in || !*in || !*inb) return 0; + + for (; *inb; *in+=l, *inb-=l) { + c = *(unsigned char *)*in; + l = 1; + if (type < 8 || c >= 0x80) switch (type) { + case UTF_8: + l = mbrtowc_utf8(&wc, *in, *inb, &st); + if (!l) l++; + else if (l == (size_t)-1) goto ilseq; + else if (l == (size_t)-2) goto starved; + c = wc; + break; + case LATIN_9: + if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) { + static const unsigned char map[] = { + 0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0, + 0x52, 0x53, 0x78 + }; + if (c == 0xa4) c = 0x20ac; + else if (map[c-0xa5]) c = 0x100 | map[c-0xa5]; + } + break; + case TIS_620: + if (c >= 0xa1) c += 0x0e01-0xa1; + break; + case JIS_0201: + if (c >= 0xa1) + if (c <= 0xdf) c += 0xff61-0xa1; + else goto ilseq; + break; + case 9: case 10: case 11: case 13: case 14: + if (c < elide) break; + c = get_mapping(map, c-elide, type); + if (!c) { + case US_ASCII: + goto ilseq; + } + break; + case WCHAR_T: + l = sizeof(wchar_t); + if (*inb < l) goto starved; + c = *(wchar_t *)*in; + if (0) { + case UTF_32BE: + case UTF_32LE: + l = 4; + if (*inb < 4) goto starved; + c = get_32(*in, type); + } + if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq; + break; + case UCS2BE: + case UCS2LE: + case UTF_16BE: + case UTF_16LE: + l = 2; + if (*inb < 2) goto starved; + c = get_16(*in, type); + if ((unsigned)(c-0xdc00) < 0x400) goto ilseq; + if ((unsigned)(c-0xd800) < 0x400) { + if (type-UCS2BE < 2U) goto ilseq; + l = 4; + if (*inb < 4) goto starved; + d = get_16(*in + 2, from); + if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq; + c = ((c-0xd800)<<10) | (d-0xdc00); + } + break; + } + + switch (totype) { + case WCHAR_T: + if (*outb < sizeof(wchar_t)) goto toobig; + *(wchar_t *)*out = c; + *out += sizeof(wchar_t); + *outb -= sizeof(wchar_t); + break; + case UTF_8: + if (*outb < 4) { + char tmp[4]; + k = wctomb_utf8(tmp, c); + if (*outb < k) goto toobig; + memcpy(*out, tmp, k); + } else k = wctomb_utf8(*out, c); + *out += k; + *outb -= k; + break; + case TIS_620: + if (c-0xe01u <= 0xff-0xa1) + c -= 0xe01-0xa1; + else if (c >= 0xa1) + goto ascii; + goto revout; + case JIS_0201: + if (c-0xff61u <= 0xdf-0xa1) + c -= 0xff61-0xa1; + else if (c >= 0xa1) + goto ascii; + goto revout; + case LATIN_9: + if (c == 0x20ac) { + c=0xa4; + } else if (c-0x150u<=0x12 && (1<<c-0x150 & 0x3000c)) { + static const unsigned char map[] = + { 0xa6,0xa8,0xbc,0xbd }; + c = map[c&3]; + } else if (c-0x178u<=0x7 && (1<<c-0x178 & 0x61)) { + static const unsigned char map[] = + { 0xbe,0,0,0,0,0xb4,0xb8 }; + c = map[c&7]; + } else if (c>0x100 || + c-0xa5u<=0xbeu-0xa5 + && (1<<c-0xa5 & 0x388800a)) + case US_ASCII: ascii: + if (c > 0x7f) x++, c='*'; + case 9: case 10: case 11: case 13: case 14: + if (*outb < 1) goto toobig; + if (c < toelide) { + revout: + *(*out)++ = c; + *outb -= 1; + break; + } + for (d=0; d<256-toelide; d++) { + if (c == get_mapping(tomap, d, totype)) { + c = d + toelide; + goto revout; + } + } + x++; + c = '*'; + goto revout; + case UCS2BE: + case UCS2LE: + case UTF_16BE: + case UTF_16LE: + if (c < 0x10000) { + if (*outb < 2) goto toobig; + put_16(*out, c, totype); + *out += 2; + *outb -= 2; + break; + } + if (type-UCS2BE < 2U) goto ilseq; + if (*outb < 4) goto toobig; + put_16(*out, (c>>10)|0xd800, totype); + put_16(*out + 2, (c&0x3ff)|0xdc00, totype); + *out += 4; + *outb -= 4; + break; + case UTF_32BE: + case UTF_32LE: + if (*outb < 4) goto toobig; + put_32(*out, c, totype); + *out += 4; + *outb -= 4; + break; + } + } + return x; +ilseq: + err = EILSEQ; + x = -1; + goto end; +toobig: + err = E2BIG; + goto end; +starved: + err = EINVAL; +end: + errno = err; + return x; +} diff --git a/src/locale/intl.c b/src/locale/intl.c new file mode 100644 index 00000000..964f7da1 --- /dev/null +++ b/src/locale/intl.c @@ -0,0 +1,67 @@ +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <errno.h> + +char *gettext(const char *msgid) +{ + return (char *) msgid; +} + +char *dgettext(const char *domainname, const char *msgid) +{ + return (char *) msgid; +} + +char *dcgettext(const char *domainname, const char *msgid, int category) +{ + return (char *) msgid; +} + +char *ngettext(const char *msgid1, const char *msgid2, unsigned long int n) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *dngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category) +{ + return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *textdomain(const char *domainname) +{ + static const char default_str[] = "messages"; + + if (domainname && *domainname && strcmp(domainname, default_str)) { + errno = EINVAL; + return NULL; + } + return (char *) default_str; +} + +char *bindtextdomain(const char *domainname, const char *dirname) +{ + static const char dir[] = "/"; + + if (!domainname || !*domainname + || (dirname && ((dirname[0] != '/') || dirname[1])) + ) { + errno = EINVAL; + return NULL; + } + + return (char *) dir; +} + +char *bind_textdomain_codeset(const char *domainname, const char *codeset) +{ + if (!domainname || !*domainname || (codeset && strcasecmp(codeset, "UTF-8"))) { + errno = EINVAL; + } + return NULL; +} diff --git a/src/locale/isalnum_l.c b/src/locale/isalnum_l.c new file mode 100644 index 00000000..b8a6eef3 --- /dev/null +++ b/src/locale/isalnum_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalnum_l(int c, locale_t l) +{ + return isalnum(c); +} diff --git a/src/locale/isalpha_l.c b/src/locale/isalpha_l.c new file mode 100644 index 00000000..2e1205c6 --- /dev/null +++ b/src/locale/isalpha_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalpha_l(int c, locale_t l) +{ + return isalpha(c); +} diff --git a/src/locale/isblank_l.c b/src/locale/isblank_l.c new file mode 100644 index 00000000..27479aa1 --- /dev/null +++ b/src/locale/isblank_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isblank_l(int c, locale_t l) +{ + return isblank(c); +} diff --git a/src/locale/iscntrl_l.c b/src/locale/iscntrl_l.c new file mode 100644 index 00000000..ca596fa9 --- /dev/null +++ b/src/locale/iscntrl_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int iscntrl_l(int c, locale_t l) +{ + return iscntrl(c); +} diff --git a/src/locale/isdigit_l.c b/src/locale/isdigit_l.c new file mode 100644 index 00000000..c8ae7bd3 --- /dev/null +++ b/src/locale/isdigit_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isdigit_l(int c, locale_t l) +{ + return isdigit(c); +} diff --git a/src/locale/isgraph_l.c b/src/locale/isgraph_l.c new file mode 100644 index 00000000..713a86e6 --- /dev/null +++ b/src/locale/isgraph_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isgraph_l(int c, locale_t l) +{ + return isgraph(c); +} diff --git a/src/locale/islower_l.c b/src/locale/islower_l.c new file mode 100644 index 00000000..25ec97a1 --- /dev/null +++ b/src/locale/islower_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int islower_l(int c, locale_t l) +{ + return islower(c); +} diff --git a/src/locale/isprint_l.c b/src/locale/isprint_l.c new file mode 100644 index 00000000..79ef3514 --- /dev/null +++ b/src/locale/isprint_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isprint_l(int c, locale_t l) +{ + return isprint(c); +} diff --git a/src/locale/ispunct_l.c b/src/locale/ispunct_l.c new file mode 100644 index 00000000..1c0bd046 --- /dev/null +++ b/src/locale/ispunct_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int ispunct_l(int c, locale_t l) +{ + return ispunct(c); +} diff --git a/src/locale/isspace_l.c b/src/locale/isspace_l.c new file mode 100644 index 00000000..e1a0efed --- /dev/null +++ b/src/locale/isspace_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isspace_l(int c, locale_t l) +{ + return isspace(c); +} diff --git a/src/locale/isupper_l.c b/src/locale/isupper_l.c new file mode 100644 index 00000000..11ba7036 --- /dev/null +++ b/src/locale/isupper_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isupper_l(int c, locale_t l) +{ + return isupper(c); +} diff --git a/src/locale/isxdigit_l.c b/src/locale/isxdigit_l.c new file mode 100644 index 00000000..68649d09 --- /dev/null +++ b/src/locale/isxdigit_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isxdigit_l(int c, locale_t l) +{ + return isxdigit(c); +} diff --git a/src/locale/langinfo.c b/src/locale/langinfo.c new file mode 100644 index 00000000..f7f56012 --- /dev/null +++ b/src/locale/langinfo.c @@ -0,0 +1,58 @@ +#include <locale.h> +#include <langinfo.h> + +static const char c_time[] = + "Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" + "Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0" + "Thursday\0" "Friday\0" "Saturday\0" + "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" + "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0" + "January\0" "February\0" "March\0" "April\0" + "May\0" "June\0" "July\0" "August\0" + "September\0" "October\0" "November\0" "December\0" + "AM\0" "PM\0" + "%a %b %e %T %Y\0" + "%m/%d/%y\0" + "%H:%M:%S\0" + "%I:%M:%S %p\0" + "\0" + "%m/%d/%y\0" + "0123456789" + "%a %b %e %T %Y\0" + "%H:%M:%S"; + +static const char c_messages[] = "^[yY]\0" "^[nN]"; +static const char c_numeric[] = ".\0" ""; + +const char *__langinfo(nl_item item) +{ + int cat = item >> 16; + int idx = item & 65535; + const char *str; + + if (item == CODESET) return "UTF-8"; + + switch (cat) { + case LC_NUMERIC: + if (idx > 1) return NULL; + str = c_numeric; + break; + case LC_TIME: + if (idx > 0x31) return NULL; + str = c_time; + break; + case LC_MONETARY: + if (idx > 0) return NULL; + str = ""; + break; + case LC_MESSAGES: + if (idx > 1) return NULL; + str = c_messages; + break; + default: + return NULL; + } + + for (; idx; idx--, str++) for (; *str; str++); + return str; +} diff --git a/src/locale/localeconv.c b/src/locale/localeconv.c new file mode 100644 index 00000000..d79d1c07 --- /dev/null +++ b/src/locale/localeconv.c @@ -0,0 +1,22 @@ +#include <locale.h> +#include <string.h> +#include <stdlib.h> + +struct lconv *localeconv(void) +{ + static struct lconv *posix_lconv; + if (posix_lconv) return posix_lconv; + posix_lconv = malloc(sizeof *posix_lconv); + memset(posix_lconv, -1, sizeof *posix_lconv); + posix_lconv->decimal_point = "."; + posix_lconv->thousands_sep = ""; + posix_lconv->grouping = "\xff"; + posix_lconv->int_curr_symbol = ""; //"\xc2\xa4"; + posix_lconv->currency_symbol = ""; + posix_lconv->mon_decimal_point = ""; + posix_lconv->mon_thousands_sep = ""; + posix_lconv->mon_grouping = "\xff"; + posix_lconv->positive_sign = ""; // "+"; + posix_lconv->negative_sign = ""; // "-"; + return posix_lconv; +} diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c new file mode 100644 index 00000000..986e796f --- /dev/null +++ b/src/locale/newlocale.c @@ -0,0 +1,11 @@ +#include <stdlib.h> +#include <string.h> +#include "locale_impl.h" + +locale_t newlocale(int mask, const char *name, locale_t base) +{ + if (*name && strcmp(name, "C") && strcmp(name, "POSIX")) + return 0; + if (!base) base = calloc(1, sizeof *base); + return base; +} diff --git a/src/locale/nl_langinfo.c b/src/locale/nl_langinfo.c new file mode 100644 index 00000000..bb3a2c46 --- /dev/null +++ b/src/locale/nl_langinfo.c @@ -0,0 +1,13 @@ +#include <langinfo.h> + +// FIXME: other items + +char *nl_langinfo(nl_item item) +{ + switch (item) { + case CODESET: + return "UTF-8"; + default: + return ""; + } +} diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c new file mode 100644 index 00000000..28f29b80 --- /dev/null +++ b/src/locale/setlocale.c @@ -0,0 +1,9 @@ +#include <locale.h> + +char *setlocale(int category, const char *locale) +{ + /* Note: plain "C" would be better, but puts some broken + * software into legacy 8-bit-codepage mode, ignoring + * the standard library's multibyte encoding */ + return "C.UTF-8"; +} diff --git a/src/locale/strcoll.c b/src/locale/strcoll.c new file mode 100644 index 00000000..30bccd62 --- /dev/null +++ b/src/locale/strcoll.c @@ -0,0 +1,6 @@ +#include <string.h> + +int strcoll(const char *l, const char *r) +{ + return strcmp(l, r); +} diff --git a/src/locale/strxfrm.c b/src/locale/strxfrm.c new file mode 100644 index 00000000..8f123399 --- /dev/null +++ b/src/locale/strxfrm.c @@ -0,0 +1,9 @@ +#include <string.h> + +/* collate only by code points */ +size_t strxfrm(char *dest, const char *src, size_t n) +{ + size_t l = strlen(src); + if (n > l) strcpy(dest, src); + return l; +} diff --git a/src/locale/tmp b/src/locale/tmp new file mode 100644 index 00000000..aa71779f --- /dev/null +++ b/src/locale/tmp @@ -0,0 +1,390 @@ +"iso88591\0\x08\x80" +"iso88592\0\x0a\x21" +"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a" +"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c" +"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e" +"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55" +"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43" +"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44" +"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56" +"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55" +"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43" +"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44" +"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56" +"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d" +"iso88593\0\x0a0x21" +"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a" +"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c" +"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e" +"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30" +"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32" +"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00" +"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47" +"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38" +"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a" +"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00" +"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47" +"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d" +"iso88594\0\x0a\x21" +"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a" +"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c" +"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e" +"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40" +"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43" +"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44" +"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36" +"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40" +"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43" +"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44" +"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e" +"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d" +"iso88595\0\x0d\x21" +"\x01\x84\x00\x30\x40\x10\x10\x05\x84\x01" +"\x70\x40\x20\x10\x09\x84\x02\xb0\x40\x30" +"\x10\xad\x80\x03\xf0\x40\x40\x10\x11\x84" +"\x04\x30\x41\x50\x10\x15\x84\x05\x70\x41" +"\x60\x10\x19\x84\x06\xb0\x41\x70\x10\x1d" +"\x84\x07\xf0\x41\x80\x10\x21\x84\x08\x30" +"\x42\x90\x10\x25\x84\x09\x70\x42\xa0\x10" +"\x29\x84\x0a\xb0\x42\xb0\x10\x2d\x84\x0b" +"\xf0\x42\xc0\x10\x31\x84\x0c\x30\x43\xd0" +"\x10\x35\x84\x0d\x70\x43\xe0\x10\x39\x84" +"\x0e\xb0\x43\xf0\x10\x3d\x84\x0f\xf0\x43" +"\x00\x11\x41\x84\x10\x30\x44\x10\x11\x45" +"\x84\x11\x70\x44\x20\x11\x49\x84\x12\xb0" +"\x44\x30\x11\x4d\x84\x13\xf0\x44\x58\x84" +"\x51\x84\x14\x30\x45\x50\x11\x55\x84\x15" +"\x70\x45\x60\x11\x59\x84\x16\xb0\x45\x70" +"\x11\xa7\x80\x17\xf0\x45\x00" +"iso88596\0\x0b\x21" +"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\xc0\x86\x00\x00\x00" +"\x00\x7c\x18\x00\x21\x16\xf1\x88\x48\x5c" +"\x62\x13\x9c\x18\xc5\x29\x56\xf1\x8a\x58" +"\xdc\x62\x17\xbc\x18\xc6\x31\x96\xf1\x8c" +"\x68\x5c\x63\x1b\xdc\x18\xc7\x39\xd6\x31" +"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16" +"\xf2\x90\x88\x5c\x64\x23\x1c\x19\xc9\x49" +"\x56\xf2\x92\x98\xdc\x64\x27\x3c\x19\xca" +"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00" +"iso88597\0\x0d\x21" +"\x18\x60\x06\x30\x0a\xb0\x82\xaf\xa0\x29" +"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0" +"\x02\xad\x00\x00\x50\x01\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b" +"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd" +"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30" +"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e" +"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7" +"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90" +"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83" +"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a" +"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5" +"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0" +"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f" +"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1" +"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30" +"\x0f\xcd\x83\xf3\x00\x00\x00" +"iso88598\0\x0d\x21" +"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29" +"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0" +"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80" +"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b" +"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01" +"\x40\x17\xd1\x85\x74\x30\x5d\x50\x17\xd5" +"\x85\x75\x70\x5d\x60\x17\xd9\x85\x76\xb0" +"\x5d\x70\x17\xdd\x85\x77\xf0\x5d\x80\x17" +"\xe1\x85\x78\x30\x5e\x90\x17\xe5\x85\x79" +"\x70\x5e\xa0\x17\xe9\x85\x7a\x00\x00\x00" +"\x00\x0e\xe0\x03\x00\x00\x00" +"iso88599\0\x09\x50" +"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8" +"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2" +"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9" +"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b" +"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7" +"\x2f\xe6\xd7\x7f" +"iso885910\0\x0d\x21" +"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d" +"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4" +"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1" +"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b" +"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15" +"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30" +"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04" +"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33" +"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50" +"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81" +"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d" +"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5" +"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0" +"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03" +"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d" +"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0" +"\x03\xfd\x80\x3f\x80\x13\x00" +"iso885913\0\x0d\x21" +"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29" +"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0" +"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b" +"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60" +"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04" +"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a" +"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30" +"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81" +"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d" +"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5" +"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70" +"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05" +"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d" +"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0" +"\x03\x7c\x81\x5f\x90\x01\x00" +"iso885914\0\x0c\x21" +"\x02\x7e\xc0\x8c\x02\x85\xb0\x10\x14\xfc" +"\x29\x00\xf4\xa9\x40\xd0\x2c\x78\x79\xd0" +"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84" +"\x04\x20\x10\xe4\x6c\x81\x95\x08\xf4\x57" +"\x7e\xd0\x80\xf9\x79\x40\xe8\x0a\x7d\x98" +"\x00\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c" +"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03" +"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40" +"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc0" +"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec" +"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72" +"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d" +"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b" +"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1" +"\x9a\xc0\x07\xf9\x40\x1f\xec\x03\x7e\xd0" +"\x0f\xee\xc2\x3f\x00" +"iso885916\0\x0d\x21" +"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58" +"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4" +"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00" +"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b" +"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53" +"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20" +"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03" +"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33" +"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50" +"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80" +"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d" +"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07" +"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0" +"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04" +"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d" +"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0" +"\x03\x19\xc1\x86\xf0\x0f\x00" +; + + +'i','s','o','8','8','5','9','1',0, +8,128, +'i','s','o','8','8','5','9','2',0, +10, 33, +0x04, 0x61, 0x1b, 0x14, 0x29, 0x3d, 0x69, 0x75, 0x0a, 0x2a, +0x60, 0x79, 0x45, 0x56, 0x5e, 0xad, 0xf4, 0xb5, 0x17, 0x2c, +0x05, 0x6d, 0x2b, 0x14, 0x2d, 0x3e, 0x6d, 0x75, 0x2c, 0x2e, +0x61, 0x7d, 0x55, 0x96, 0x5e, 0xdd, 0xfa, 0xc5, 0x17, 0x55, +0xc1, 0x08, 0x23, 0x10, 0x31, 0x39, 0x19, 0x74, 0x0c, 0x43, +0xc9, 0x60, 0xb4, 0x8c, 0x46, 0xcd, 0x38, 0xe3, 0x10, 0x44, +0x43, 0x1d, 0x35, 0x0d, 0x35, 0x50, 0x59, 0x73, 0x0d, 0x56, +0x6e, 0x69, 0x03, 0x17, 0x37, 0xdd, 0x88, 0xf5, 0x4d, 0x55, +0xe1, 0x88, 0x33, 0x10, 0x39, 0x3a, 0x1d, 0x74, 0x4e, 0x43, +0xe9, 0x64, 0xb4, 0xce, 0x46, 0xed, 0xb8, 0xf3, 0x50, 0x44, +0x44, 0x21, 0x35, 0x0f, 0x3d, 0x51, 0xd9, 0x73, 0x4f, 0x56, +0x6f, 0xe9, 0x13, 0x17, 0x3f, 0xfd, 0x8c, 0x95, 0x2d, +'i','s','o','8','8','5','9','3',0, +10, 33, +0x26, 0x61, 0x3b, 0x0a, 0x29, 0x00, 0x90, 0x74, 0x0a, 0x2a, +0x30, 0x79, 0xe5, 0x11, 0x4d, 0xad, 0x00, 0xb0, 0x17, 0x2c, +0x27, 0xc9, 0x32, 0x0b, 0x2d, 0xb5, 0x94, 0x74, 0x0b, 0x2e, +0x31, 0x7d, 0xf5, 0x51, 0x4d, 0xbd, 0x00, 0xc0, 0x17, 0x30, +0xc1, 0x08, 0x03, 0x00, 0x31, 0x0a, 0x21, 0x74, 0x0c, 0x32, +0xc9, 0x28, 0xb3, 0x0c, 0x33, 0xcd, 0x38, 0xf3, 0x0c, 0x00, +0xd1, 0x48, 0x33, 0x0d, 0x35, 0x20, 0x59, 0x73, 0x0d, 0x47, +0xd9, 0x68, 0xb3, 0x0d, 0x37, 0x6c, 0x71, 0xf5, 0x0d, 0x38, +0xe1, 0x88, 0x03, 0x00, 0x39, 0x0b, 0x25, 0x74, 0x0e, 0x3a, +0xe9, 0xa8, 0xb3, 0x0e, 0x3b, 0xed, 0xb8, 0xf3, 0x0e, 0x00, +0xf1, 0xc8, 0x33, 0x0f, 0x3d, 0x21, 0xd9, 0x73, 0x4f, 0x47, +0xf9, 0xe8, 0xb3, 0x0f, 0x3f, 0x6d, 0x75, 0x95, 0x2d, +'i','s','o','8','8','5','9','4',0, +10, 33, +0x04, 0xe1, 0x64, 0x15, 0x29, 0x28, 0xed, 0x74, 0x0a, 0x2a, +0x60, 0x49, 0x24, 0x92, 0x59, 0xad, 0xf4, 0xf5, 0x0a, 0x2c, +0x05, 0x6d, 0x7b, 0x15, 0x2d, 0x29, 0xf1, 0x74, 0x2c, 0x2e, +0x61, 0x4d, 0x34, 0xd2, 0x59, 0x4a, 0xf9, 0xb5, 0x14, 0x40, +0xc1, 0x08, 0x33, 0x0c, 0x31, 0xc5, 0x18, 0xe3, 0x12, 0x43, +0xc9, 0x60, 0xb4, 0x8c, 0x45, 0xcd, 0x38, 0xa3, 0x12, 0x44, +0x45, 0x31, 0x65, 0x13, 0x35, 0xd5, 0x58, 0x73, 0x0d, 0x36, +0x72, 0x69, 0xb3, 0x0d, 0x37, 0x68, 0xa9, 0xf5, 0x4d, 0x40, +0xe1, 0x88, 0x33, 0x0e, 0x39, 0xe5, 0x98, 0xf3, 0x52, 0x43, +0xe9, 0x64, 0xb4, 0xce, 0x45, 0xed, 0xb8, 0xb3, 0x52, 0x44, +0x46, 0x35, 0x75, 0x13, 0x3d, 0xf5, 0xd8, 0x73, 0x0f, 0x3e, +0x73, 0xe9, 0xb3, 0x0f, 0x3f, 0x69, 0xad, 0x95, 0x2d, +'i','s','o','8','8','5','9','5',0, +14, 33, +0x01, 0x84, 0x00, 0x30, 0x40, 0x10, 0x10, 0x05, 0x84, 0x01, +0x70, 0x40, 0x20, 0x10, 0x09, 0x84, 0x02, 0xb0, 0x40, 0x30, +0x10, 0xad, 0x80, 0x03, 0xf0, 0x40, 0x40, 0x10, 0x11, 0x84, +0x04, 0x30, 0x41, 0x50, 0x10, 0x15, 0x84, 0x05, 0x70, 0x41, +0x60, 0x10, 0x19, 0x84, 0x06, 0xb0, 0x41, 0x70, 0x10, 0x1d, +0x84, 0x07, 0xf0, 0x41, 0x80, 0x10, 0x21, 0x84, 0x08, 0x30, +0x42, 0x90, 0x10, 0x25, 0x84, 0x09, 0x70, 0x42, 0xa0, 0x10, +0x29, 0x84, 0x0a, 0xb0, 0x42, 0xb0, 0x10, 0x2d, 0x84, 0x0b, +0xf0, 0x42, 0xc0, 0x10, 0x31, 0x84, 0x0c, 0x30, 0x43, 0xd0, +0x10, 0x35, 0x84, 0x0d, 0x70, 0x43, 0xe0, 0x10, 0x39, 0x84, +0x0e, 0xb0, 0x43, 0xf0, 0x10, 0x3d, 0x84, 0x0f, 0xf0, 0x43, +0x00, 0x11, 0x41, 0x84, 0x10, 0x30, 0x44, 0x10, 0x11, 0x45, +0x84, 0x11, 0x70, 0x44, 0x20, 0x11, 0x49, 0x84, 0x12, 0xb0, +0x44, 0x30, 0x11, 0x4d, 0x84, 0x13, 0xf0, 0x44, 0x58, 0x84, +0x51, 0x84, 0x14, 0x30, 0x45, 0x50, 0x11, 0x55, 0x84, 0x15, +0x70, 0x45, 0x60, 0x11, 0x59, 0x84, 0x16, 0xb0, 0x45, 0x70, +0x11, 0xa7, 0x80, 0x17, 0xf0, 0x45, 0x00, +'i','s','o','8','8','5','9','6',0, +11, 33, +0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xdc, 0x0a, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x86, 0x00, 0x00, 0x00, +0x00, 0x7c, 0x18, 0x00, 0x21, 0x16, 0xf1, 0x88, 0x48, 0x5c, +0x62, 0x13, 0x9c, 0x18, 0xc5, 0x29, 0x56, 0xf1, 0x8a, 0x58, +0xdc, 0x62, 0x17, 0xbc, 0x18, 0xc6, 0x31, 0x96, 0xf1, 0x8c, +0x68, 0x5c, 0x63, 0x1b, 0xdc, 0x18, 0xc7, 0x39, 0xd6, 0x31, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x41, 0x16, +0xf2, 0x90, 0x88, 0x5c, 0x64, 0x23, 0x1c, 0x19, 0xc9, 0x49, +0x56, 0xf2, 0x92, 0x98, 0xdc, 0x64, 0x27, 0x3c, 0x19, 0xca, +0x51, 0x96, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, +'i','s','o','8','8','5','9','7',0, +14, 33, +0x18, 0x60, 0x06, 0x30, 0x0a, 0xb0, 0x82, 0xaf, 0xa0, 0x29, +0x70, 0x0a, 0xa0, 0x02, 0xa9, 0x80, 0xde, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x00, 0x00, 0x50, 0x01, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0x10, 0x0e, 0x85, 0x83, 0xe1, 0x70, 0x0b, +0x20, 0x0e, 0x89, 0x83, 0xe2, 0xb0, 0x0b, 0x30, 0x0e, 0xbd, +0x80, 0xe3, 0xf0, 0x38, 0x40, 0x0e, 0x91, 0x83, 0xe4, 0x30, +0x39, 0x50, 0x0e, 0x95, 0x83, 0xe5, 0x70, 0x39, 0x60, 0x0e, +0x99, 0x83, 0xe6, 0xb0, 0x39, 0x70, 0x0e, 0x9d, 0x83, 0xe7, +0xf0, 0x39, 0x80, 0x0e, 0xa1, 0x03, 0x00, 0x30, 0x3a, 0x90, +0x0e, 0xa5, 0x83, 0xe9, 0x70, 0x3a, 0xa0, 0x0e, 0xa9, 0x83, +0xea, 0xb0, 0x3a, 0xb0, 0x0e, 0xad, 0x83, 0xeb, 0xf0, 0x3a, +0xc0, 0x0e, 0xb1, 0x83, 0xec, 0x30, 0x3b, 0xd0, 0x0e, 0xb5, +0x83, 0xed, 0x70, 0x3b, 0xe0, 0x0e, 0xb9, 0x83, 0xee, 0xb0, +0x3b, 0xf0, 0x0e, 0xbd, 0x83, 0xef, 0xf0, 0x3b, 0x00, 0x0f, +0xc1, 0x83, 0xf0, 0x30, 0x3c, 0x10, 0x0f, 0xc5, 0x83, 0xf1, +0x70, 0x3c, 0x20, 0x0f, 0xc9, 0x83, 0xf2, 0xb0, 0x3c, 0x30, +0x0f, 0xcd, 0x83, 0xf3, 0x00, 0x00, 0x00, +'i','s','o','8','8','5','9','8',0, +14, 33, +0x00, 0x80, 0x28, 0x30, 0x0a, 0x90, 0x02, 0xa5, 0x80, 0x29, +0x70, 0x0a, 0xa0, 0x02, 0xa9, 0xc0, 0x35, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x80, 0x2b, 0xf0, 0x0a, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0xd0, 0x02, 0xb5, 0x80, 0x2d, 0x70, 0x0b, +0xe0, 0x02, 0xb9, 0xc0, 0x3d, 0xb0, 0x0b, 0xf0, 0x02, 0xbd, +0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, +0x40, 0x17, 0xd1, 0x85, 0x74, 0x30, 0x5d, 0x50, 0x17, 0xd5, +0x85, 0x75, 0x70, 0x5d, 0x60, 0x17, 0xd9, 0x85, 0x76, 0xb0, +0x5d, 0x70, 0x17, 0xdd, 0x85, 0x77, 0xf0, 0x5d, 0x80, 0x17, +0xe1, 0x85, 0x78, 0x30, 0x5e, 0x90, 0x17, 0xe5, 0x85, 0x79, +0x70, 0x5e, 0xa0, 0x17, 0xe9, 0x85, 0x7a, 0x00, 0x00, 0x00, +0x00, 0x0e, 0xe0, 0x03, 0x00, 0x00, 0x00, +'i','s','o','8','8','5','9','9',0, +9, 80, +0x1e, 0xa3, 0x49, 0x9b, 0x46, 0xad, 0x9a, 0xb5, 0x6b, 0xd8, +0xb2, 0x69, 0xdb, 0xc6, 0x0d, 0xa6, 0xd7, 0x6f, 0xe0, 0xc2, +0x89, 0x1b, 0x47, 0xae, 0x9c, 0xb9, 0x73, 0xe8, 0xd2, 0xa9, +0x5b, 0xc7, 0xae, 0x9d, 0xbb, 0x77, 0x1f, 0xe3, 0xc9, 0x9b, +0x47, 0xaf, 0x9e, 0xbd, 0x7b, 0xf8, 0xf2, 0xe9, 0xdb, 0xc7, +0x2f, 0xe6, 0xd7, 0x7f, +'i','s','o','8','8','5','9','1','0',0, +14, 33, +0x04, 0x81, 0x44, 0x20, 0x12, 0xa8, 0x04, 0x28, 0x81, 0x4d, +0x70, 0x0a, 0xec, 0x04, 0x10, 0x01, 0x58, 0x60, 0x16, 0xf4, +0x05, 0xad, 0x80, 0x5a, 0xa0, 0x14, 0xc0, 0x02, 0x05, 0xc1, +0x44, 0x30, 0x12, 0xac, 0x04, 0x29, 0xc1, 0x4d, 0x70, 0x0b, +0xf0, 0x04, 0x11, 0x41, 0x58, 0x70, 0x16, 0xf8, 0x05, 0x15, +0xe0, 0x5a, 0xb0, 0x14, 0x00, 0x04, 0xc1, 0x80, 0x30, 0x30, +0x0c, 0x10, 0x03, 0xc5, 0x80, 0x31, 0xe0, 0x12, 0x30, 0x04, +0xc9, 0x00, 0x46, 0xb0, 0x0c, 0x58, 0x04, 0xcd, 0x80, 0x33, +0xf0, 0x0c, 0x40, 0x03, 0x45, 0x01, 0x53, 0x30, 0x0d, 0x50, +0x03, 0xd5, 0x80, 0x35, 0x80, 0x16, 0x60, 0x03, 0x72, 0x81, +0x36, 0xb0, 0x0d, 0x70, 0x03, 0xdd, 0x80, 0x37, 0xf0, 0x0d, +0x04, 0x04, 0xe1, 0x80, 0x38, 0x30, 0x0e, 0x90, 0x03, 0xe5, +0x80, 0x39, 0xf0, 0x12, 0x34, 0x04, 0xe9, 0x40, 0x46, 0xb0, +0x0e, 0x5c, 0x04, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0xc0, 0x03, +0x46, 0x41, 0x53, 0x30, 0x0f, 0xd0, 0x03, 0xf5, 0x80, 0x3d, +0x90, 0x16, 0xe0, 0x03, 0x73, 0x81, 0x3e, 0xb0, 0x0f, 0xf0, +0x03, 0xfd, 0x80, 0x3f, 0x80, 0x13, 0x00, +'i','s','o','8','8','5','9','1','3',0, +14, 33, +0x1d, 0xa0, 0x28, 0x30, 0x0a, 0x90, 0x02, 0x1e, 0xa0, 0x29, +0x70, 0x0a, 0x60, 0x03, 0xa9, 0x80, 0x55, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x80, 0x2b, 0x60, 0x0c, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0x70, 0x80, 0xb5, 0x80, 0x2d, 0x70, 0x0b, +0xe0, 0x03, 0xb9, 0xc0, 0x55, 0xb0, 0x0b, 0xf0, 0x02, 0xbd, +0x80, 0x2f, 0x60, 0x0e, 0x10, 0x04, 0x2e, 0x01, 0x40, 0x60, +0x10, 0x10, 0x03, 0xc5, 0x00, 0x46, 0x20, 0x11, 0x30, 0x04, +0xc9, 0x40, 0x5e, 0x60, 0x11, 0x88, 0x04, 0x36, 0x81, 0x4a, +0xb0, 0x13, 0x80, 0x05, 0x43, 0x41, 0x51, 0x30, 0x0d, 0x30, +0x05, 0xd5, 0x80, 0x35, 0x70, 0x0d, 0xc8, 0x05, 0x41, 0x81, +0x56, 0xa0, 0x16, 0x70, 0x03, 0x7b, 0x41, 0x5f, 0xf0, 0x0d, +0x14, 0x04, 0x2f, 0x41, 0x40, 0x70, 0x10, 0x90, 0x03, 0xe5, +0x40, 0x46, 0x30, 0x11, 0x34, 0x04, 0xe9, 0x80, 0x5e, 0x70, +0x11, 0x8c, 0x04, 0x37, 0xc1, 0x4a, 0xc0, 0x13, 0x84, 0x05, +0x44, 0x81, 0x51, 0x30, 0x0f, 0x34, 0x05, 0xf5, 0x80, 0x3d, +0x70, 0x0f, 0xcc, 0x05, 0x42, 0xc1, 0x56, 0xb0, 0x16, 0xf0, +0x03, 0x7c, 0x81, 0x5f, 0x90, 0x01, 0x00, +'i','s','o','8','8','5','9','1','4',0, +13, 33, +0x02, 0x7e, 0xc0, 0x8c, 0x02, 0x85, 0xb0, 0x10, 0x14, 0xfc, +0x29, 0x00, 0xf4, 0xa9, 0x40, 0xd0, 0x2c, 0x78, 0x79, 0xd0, +0x0a, 0x5c, 0x01, 0x5e, 0xf0, 0xf0, 0x1f, 0x1e, 0x24, 0x84, +0x04, 0x20, 0x10, 0xe4, 0x6c, 0x81, 0x95, 0x08, 0xf4, 0x57, +0x7e, 0xd0, 0x80, 0xf9, 0x79, 0x40, 0xe8, 0x0a, 0x7d, 0x98, +0x00, 0x06, 0xc1, 0x40, 0x18, 0x0c, 0x03, 0x62, 0x50, 0x0c, +0x8c, 0xc1, 0x31, 0x40, 0x06, 0xc9, 0x40, 0x19, 0x2c, 0x03, +0x66, 0xd0, 0x0c, 0x9c, 0xc1, 0x33, 0xa0, 0x0b, 0xd1, 0x40, +0x1a, 0x4c, 0x03, 0x6a, 0x50, 0x0d, 0xac, 0x81, 0x9a, 0xc0, +0x06, 0xd9, 0x40, 0x1b, 0x6c, 0x03, 0x6e, 0xd0, 0x0d, 0xec, +0xc2, 0x37, 0x00, 0x07, 0xe1, 0x40, 0x1c, 0x8c, 0x03, 0x72, +0x50, 0x0e, 0xcc, 0xc1, 0x39, 0x40, 0x07, 0xe9, 0x40, 0x1d, +0xac, 0x03, 0x76, 0xd0, 0x0e, 0xdc, 0xc1, 0x3b, 0xa8, 0x0b, +0xf1, 0x40, 0x1e, 0xcc, 0x03, 0x7a, 0x50, 0x0f, 0xec, 0xc1, +0x9a, 0xc0, 0x07, 0xf9, 0x40, 0x1f, 0xec, 0x03, 0x7e, 0xd0, +0x0f, 0xee, 0xc2, 0x3f, 0x00, +'i','s','o','8','8','5','9','1','6',0, +14, 33, +0x04, 0x41, 0x41, 0x10, 0x14, 0xb0, 0x82, 0x1e, 0x20, 0x58, +0x70, 0x0a, 0x84, 0x05, 0xa9, 0x00, 0x86, 0xb0, 0x0a, 0xe4, +0x05, 0xad, 0x80, 0x5e, 0xb0, 0x17, 0xc0, 0x02, 0xb1, 0x00, +0x43, 0x20, 0x14, 0xf4, 0x05, 0x1d, 0xa0, 0x2d, 0x70, 0x0b, +0xf8, 0x05, 0x0d, 0x41, 0x86, 0xb0, 0x0b, 0x48, 0x05, 0x53, +0x01, 0x5e, 0xc0, 0x17, 0x00, 0x03, 0xc1, 0x80, 0x30, 0x20, +0x10, 0x10, 0x03, 0x06, 0x81, 0x31, 0x70, 0x0c, 0x20, 0x03, +0xc9, 0x80, 0x32, 0xb0, 0x0c, 0x30, 0x03, 0xcd, 0x80, 0x33, +0xf0, 0x0c, 0x40, 0x04, 0x43, 0x81, 0x34, 0x30, 0x0d, 0x50, +0x03, 0x50, 0x81, 0x35, 0xa0, 0x15, 0xc0, 0x05, 0xd9, 0x80, +0x36, 0xb0, 0x0d, 0x70, 0x03, 0x18, 0x81, 0x86, 0xf0, 0x0d, +0x80, 0x03, 0xe1, 0x80, 0x38, 0x30, 0x10, 0x90, 0x03, 0x07, +0x81, 0x39, 0x70, 0x0e, 0xa0, 0x03, 0xe9, 0x80, 0x3a, 0xb0, +0x0e, 0xb0, 0x03, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0x44, 0x04, +0x44, 0x81, 0x3c, 0x30, 0x0f, 0xd0, 0x03, 0x51, 0x81, 0x3d, +0xb0, 0x15, 0xc4, 0x05, 0xf9, 0x80, 0x3e, 0xb0, 0x0f, 0xf0, +0x03, 0x19, 0xc1, 0x86, 0xf0, 0x0f, 0x00, diff --git a/src/locale/tolower_l.c b/src/locale/tolower_l.c new file mode 100644 index 00000000..ba277919 --- /dev/null +++ b/src/locale/tolower_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int tolower_l(int c, locale_t l) +{ + return tolower(c); +} diff --git a/src/locale/toupper_l.c b/src/locale/toupper_l.c new file mode 100644 index 00000000..73f2f39b --- /dev/null +++ b/src/locale/toupper_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int toupper_l(int c, locale_t l) +{ + return toupper(c); +} diff --git a/src/locale/wcscoll.c b/src/locale/wcscoll.c new file mode 100644 index 00000000..cdbce1c2 --- /dev/null +++ b/src/locale/wcscoll.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +/* FIXME: stub */ +int wcscoll(const wchar_t *l, const wchar_t *r) +{ + return wcscmp(l, r); +} diff --git a/src/locale/wcsxfrm.c b/src/locale/wcsxfrm.c new file mode 100644 index 00000000..5f76e5a7 --- /dev/null +++ b/src/locale/wcsxfrm.c @@ -0,0 +1,12 @@ +#include <wchar.h> + +/* collate only by code points */ +size_t wcsxfrm(wchar_t *dest, const wchar_t *src, size_t n) +{ + size_t l = wcslen(src); + if (l >= n) { + wmemcpy(dest, src, n-1); + dest[n-1] = 0; + } else wcscpy(dest, src); + return l; +} diff --git a/src/malloc/DESIGN b/src/malloc/DESIGN new file mode 100644 index 00000000..58b0523f --- /dev/null +++ b/src/malloc/DESIGN @@ -0,0 +1,22 @@ + + +In principle, this memory allocator is roughly equivalent to Doug +Lea's dlmalloc with fine-grained locking. + + + +malloc: + +Uses a freelist binned by chunk size, with a bitmap to optimize +searching for the smallest non-empty bin which can satisfy an +allocation. If no free chunks are available, it creates a new chunk of +the requested size and attempts to merge it with any existing free +chunk immediately below the newly created chunk. + +Whether the chunk was obtained from a bin or newly created, it's +likely to be larger than the requested allocation. malloc always +finishes its work by passing the new chunk to realloc, which will +split it into two chunks and free the tail portion. + + + diff --git a/src/malloc/__brk.c b/src/malloc/__brk.c new file mode 100644 index 00000000..e3b3af31 --- /dev/null +++ b/src/malloc/__brk.c @@ -0,0 +1,7 @@ +#include <stdint.h> +#include "syscall.h" + +uintptr_t __brk(uintptr_t newbrk) +{ + return syscall1(__NR_brk, newbrk); +} diff --git a/src/malloc/__simple_malloc.c b/src/malloc/__simple_malloc.c new file mode 100644 index 00000000..49b74c8e --- /dev/null +++ b/src/malloc/__simple_malloc.c @@ -0,0 +1,44 @@ +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <errno.h> +#include "libc.h" + +uintptr_t __brk(uintptr_t); + +#define ALIGN 16 + +void *__simple_malloc(size_t n) +{ + static uintptr_t cur, brk; + uintptr_t base, new; + static int lock; + size_t align=1; + + if (n < SIZE_MAX - ALIGN) + while (align<n && align<ALIGN) + align += align; + n = n + align - 1 & -align; + + LOCK(&lock); + if (!cur) cur = brk = __brk(0)+16; + if (n > SIZE_MAX - brk) goto fail; + + base = cur + align-1 & -align; + if (base+n > brk) { + new = base+n + PAGE_SIZE-1 & -PAGE_SIZE; + if (__brk(new) != new) goto fail; + brk = new; + } + cur = base+n; + UNLOCK(&lock); + + return (void *)base; + +fail: + UNLOCK(&lock); + errno = ENOMEM; + return 0; +} + +weak_alias(__simple_malloc, malloc); diff --git a/src/malloc/calloc.c b/src/malloc/calloc.c new file mode 100644 index 00000000..9d574562 --- /dev/null +++ b/src/malloc/calloc.c @@ -0,0 +1,23 @@ +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +void *calloc(size_t m, size_t n) +{ + void *p; + size_t *z; + if (n && m > (size_t)-1/n) { + errno = ENOMEM; + return 0; + } + n *= m; + p = malloc(n); + if (!p) return 0; + /* Only do this for non-mmapped chunks */ + if (((size_t *)p)[-1] & 7) { + /* Only write words that are not already zero */ + m = (n + sizeof *z - 1)/sizeof *z; + for (z=p; m; m--, z++) if (*z) *z=0; + } + return p; +} diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c new file mode 100644 index 00000000..d9a30fe4 --- /dev/null +++ b/src/malloc/malloc.c @@ -0,0 +1,515 @@ +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <errno.h> +#include <sys/mman.h> +#include "libc.h" +#include "atomic.h" +#include "pthread_impl.h" + +uintptr_t __brk(uintptr_t); +void *__mmap(void *, size_t, int, int, int, off_t); +int __munmap(void *, size_t); +void *__mremap(void *, size_t, size_t, int, ...); +int __madvise(void *, size_t, int); + +struct chunk { + size_t data[1]; + struct chunk *next; + struct chunk *prev; +}; + +struct bin { + int lock[2]; + struct chunk *head; + struct chunk *tail; +}; + +static struct { + uintptr_t brk; + size_t *heap; + uint64_t binmap; + struct bin bins[64]; + int brk_lock[2]; + int free_lock[2]; +} mal; + + +#define SIZE_ALIGN (4*sizeof(size_t)) +#define SIZE_MASK (-SIZE_ALIGN) +#define OVERHEAD (2*sizeof(size_t)) +#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN) +#define DONTCARE 16 +#define RECLAIM 163840 + +#define CHUNK_SIZE(c) ((c)->data[0] & SIZE_MASK) +#define CHUNK_PSIZE(c) ((c)->data[-1] & SIZE_MASK) +#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c))) +#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c))) +#define MEM_TO_CHUNK(p) (struct chunk *)((size_t *)p - 1) +#define CHUNK_TO_MEM(c) (void *)((c)->data+1) +#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) + +#define C_INUSE ((size_t)1) +#define C_FLAGS ((size_t)3) +#define C_SIZE SIZE_MASK + +#define IS_MMAPPED(c) !((c)->data[0] & (C_INUSE)) + + +/* Synchronization tools */ + +static void lock(volatile int *lk) +{ + if (!libc.threads_minus_1) return; + while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1); +} + +static void unlock(volatile int *lk) +{ + if (!libc.threads_minus_1) return; + a_store(lk, 0); + if (lk[1]) __wake(lk, 1, 1); +} + +static void lock_bin(int i) +{ + if (libc.threads_minus_1) + lock(mal.bins[i].lock); + if (!mal.bins[i].head) + mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); +} + +static void unlock_bin(int i) +{ + if (!libc.threads_minus_1) return; + unlock(mal.bins[i].lock); +} + +static int first_set(uint64_t x) +{ +#if 1 + return a_ctz_64(x); +#else + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x>>32; + return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; +#endif +} + +static int bin_index(size_t x) +{ + x = x / SIZE_ALIGN - 1; + if (x <= 32) return x; + if (x > 0x1c00) return 63; + return ((union { float v; uint32_t r; }){ x }.r>>21) - 496; +} + +static int bin_index_up(size_t x) +{ + x = x / SIZE_ALIGN - 1; + if (x <= 32) return x; + return ((union { float v; uint32_t r; }){ x }.r+0x1fffff>>21) - 496; +} + +#if 0 +void __dump_heap(int x) +{ + struct chunk *c; + int i; + for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) + fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", + c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), + c->data[0] & 15, + NEXT_CHUNK(c)->data[-1] & 15); + for (i=0; i<64; i++) { + if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { + fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); + if (!(mal.binmap & 1ULL<<i)) + fprintf(stderr, "missing from binmap!\n"); + } else if (mal.binmap & 1ULL<<i) + fprintf(stderr, "binmap wrongly contains %d!\n", i); + } +} +#endif + +static struct chunk *expand_heap(size_t n) +{ + struct chunk *w; + uintptr_t new; + + lock(mal.brk_lock); + + if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail; + new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE; + n = new - mal.brk; + + if (__brk(new) != new) goto fail; + + w = MEM_TO_CHUNK(new); + w->data[-1] = n | C_INUSE; + w->data[0] = 0 | C_INUSE; + + w = MEM_TO_CHUNK(mal.brk); + w->data[0] = n | C_INUSE; + mal.brk = new; + + unlock(mal.brk_lock); + + return w; +fail: + unlock(mal.brk_lock); + return 0; +} + +static int init_malloc() +{ + static int init, waiters; + int state; + struct chunk *c; + + if (init == 2) return 0; + + while ((state=a_swap(&init, 1)) == 1) + __wait(&init, &waiters, 1, 1); + if (state) { + a_store(&init, 2); + return 0; + } + + mal.brk = __brk(0) + 2*SIZE_ALIGN-1 & -SIZE_ALIGN; + + c = expand_heap(1); + + if (!c) { + a_store(&init, 0); + if (waiters) __wake(&init, 1, 1); + return -1; + } + + mal.heap = (void *)c; + c->data[-1] = 0 | C_INUSE; + free(CHUNK_TO_MEM(c)); + + a_store(&init, 2); + if (waiters) __wake(&init, -1, 1); + return 0; +} + +static int adjust_size(size_t *n) +{ + /* Result of pointer difference must fit in ptrdiff_t. */ + if (*n > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { + errno = ENOMEM; + return -1; + } + *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; + return 0; +} + +static void unbin(struct chunk *c, int i) +{ + if (c->prev == c->next) + a_and_64(&mal.binmap, ~(1ULL<<i)); + c->prev->next = c->next; + c->next->prev = c->prev; + c->data[0] |= C_INUSE; + NEXT_CHUNK(c)->data[-1] |= C_INUSE; +} + +static int alloc_fwd(struct chunk *c) +{ + int i; + size_t k; + while (!((k=c->data[0]) & C_INUSE)) { + i = bin_index(k); + lock_bin(i); + if (c->data[0] == k) { + unbin(c, i); + unlock_bin(i); + return 1; + } + unlock_bin(i); + } + return 0; +} + +static int alloc_rev(struct chunk *c) +{ + int i; + size_t k; + while (!((k=c->data[-1]) & C_INUSE)) { + i = bin_index(k); + lock_bin(i); + if (c->data[-1] == k) { + unbin(PREV_CHUNK(c), i); + unlock_bin(i); + return 1; + } + unlock_bin(i); + } + return 0; +} + + +/* pretrim - trims a chunk _prior_ to removing it from its bin. + * Must be called with i as the ideal bin for size n, j the bin + * for the _free_ chunk self, and bin j locked. */ +static int pretrim(struct chunk *self, size_t n, int i, int j) +{ + size_t n1; + struct chunk *next, *split; + + /* We cannot pretrim if it would require re-binning. */ + if (j < 40) return 0; + if (j < i+3) { + if (j != 63) return 0; + n1 = CHUNK_SIZE(self); + if (n1-n <= MMAP_THRESHOLD) return 0; + } else { + n1 = CHUNK_SIZE(self); + } + if (bin_index(n1-n) != j) return 0; + + next = NEXT_CHUNK(self); + split = (void *)((char *)self + n); + + split->prev = self->prev; + split->next = self->next; + split->prev->next = split; + split->next->prev = split; + split->data[-1] = n | C_INUSE; + split->data[0] = n1-n; + next->data[-1] = n1-n; + self->data[0] = n | C_INUSE; + return 1; +} + +static void trim(struct chunk *self, size_t n) +{ + size_t n1 = CHUNK_SIZE(self); + struct chunk *next, *split; + + if (n >= n1 - DONTCARE) return; + + next = NEXT_CHUNK(self); + split = (void *)((char *)self + n); + + split->data[-1] = n | C_INUSE; + split->data[0] = n1-n | C_INUSE; + next->data[-1] = n1-n | C_INUSE; + self->data[0] = n | C_INUSE; + + free(CHUNK_TO_MEM(split)); +} + +void *malloc(size_t n) +{ + struct chunk *c; + int i, j; + + if (!n || adjust_size(&n) < 0) return 0; + + if (n > MMAP_THRESHOLD) { + size_t len = n + PAGE_SIZE - 1 & -PAGE_SIZE; + char *base = __mmap(0, len, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (base == (void *)-1) return 0; + c = (void *)(base + SIZE_ALIGN - sizeof(size_t)); + c->data[0] = len - (SIZE_ALIGN - sizeof(size_t)); + c->data[-1] = SIZE_ALIGN - sizeof(size_t); + return CHUNK_TO_MEM(c); + } + + i = bin_index_up(n); + for (;;) { + uint64_t mask = mal.binmap & -(1ULL<<i); + if (!mask) { + init_malloc(); + c = expand_heap(n); + if (!c) return 0; + if (alloc_rev(c)) { + struct chunk *x = c; + c = PREV_CHUNK(c); + NEXT_CHUNK(x)->data[-1] = c->data[0] = + x->data[0] + CHUNK_SIZE(c); + } + break; + } + j = first_set(mask); + lock_bin(j); + c = mal.bins[j].head; + if (c != BIN_TO_CHUNK(j) && j == bin_index(c->data[0])) { + if (!pretrim(c, n, i, j)) unbin(c, j); + unlock_bin(j); + break; + } + unlock_bin(j); + } + + /* Now patch up in case we over-allocated */ + trim(c, n); + + return CHUNK_TO_MEM(c); +} + +void *realloc(void *p, size_t n) +{ + struct chunk *self, *next; + size_t n0, n1; + void *new; + + if (!p) return malloc(n); + else if (!n) return free(p), (void *)0; + + if (adjust_size(&n) < 0) return 0; + + self = MEM_TO_CHUNK(p); + n1 = n0 = CHUNK_SIZE(self); + + if (IS_MMAPPED(self)) { + size_t extra = self->data[-1]; + char *base = (char *)self - extra; + size_t oldlen = n0 + extra; + size_t newlen = n + extra; + if (newlen < PAGE_SIZE && (new = malloc(n))) { + memcpy(new, p, n-OVERHEAD); + free(p); + return new; + } + newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE; + if (oldlen == newlen) return p; + base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); + if (base == (void *)-1) + return newlen < oldlen ? p : 0; + self = (void *)(base + extra); + self->data[0] = newlen - extra; + return CHUNK_TO_MEM(self); + } + + next = NEXT_CHUNK(self); + + /* Merge adjacent chunks if we need more space. This is not + * a waste of time even if we fail to get enough space, because our + * subsequent call to free would otherwise have to do the merge. */ + if (n > n1 && alloc_fwd(next)) { + n1 += CHUNK_SIZE(next); + next = NEXT_CHUNK(next); + } + /* FIXME: find what's wrong here and reenable it..? */ + if (0 && n > n1 && alloc_rev(self)) { + self = PREV_CHUNK(self); + n1 += CHUNK_SIZE(self); + } + self->data[0] = n1 | C_INUSE; + next->data[-1] = n1 | C_INUSE; + + /* If we got enough space, split off the excess and return */ + if (n <= n1) { + //memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD); + trim(self, n); + return CHUNK_TO_MEM(self); + } + + /* As a last resort, allocate a new chunk and copy to it. */ + new = malloc(n-OVERHEAD); + if (!new) return 0; + memcpy(new, p, n0-OVERHEAD); + free(CHUNK_TO_MEM(self)); + return new; +} + +void free(void *p) +{ + struct chunk *self = MEM_TO_CHUNK(p); + struct chunk *next; + size_t final_size, new_size, size; + int reclaim=0; + int i; + + if (!p) return; + + if (IS_MMAPPED(self)) { + size_t extra = self->data[-1]; + char *base = (char *)self - extra; + size_t len = CHUNK_SIZE(self) + extra; + __munmap(base, len); + return; + } + + final_size = new_size = CHUNK_SIZE(self); + next = NEXT_CHUNK(self); + + for (;;) { + /* Replace middle of large chunks with fresh zero pages */ + if (reclaim && (self->data[-1] & next->data[0] & C_INUSE)) { + uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE; + uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; +#if 1 + __madvise((void *)a, b-a, MADV_DONTNEED); +#else + __mmap((void *)a, b-a, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); +#endif + } + + if (self->data[-1] & next->data[0] & C_INUSE) { + self->data[0] = final_size | C_INUSE; + next->data[-1] = final_size | C_INUSE; + i = bin_index(final_size); + lock_bin(i); + lock(mal.free_lock); + if (self->data[-1] & next->data[0] & C_INUSE) + break; + unlock(mal.free_lock); + unlock_bin(i); + } + + if (alloc_rev(self)) { + self = PREV_CHUNK(self); + size = CHUNK_SIZE(self); + final_size += size; + if (new_size+size > RECLAIM && (new_size+size^size) > size) + reclaim = 1; + } + + if (alloc_fwd(next)) { + size = CHUNK_SIZE(next); + final_size += size; + if (new_size+size > RECLAIM && (new_size+size^size) > size) + reclaim = 1; + next = NEXT_CHUNK(next); + } + } + + self->data[0] = final_size; + next->data[-1] = final_size; + unlock(mal.free_lock); + + self->next = BIN_TO_CHUNK(i); + self->prev = mal.bins[i].tail; + self->next->prev = self; + self->prev->next = self; + + if (!(mal.binmap & 1ULL<<i)) + a_or_64(&mal.binmap, 1ULL<<i); + + unlock_bin(i); +} diff --git a/src/malloc/memalign.c b/src/malloc/memalign.c new file mode 100644 index 00000000..61f456e4 --- /dev/null +++ b/src/malloc/memalign.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <errno.h> + +void *memalign(size_t align, size_t len) +{ + void *mem; + int ret; + if ((ret = posix_memalign(&mem, align, len))) { + errno = ret; + return 0; + } + return mem; +} diff --git a/src/malloc/posix_memalign.c b/src/malloc/posix_memalign.c new file mode 100644 index 00000000..ef86260d --- /dev/null +++ b/src/malloc/posix_memalign.c @@ -0,0 +1,47 @@ +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> + +/* This function should work with most dlmalloc-like chunk bookkeeping + * systems, but it's only guaranteed to work with the native implementation + * used in this library. */ + +int posix_memalign(void **res, size_t align, size_t len) +{ + unsigned char *mem, *new, *end; + size_t header, footer; + + if ((align & -align) != align) return EINVAL; + if (len > SIZE_MAX - align) return ENOMEM; + + if (align <= 4*sizeof(size_t)) { + if (!(mem = malloc(len))) + return errno; + *res = mem; + return 0; + } + + if (!(mem = malloc(len + align-1))) + return errno; + + header = ((size_t *)mem)[-1]; + end = mem + (header & -8); + footer = ((size_t *)end)[-2]; + new = (void *)((uintptr_t)mem + align-1 & -align); + + if (!(header & 7)) { + ((size_t *)new)[-2] = ((size_t *)mem)[-2] + (new-mem); + ((size_t *)new)[-1] = ((size_t *)mem)[-1] - (new-mem); + *res = new; + return 0; + } + + ((size_t *)mem)[-1] = header&7 | new-mem; + ((size_t *)new)[-2] = footer&7 | new-mem; + ((size_t *)new)[-1] = header&7 | end-new; + ((size_t *)end)[-2] = footer&7 | end-new; + + if (new != mem) free(mem); + *res = new; + return 0; +} diff --git a/src/math/__fpclassify.c b/src/math/__fpclassify.c new file mode 100644 index 00000000..16051100 --- /dev/null +++ b/src/math/__fpclassify.c @@ -0,0 +1,14 @@ +#include <stdint.h> +#include <math.h> + +int __fpclassify(double __x) +{ + union { + double __d; + __uint64_t __i; + } __y = { __x }; + int __ee = __y.__i>>52 & 0x7ff; + if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (__ee==0x7ff) return __y.__i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/math/__fpclassifyf.c b/src/math/__fpclassifyf.c new file mode 100644 index 00000000..bf59d0d4 --- /dev/null +++ b/src/math/__fpclassifyf.c @@ -0,0 +1,14 @@ +#include <stdint.h> +#include <math.h> + +int __fpclassifyf(float __x) +{ + union { + float __f; + __uint32_t __i; + } __y = { __x }; + int __ee = __y.__i>>23 & 0xff; + if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (__ee==0xff) return __y.__i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/math/__fpclassifyl.c b/src/math/__fpclassifyl.c new file mode 100644 index 00000000..4f93bef1 --- /dev/null +++ b/src/math/__fpclassifyl.c @@ -0,0 +1,16 @@ +#include <stdint.h> +#include <math.h> + +/* FIXME: move this to arch-specific file */ +int __fpclassifyl(long double __x) +{ + union { + long double __ld; + __uint16_t __hw[5]; + __uint64_t __m; + } __y = { __x }; + int __ee = __y.__hw[4]&0x7fff; + if (!__ee) return __y.__m ? FP_SUBNORMAL : FP_ZERO; + if (__ee==0x7fff) return __y.__m ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/math/e_acos.c b/src/math/e_acos.c new file mode 100644 index 00000000..e0236391 --- /dev/null +++ b/src/math/e_acos.c @@ -0,0 +1,99 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <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 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +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 */ + +double +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 */ + uint32_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); + } +} diff --git a/src/math/e_acosf.c b/src/math/e_acosf.c new file mode 100644 index 00000000..4c59781b --- /dev/null +++ b/src/math/e_acosf.c @@ -0,0 +1,77 @@ +/* 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 <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 */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pS0 = 1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 = 3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 = 2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 = 7.7038154006e-02; /* 0x3d9dc62e */ + +float +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(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */ + } else if(ix>0x3f800000) { /* |x| >= 1 */ + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3f000000) { /* |x| < 0.5 */ + if(ix<=0x23000000) 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)*(float)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 = 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+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + w = r*s+c; + return (float)2.0*(df+w); + } +} diff --git a/src/math/e_acosh.c b/src/math/e_acosh.c new file mode 100644 index 00000000..8b454e75 --- /dev/null +++ b/src/math/e_acosh.c @@ -0,0 +1,59 @@ + +/* @(#)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. + * ==================================================== + * + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double +one = 1.0, +ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */ + +double +acosh(double x) +{ + double t; + int32_t hx; + uint32_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 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 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/math/e_acoshf.c b/src/math/e_acoshf.c new file mode 100644 index 00000000..b7f1df69 --- /dev/null +++ b/src/math/e_acoshf.c @@ -0,0 +1,45 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float +one = 1.0, +ln2 = 6.9314718246e-01; /* 0x3f317218 */ + +float +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 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 logf((float)2.0*x-one/(x+sqrtf(t-one))); + } else { /* 1<x<2 */ + t = x-one; + return log1pf(t+sqrtf((float)2.0*t+t*t)); + } +} diff --git a/src/math/e_asin.c b/src/math/e_asin.c new file mode 100644 index 00000000..4bf162a1 --- /dev/null +++ b/src/math/e_asin.c @@ -0,0 +1,109 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <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 */ + +double +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 */ + uint32_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<0x3e400000) { /* if |x| < 2**-27 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } else + 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; +} diff --git a/src/math/e_asinf.c b/src/math/e_asinf.c new file mode 100644 index 00000000..9c693970 --- /dev/null +++ b/src/math/e_asinf.c @@ -0,0 +1,80 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +huge = 1.000e+30, +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pio4_hi = 7.8539818525e-01, /* 0x3f490fdb */ + /* coefficient for R(x^2) */ +pS0 = 1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 = 3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 = 2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 = 7.7038154006e-02; /* 0x3d9dc62e */ + +float +asinf(float x) +{ + float t=0.0,w,p,q,c,r,s; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix==0x3f800000) { + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + } else if(ix> 0x3f800000) { /* |x|>= 1 */ + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3f000000) { /* |x|<0.5 */ + if(ix<0x32000000) { /* if |x| < 2**-27 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } else + 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-fabsf(x); + t = w*(float)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 = sqrtf(t); + if(ix>=0x3F79999A) { /* if |x| > 0.975 */ + w = p/q; + t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo); + } else { + int32_t iw; + w = s; + GET_FLOAT_WORD(iw,w); + SET_FLOAT_WORD(w,iw&0xfffff000); + c = (t-w*w)/(s+w); + r = p/q; + p = (float)2.0*s*r-(pio2_lo-(float)2.0*c); + q = pio4_hi-(float)2.0*w; + t = pio4_hi-(p-q); + } + if(hx>0) return t; else return -t; +} diff --git a/src/math/e_atan2.c b/src/math/e_atan2.c new file mode 100644 index 00000000..dd021164 --- /dev/null +++ b/src/math/e_atan2.c @@ -0,0 +1,120 @@ + +/* @(#)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. + * ==================================================== + * + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double +tiny = 1.0e-300, +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 */ +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double +atan2(double y, double x) +{ + double z; + int32_t k,m,hx,hy,ix,iy; + uint32_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) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */ + else if(hx<0&&k<-60) z=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: { + uint32_t zh; + GET_HIGH_WORD(zh,z); + SET_HIGH_WORD(z,zh ^ 0x80000000); + } + return z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/src/math/e_atan2f.c b/src/math/e_atan2f.c new file mode 100644 index 00000000..535e10a0 --- /dev/null +++ b/src/math/e_atan2f.c @@ -0,0 +1,93 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float +tiny = 1.0e-30, +zero = 0.0, +pi_o_4 = 7.8539818525e-01, /* 0x3f490fdb */ +pi_o_2 = 1.5707963705e+00, /* 0x3fc90fdb */ +pi = 3.1415927410e+00, /* 0x40490fdb */ +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float +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 > 60) z=pi_o_2+(float)0.5*pi_lo; /* |y/x| > 2**60 */ + else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */ + else z=atanf(fabsf(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: { + uint32_t zh; + GET_FLOAT_WORD(zh,z); + SET_FLOAT_WORD(z,zh ^ 0x80000000); + } + return z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/src/math/e_atanh.c b/src/math/e_atanh.c new file mode 100644 index 00000000..45f1c966 --- /dev/null +++ b/src/math/e_atanh.c @@ -0,0 +1,59 @@ + +/* @(#)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. + * ==================================================== + * + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double one = 1.0, huge = 1e300; +static const double zero = 0.0; + +double +atanh(double x) +{ + double t; + int32_t hx,ix; + uint32_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/math/e_atanhf.c b/src/math/e_atanhf.c new file mode 100644 index 00000000..7356cfc9 --- /dev/null +++ b/src/math/e_atanhf.c @@ -0,0 +1,42 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float one = 1.0, huge = 1e30; + +static const float zero = 0.0; + +float +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/math/e_cosh.c b/src/math/e_cosh.c new file mode 100644 index 00000000..ad425bd3 --- /dev/null +++ b/src/math/e_cosh.c @@ -0,0 +1,82 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double one = 1.0, half=0.5, huge = 1.0e300; + +double +cosh(double x) +{ + double t,w; + int32_t ix; + uint32_t lx; + + /* 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 = exp(fabs(x)); + return half*t+half/t; + } + + /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ + if (ix < 0x40862E42) return half*exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + GET_LOW_WORD(lx,x); + if (ix<0x408633CE || + ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) { + w = exp(half*fabs(x)); + t = half*w; + return t*w; + } + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} diff --git a/src/math/e_coshf.c b/src/math/e_coshf.c new file mode 100644 index 00000000..6db10885 --- /dev/null +++ b/src/math/e_coshf.c @@ -0,0 +1,59 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float one = 1.0, half=0.5, huge = 1.0e30; + +float +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<0x24000000) 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 < 0x41b00000) { + t = expf(fabsf(x)); + return half*t+half/t; + } + + /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ + if (ix < 0x42b17180) return half*expf(fabsf(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x42b2d4fc) { + w = expf(half*fabsf(x)); + t = half*w; + return t*w; + } + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} diff --git a/src/math/e_exp.c b/src/math/e_exp.c new file mode 100644 index 00000000..66107b95 --- /dev/null +++ b/src/math/e_exp.c @@ -0,0 +1,155 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+300, +twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/ +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 */ + + +double +exp(double x) /* default IEEE double exp */ +{ + double y,hi=0.0,lo=0.0,c,t; + int32_t k=0,xsb; + uint32_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) { + uint32_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 */ + } + + /* 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]; + } + 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; + 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) { + uint32_t hy; + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(y,hy+(k<<20)); /* add k to y's exponent */ + return y; + } else { + uint32_t hy; + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */ + return y*twom1000; + } +} diff --git a/src/math/e_expf.c b/src/math/e_expf.c new file mode 100644 index 00000000..99818edc --- /dev/null +++ b/src/math/e_expf.c @@ -0,0 +1,91 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+30, +twom100 = 7.8886090522e-31, /* 2**-100=0x0d800000 */ +o_threshold= 8.8721679688e+01, /* 0x42b17180 */ +u_threshold= -1.0397208405e+02, /* 0xc2cff1b5 */ +ln2HI[2] ={ 6.9313812256e-01, /* 0x3f317180 */ + -6.9313812256e-01,}, /* 0xbf317180 */ +ln2LO[2] ={ 9.0580006145e-06, /* 0x3717f7d1 */ + -9.0580006145e-06,}, /* 0xb717f7d1 */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +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 */ + +float +expf(float x) /* default IEEE double exp */ +{ + float y,hi=0.0,lo=0.0,c,t; + int32_t k=0,xsb; + uint32_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]; + } + x = hi - lo; + } + else if(hx < 0x31800000) { /* 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; + c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + 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) { + uint32_t hy; + GET_FLOAT_WORD(hy,y); + SET_FLOAT_WORD(y,hy+(k<<23)); /* add k to y's exponent */ + return y; + } else { + uint32_t hy; + GET_FLOAT_WORD(hy,y); + SET_FLOAT_WORD(y,hy+((k+100)<<23)); /* add k to y's exponent */ + return y*twom100; + } +} diff --git a/src/math/e_fmod.c b/src/math/e_fmod.c new file mode 100644 index 00000000..99afe489 --- /dev/null +++ b/src/math/e_fmod.c @@ -0,0 +1,129 @@ + +/* @(#)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. + * ==================================================== + */ + +/* + * fmod(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +double +fmod(double x, double y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + uint32_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[(uint32_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[(uint32_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[(uint32_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)|((uint32_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/math/e_fmodf.c b/src/math/e_fmodf.c new file mode 100644 index 00000000..fe86cb04 --- /dev/null +++ b/src/math/e_fmodf.c @@ -0,0 +1,101 @@ +/* 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. + * ==================================================== + */ + +/* + * fmodf(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0, Zero[] = {0.0, -0.0,}; + +float +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[(uint32_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[(uint32_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[(uint32_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/math/e_hypot.c b/src/math/e_hypot.c new file mode 100644 index 00000000..e925adc3 --- /dev/null +++ b/src/math/e_hypot.c @@ -0,0 +1,121 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +double +hypot(double x, double y) +{ + double a=x,b=y,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;} + SET_HIGH_WORD(a,ha); /* a <- |a| */ + SET_HIGH_WORD(b,hb); /* b <- |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 */ + uint32_t low; + w = a+b; /* for sNaN */ + 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 */ + uint32_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) { + uint32_t high; + t1 = 1.0; + GET_HIGH_WORD(high,t1); + SET_HIGH_WORD(t1,high+(k<<20)); + return t1*w; + } else return w; +} diff --git a/src/math/e_hypotf.c b/src/math/e_hypotf.c new file mode 100644 index 00000000..13773554 --- /dev/null +++ b/src/math/e_hypotf.c @@ -0,0 +1,79 @@ +/* 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 <math.h> +#include "math_private.h" + +float +hypotf(float x, float y) +{ + float a=x,b=y,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;} + SET_FLOAT_WORD(a,ha); /* a <- |a| */ + SET_FLOAT_WORD(b,hb); /* b <- |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 */ + w = a+b; /* for sNaN */ + 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 = 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); + t2 = a - t1; + w = 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/math/e_log.c b/src/math/e_log.c new file mode 100644 index 00000000..9eb0e444 --- /dev/null +++ b/src/math/e_log.c @@ -0,0 +1,131 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <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; + +double +log(double x) +{ + double hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,hx,i,j; + uint32_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) { /* |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/math/e_log10.c b/src/math/e_log10.c new file mode 100644 index 00000000..3be179f7 --- /dev/null +++ b/src/math/e_log10.c @@ -0,0 +1,83 @@ + +/* @(#)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. + * ==================================================== + */ + +/* log10(x) + * Return the base 10 logarithm of x + * + * Method : + * Let log10_2hi = leading 40 bits of log10(2) and + * log10_2lo = log10(2) - log10_2hi, + * ivln10 = 1/log(10) rounded. + * Then + * n = ilogb(x), + * if(n<0) n = n+1; + * x = scalbn(x,-n); + * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x)) + * + * Note 1: + * To guarantee log10(10**n)=n, where 10**n is normal, the rounding + * mode must set to Round-to-Nearest. + * Note 2: + * [1/log(10)] rounded to 53 bits has error .198 ulps; + * log10 is monotonic at all binary break points. + * + * Special cases: + * log10(x) is NaN with signal if x < 0; + * log10(+INF) is +INF with no signal; log10(0) is -INF with signal; + * log10(NaN) is that NaN with no signal; + * log10(10**N) = N for N=0,1,...,22. + * + * 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 <math.h> +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ + +static const double zero = 0.0; + +double +log10(double x) +{ + double y,z; + int32_t i,k,hx; + uint32_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; + i = ((uint32_t)k&0x80000000)>>31; + hx = (hx&0x000fffff)|((0x3ff-i)<<20); + y = (double)(k+i); + SET_HIGH_WORD(x,hx); + z = y*log10_2lo + ivln10*log(x); + return z+y*log10_2hi; +} diff --git a/src/math/e_log10f.c b/src/math/e_log10f.c new file mode 100644 index 00000000..8fc5c5ca --- /dev/null +++ b/src/math/e_log10f.c @@ -0,0 +1,51 @@ +/* e_log10f.c -- float version of e_log10.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 <math.h> +#include "math_private.h" + +static const float +two25 = 3.3554432000e+07, /* 0x4c000000 */ +ivln10 = 4.3429449201e-01, /* 0x3ede5bd9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07; /* 0x355427db */ + +static const float zero = 0.0; + +float +log10f(float x) +{ + float y,z; + 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; + k += (hx>>23)-127; + i = ((uint32_t)k&0x80000000)>>31; + hx = (hx&0x007fffff)|((0x7f-i)<<23); + y = (float)(k+i); + SET_FLOAT_WORD(x,hx); + z = y*log10_2lo + ivln10*logf(x); + return z+y*log10_2hi; +} diff --git a/src/math/e_logf.c b/src/math/e_logf.c new file mode 100644 index 00000000..46a8b8ce --- /dev/null +++ b/src/math/e_logf.c @@ -0,0 +1,81 @@ +/* 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 <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 */ +Lg1 = 6.6666668653e-01, /* 3F2AAAAB */ +Lg2 = 4.0000000596e-01, /* 3ECCCCCD */ +Lg3 = 2.8571429849e-01, /* 3E924925 */ +Lg4 = 2.2222198546e-01, /* 3E638E29 */ +Lg5 = 1.8183572590e-01, /* 3E3A3325 */ +Lg6 = 1.5313838422e-01, /* 3E1CD04F */ +Lg7 = 1.4798198640e-01; /* 3E178897 */ + +static const float zero = 0.0; + +float +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&(15+ix))<16) { /* |f| < 2**-20 */ + 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+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + 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/math/e_pow.c b/src/math/e_pow.c new file mode 100644 index 00000000..aad24287 --- /dev/null +++ b/src/math/e_pow.c @@ -0,0 +1,300 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <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*/ + +double +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; + uint32_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; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=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>=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 y - y; /* inf**+-1 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==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 = ((uint32_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/math/e_powf.c b/src/math/e_powf.c new file mode 100644 index 00000000..ae61c246 --- /dev/null +++ b/src/math/e_powf.c @@ -0,0 +1,243 @@ +/* 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 <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.6179199219e-01, /* 0x3f763800 =head of cp */ +cp_l = 4.7017383622e-06, /* 0x369dc3a0 =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*/ + +float +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; + + /* +-NaN return x+y */ + if(ix > 0x7f800000 || + iy > 0x7f800000) + 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>=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 y - y; /* inf**+-1 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==0x3f000000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return 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 = ((uint32_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/math/e_rem_pio2.c b/src/math/e_rem_pio2.c new file mode 100644 index 00000000..9eee36ae --- /dev/null +++ b/src/math/e_rem_pio2.c @@ -0,0 +1,163 @@ + +/* @(#)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. + * ==================================================== + * + */ + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include <math.h> +#include "math_private.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +static const int32_t two_over_pi[] = { +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, +}; + +static const int32_t npio2_hw[] = { +0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, +0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, +0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, +0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C, +0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB, +0x404858EB, 0x404921FB, +}; + +/* + * 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 */ +half = 5.00000000000000000000e-01, /* 0x3FE00000, 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 */ + +int32_t __ieee754_rem_pio2(double x, double *y) +{ + double z,w,t,r,fn; + double tx[3]; + int32_t e0,i,j,nx,n,ix,hx; + uint32_t low; + + GET_HIGH_WORD(hx,x); /* high word of x */ + ix = hx&0x7fffffff; + if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */ + t = fabs(x); + n = (int32_t) (t*invpio2+half); + fn = (double)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + if(n<32&&ix!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + uint32_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; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else 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,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} diff --git a/src/math/e_rem_pio2f.c b/src/math/e_rem_pio2f.c new file mode 100644 index 00000000..4992ea0c --- /dev/null +++ b/src/math/e_rem_pio2f.c @@ -0,0 +1,175 @@ +/* e_rem_pio2f.c -- float version of e_rem_pio2.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. + * ==================================================== + */ + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2f() + */ + +#include <math.h> +#include "math_private.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +static const int32_t two_over_pi[] = { +0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC, +0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62, +0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63, +0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A, +0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09, +0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29, +0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44, +0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41, +0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C, +0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8, +0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11, +0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF, +0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E, +0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5, +0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92, +0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08, +0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0, +0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3, +0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85, +0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80, +0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA, +0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B, +}; + +/* This array is like the one in e_rem_pio2.c, but the numbers are + single precision and the last 8 bits are forced to 0. */ +static const int32_t npio2_hw[] = { +0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00, +0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00, +0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100, +0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00, +0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00, +0x4242c700, 0x42490f00 +}; + +/* + * invpio2: 24 bits of 2/pi + * pio2_1: first 17 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 17 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 17 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const float +zero = 0.0000000000e+00, /* 0x00000000 */ +half = 5.0000000000e-01, /* 0x3f000000 */ +two8 = 2.5600000000e+02, /* 0x43800000 */ +invpio2 = 6.3661980629e-01, /* 0x3f22f984 */ +pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */ +pio2_1t = 1.0804334124e-05, /* 0x37354443 */ +pio2_2 = 1.0804273188e-05, /* 0x37354400 */ +pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */ +pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */ +pio2_3t = 6.1232342629e-17; /* 0x248d3132 */ + +int32_t __ieee754_rem_pio2f(float x, float *y) +{ + float z,w,t,r,fn; + float tx[3]; + int32_t e0,i,j,nx,n,ix,hx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */ + t = fabsf(x); + n = (int32_t) (t*invpio2+half); + fn = (float)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 40 bit */ + if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + uint32_t high; + j = ix>>23; + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>8) { /* 2nd iteration needed, good to 57 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>25) { /* 3rd iteration need, 74 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; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7f800000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-7) */ + e0 = (ix>>23)-134; /* e0 = ilogb(z)-7; */ + SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23))); + for(i=0;i<2;i++) { + tx[i] = (float)((int32_t)(z)); + z = (z-tx[i])*two8; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} diff --git a/src/math/e_remainder.c b/src/math/e_remainder.c new file mode 100644 index 00000000..9cb56919 --- /dev/null +++ b/src/math/e_remainder.c @@ -0,0 +1,69 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double zero = 0.0; + + +double +remainder(double x, double p) +{ + int32_t hx,hp; + uint32_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 (x*p)/(x*p); + + + if (hp<=0x7fdfffff) x = 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); + SET_HIGH_WORD(x,hx^sx); + return x; +} diff --git a/src/math/e_remainderf.c b/src/math/e_remainderf.c new file mode 100644 index 00000000..c292367d --- /dev/null +++ b/src/math/e_remainderf.c @@ -0,0 +1,61 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float zero = 0.0; + + +float +remainderf(float x, float p) +{ + int32_t hx,hp; + uint32_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 (x*p)/(x*p); + + + if (hp<=0x7effffff) x = 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); + SET_FLOAT_WORD(x,hx^sx); + return x; +} diff --git a/src/math/e_scalb.c b/src/math/e_scalb.c new file mode 100644 index 00000000..cee2b44f --- /dev/null +++ b/src/math/e_scalb.c @@ -0,0 +1,35 @@ + +/* @(#)e_scalb.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. + * ==================================================== + */ + +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#include <math.h> +#include "math_private.h" + +double +scalb(double x, double fn) +{ + if (isnan(x)||isnan(fn)) return x*fn; + if (!isfinite(fn)) { + if(fn>0.0) return x*fn; + else return x/(-fn); + } + if (rint(fn)!=fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x,-65000); + return scalbn(x,(int)fn); +} diff --git a/src/math/e_scalbf.c b/src/math/e_scalbf.c new file mode 100644 index 00000000..de7d7f67 --- /dev/null +++ b/src/math/e_scalbf.c @@ -0,0 +1,31 @@ +/* e_scalbf.c -- float version of e_scalb.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 <math.h> +#include "math_private.h" + +float +scalbf(float x, float fn) +{ + if (isnan(x)||isnan(fn)) return x*fn; + if (!isfinite(fn)) { + if(fn>(float)0.0) return x*fn; + else return x/(-fn); + } + if (rintf(fn)!=fn) return (fn-fn)/(fn-fn); + if ( fn > (float)65000.0) return scalbnf(x, 65000); + if (-fn > (float)65000.0) return scalbnf(x,-65000); + return scalbnf(x,(int)fn); +} diff --git a/src/math/e_sinh.c b/src/math/e_sinh.c new file mode 100644 index 00000000..3a574274 --- /dev/null +++ b/src/math/e_sinh.c @@ -0,0 +1,75 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double one = 1.0, shuge = 1.0e307; + +double +sinh(double x) +{ + double t,w,h; + int32_t ix,jx; + uint32_t lx; + + /* 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*exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + GET_LOW_WORD(lx,x); + if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) { + w = exp(0.5*fabs(x)); + t = h*w; + return t*w; + } + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} diff --git a/src/math/e_sinhf.c b/src/math/e_sinhf.c new file mode 100644 index 00000000..fe60608a --- /dev/null +++ b/src/math/e_sinhf.c @@ -0,0 +1,56 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float one = 1.0, shuge = 1.0e37; + +float +sinhf(float x) +{ + float t,w,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,22], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x41b00000) { /* |x|<22 */ + if (ix<0x31800000) /* |x|<2**-28 */ + 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 [22, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix < 0x42b17180) return h*expf(fabsf(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x42b2d4fc) { + w = expf((float)0.5*fabsf(x)); + t = h*w; + return t*w; + } + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} diff --git a/src/math/e_sqrt.c b/src/math/e_sqrt.c new file mode 100644 index 00000000..2bc68747 --- /dev/null +++ b/src/math/e_sqrt.c @@ -0,0 +1,442 @@ + +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +static const double one = 1.0, tiny=1.0e-300; + +double +sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + uint32_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==(uint32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(uint32_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; +} + +/* +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/math/e_sqrtf.c b/src/math/e_sqrtf.c new file mode 100644 index 00000000..03a15beb --- /dev/null +++ b/src/math/e_sqrtf.c @@ -0,0 +1,85 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float one = 1.0, tiny=1.0e-30; + +float +sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + uint32_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/math/i386/e_exp.s b/src/math/i386/e_exp.s new file mode 100644 index 00000000..d6c54a30 --- /dev/null +++ b/src/math/i386/e_exp.s @@ -0,0 +1,36 @@ +.global expf +expf: + mov 4(%esp),%eax + flds 4(%esp) + shr $23,%eax + inc %al + jz 1f + jmp 0f + +.global exp +exp: + mov 8(%esp),%eax + fldl 4(%esp) + shl %eax + cmp $0xffe00000,%eax + jae 1f + +0: fldl2e + fmulp + fst %st(1) + frndint + fst %st(2) + fsubrp + f2xm1 + fld1 + faddp + fscale + fstp %st(1) + ret + +1: fsts 4(%esp) + cmpl $0xff800000,4(%esp) + jnz 1f + fstp %st(0) + fldz +1: ret diff --git a/src/math/i386/e_expf.s b/src/math/i386/e_expf.s new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/math/i386/e_expf.s @@ -0,0 +1 @@ + diff --git a/src/math/i386/e_log.s b/src/math/i386/e_log.s new file mode 100644 index 00000000..34b8d38d --- /dev/null +++ b/src/math/i386/e_log.s @@ -0,0 +1,6 @@ +.global log +log: + fldln2 + fldl 4(%esp) + fyl2x + ret diff --git a/src/math/i386/e_log10.s b/src/math/i386/e_log10.s new file mode 100644 index 00000000..7f48941b --- /dev/null +++ b/src/math/i386/e_log10.s @@ -0,0 +1,6 @@ +.global log10 +log10: + fldlg2 + fldl 4(%esp) + fyl2x + ret diff --git a/src/math/i386/e_log10f.s b/src/math/i386/e_log10f.s new file mode 100644 index 00000000..311486ea --- /dev/null +++ b/src/math/i386/e_log10f.s @@ -0,0 +1,6 @@ +.global log10f +log10f: + fldlg2 + flds 4(%esp) + fyl2x + ret diff --git a/src/math/i386/e_logf.s b/src/math/i386/e_logf.s new file mode 100644 index 00000000..b8beec0f --- /dev/null +++ b/src/math/i386/e_logf.s @@ -0,0 +1,6 @@ +.global logf +logf: + fldln2 + flds 4(%esp) + fyl2x + ret diff --git a/src/math/i386/e_remainder.s b/src/math/i386/e_remainder.s new file mode 100644 index 00000000..b7ff3ef8 --- /dev/null +++ b/src/math/i386/e_remainder.s @@ -0,0 +1,16 @@ +.global remainderf +remainderf: + flds 8(%esp) + flds 4(%esp) + jmp 1f + +.global remainder +remainder: + fldl 12(%esp) + fldl 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) + ret diff --git a/src/math/i386/e_remainderf.s b/src/math/i386/e_remainderf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/e_remainderf.s diff --git a/src/math/i386/e_sqrt.s b/src/math/i386/e_sqrt.s new file mode 100644 index 00000000..11314dca --- /dev/null +++ b/src/math/i386/e_sqrt.s @@ -0,0 +1,4 @@ +.global sqrt +sqrt: fldl 4(%esp) + fsqrt + ret diff --git a/src/math/i386/e_sqrtf.s b/src/math/i386/e_sqrtf.s new file mode 100644 index 00000000..015e24cd --- /dev/null +++ b/src/math/i386/e_sqrtf.s @@ -0,0 +1,4 @@ +.global sqrtf +sqrtf: flds 4(%esp) + fsqrt + ret diff --git a/src/math/i386/s_ceil.s b/src/math/i386/s_ceil.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ceil.s diff --git a/src/math/i386/s_ceilf.s b/src/math/i386/s_ceilf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ceilf.s diff --git a/src/math/i386/s_fabs.s b/src/math/i386/s_fabs.s new file mode 100644 index 00000000..10c70f37 --- /dev/null +++ b/src/math/i386/s_fabs.s @@ -0,0 +1,5 @@ +.global fabs +fabs: + fldl 4(%esp) + fabs + ret diff --git a/src/math/i386/s_fabsf.s b/src/math/i386/s_fabsf.s new file mode 100644 index 00000000..45442699 --- /dev/null +++ b/src/math/i386/s_fabsf.s @@ -0,0 +1,5 @@ +.global fabsf +fabsf: + flds 4(%esp) + fabs + ret diff --git a/src/math/i386/s_floor.s b/src/math/i386/s_floor.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_floor.s diff --git a/src/math/i386/s_floorf.s b/src/math/i386/s_floorf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_floorf.s diff --git a/src/math/i386/s_ldexp.s b/src/math/i386/s_ldexp.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ldexp.s diff --git a/src/math/i386/s_ldexpf.s b/src/math/i386/s_ldexpf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ldexpf.s diff --git a/src/math/i386/s_rint.s b/src/math/i386/s_rint.s new file mode 100644 index 00000000..5ba4ab4a --- /dev/null +++ b/src/math/i386/s_rint.s @@ -0,0 +1,5 @@ +.global rint +rint: + fldl 4(%esp) + frndint + ret diff --git a/src/math/i386/s_rintf.s b/src/math/i386/s_rintf.s new file mode 100644 index 00000000..d7aacd8f --- /dev/null +++ b/src/math/i386/s_rintf.s @@ -0,0 +1,5 @@ +.global rintf +rintf: + flds 4(%esp) + frndint + ret diff --git a/src/math/i386/s_scalbln.s b/src/math/i386/s_scalbln.s new file mode 100644 index 00000000..bd022b46 --- /dev/null +++ b/src/math/i386/s_scalbln.s @@ -0,0 +1,11 @@ +.global ldexp +.global scalbn +.global scalbln +ldexp: +scalbn: +scalbln: + fildl 12(%esp) + fldl 4(%esp) + fscale + fstp %st(1) + ret diff --git a/src/math/i386/s_scalblnf.s b/src/math/i386/s_scalblnf.s new file mode 100644 index 00000000..379ec919 --- /dev/null +++ b/src/math/i386/s_scalblnf.s @@ -0,0 +1,11 @@ +.global ldexpf +.global scalbnf +.global scalblnf +ldexpf: +scalbnf: +scalblnf: + fildl 8(%esp) + flds 4(%esp) + fscale + fstp %st(1) + ret diff --git a/src/math/i386/s_trunc.s b/src/math/i386/s_trunc.s new file mode 100644 index 00000000..0773891a --- /dev/null +++ b/src/math/i386/s_trunc.s @@ -0,0 +1,36 @@ +.global ceilf +ceilf: flds 4(%esp) + jmp 1f + +.global ceil +ceil: fldl 4(%esp) +1: mov $0x08fb,%edx + jmp 0f + +.global floorf +floorf: flds 4(%esp) + jmp 1f + +.global floor +floor: fldl 4(%esp) +1: mov $0x04f7,%edx + jmp 0f + +.global truncf +truncf: flds 4(%esp) + jmp 1f + +.global trunc +trunc: fldl 4(%esp) +1: mov $0x0cff,%edx + +0: fstcw 4(%esp) + mov 5(%esp),%ah + or %dh,%ah + and %dl,%ah + xchg %ah,5(%esp) + fldcw 4(%esp) + frndint + mov %ah,5(%esp) + fldcw 4(%esp) + ret diff --git a/src/math/i386/s_truncf.s b/src/math/i386/s_truncf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_truncf.s diff --git a/src/math/k_cos.c b/src/math/k_cos.c new file mode 100644 index 00000000..22e9841e --- /dev/null +++ b/src/math/k_cos.c @@ -0,0 +1,85 @@ + +/* @(#)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. + * ==================================================== + */ + +/* + * __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 when x > 0.3, let qx = |x|/4 with + * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. + * Then + * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)). + * Note that 1-qx and (x*x/2-qx) is EXACT here, and the + * magnitude of the latter is at least a quarter of x*x/2, + * thus, reducing the rounding error in the subtraction. + */ + +#include <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 */ + +double +__kernel_cos(double x, double y) +{ + double a,hz,z,r,qx; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; /* ix = |x|'s high word*/ + if(ix<0x3e400000) { /* if x < 2**27 */ + if(((int)x)==0) return one; /* generate inexact */ + } + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); + if(ix < 0x3FD33333) /* if |x| < 0.3 */ + return one - (0.5*z - (z*r - x*y)); + else { + if(ix > 0x3fe90000) { /* x > 0.78125 */ + qx = 0.28125; + } else { + INSERT_WORDS(qx,ix-0x00200000,0); /* x/4 */ + } + hz = 0.5*z-qx; + a = one-qx; + return a - (hz - (z*r-x*y)); + } +} diff --git a/src/math/k_cosf.c b/src/math/k_cosf.c new file mode 100644 index 00000000..61dc3749 --- /dev/null +++ b/src/math/k_cosf.c @@ -0,0 +1,52 @@ +/* k_cosf.c -- float version of k_cos.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 <math.h> +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3f800000 */ +C1 = 4.1666667908e-02, /* 0x3d2aaaab */ +C2 = -1.3888889225e-03, /* 0xbab60b61 */ +C3 = 2.4801587642e-05, /* 0x37d00d01 */ +C4 = -2.7557314297e-07, /* 0xb493f27c */ +C5 = 2.0875723372e-09, /* 0x310f74f6 */ +C6 = -1.1359647598e-11; /* 0xad47d74e */ + +float +__kernel_cosf(float x, float y) +{ + float a,hz,z,r,qx; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* ix = |x|'s high word*/ + if(ix<0x32000000) { /* if x < 2**27 */ + if(((int)x)==0) return one; /* generate inexact */ + } + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); + if(ix < 0x3e99999a) /* if |x| < 0.3 */ + return one - ((float)0.5*z - (z*r - x*y)); + else { + if(ix > 0x3f480000) { /* x > 0.78125 */ + qx = (float)0.28125; + } else { + SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */ + } + hz = (float)0.5*z-qx; + a = one-qx; + return a - (hz - (z*r-x*y)); + } +} diff --git a/src/math/k_rem_pio2.c b/src/math/k_rem_pio2.c new file mode 100644 index 00000000..d993e4f2 --- /dev/null +++ b/src/math/k_rem_pio2.c @@ -0,0 +1,300 @@ + +/* @(#)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. + * ==================================================== + */ + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + * double x[],y[]; int e0,nx,prec; int ipio2[]; + * + * __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] + * + * 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) + * + * ipio2[] + * 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)). + * + * 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 recommended value is 2,3,4, + * 6 for single, double, extended,and quad. + * + * 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 <math.h> +#include "math_private.h" + +static const int init_jk[] = {2,3,4,6}; /* initial value for jk */ + +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 */ + + int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2) +{ + 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]; + 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/math/k_rem_pio2f.c b/src/math/k_rem_pio2f.c new file mode 100644 index 00000000..b543f084 --- /dev/null +++ b/src/math/k_rem_pio2f.c @@ -0,0 +1,192 @@ +/* k_rem_pio2f.c -- float version of k_rem_pio2.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 <math.h> +#include "math_private.h" + +/* In the float version, the input parameter x contains 8 bit + integers, not 24 bit integers. 113 bit precision is not supported. */ + +static const int init_jk[] = {4,7,9}; /* initial value for jk */ + +static const float PIo2[] = { + 1.5703125000e+00, /* 0x3fc90000 */ + 4.5776367188e-04, /* 0x39f00000 */ + 2.5987625122e-05, /* 0x37da0000 */ + 7.5437128544e-08, /* 0x33a20000 */ + 6.0026650317e-11, /* 0x2e840000 */ + 7.3896444519e-13, /* 0x2b500000 */ + 5.3845816694e-15, /* 0x27c20000 */ + 5.6378512969e-18, /* 0x22d00000 */ + 8.3009228831e-20, /* 0x1fc40000 */ + 3.2756352257e-22, /* 0x1bc60000 */ + 6.3331015649e-25, /* 0x17440000 */ +}; + +static const float +zero = 0.0, +one = 1.0, +two8 = 2.5600000000e+02, /* 0x43800000 */ +twon8 = 3.9062500000e-03; /* 0x3b800000 */ + + int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + float 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)/8; if(jv<0) jv=0; + q0 = e0-8*(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 : (float) 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 = (float)((int32_t)(twon8* z)); + iq[i] = (int32_t)(z-two8*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbnf(z,q0); /* actual value of z */ + z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */ + n = (int32_t) z; + z -= (float)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(8-q0)); n += i; + iq[jz-1] -= i<<(8-q0); + ih = iq[jz-1]>>(7-q0); + } + else if(q0==0) ih = iq[jz-1]>>7; + else if(z>=(float)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] = 0x100- j; + } + } else iq[i] = 0xff - j; + } + if(q0>0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7f; break; + case 2: + iq[jz-1] &= 0x3f; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbnf(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] = (float) 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==(float)0.0) { + jz -= 1; q0 -= 8; + while(iq[jz]==0) { jz--; q0-=8;} + } else { /* break z into 8-bit if necessary */ + z = scalbnf(z,-q0); + if(z>=two8) { + fw = (float)((int32_t)(twon8*z)); + iq[jz] = (int32_t)(z-two8*fw); + jz += 1; q0 += 8; + iq[jz] = (int32_t) fw; + } else iq[jz] = (int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbnf(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(float)iq[i]; fw*=twon8; + } + + /* 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]; + 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/math/k_sin.c b/src/math/k_sin.c new file mode 100644 index 00000000..9def2589 --- /dev/null +++ b/src/math/k_sin.c @@ -0,0 +1,68 @@ + +/* @(#)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. + * ==================================================== + */ + +/* __kernel_sin( x, y, iy) + * kernel sin function on [-pi/4, pi/4], 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. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0. + * 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 <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 */ + +double +__kernel_sin(double x, double y, int iy) +{ + double z,r,v; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; /* high word of x */ + if(ix<0x3e400000) /* |x| < 2**-27 */ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*S6))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/math/k_sinf.c b/src/math/k_sinf.c new file mode 100644 index 00000000..617f6148 --- /dev/null +++ b/src/math/k_sinf.c @@ -0,0 +1,42 @@ +/* k_sinf.c -- float version of k_sin.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 <math.h> +#include "math_private.h" + +static const float +half = 5.0000000000e-01,/* 0x3f000000 */ +S1 = -1.6666667163e-01, /* 0xbe2aaaab */ +S2 = 8.3333337680e-03, /* 0x3c088889 */ +S3 = -1.9841270114e-04, /* 0xb9500d01 */ +S4 = 2.7557314297e-06, /* 0x3638ef1b */ +S5 = -2.5050759689e-08, /* 0xb2d72f34 */ +S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */ + +float +__kernel_sinf(float x, float y, int iy) +{ + float z,r,v; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* high word of x */ + if(ix<0x32000000) /* |x| < 2**-27 */ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*S6))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/math/k_tan.c b/src/math/k_tan.c new file mode 100644 index 00000000..f721ae6d --- /dev/null +++ b/src/math/k_tan.c @@ -0,0 +1,149 @@ +/* @(#)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. + * ==================================================== + */ + +/* __kernel_tan( x, y, k ) + * kernel tan function on [-pi/4, pi/4], 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. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0. + * 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 <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 < 0x3e300000) { /* x < 2**-28 */ + if ((int) x == 0) { /* generate inexact */ + uint32_t low; + GET_LOW_WORD(low,x); + if (((ix | low) | (iy + 1)) == 0) + return one / fabs(x); + else { + if (iy == 1) + return x; + else { /* compute -1 / (x+y) carefully */ + double a, t; + + z = w = x + y; + SET_LOW_WORD(z, 0); + v = y - (z - x); + t = a = -one / w; + SET_LOW_WORD(t, 0); + s = one + t * z; + return t + a * (s + t * v); + } + } + } + } + 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/math/k_tanf.c b/src/math/k_tanf.c new file mode 100644 index 00000000..99ede58c --- /dev/null +++ b/src/math/k_tanf.c @@ -0,0 +1,105 @@ +/* k_tanf.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * 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. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" +static const float +one = 1.0000000000e+00, /* 0x3f800000 */ +pio4 = 7.8539812565e-01, /* 0x3f490fda */ +pio4lo= 3.7748947079e-08, /* 0x33222168 */ +T[] = { + 3.3333334327e-01, /* 0x3eaaaaab */ + 1.3333334029e-01, /* 0x3e088889 */ + 5.3968254477e-02, /* 0x3d5d0dd1 */ + 2.1869488060e-02, /* 0x3cb327a4 */ + 8.8632395491e-03, /* 0x3c11371f */ + 3.5920790397e-03, /* 0x3b6b6916 */ + 1.4562094584e-03, /* 0x3abede48 */ + 5.8804126456e-04, /* 0x3a1a26c8 */ + 2.4646313977e-04, /* 0x398137b9 */ + 7.8179444245e-05, /* 0x38a3f445 */ + 7.1407252108e-05, /* 0x3895c07a */ + -1.8558637748e-05, /* 0xb79bae5f */ + 2.5907305826e-05, /* 0x37d95384 */ +}; + +float +__kernel_tanf(float x, float y, int iy) +{ + float z,r,v,w,s; + int32_t ix,hx; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; /* high word of |x| */ + if(ix<0x31800000) { /* x < 2**-28 */ + if ((int) x == 0) { /* generate inexact */ + if ((ix | (iy + 1)) == 0) + return one / fabsf(x); + else { + if (iy == 1) + return x; + else { /* compute -1 / (x+y) carefully */ + double a, t; + + z = w = x + y; + GET_FLOAT_WORD(ix, z); + SET_FLOAT_WORD(z, ix & 0xfffff000); + v = y - (z - x); + t = a = -one / w; + GET_FLOAT_WORD(ix, t); + SET_FLOAT_WORD(t, ix & 0xfffff000); + s = one + t * z; + return t + a * (s + t * v); + } + } + } + } + if(ix>=0x3f2ca140) { /* |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>=0x3f2ca140) { + v = (float)iy; + return (float)(1-((hx>>30)&2))*(v-(float)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 */ + float a,t; + int32_t i; + z = w; + GET_FLOAT_WORD(i,z); + SET_FLOAT_WORD(z,i&0xfffff000); + v = r-(z - x); /* z+v = r+x */ + t = a = -(float)1.0/w; /* a = -1.0/w */ + GET_FLOAT_WORD(i,t); + SET_FLOAT_WORD(t,i&0xfffff000); + s = (float)1.0+t*z; + return t+a*(s+t*v); + } +} diff --git a/src/math/math_private.h b/src/math/math_private.h new file mode 100644 index 00000000..28a6a195 --- /dev/null +++ b/src/math/math_private.h @@ -0,0 +1,143 @@ +/* + * ==================================================== + * 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 _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include <inttypes.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. + */ + +typedef union +{ + double value; + uint64_t words; +} ieee_double_shape_type; + +/* 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.words >> 32; \ + (ix1) = (uint32_t)ew_u.words; \ +} 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.words >> 32; \ +} 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) = (uint32_t)gl_u.words; \ +} 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.words = ((uint64_t)(ix0) << 32) | (ix1); \ + (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.words &= 0xffffffff; \ + sh_u.words |= ((uint64_t)(v) << 32); \ + (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.words &= 0xffffffff00000000ull; \ + sl_u.words |= (uint32_t)(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; + uint32_t 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) + +/* fdlibm kernel function */ +int __ieee754_rem_pio2(double,double*); +double __kernel_sin(double,double,int); +double __kernel_cos(double,double); +double __kernel_tan(double,double,int); +int __kernel_rem_pio2(double*,double*,int,int,int,const int*); + +/* float versions of fdlibm kernel functions */ +int __ieee754_rem_pio2f(float,float*); +float __kernel_sinf(float,float,int); +float __kernel_cosf(float,float); +float __kernel_tanf(float,float,int); +int __kernel_rem_pio2f(float*,float*,int,int,int,const int*); + +#endif /* !_MATH_PRIVATE_H_ */ diff --git a/src/math/s_asinh.c b/src/math/s_asinh.c new file mode 100644 index 00000000..26016091 --- /dev/null +++ b/src/math/s_asinh.c @@ -0,0 +1,53 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <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; + +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 = log(fabs(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabs(x); + w = log(2.0*t+one/(sqrt(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1p(fabs(x)+t/(one+sqrt(one+t))); + } + if(hx>0) return w; else return -w; +} diff --git a/src/math/s_asinhf.c b/src/math/s_asinhf.c new file mode 100644 index 00000000..04f8d072 --- /dev/null +++ b/src/math/s_asinhf.c @@ -0,0 +1,45 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +ln2 = 6.9314718246e-01, /* 0x3f317218 */ +huge= 1.0000000000e+30; + +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 = logf(fabsf(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabsf(x); + w = logf((float)2.0*t+one/(sqrtf(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1pf(fabsf(x)+t/(one+sqrtf(one+t))); + } + if(hx>0) return w; else return -w; +} diff --git a/src/math/s_atan.c b/src/math/s_atan.c new file mode 100644 index 00000000..1faac024 --- /dev/null +++ b/src/math/s_atan.c @@ -0,0 +1,115 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <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; + +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 */ + uint32_t low; + GET_LOW_WORD(low,x); + if(ix>0x7ff00000|| + (ix==0x7ff00000&&(low!=0))) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+atanlo[3]; + else return -atanhi[3]-atanlo[3]; + } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e200000) { /* |x| < 2^-29 */ + 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; + } +} diff --git a/src/math/s_atanf.c b/src/math/s_atanf.c new file mode 100644 index 00000000..03067e18 --- /dev/null +++ b/src/math/s_atanf.c @@ -0,0 +1,95 @@ +/* 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 <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.3333334327e-01, /* 0x3eaaaaaa */ + -2.0000000298e-01, /* 0xbe4ccccd */ + 1.4285714924e-01, /* 0x3e124925 */ + -1.1111110449e-01, /* 0xbde38e38 */ + 9.0908870101e-02, /* 0x3dba2e6e */ + -7.6918758452e-02, /* 0xbd9d8795 */ + 6.6610731184e-02, /* 0x3d886b35 */ + -5.8335702866e-02, /* 0xbd6ef16b */ + 4.9768779427e-02, /* 0x3d4bda59 */ + -3.6531571299e-02, /* 0xbd15a221 */ + 1.6285819933e-02, /* 0x3c8569d7 */ +}; + + static const float +one = 1.0, +huge = 1.0e30; + +float +atanf(float x) +{ + float w,s1,s2,z; + int32_t ix,hx,id; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x50800000) { /* if |x| >= 2^34 */ + if(ix>0x7f800000) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+atanlo[3]; + else return -atanhi[3]-atanlo[3]; + } if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x31000000) { /* |x| < 2^-29 */ + 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^66 */ + 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]+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; + } +} diff --git a/src/math/s_cbrt.c b/src/math/s_cbrt.c new file mode 100644 index 00000000..8adcb191 --- /dev/null +++ b/src/math/s_cbrt.c @@ -0,0 +1,77 @@ +/* @(#)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. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +/* cbrt(x) + * Return cube root of x + */ +static const uint32_t + B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */ + B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */ + +static const double +C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */ +D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */ +E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */ +F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */ +G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */ + +double +cbrt(double x) +{ + int32_t hx; + double r,s,t=0.0,w; + uint32_t sign; + uint32_t high,low; + + GET_HIGH_WORD(hx,x); + sign=hx&0x80000000; /* sign= sign(x) */ + hx ^=sign; + if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */ + GET_LOW_WORD(low,x); + if((hx|low)==0) + return(x); /* cbrt(0) is itself */ + + SET_HIGH_WORD(x,hx); /* x <- |x| */ + /* rough cbrt to 5 bits */ + if(hx<0x00100000) /* subnormal number */ + {SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */ + t*=x; GET_HIGH_WORD(high,t); SET_HIGH_WORD(t,high/3+B2); + } + else + SET_HIGH_WORD(t,hx/3+B1); + + + /* new cbrt to 23 bits, may be implemented in single precision */ + r=t*t/x; + s=C+r*t; + t*=G+F/(s+E+D/s); + + /* chopped to 20 bits and make it larger than cbrt(x) */ + GET_HIGH_WORD(high,t); + INSERT_WORDS(t,high+0x00000001,0); + + + /* one step newton iteration to 53 bits with error less than 0.667 ulps */ + s=t*t; /* t*t is exact */ + r=x/s; + w=t+t; + r=(r-t)/(w+r); /* r-s is exact */ + t=t+t*r; + + /* retore the sign bit */ + GET_HIGH_WORD(high,t); + SET_HIGH_WORD(t,high|sign); + return(t); +} diff --git a/src/math/s_cbrtf.c b/src/math/s_cbrtf.c new file mode 100644 index 00000000..e7b46de7 --- /dev/null +++ b/src/math/s_cbrtf.c @@ -0,0 +1,67 @@ +/* s_cbrtf.c -- float version of s_cbrt.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 <math.h> +#include "math_private.h" + +/* cbrtf(x) + * Return cube root of x + */ +static const unsigned + B1 = 709958130, /* B1 = (84+2/3-0.03306235651)*2**23 */ + B2 = 642849266; /* B2 = (76+2/3-0.03306235651)*2**23 */ + +static const float +C = 5.4285717010e-01, /* 19/35 = 0x3f0af8b0 */ +D = -7.0530611277e-01, /* -864/1225 = 0xbf348ef1 */ +E = 1.4142856598e+00, /* 99/70 = 0x3fb50750 */ +F = 1.6071428061e+00, /* 45/28 = 0x3fcdb6db */ +G = 3.5714286566e-01; /* 5/14 = 0x3eb6db6e */ + +float +cbrtf(float x) +{ + float r,s,t; + int32_t hx; + uint32_t sign; + uint32_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 */ + if(hx==0) + return(x); /* cbrt(0) is itself */ + + SET_FLOAT_WORD(x,hx); /* x <- |x| */ + /* rough cbrt to 5 bits */ + if(hx<0x00800000) /* subnormal number */ + {SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */ + t*=x; GET_FLOAT_WORD(high,t); SET_FLOAT_WORD(t,high/3+B2); + } + else + SET_FLOAT_WORD(t,hx/3+B1); + + + /* new cbrt to 23 bits */ + r=t*t/x; + s=C+r*t; + t*=G+F/(s+E+D/s); + + /* retore the sign bit */ + GET_FLOAT_WORD(high,t); + SET_FLOAT_WORD(t,high|sign); + return(t); +} diff --git a/src/math/s_ceil.c b/src/math/s_ceil.c new file mode 100644 index 00000000..1670cade --- /dev/null +++ b/src/math/s_ceil.c @@ -0,0 +1,68 @@ +/* @(#)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. + * ==================================================== + */ + +/* + * 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 <math.h> +#include "math_private.h" + +static const double huge = 1.0e300; + +double +ceil(double x) +{ + int32_t i0,i1,j0; + uint32_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 = ((uint32_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; +} diff --git a/src/math/s_ceilf.c b/src/math/s_ceilf.c new file mode 100644 index 00000000..3615041f --- /dev/null +++ b/src/math/s_ceilf.c @@ -0,0 +1,49 @@ +/* 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 <math.h> +#include "math_private.h" + +static const float huge = 1.0e30; + +float +ceilf(float x) +{ + int32_t i0,j0; + uint32_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/math/s_copysign.c b/src/math/s_copysign.c new file mode 100644 index 00000000..59d3877c --- /dev/null +++ b/src/math/s_copysign.c @@ -0,0 +1,30 @@ +/* @(#)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. + * ==================================================== + */ + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include <math.h> +#include "math_private.h" + +double +copysign(double x, double y) +{ + uint32_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/math/s_copysignf.c b/src/math/s_copysignf.c new file mode 100644 index 00000000..d650e8e5 --- /dev/null +++ b/src/math/s_copysignf.c @@ -0,0 +1,33 @@ +/* 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. + * ==================================================== + */ + +/* + * copysignf(float x, float y) + * copysignf(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include <math.h> +#include "math_private.h" + +float +copysignf(float x, float y) +{ + uint32_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/math/s_cos.c b/src/math/s_cos.c new file mode 100644 index 00000000..1893ab13 --- /dev/null +++ b/src/math/s_cos.c @@ -0,0 +1,74 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <math.h> +#include "math_private.h" + +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) 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); + } + } +} diff --git a/src/math/s_cosf.c b/src/math/s_cosf.c new file mode 100644 index 00000000..14b8e98b --- /dev/null +++ b/src/math/s_cosf.c @@ -0,0 +1,47 @@ +/* s_cosf.c -- float version of s_cos.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 <math.h> +#include "math_private.h" + +static const float one=1.0; + +float +cosf(float x) +{ + float y[2],z=0.0; + int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fd8) return __kernel_cosf(x,z); + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + switch(n&3) { + case 0: return __kernel_cosf(y[0],y[1]); + case 1: return -__kernel_sinf(y[0],y[1],1); + case 2: return -__kernel_cosf(y[0],y[1]); + default: + return __kernel_sinf(y[0],y[1],1); + } + } +} diff --git a/src/math/s_erf.c b/src/math/s_erf.c new file mode 100644 index 00000000..e321feea --- /dev/null +++ b/src/math/s_erf.c @@ -0,0 +1,298 @@ +/* @(#)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. + * ==================================================== + */ + +/* 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 <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 */ + +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 = ((uint32_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 = exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +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)(((uint32_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))))))); + |