Port a lot more code to AARCH64

- Introduce epoll_pwait()
- Rewrite -ftrapv and ffs() libraries in C code
- Use more FreeBSD code in math function library
- Get significantly more tests passing on qemu-aarch64
- Fix many Musl long double functions that were broken on AARCH64
This commit is contained in:
Justine Tunney 2023-05-14 09:32:15 -07:00
parent 91791e9f38
commit 550b52abf6
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
158 changed files with 6018 additions and 3499 deletions

View file

@ -234,7 +234,8 @@ o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.c o/$(MODE)/%-clang.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: CC = $(CLANG) # TODO(jart): Make intrinsics support Clang.
# o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1 o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.cc o/$(MODE)/%-clang.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $< @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<

View file

@ -8,16 +8,8 @@ DSP_CORE = $(DSP_CORE_A_DEPS) $(DSP_CORE_A)
DSP_CORE_A = o/$(MODE)/dsp/core/core.a DSP_CORE_A = o/$(MODE)/dsp/core/core.a
DSP_CORE_A_FILES := $(wildcard dsp/core/*) DSP_CORE_A_FILES := $(wildcard dsp/core/*)
DSP_CORE_A_HDRS = $(filter %.h,$(DSP_CORE_A_FILES)) DSP_CORE_A_HDRS = $(filter %.h,$(DSP_CORE_A_FILES))
DSP_CORE_A_SRCS_S = $(filter %.S,$(DSP_CORE_A_FILES)) DSP_CORE_A_SRCS = $(filter %.c,$(DSP_CORE_A_FILES))
DSP_CORE_A_SRCS_C = $(filter %.c,$(DSP_CORE_A_FILES)) DSP_CORE_A_OBJS = $(DSP_CORE_A_SRCS:%.c=o/$(MODE)/%.o)
DSP_CORE_A_SRCS = \
$(DSP_CORE_A_SRCS_S) \
$(DSP_CORE_A_SRCS_C)
DSP_CORE_A_OBJS = \
$(DSP_CORE_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(DSP_CORE_A_SRCS_C:%.c=o/$(MODE)/%.o)
DSP_CORE_A_CHECKS = \ DSP_CORE_A_CHECKS = \
$(DSP_CORE_A).pkg \ $(DSP_CORE_A).pkg \

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.balign 16
// Mixes audio.
//
// @param rdi is # aligned int16[16] sample chunks to process
// @param rsi points to aligned pcm s16le input/output memory
// @param rdx points to aligned pcm s16le [0..1] input memory
sad16x8n:
.leafprologue
.profilable
test %rdi,%rdi
jz 1f
shl $3,%rdi
0: sub $8,%rdi
movdqa (%rsi,%rdi,2),%xmm0
paddsw (%rdx,%rdi,2),%xmm0
movdqa %xmm0,(%rsi,%rdi,2)
jnz 0b
1: .leafepilogue
.endfn sad16x8n,globl,hidden

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,13 +16,31 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "dsp/core/core.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "third_party/aarch64/arm_neon.h"
#include "third_party/intel/emmintrin.internal.h"
/** /**
* Returns absolute value of long long integer. * Mixes audio.
* @note `llabs(LONG_LONG_MIN)` returns `LONG_LONG_MIN` unless `-ftrapv` *
* @note consider ABS() to avoid narrowing * This function performs saturated addition on an array of shorts.
*
* @param x needs to be 16-byte aligned
* @param y needs to be 16-byte aligned
*/ */
long long llabs(long long x) { void sad16x8n(size_t n, short x[n][8], const short y[n][8]) {
return 0 < x ? x : -x; size_t i, j;
for (i = 0; i < n; ++i) {
#ifdef __x86_64__
*(__m128i *)x[i] = _mm_adds_epi16(*(__m128i *)x[i], *(__m128i *)y[i]);
#elif defined(__aarch64__)
*(int16x4_t *)x[i] = vqadd_s16(*(int16x4_t *)x[i], *(int16x4_t *)y[i]);
#else
for (j = 0; j < 8; ++j) {
x[i][j] = MIN(MAX(x[i][j] + y[i][j], INT16_MIN), INT16_MAX);
}
#endif
}
} }

View file

@ -37,7 +37,8 @@ DSP_MPEG_A_DIRECTDEPS = \
LIBC_STUBS \ LIBC_STUBS \
LIBC_SYSV \ LIBC_SYSV \
LIBC_TIME \ LIBC_TIME \
LIBC_TINYMATH LIBC_TINYMATH \
THIRD_PARTY_COMPILER_RT
DSP_MPEG_A_DEPS := \ DSP_MPEG_A_DEPS := \
$(call uniq,$(foreach x,$(DSP_MPEG_A_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(DSP_MPEG_A_DIRECTDEPS),$($(x))))

View file

@ -608,6 +608,7 @@ static const uint16_t kPledgeStdio[] = {
#endif // #endif //
__NR_linux_msync, // __NR_linux_msync, //
__NR_linux_mmap | NOEXEC, // __NR_linux_mmap | NOEXEC, //
__NR_linux_mlock, //
__NR_linux_mremap, // __NR_linux_mremap, //
__NR_linux_munmap, // __NR_linux_munmap, //
__NR_linux_mincore, // __NR_linux_mincore, //

View file

@ -88,9 +88,9 @@ int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout,
&millis)) { &millis)) {
millis = -1; millis = -1;
} }
if (sigmask) sigprocmask(SIG_SETMASK, sigmask, &oldmask); if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = poll(fds, nfds, millis); rc = poll(fds, nfds, millis);
if (sigmask) sigprocmask(SIG_SETMASK, &oldmask, 0); if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
} }
} else { } else {
if (!timeout || __builtin_add_overflow( if (!timeout || __builtin_add_overflow(

View file

@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_COMPLEX_H_ #ifndef _COMPLEX_H
#define COSMOPOLITAN_LIBC_COMPLEX_H_ #define _COMPLEX_H
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#if __STDC_VERSION__ + 0 >= 201112 && !defined(__STDC_NO_COMPLEX__) #if __STDC_VERSION__ + 0 >= 201112 && !defined(__STDC_NO_COMPLEX__)
@ -118,4 +118,4 @@ complex long double cpowl(complex long double, complex long double);
#endif /* C11 */ #endif /* C11 */
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_COMPLEX_H_ */ #endif /* _COMPLEX_H */

View file

@ -17,11 +17,33 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
/** /**
* Returns absolute value of x. * Returns absolute value of 𝑥.
*
* This function is a footgun since your argument may be narrrowed.
* Consider using labs(), llabs(), or better yet a macro like this:
*
* #define ABS(X) ((X) >= 0 ? (X) : -(X))
*
* Note that passing `x` as `INT_MIN` is undefined behavior, which
* depends on whether or not your c library as well as the objects
* that call it were built using the `-fwrapv` or `-ftrapv` flags.
*/ */
int abs(int x) { int abs(int x) {
return ABS(x); return x < 0 ? -x : x;
}
/**
* Returns absolute value of 𝑥.
*/
long labs(long x) {
return x < 0 ? -x : x;
}
/**
* Returns absolute value of 𝑥.
*/
long long llabs(long long x) {
return x < 0 ? -x : x;
} }

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥+𝑦, aborting on overflow.
//
// @param rdi is int64 𝑥
// @param rsi is int64 𝑦
// @return rax is 𝑥+𝑦
// @see -ftrapv
__addvdi3:
mov %rdi,%rax
add %rsi,%rax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __addvdi3,globl

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥+𝑦, aborting on overflow.
//
// @param edi is int32 𝑥
// @param esi is int32 𝑦
// @return eax is 𝑥+𝑦
// @see -ftrapv
__addvsi3:
mov %edi,%eax
add %esi,%eax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __addvsi3,globl

View file

@ -1,41 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥+𝑦, aborting on overflow.
//
// @param rdi:rsi is int128 𝑥
// @param rdx:rcx is int128 𝑦
// @return rdx:rax is 𝑥+𝑦
// @see -ftrapv
__addvti3:
mov %rdi,%rax
add %rdx,%rax
mov %rsi,%rdx
adc %rcx,%rdx
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __addvti3,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,13 +16,25 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/intrin/intrin.h"
/** /**
* Returns absolute value of 32-bit integer. * Finds lowest set bit in word.
* @note `labs(LONG_MIN)` returns `LONG_MIN` unless `-ftrapv`
* @note consider ABS() to avoid narrowing
*/ */
int abs(int x) { int ffs(int x) {
return 0 < x ? x : -x; return __builtin_ffs(x);
}
/**
* Finds lowest set bit in word.
*/
long ffsl(long x) {
return __builtin_ffsl(x);
}
/**
* Finds lowest set bit in word.
*/
long long ffsll(long long x) {
return __builtin_ffsll(x);
} }

186
libc/intrin/ftrapv.c Normal file
View file

@ -0,0 +1,186 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/intrin.h"
#include "libc/limits.h"
#include "libc/runtime/internal.h"
/**
* Returns -𝑥, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int __negvsi2(int x) {
if (x == INT_MIN) {
__on_arithmetic_overflow();
}
return -x;
}
/**
* Returns -𝑥 on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
long __negvdi2(long x) {
if (x == LONG_MIN) {
__on_arithmetic_overflow();
}
return -x;
}
/**
* Returns -𝑥, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int128_t __negvti2(int128_t x) {
if (x == INT128_MIN) {
__on_arithmetic_overflow();
}
return -x;
}
/**
* Returns 𝑥+𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int __addvsi3(int x, int y) {
int z;
if (__builtin_add_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥+𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
long __addvdi3(long x, long y) {
long z;
if (__builtin_add_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥+𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int128_t __addvti3(int128_t x, int128_t y) {
int128_t z;
if (__builtin_add_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥-𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int __subvsi3(int x, int y) {
int z;
if (__builtin_sub_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥-𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
long __subvdi3(long x, long y) {
long z;
if (__builtin_sub_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥-𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int128_t __subvti3(int128_t x, int128_t y) {
int128_t z;
if (__builtin_sub_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥*𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int __mulvsi3(int x, int y) {
int z;
if (__builtin_mul_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥*𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
long __mulvdi3(long x, long y) {
long z;
if (__builtin_mul_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}
/**
* Returns 𝑥*𝑦, aborting on overflow.
*
* @see __on_arithmetic_overflow()
* @see -ftrapv to enable
*/
int128_t __mulvti3(int128_t x, int128_t y) {
int128_t z;
if (__builtin_mul_overflow(x, y, &z)) {
__on_arithmetic_overflow();
}
return z;
}

View file

@ -126,6 +126,14 @@ o/$(MODE)/libc/intrin/restorewintty.o: private \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-fno-sanitize=all -fno-sanitize=all
# we can't use -ftrapv because:
# this file implements it
o/$(MODE)/libc/intrin/ftrapv.o: private \
OVERRIDE_CFLAGS += \
-ffunction-sections \
-ffreestanding \
-fwrapv
# we can't use asan because: # we can't use asan because:
# sys_mmap() calls these which sets up shadow memory # sys_mmap() calls these which sets up shadow memory
o/$(MODE)/libc/intrin/describeflags.o \ o/$(MODE)/libc/intrin/describeflags.o \

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥*𝑦, aborting on overflow.
//
// @param rdi is int64 𝑥
// @param rdi is int64 𝑦
// @return rax is 𝑥*𝑦
// @see -ftrapv
__mulvdi3:
mov %rdi,%rax
imul %rsi
jc 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __mulvdi3,globl

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥*𝑦, aborting on overflow.
//
// @param edi is int32 𝑥
// @param esi is int32 𝑦
// @return eax is 𝑥*𝑦
// @see -ftrapv
__mulvsi3:
mov %edi,%eax
imul %esi
jc 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __mulvsi3,globl

View file

@ -1,134 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥*𝑦, aborting on overflow.
//
// @param rdi:rsi is int128 𝑥
// @param rdx:rcx is int128 𝑦
// @return rdx:rax is 𝑥*𝑦
// @see -ftrapv
__mulvti3:
push %rbp
mov %rsp,%rbp
push %rbx
push %rbx
push %r12
push %r13
push %r14
push %r15
mov %rdx,%r10
mov %rdi,%rdx
xor %r11d,%r11d
mov %r10,%rax
sar $63,%rdx
sar $63,%rax
cmp %rsi,%rdx
jne 4f
cmp %rcx,%rax
jne 5f
mov %rdi,%rax
imul %r10
mov %rax,%r14
mov %rdx,%r8
jmp 2f
5: mov %r10,%r12
mov %rcx,%r13
mov %rcx,%r8
mov %rdi,%rbx
jmp 6f
4: cmp %rcx,%rax
jne 7f
mov %rdi,%r12
mov %rsi,%r13
mov %rsi,%r8
mov %r10,%rbx
6: mov %rdi,%rax
mul %r10
mov %rax,%r14
mov %rbx,%rax
mov %rdx,%r15
mul %r8
test %r8,%r8
jns 8f
xor %r8d,%r8d
sub %r8,%rax
sbb %rbx,%rdx
8: test %rbx,%rbx
jns 9f
sub %r12,%rax
sbb %r13,%rdx
9: mov %r15,%r8
xor %r9d,%r9d
add %rax,%r8
adc %rdx,%r9
mov %r8,%rdx
sar $63,%rdx
cmp %r9,%rdx
je 2f
imul %r10,%rsi
mov %rdi,%rax
imul %rdi,%rcx
mul %r10
lea (%rsi,%rcx),%r8
add %rdx,%r8
mov %rax,%r14
jmp 3f
7: mov %rsi,%r8
mov %rcx,%rdx
mov %rdi,%rax
imul %rdi,%rdx
imul %r10,%r8
add %rdx,%r8
mul %r10
mov %rax,%r14
lea 1(%rsi),%rax
add %rdx,%r8
cmp $1,%rax
ja 3f
lea 1(%rcx),%rax
cmp $1,%rax
ja 3f
cmp %rcx,%rsi
jne 11f
cmp %r14,%r11
mov %r11,%rax
sbb %r8,%rax
jl 2f
jmp 3f
11: test %r8,%r8
js 2f
3: mov $1,%r11d
2: test %r11,%r11
je 1f
mov %r8,-8(%rbp)
call __on_arithmetic_overflow
mov -8(%rbp),%r8
1: mov %r14,%rax
mov %r8,%rdx
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
leave
ret
.endfn __mulvti3,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns -𝑥, aborting on overflow (two's complement bane).
//
// @param rdi is int64 𝑥
// @return rax is -𝑥
// @see -ftrapv
__negvdi2:
mov %rdi,%rax
neg %rax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __negvdi2,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns -𝑥, aborting on overflow (two's complement bane).
//
// @param edi is int32 𝑥
// @return eax is -𝑥
// @see -ftrapv
__negvsi2:
mov %edi,%eax
neg %eax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __negvsi2,globl

View file

@ -1,42 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns -𝑥, aborting on overflow.
//
// @param rdi:rsi is int128 𝑥
// @return rdx:rax is -𝑥
// @see -ftrapv
__negvti2:
mov %rdi,%rax
mov %rsi,%rdx
neg %rax
not %rdx
cmc
adc $0,%rdx
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __negvti2,globl

View file

@ -1,30 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
// Arithmetic overflow handler.
// @see -ftrapv
__on_arithmetic_overflow:
push %rbp
mov %rsp,%rbp
int3
0: ud2
jmp 0b
.endfn __on_arithmetic_overflow,weak

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,13 +16,21 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/intrin/intrin.h"
#include "libc/intrin/kprintf.h"
/** /**
* Returns absolute value of long integer. * Arithmetic overflow handler.
* @note `labs(LONG_MIN)` returns `LONG_MIN` unless `-ftrapv` *
* @note consider ABS() to avoid narrowing * This function is provided weakly, so that programs which depend on
* this library may define it themselves. This default implementation
* will print a message to standard error and raise SIGTRAP. A custom
* implementation may return from this function, in which case the op
* shall have `-fwrapv` i.e. signed two's complement behavior.
*
* @see -ftrapv
*/ */
long labs(long x) { __attribute__((__weak__)) void __on_arithmetic_overflow(void) {
return 0 < x ? x : -x; kprintf("error: -ftrapv caught arithmetic overflow\n");
__builtin_trap();
} }

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥-𝑦, aborting on overflow.
//
// @param rdi is int64 𝑥
// @param rsi is int64 𝑦
// @return rax is 𝑥-𝑦
// @see -ftrapv
__subvdi3:
mov %rdi,%rax
sub %rsi,%rax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __subvdi3,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥-𝑦, aborting on overflow.
//
// @param edi is int32 𝑥
// @param esi is int32 𝑦
// @see -ftrapv
__subvsi3:
mov %edi,%eax
sub %esi,%eax
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __subvsi3,globl

View file

@ -1,41 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.privileged
.alignfunc
// Returns 𝑥-𝑦, aborting on overflow.
//
// @param rdi:rsi is int128 𝑥
// @param rdx:rcx is int128 𝑦
// @return rdx:rax is 𝑥-𝑦
// @see -ftrapv
__subvti3:
mov %rdi,%rax
sub %rdx,%rax
mov %rsi,%rdx
sbb %rcx,%rdx
jo 1f
ret
1: push %rbp
mov %rsp,%rbp
call __on_arithmetic_overflow
pop %rbp
ret
.endfn __subvti3,globl

View file

@ -4,6 +4,7 @@
forceinline long LinuxMmap(void *addr, size_t size, long prot, long flags, forceinline long LinuxMmap(void *addr, size_t size, long prot, long flags,
long fd, long off) { long fd, long off) {
#ifdef __x86_64__
long rc; long rc;
register long flags_ asm("r10") = flags; register long flags_ asm("r10") = flags;
register long fd_ asm("r8") = fd; register long fd_ asm("r8") = fd;
@ -14,6 +15,23 @@ forceinline long LinuxMmap(void *addr, size_t size, long prot, long flags,
"r"(off_) "r"(off_)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
return rc; return rc;
#elif defined(__aarch64__)
register long r0 asm("x0") = (long)addr;
register long r1 asm("x1") = (long)size;
register long r2 asm("x2") = (long)prot;
register long r3 asm("x3") = (long)flags;
register long r4 asm("x4") = (long)fd;
register long r5 asm("x5") = (long)off;
register long res_x0 asm("x0");
asm volatile("mov\tx8,%1\n\t"
"svc\t0"
: "=r"(res_x0)
: "i"(222), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)
: "x8", "memory");
return res_x0;
#else
#error "unsupported architecture"
#endif
} }
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -3,12 +3,26 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
forceinline long LinuxMunmap(void *addr, size_t size) { forceinline long LinuxMunmap(void *addr, size_t size) {
#ifdef __x86_64__
long rc; long rc;
asm volatile("syscall" asm volatile("syscall"
: "=a"(rc) : "=a"(rc)
: "0"(0xb), "D"(addr), "S"(size) : "0"(0xb), "D"(addr), "S"(size)
: "rcx", "r11", "memory"); : "rcx", "r11", "memory");
return rc; return rc;
#elif defined(__aarch64__)
register long r0 asm("x0") = (long)addr;
register long r1 asm("x1") = (long)size;
register long res_x0 asm("x0");
asm volatile("mov\tx8,%1\n\t"
"svc\t0"
: "=r"(res_x0)
: "i"(215), "r"(r0), "r"(r1)
: "x8", "memory");
return res_x0;
#else
#error "unsupported architecture"
#endif
} }
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,44 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Finds lowest set bit in word.
//
// uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
// 0x00000000 wut 32 0 wut 32
// 0x00000001 0 0 1 0 31
// 0x80000001 0 0 1 31 0
// 0x80000000 31 31 32 31 0
// 0x00000010 4 4 5 4 27
// 0x08000010 4 4 5 27 4
// 0x08000000 27 27 28 27 4
// 0xffffffff 0 0 1 31 0
//
// @param edi is the input number
// @return number in range [1,32] or 0 if no bits set
// @see also treasure trove of nearly identical functions
// @asyncsignalsafe
ffs: .leafprologue
.profilable
or $-1,%edx
bsf %edi,%eax
cmovz %edx,%eax
inc %eax
.leafepilogue
.endfn ffs,globl

View file

@ -3,20 +3,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
/*
* BIT SCANNING 101
* ctz(𝑥) 31^clz(𝑥) clz(𝑥)
* uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
* 0x00000000 wut 32 0 wut 32
* 0x00000001 0 0 1 0 31
* 0x80000001 0 0 1 31 0
* 0x80000000 31 31 32 31 0
* 0x00000010 4 4 5 4 27
* 0x08000010 4 4 5 27 4
* 0x08000000 27 27 28 27 4
* 0xffffffff 0 0 1 31 0
*/
int ffs(int) pureconst; int ffs(int) pureconst;
int ffsl(long) pureconst; int ffsl(long) pureconst;
int ffsll(long long) pureconst; int ffsll(long long) pureconst;

View file

@ -1,45 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Finds lowest set bit in word.
//
// uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
// 0x00000000 wut 32 0 wut 32
// 0x00000001 0 0 1 0 31
// 0x80000001 0 0 1 31 0
// 0x80000000 31 31 32 31 0
// 0x00000010 4 4 5 4 27
// 0x08000010 4 4 5 27 4
// 0x08000000 27 27 28 27 4
// 0xffffffff 0 0 1 31 0
//
// @param rdi is the input number
// @return number in range [1,64] or 0 if no bits set
// @see also treasure trove of nearly identical functions
// @asyncsignalsafe
ffsl: .leafprologue
.profilable
or $-1,%edx
bsf %rdi,%rax
cmovz %edx,%eax
inc %eax
.leafepilogue
.endfn ffsl,globl
.alias ffsl,ffsll

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_NT_SYNCHRONIZATION_H_ #ifndef COSMOPOLITAN_LIBC_NT_SYNCHRONIZATION_H_
#define COSMOPOLITAN_LIBC_NT_SYNCHRONIZATION_H_ #define COSMOPOLITAN_LIBC_NT_SYNCHRONIZATION_H_
#include "libc/intrin/atomic.h"
#include "libc/nt/struct/criticalsection.h" #include "libc/nt/struct/criticalsection.h"
#include "libc/nt/struct/filetime.h" #include "libc/nt/struct/filetime.h"
#include "libc/nt/struct/linkedlist.h" #include "libc/nt/struct/linkedlist.h"
@ -33,20 +34,13 @@ COSMOPOLITAN_C_START_
cosmopolitan § new technology » synchronization cosmopolitan § new technology » synchronization
*/ */
#define InterlockedAdd(PTR, VAL) \ static inline int32_t InterlockedAdd(int32_t volatile *p, int32_t x) {
({ \ return atomic_fetch_add((_Atomic(int32_t) *)p, x) + x;
typeof(*(PTR)) Res; \ }
typeof(Res) Val = (VAL); \
asm volatile("lock xadd\t%0,%1" : "=r"(Res), "+m"(*(PTR)) : "0"(Val)); \
Res + Val; \
})
#define InterlockedExchange(PTR, VAL) \ static inline int32_t InterlockedExchange(int32_t volatile *p, int32_t x) {
({ \ return atomic_exchange((_Atomic(int32_t) *)p, x);
typeof(*(PTR)) Res = (VAL); \ }
asm volatile("xchg\t%0,%1" : "+r"(Res), "+m"(*(PTR))); \
Res; \
})
typedef void (*NtTimerapcroutine)(void *lpArgToCompletionRoutine, typedef void (*NtTimerapcroutine)(void *lpArgToCompletionRoutine,
uint32_t dwTimerLowValue, uint32_t dwTimerLowValue,

View file

@ -1,29 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns granularity of memory manager.
//
// @see sysconf(_SC_PAGE_SIZE) which is portable
getpagesize:
.leafprologue
.profilable
mov $FRAMESIZE,%eax
.leafepilogue
.endfn getpagesize,globl

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,12 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
TEST(omg, test) { /**
SPAWN(fork); * Returns granularity of memory manager.
EXITS(0); * @see sysconf(_SC_PAGE_SIZE) which is portable
*/
int getpagesize(void) {
return FRAMESIZE;
} }

View file

@ -48,6 +48,7 @@ noasan void *_Mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) _Hide; int64_t off) _Hide;
noasan int _Munmap(char *, size_t) _Hide; noasan int _Munmap(char *, size_t) _Hide;
void InitializeFileDescriptors(void); void InitializeFileDescriptors(void);
void __on_arithmetic_overflow(void);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -36,7 +36,9 @@
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/cp.internal.h" #include "libc/calls/cp.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -71,10 +73,9 @@
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/epoll.h" #include "libc/sysv/consts/epoll.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__
/** /**
* @fileoverview epoll * @fileoverview epoll
* *
@ -1520,10 +1521,15 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev) {
*/ */
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
int timeoutms) { int timeoutms) {
int rc; int e, rc;
BEGIN_CANCELLATION_POINT; BEGIN_CANCELLATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {
e = errno;
rc = sys_epoll_wait(epfd, events, maxevents, timeoutms); rc = sys_epoll_wait(epfd, events, maxevents, timeoutms);
if (rc == -1 && errno == ENOSYS) {
errno = e;
rc = sys_epoll_pwait(epfd, events, maxevents, timeoutms, 0, 0);
}
} else { } else {
rc = sys_epoll_wait_nt(epfd, events, maxevents, timeoutms); rc = sys_epoll_wait_nt(epfd, events, maxevents, timeoutms);
} }
@ -1533,4 +1539,39 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
return rc; return rc;
} }
#endif /* __x86_64__ */ /**
* Receives socket events.
*
* @param events will receive information about what happened
* @param maxevents is array length of events
* @param timeoutms is milliseconds, 0 to not block, or -1 for forever
* @param sigmask is an optional sigprocmask() to use during call
* @return number of events stored, 0 on timeout, or -1 w/ errno
* @cancellationpoint
* @norestart
*/
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents,
int timeoutms, const sigset_t *sigmask) {
int e, rc;
sigset_t oldmask;
BEGIN_CANCELLATION_POINT;
if (!IsWindows()) {
e = errno;
rc = sys_epoll_pwait(epfd, events, maxevents, timeoutms, sigmask,
sizeof(*sigmask));
if (rc == -1 && errno == ENOSYS) {
errno = e;
if (sigmask) sys_sigprocmask(SIG_SETMASK, sigmask, &oldmask);
rc = sys_epoll_wait(epfd, events, maxevents, timeoutms);
if (sigmask) sys_sigprocmask(SIG_SETMASK, &oldmask, 0);
}
} else {
if (sigmask) __sig_mask(SIG_SETMASK, sigmask, &oldmask);
rc = sys_epoll_wait_nt(epfd, events, maxevents, timeoutms);
if (sigmask) __sig_mask(SIG_SETMASK, &oldmask, 0);
}
END_CANCELLATION_POINT;
STRACE("epoll_pwait(%d, %p, %d, %d) → %d% m", epfd, events, maxevents,
timeoutms, DescribeSigset(0, sigmask), rc);
return rc;
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_SOCK_WEPOLL_H_ #define COSMOPOLITAN_LIBC_SOCK_WEPOLL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#include "libc/calls/struct/sigset.h"
typedef union epoll_data { typedef union epoll_data {
void *ptr; void *ptr;
@ -19,6 +20,7 @@ int epoll_create(int);
int epoll_create1(int); int epoll_create1(int);
int epoll_ctl(int, int, int, struct epoll_event *); int epoll_ctl(int, int, int, struct epoll_event *);
int epoll_wait(int, struct epoll_event *, int, int); int epoll_wait(int, struct epoll_event *, int, int);
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_ #ifndef COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_
#define COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_ #define COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.h"
#include "libc/nt/struct/overlapped.h" #include "libc/nt/struct/overlapped.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
@ -79,6 +80,8 @@ int sys_setsockopt(int, int, int, const void *, uint32_t) _Hide;
int32_t sys_epoll_create(int32_t) _Hide; int32_t sys_epoll_create(int32_t) _Hide;
int32_t sys_epoll_ctl(int32_t, int32_t, int32_t, void *) _Hide; int32_t sys_epoll_ctl(int32_t, int32_t, int32_t, void *) _Hide;
int32_t sys_epoll_wait(int32_t, void *, int32_t, int32_t) _Hide; int32_t sys_epoll_wait(int32_t, void *, int32_t, int32_t) _Hide;
int32_t sys_epoll_pwait(int32_t, void *, int32_t, int32_t, const sigset_t *,
size_t);
int sys_socket_nt(int, int, int) _Hide; int sys_socket_nt(int, int, int) _Hide;

View file

@ -44,7 +44,6 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "net/http/ip.h" #include "net/http/ip.h"
#ifdef __x86_64__ #ifdef __x86_64__
#define ORIG_RAX 120 #define ORIG_RAX 120

View file

@ -1,2 +1,2 @@
#include "libc/sysv/macros.internal.h" #include "libc/sysv/macros.internal.h"
.scall sys_epoll_pwait,0xfffffffffffff119,0x016,globl .scall sys_epoll_pwait,0xfffffffffffff919,0x016,globl,hidden

View file

@ -305,7 +305,7 @@ scall posix_fallocate 0x9dffffa12fffffff 0xfff globl hidden # └─ cosmopoli
scall __sys_accept4 0xfff85da1dffff920 0x0f2 globl hidden # Linux 2.6.28+ scall __sys_accept4 0xfff85da1dffff920 0x0f2 globl hidden # Linux 2.6.28+
scall __sys_dup3 0x1c6066fffffff124 0x018 globl hidden # Linux 2.6.27+ scall __sys_dup3 0x1c6066fffffff124 0x018 globl hidden # Linux 2.6.27+
scall __sys_pipe2 0x1c506521effff125 0x03b globl hidden # Linux 2.6.27+ scall __sys_pipe2 0x1c506521effff125 0x03b globl hidden # Linux 2.6.27+
scall sys_epoll_pwait 0xfffffffffffff119 0x016 globl # no wrapper scall sys_epoll_pwait 0xfffffffffffff919 0x016 globl hidden
scall sys_epoll_create1 0xfffffffffffff123 0x014 globl hidden scall sys_epoll_create1 0xfffffffffffff123 0x014 globl hidden
scall sys_perf_event_open 0xfffffffffffff12a 0x0f1 globl # no wrapper scall sys_perf_event_open 0xfffffffffffff12a 0x0f1 globl # no wrapper
scall sys_inotify_init1 0xfffffffffffff126 0x01a globl # no wrapper scall sys_inotify_init1 0xfffffffffffff126 0x01a globl # no wrapper

View file

@ -27,17 +27,21 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "third_party/xed/x86.h" #include "third_party/xed/x86.h"
#ifdef __x86_64__
static volatile _Thread_local int gotsignal; static volatile _Thread_local int gotsignal;
static void ContinueOnError(int sig, siginfo_t *si, void *vctx) { static void ContinueOnError(int sig, siginfo_t *si, void *vctx) {
struct XedDecodedInst xedd;
struct ucontext *ctx = vctx; struct ucontext *ctx = vctx;
gotsignal = sig;
#ifdef __aarch64__
ctx->uc_mcontext.pc += 4;
#elif defined(__x86_64__)
struct XedDecodedInst xedd;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
ctx->uc_mcontext.rip += xedd.length; ctx->uc_mcontext.rip += xedd.length;
gotsignal = sig; #else
#error "unsupported architecture"
#endif /* __x86_64__ */
} }
/** /**
@ -63,5 +67,3 @@ noasan bool testlib_memoryexists(const void *p) {
_npassert(!sigaction(SIGSEGV, old + 0, 0)); _npassert(!sigaction(SIGSEGV, old + 0, 0));
return !gotsignal; return !gotsignal;
} }
#endif /* __x86_64__ */

View file

@ -35,7 +35,6 @@
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#ifdef __x86_64__ #ifdef __x86_64__
int systemfive_cancel(void); int systemfive_cancel(void);

View file

@ -2,60 +2,108 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/e_acoshl.c
Copyright © 2005-2014 Rich Felker, et al. Converted to ldbl by David Schultz <das@FreeBSD.ORG> and Bruce D. Evans.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/ldshape.internal.h" #include "libc/tinymath/freebsd.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
/* EXP_LARGE is the threshold above which we use acosh(x) ~= log(2x). */
#if LDBL_MANT_DIG == 64
#define EXP_LARGE 34
#elif LDBL_MANT_DIG == 113
#define EXP_LARGE 58
#else
#error "Unsupported long double format"
#endif
#if LDBL_MAX_EXP != 0x4000
/* We also require the usual expsign encoding. */
#error "Unsupported long double format"
#endif
#define BIAS (LDBL_MAX_EXP - 1)
static const double
one = 1.0;
#if LDBL_MANT_DIG == 64
static const union IEEEl2bits
u_ln2 = LD80C(0xb17217f7d1cf79ac, -1, 6.93147180559945309417e-1L);
#define ln2 u_ln2.e
#elif LDBL_MANT_DIG == 113
static const long double
ln2 = 6.93147180559945309417232121458176568e-1L; /* 0x162e42fefa39ef35793c7673007e6.0p-113 */
#else
#error "Unsupported long double format"
#endif
/** /**
* Returns inverse hyperbolic cosine of 𝑥. * Returns inverse hyperbolic cosine of 𝑥.
* @define acosh(x) = log(x + sqrt(x*x-1)) * @define acosh(x) = log(x + sqrt(x*x-1))
*/ */
long double acoshl(long double x) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 acoshl(long double x)
return acosh(x); {
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 long double t;
union ldshape u = {x}; int16_t hx;
int e = u.i.se & 0x7fff;
if (e < 0x3fff + 1) ENTERI();
/* |x| < 2, invalid if x < 1 or nan */ GET_LDBL_EXPSIGN(hx, x);
return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); if (hx < 0x3fff) { /* x < 1, or misnormal */
if (e < 0x3fff + 32) RETURNI((x-x)/(x-x));
/* |x| < 0x1p32 */ } else if (hx >= BIAS + EXP_LARGE) { /* x >= LARGE */
return logl(2*x - 1/(x+sqrtl(x*x-1))); if (hx >= 0x7fff) { /* x is inf, NaN or misnormal */
return logl(x) + 0.693147180559945309417232121458176568L; RETURNI(x+x);
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 } else {
// TODO: broken implementation to make things compile RETURNI(logl(x)+ln2); /* acosh(huge)=log(2x), or misnormal */
return acosh(x); }
#else } else if (hx == 0x3fff && x == 1) {
#error "architecture unsupported" RETURNI(0.0); /* acosh(1) = 0 */
#endif } else if (hx >= 0x4000) { /* LARGE > x >= 2, or misnormal */
t=x*x;
RETURNI(logl(2.0*x-one/(x+sqrtl(t-one))));
} else { /* 1<x<2 */
t = x-one;
RETURNI(log1pl(t+sqrtl(2.0*t+t*t)));
}
} }

View file

@ -32,7 +32,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/** /**
* Returns inverse hyperbolic sine of 𝑥. * Returns inverse hyperbolic sine of 𝑥.

View file

@ -2,74 +2,110 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/s_asinhl.c
Copyright © 2005-2014 Rich Felker, et al. Converted to ldbl by David Schultz <das@FreeBSD.ORG> and Bruce D. Evans.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/feval.internal.h" #include "libc/tinymath/freebsd.internal.h"
#include "libc/tinymath/internal.h"
#include "libc/tinymath/ldshape.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
/* EXP_LARGE is the threshold above which we use asinh(x) ~= log(2x). */
/* EXP_TINY is the threshold below which we use asinh(x) ~= x. */
#if LDBL_MANT_DIG == 64
#define EXP_LARGE 34
#define EXP_TINY -34
#elif LDBL_MANT_DIG == 113
#define EXP_LARGE 58
#define EXP_TINY -58
#else
#error "Unsupported long double format"
#endif
#if LDBL_MAX_EXP != 0x4000
/* We also require the usual expsign encoding. */
#error "Unsupported long double format"
#endif
#define BIAS (LDBL_MAX_EXP - 1)
static const double
one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
huge= 1.00000000000000000000e+300;
#if LDBL_MANT_DIG == 64
static const union IEEEl2bits
u_ln2 = LD80C(0xb17217f7d1cf79ac, -1, 6.93147180559945309417e-1L);
#define ln2 u_ln2.e
#elif LDBL_MANT_DIG == 113
static const long double
ln2 = 6.93147180559945309417232121458176568e-1L; /* 0x162e42fefa39ef35793c7673007e6.0p-113 */
#else
#error "Unsupported long double format"
#endif
/** /**
* Returns inverse hyperbolic sine of 𝑥. * Returns inverse hyperbolic sine of 𝑥.
* @define asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) * @define asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5)
*/ */
long double asinhl(long double x) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 asinhl(long double x)
return asinh(x); {
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 long double t, w;
union ldshape u = {x}; uint16_t hx, ix;
unsigned e = u.i.se & 0x7fff;
unsigned s = u.i.se >> 15;
/* |x| */ ENTERI();
u.i.se = e; GET_LDBL_EXPSIGN(hx, x);
x = u.f; ix = hx & 0x7fff;
if (ix >= 0x7fff) RETURNI(x+x); /* x is inf, NaN or misnormal */
if (e >= 0x3fff + 32) { if (ix < BIAS + EXP_TINY) { /* |x| < TINY, or misnormal */
/* |x| >= 0x1p32 or inf or nan */ if (huge + x > one) RETURNI(x); /* return x inexact except 0 */
x = logl(x) + 0.693147180559945309417232121458176568L;
} else if (e >= 0x3fff + 1) {
/* |x| >= 2 */
x = logl(2*x + 1/(sqrtl(x*x+1)+x));
} else if (e >= 0x3fff - 32) {
/* |x| >= 0x1p-32 */
x = log1pl(x + x*x/(sqrtl(x*x+1)+1));
} else {
/* |x| < 0x1p-32, raise inexact if x!=0 */
FORCE_EVAL(x + 0x1p120f);
} }
return s ? -x : x; if (ix >= BIAS + EXP_LARGE) { /* |x| >= LARGE, or misnormal */
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 w = logl(fabsl(x))+ln2;
// TODO: broken implementation to make things compile } else if (ix >= 0x4000) { /* LARGE > |x| >= 2.0, or misnormal */
return asinh(x); t = fabsl(x);
#else w = logl(2.0*t+one/(sqrtl(x*x+one)+t));
#error "architecture unsupported" } else { /* 2.0 > |x| >= TINY, or misnormal */
#endif t = x*x;
w =log1pl(fabsl(x)+t/(one+sqrtl(one+t)));
}
RETURNI((hx & 0x8000) == 0 ? w : -w);
} }

View file

@ -1,174 +1,154 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Optimized Routines FreeBSD lib/msun/src/e_atan2.c
Copyright (c) 1999-2022, Arm Limited.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/intrin/likely.h"
#include "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/atan_common.internal.h" #include "libc/tinymath/freebsd.internal.h"
#include "libc/tinymath/internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Optimized Routines (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2022 ARM Limited\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
#define Pi (0x1.921fb54442d18p+1) /* atan2(y,x)
#define PiOver2 (0x1.921fb54442d18p+0) * Method :
#define PiOver4 (0x1.921fb54442d18p-1) * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
#define SignMask (0x8000000000000000) * 2. Reduce x to positive by (if x and y are unexceptional):
#define ExpMask (0x7ff0000000000000) * 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.
*/
/* We calculate atan2 by P(n/d), where n and d are similar to the input static volatile double
arguments, and P is a polynomial. Evaluating P(x) requires calculating x^8, tiny = 1.0e-300;
which may underflow if n and d have very different magnitude. static const double
POW8_EXP_UFLOW_BOUND is the lower bound of the difference in exponents of n zero = 0.0,
and d for which P underflows, and is used to special-case such inputs. */ pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
#define POW8_EXP_UFLOW_BOUND 62 pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
pi = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */
static volatile double
pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
static inline int64_t /**
biased_exponent (double f) * Returns arc tangent of 𝑦/𝑥.
{ */
uint64_t fi = asuint64 (f);
return (fi & ExpMask) >> 52;
}
/* Fast implementation of scalar atan2. Largest errors are when y and x are
close together. The greatest observed error is 2.28 ULP:
atan2(-0x1.5915b1498e82fp+732, 0x1.54d11ef838826p+732)
got -0x1.954f42f1fa841p-1 want -0x1.954f42f1fa843p-1. */
double double
atan2(double y, double x) atan2(double y, double x)
{ {
uint64_t ix = asuint64 (x); double z;
uint64_t iy = asuint64 (y); int32_t k,m,hx,hy,ix,iy;
uint32_t lx,ly;
uint64_t sign_x = ix & SignMask; EXTRACT_WORDS(hx,lx,x);
uint64_t sign_y = iy & SignMask; 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 nan_mix(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) */
uint64_t iax = ix & ~SignMask; /* when y = 0 */
uint64_t iay = iy & ~SignMask; if((iy|ly)==0) {
switch(m) {
bool xisnan = isnan (x);
if (UNLIKELY (isnan (y) && !xisnan))
return __math_invalid (y);
if (UNLIKELY (xisnan))
return __math_invalid (x);
/* m = 2 * sign(x) + sign(y). */
uint32_t m = ((iy >> 63) & 1) | ((ix >> 62) & 2);
int64_t exp_diff = biased_exponent (x) - biased_exponent (y);
/* y = 0. */
if (iay == 0)
{
switch (m)
{
case 0: case 0:
case 1: case 1: return y; /* atan(+-0,+anything)=+-0 */
return y; /* atan(+-0,+anything)=+-0. */ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
case 2: case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
return Pi; /* atan(+0,-anything) = pi. */
case 3:
return -Pi; /* atan(-0,-anything) =-pi. */
} }
} }
/* Special case for (x, y) either on or very close to the y axis. Either x = /* when x = 0 */
0, or y is much larger than x (difference in exponents >= if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
POW8_EXP_UFLOW_BOUND). */
if (UNLIKELY (iax == 0 || exp_diff <= -POW8_EXP_UFLOW_BOUND))
return sign_y ? -PiOver2 : PiOver2;
/* Special case for either x is INF or (x, y) is very close to x axis and x is /* when x is INF */
negative. */ if(ix==0x7ff00000) {
if (UNLIKELY (iax == 0x7ff0000000000000 if(iy==0x7ff00000) {
|| (exp_diff >= POW8_EXP_UFLOW_BOUND && m >= 2))) switch(m) {
{ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
if (iay == 0x7ff0000000000000) case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
{ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
switch (m) case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
{
case 0:
return PiOver4; /* atan(+INF,+INF). */
case 1:
return -PiOver4; /* atan(-INF,+INF). */
case 2:
return 3.0 * PiOver4; /* atan(+INF,-INF). */
case 3:
return -3.0 * PiOver4; /* atan(-INF,-INF). */
} }
} } else {
else switch(m) {
{ case 0: return zero ; /* atan(+...,+INF) */
switch (m) case 1: return -zero ; /* atan(-...,+INF) */
{ case 2: return pi+tiny ; /* atan(+...,-INF) */
case 0: case 3: return -pi-tiny ; /* atan(-...,-INF) */
return 0.0; /* atan(+...,+INF). */
case 1:
return -0.0; /* atan(-...,+INF). */
case 2:
return Pi; /* atan(+...,-INF). */
case 3:
return -Pi; /* atan(-...,-INF). */
} }
} }
} }
/* y is INF. */ /* when y is INF */
if (iay == 0x7ff0000000000000) if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
return sign_y ? -PiOver2 : PiOver2;
uint64_t sign_xy = sign_x ^ sign_y; /* compute y/x */
k = (iy-ix)>>20;
double ax = asdouble (iax); if(k > 60) { /* |y/x| > 2**60 */
double ay = asdouble (iay); z=pi_o_2+0.5*pi_lo;
uint64_t pred_aygtax = (ay > ax); m&=1;
/* Set up z for call to atan. */
double n = pred_aygtax ? -ax : ay;
double d = pred_aygtax ? ay : ax;
double z = n / d;
double ret;
if (UNLIKELY (m < 2 && exp_diff >= POW8_EXP_UFLOW_BOUND))
{
/* If (x, y) is very close to x axis and x is positive, the polynomial
will underflow and evaluate to z. */
ret = z;
} }
else else if(hx<0&&k<-60) z=0.0; /* 0 > |y|/x > -2**-60 */
{ else z=atan(fabs(y/x)); /* safe to do y/x */
/* Work out the correct shift. */ switch (m) {
double shift = sign_x ? -2.0 : 0.0; case 0: return z ; /* atan(+,+) */
shift = pred_aygtax ? shift + 1.0 : shift; case 1: return -z ; /* atan(-,+) */
shift *= PiOver2; case 2: return pi-(z-pi_lo);/* atan(+,-) */
default: /* case 3 */
ret = eval_poly (z, z, shift); return (z-pi_lo)-pi;/* atan(-,-) */
} }
/* Account for the sign of x and y. */
return asdouble (asuint64 (ret) ^ sign_xy);
} }

View file

@ -59,20 +59,21 @@ asm(".include \"libc/disclaimer.inc\"");
/** /**
* Returns arc tangent of 𝑦/𝑥. * Returns arc tangent of 𝑦/𝑥.
*/ */
long double atan2l(long double y, long double x) { long double atan2l(long double y, long double x)
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 {
return atan2(y, x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
#ifdef __x86__ #ifdef __x86__
long double res;
asm("fpatan" asm("fpatan"
: "=t" (res) : "=t"(x)
: "0"(x), "u"(y) : "0"(x), "u"(y)
: "st(1)"); : "st(1)");
return res; return x;
#else #elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return atan2(y, x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
union ldshape ux, uy; union ldshape ux, uy;
long double z; long double z;
@ -129,7 +130,6 @@ long double atan2l(long double y, long double x) {
return (z-2*pio2_lo)-2*pio2_hi; /* atan(-,-) */ return (z-2*pio2_lo)-2*pio2_hi; /* atan(-,-) */
} }
#endif /* __x86__ */
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -30,7 +30,7 @@
#include "libc/tinymath/complex.internal.h" #include "libc/tinymath/complex.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\

View file

@ -30,7 +30,7 @@
#include "libc/tinymath/complex.internal.h" #include "libc/tinymath/complex.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\

View file

@ -30,7 +30,7 @@
#include "libc/tinymath/complex.internal.h" #include "libc/tinymath/complex.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\

View file

@ -57,19 +57,15 @@ asm(".include \"libc/disclaimer.inc\"");
* and David A. Schultz. * and David A. Schultz.
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double cbrtl(long double x)
{
return cbrt(x);
}
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */
/** /**
* Returns cube root of 𝑥. * Returns cube root of 𝑥.
*/ */
long double cbrtl(long double x) long double cbrtl(long double x)
{ {
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return cbrt(x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */
union ldshape u = {x}, v; union ldshape u = {x}, v;
union {float f; uint32_t i;} uft; union {float f; uint32_t i;} uft;
long double r, s, t, w; long double r, s, t, w;
@ -163,8 +159,8 @@ long double cbrtl(long double x)
t *= v.f; t *= v.f;
return t; return t;
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif
}

View file

@ -36,8 +36,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */ /* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */
/*- /*-

View file

@ -2,39 +2,102 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/s_tanhf.c
Copyright © 2005-2014 Rich Felker, et al. Converted to long double by Bruce D. Evans.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/expo.internal.h" #include "libc/tinymath/freebsd.internal.h"
#include "libc/tinymath/feval.internal.h"
#include "libc/tinymath/ldshape.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
#if LDBL_MAX_EXP != 0x4000
/* We also require the usual expsign encoding. */
#error "Unsupported long double format"
#endif
#define BIAS (LDBL_MAX_EXP - 1)
static const volatile long double huge = 0x1p10000L, tiny = 0x1p-10000L;
#if LDBL_MANT_DIG == 64
/*
* Domain [-1, 1], range ~[-1.8211e-21, 1.8211e-21]:
* |cosh(x) - c(x)| < 2**-68.8
*/
static const union IEEEl2bits
C4u = LD80C(0xaaaaaaaaaaaaac78, -5, 4.16666666666666682297e-2L);
#define C4 C4u.e
static const double
C2 = 0.5,
C6 = 1.3888888888888616e-3, /* 0x16c16c16c16b99.0p-62 */
C8 = 2.4801587301767953e-5, /* 0x1a01a01a027061.0p-68 */
C10 = 2.7557319163300398e-7, /* 0x127e4fb6c9b55f.0p-74 */
C12 = 2.0876768371393075e-9, /* 0x11eed99406a3f4.0p-81 */
C14 = 1.1469537039374480e-11, /* 0x1938c67cd18c48.0p-89 */
C16 = 4.8473490896852041e-14; /* 0x1b49c429701e45.0p-97 */
#elif LDBL_MANT_DIG == 113
/*
* Domain [-1, 1], range ~[-2.3194e-37, 2.3194e-37]:
* |cosh(x) - c(x)| < 2**-121.69
*/
static const long double
C4 = 4.16666666666666666666666666666666225e-2L, /* 0x1555555555555555555555555554e.0p-117L */
C6 = 1.38888888888888888888888888889434831e-3L, /* 0x16c16c16c16c16c16c16c16c1dd7a.0p-122L */
C8 = 2.48015873015873015873015871870962089e-5L, /* 0x1a01a01a01a01a01a01a017af2756.0p-128L */
C10 = 2.75573192239858906525574318600800201e-7L, /* 0x127e4fb7789f5c72ef01c8a040640.0p-134L */
C12 = 2.08767569878680989791444691755468269e-9L, /* 0x11eed8eff8d897b543d0679607399.0p-141L */
C14= 1.14707455977297247387801189650495351e-11L, /* 0x193974a8c07c9d24ae169a7fa9b54.0p-149L */
C16 = 4.77947733238737883626416876486279985e-14L; /* 0x1ae7f3e733b814d4e1b90f5727fe4.0p-157L */
static const double
C2 = 0.5,
C18 = 1.5619206968597871e-16, /* 0x16827863b9900b.0p-105 */
C20 = 4.1103176218528049e-19, /* 0x1e542ba3d3c269.0p-114 */
C22 = 8.8967926401641701e-22, /* 0x10ce399542a014.0p-122 */
C24 = 1.6116681626523904e-24, /* 0x1f2c981d1f0cb7.0p-132 */
C26 = 2.5022374732804632e-27; /* 0x18c7ecf8b2c4a0.0p-141 */
#else
#error "Unsupported long double format"
#endif /* LDBL_MANT_DIG == 64 */
/* log(2**16385 - 0.5) rounded up: */
static const float
o_threshold = 1.13572168e4; /* 0xb174de.0p-10 */
/** /**
* Returns hyperbolic cosine of 𝑥. * Returns hyperbolic cosine of 𝑥.
@ -43,43 +106,51 @@ asm(".include \"libc/disclaimer.inc\"");
* = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x)
* = 1 + x*x/2 + o(x^4) * = 1 + x*x/2 + o(x^4)
*/ */
long double coshl(long double x) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 coshl(long double x)
return cosh(x); {
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 long double hi,lo,x2,x4;
union ldshape u = {x}; #if LDBL_MANT_DIG == 113
unsigned ex = u.i.se & 0x7fff; double dx2;
uint32_t w; #endif
long double t; uint16_t ix;
/* |x| */ GET_LDBL_EXPSIGN(ix,x);
u.i.se = ex; ix &= 0x7fff;
x = u.f;
w = u.i.m >> 32;
/* |x| < log(2) */ /* x is INF or NaN */
if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { if(ix>=0x7fff) return x*x;
if (ex < 0x3fff-32) {
fevalf(x + 0x1p120f);
return 1;
}
t = expm1l(x);
return 1 + t*t/(2*(1+t));
}
/* |x| < log(LDBL_MAX) */ ENTERI();
if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) {
t = expl(x);
return 0.5*(t + 1/t);
}
/* |x| > log(LDBL_MAX) or nan */ /* |x| < 1, return 1 or c(x) */
t = expl(0.5*x); if(ix<0x3fff) {
return 0.5*t*t; if (ix<BIAS-(LDBL_MANT_DIG+1)/2) /* |x| < TINY */
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 RETURNI(1+tiny); /* cosh(tiny) = 1(+) with inexact */
// TODO: broken implementation to make things compile x2 = x*x;
return cosh(x); #if LDBL_MANT_DIG == 64
#else x4 = x2*x2;
#error "architecture unsupported" RETURNI(((C16*x2 + C14)*x4 + (C12*x2 + C10))*(x4*x4*x2) +
((C8*x2 + C6)*x2 + C4)*x4 + C2*x2 + 1);
#elif LDBL_MANT_DIG == 113
dx2 = x2;
RETURNI((((((((((((C26*dx2 + C24)*dx2 + C22)*dx2 +
C20)*x2 + C18)*x2 +
C16)*x2 + C14)*x2 + C12)*x2 + C10)*x2 + C8)*x2 + C6)*x2 +
C4)*(x2*x2) + C2*x2 + 1);
#endif #endif
} }
/* |x| in [1, 64), return accurate exp(|x|)/2+1/exp(|x|)/2 */
if (ix < 0x4005) {
k_hexpl(fabsl(x), &hi, &lo);
RETURNI(lo + 0.25/(hi + lo) + hi);
}
/* |x| in [64, o_threshold], return correctly-overflowing exp(|x|)/2 */
if (fabsl(x) <= o_threshold)
RETURNI(hexpl(fabsl(x)));
/* |x| > o_threshold, cosh(x) overflow */
RETURNI(huge*huge);
}

View file

@ -33,9 +33,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */ /* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */

View file

@ -36,7 +36,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */ /* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */

View file

@ -34,7 +34,7 @@ asm(".ident\t\"\\n\\n\
Double-precision math functions (MIT License)\\n\ Double-precision math functions (MIT License)\\n\
Copyright 2018 ARM Limited\""); Copyright 2018 ARM Limited\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* /*
* Double-precision e^x function. * Double-precision e^x function.

View file

@ -1,35 +1,34 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Musl Libc Permission to use, copy, modify, and/or distribute this software for
Copyright © 2005-2014 Rich Felker, et al. any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/math.h" #include "libc/math.h"
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double expl(long double x) {
return exp(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
#include "libc/tinymath/internal.h" #include "libc/tinymath/internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
@ -53,6 +52,7 @@ asm(".include \"libc/disclaimer.inc\"");
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/* /*
* Exponential function, long double precision * Exponential function, long double precision
* *
@ -104,13 +104,6 @@ asm(".include \"libc/disclaimer.inc\"");
* *
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double expl(long double x)
{
return exp(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
static const long double P[3] = { static const long double P[3] = {
1.2617719307481059087798E-4L, 1.2617719307481059087798E-4L,
3.0299440770744196129956E-2L, 3.0299440770744196129956E-2L,
@ -156,12 +149,336 @@ long double expl(long double x)
x = 1.0 + 2.0 * x; x = 1.0 + 2.0 * x;
return scalbnl(x, k); return scalbnl(x, k);
} }
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile #include "libc/tinymath/freebsd.internal.h"
long double expl(long double x)
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2009-2013 Steven G. Kargl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Optimized by Bruce D. Evans.
*/
/*
* ld128 version of s_expl.c. See ../ld80/s_expl.c for most comments.
*/
/* XXX Prevent compilers from erroneously constant folding these: */
static const volatile long double
huge = 0x1p10000L,
tiny = 0x1p-10000L;
static const long double
twom10000 = 0x1p-10000L;
static const long double
/* log(2**16384 - 0.5) rounded towards zero: */
/* log(2**16384 - 0.5 + 1) rounded towards zero for expm1l() is the same: */
o_threshold = 11356.523406294143949491931077970763428L,
/* log(2**(-16381-64-1)) rounded towards zero: */
u_threshold = -11433.462743336297878837243843452621503L;
long double
expl(long double x)
{ {
return exp(x); union IEEEl2bits u;
long double hi, lo, t, twopk;
int k;
uint16_t hx, ix;
DOPRINT_START(&x);
/* Filter out exceptional cases. */
u.e = x;
hx = u.xbits.expsign;
ix = hx & 0x7fff;
if (ix >= BIAS + 13) { /* |x| >= 8192 or x is NaN */
if (ix == BIAS + LDBL_MAX_EXP) {
if (hx & 0x8000) /* x is -Inf or -NaN */
RETURNP(-1 / x);
RETURNP(x + x); /* x is +Inf or +NaN */
} }
if (x > o_threshold)
RETURNP(huge * huge);
if (x < u_threshold)
RETURNP(tiny * tiny);
} else if (ix < BIAS - 114) { /* |x| < 0x1p-114 */
RETURN2P(1, x); /* 1 with inexact iff x != 0 */
}
ENTERI();
twopk = 1;
__k_expl(x, &hi, &lo, &k);
t = SUM2P(hi, lo);
/* Scale by 2**k. */
/*
* XXX sparc64 multiplication was so slow that scalbnl() is faster,
* but performance on aarch64 and riscv hasn't yet been quantified.
*/
if (k >= LDBL_MIN_EXP) {
if (k == LDBL_MAX_EXP)
RETURNI(t * 2 * 0x1p16383L);
SET_LDBL_EXPSIGN(twopk, BIAS + k);
RETURNI(t * twopk);
} else {
SET_LDBL_EXPSIGN(twopk, BIAS + k + 10000);
RETURNI(t * twopk * twom10000);
}
}
/*
* Our T1 and T2 are chosen to be approximately the points where method
* A and method B have the same accuracy. Tang's T1 and T2 are the
* points where method A's accuracy changes by a full bit. For Tang,
* this drop in accuracy makes method A immediately less accurate than
* method B, but our larger INTERVALS makes method A 2 bits more
* accurate so it remains the most accurate method significantly
* closer to the origin despite losing the full bit in our extended
* range for it.
*
* Split the interval [T1, T2] into two intervals [T1, T3] and [T3, T2].
* Setting T3 to 0 would require the |x| < 0x1p-113 condition to appear
* in both subintervals, so set T3 = 2**-5, which places the condition
* into the [T1, T3] interval.
*
* XXX we now do this more to (partially) balance the number of terms
* in the C and D polys than to avoid checking the condition in both
* intervals.
*
* XXX these micro-optimizations are excessive.
*/
static const double
T1 = -0.1659, /* ~-30.625/128 * log(2) */
T2 = 0.1659, /* ~30.625/128 * log(2) */
T3 = 0.03125;
/*
* Domain [-0.1659, 0.03125], range ~[2.9134e-44, 1.8404e-37]:
* |(exp(x)-1-x-x**2/2)/x - p(x)| < 2**-122.03
*
* XXX none of the long double C or D coeffs except C10 is correctly printed.
* If you re-print their values in %.35Le format, the result is always
* different. For example, the last 2 digits in C3 should be 59, not 67.
* 67 is apparently from rounding an extra-precision value to 36 decimal
* places.
*/
static const long double
C3 = 1.66666666666666666666666666666666667e-1L,
C4 = 4.16666666666666666666666666666666645e-2L,
C5 = 8.33333333333333333333333333333371638e-3L,
C6 = 1.38888888888888888888888888891188658e-3L,
C7 = 1.98412698412698412698412697235950394e-4L,
C8 = 2.48015873015873015873015112487849040e-5L,
C9 = 2.75573192239858906525606685484412005e-6L,
C10 = 2.75573192239858906612966093057020362e-7L,
C11 = 2.50521083854417203619031960151253944e-8L,
C12 = 2.08767569878679576457272282566520649e-9L,
C13 = 1.60590438367252471783548748824255707e-10L;
/*
* XXX this has 1 more coeff than needed.
* XXX can start the double coeffs but not the double mults at C10.
* With my coeffs (C10-C17 double; s = best_s):
* Domain [-0.1659, 0.03125], range ~[-1.1976e-37, 1.1976e-37]:
* |(exp(x)-1-x-x**2/2)/x - p(x)| ~< 2**-122.65
*/
static const double
C14 = 1.1470745580491932e-11, /* 0x1.93974a81dae30p-37 */
C15 = 7.6471620181090468e-13, /* 0x1.ae7f3820adab1p-41 */
C16 = 4.7793721460260450e-14, /* 0x1.ae7cd18a18eacp-45 */
C17 = 2.8074757356658877e-15, /* 0x1.949992a1937d9p-49 */
C18 = 1.4760610323699476e-16; /* 0x1.545b43aabfbcdp-53 */
/*
* Domain [0.03125, 0.1659], range ~[-2.7676e-37, -1.0367e-38]:
* |(exp(x)-1-x-x**2/2)/x - p(x)| < 2**-121.44
*/
static const long double
D3 = 1.66666666666666666666666666666682245e-1L,
D4 = 4.16666666666666666666666666634228324e-2L,
D5 = 8.33333333333333333333333364022244481e-3L,
D6 = 1.38888888888888888888887138722762072e-3L,
D7 = 1.98412698412698412699085805424661471e-4L,
D8 = 2.48015873015873015687993712101479612e-5L,
D9 = 2.75573192239858944101036288338208042e-6L,
D10 = 2.75573192239853161148064676533754048e-7L,
D11 = 2.50521083855084570046480450935267433e-8L,
D12 = 2.08767569819738524488686318024854942e-9L,
D13 = 1.60590442297008495301927448122499313e-10L;
/*
* XXX this has 1 more coeff than needed.
* XXX can start the double coeffs but not the double mults at D11.
* With my coeffs (D11-D16 double):
* Domain [0.03125, 0.1659], range ~[-1.1980e-37, 1.1980e-37]:
* |(exp(x)-1-x-x**2/2)/x - p(x)| ~< 2**-122.65
*/
static const double
D14 = 1.1470726176204336e-11, /* 0x1.93971dc395d9ep-37 */
D15 = 7.6478532249581686e-13, /* 0x1.ae892e3D16fcep-41 */
D16 = 4.7628892832607741e-14, /* 0x1.ad00Dfe41feccp-45 */
D17 = 3.0524857220358650e-15; /* 0x1.D7e8d886Df921p-49 */
long double
expm1l(long double x)
{
union IEEEl2bits u, v;
long double hx2_hi, hx2_lo, q, r, r1, t, twomk, twopk, x_hi;
long double x_lo, x2;
double dr, dx, fn, r2;
int k, n, n2;
uint16_t hx, ix;
DOPRINT_START(&x);
/* Filter out exceptional cases. */
u.e = x;
hx = u.xbits.expsign;
ix = hx & 0x7fff;
if (ix >= BIAS + 7) { /* |x| >= 128 or x is NaN */
if (ix == BIAS + LDBL_MAX_EXP) {
if (hx & 0x8000) /* x is -Inf or -NaN */
RETURNP(-1 / x - 1);
RETURNP(x + x); /* x is +Inf or +NaN */
}
if (x > o_threshold)
RETURNP(huge * huge);
/*
* expm1l() never underflows, but it must avoid
* unrepresentable large negative exponents. We used a
* much smaller threshold for large |x| above than in
* expl() so as to handle not so large negative exponents
* in the same way as large ones here.
*/
if (hx & 0x8000) /* x <= -128 */
RETURN2P(tiny, -1); /* good for x < -114ln2 - eps */
}
ENTERI();
if (T1 < x && x < T2) {
x2 = x * x;
dx = x;
if (x < T3) {
if (ix < BIAS - 113) { /* |x| < 0x1p-113 */
/* x (rounded) with inexact if x != 0: */
RETURNPI(x == 0 ? x :
(0x1p200 * x + fabsl(x)) * 0x1p-200);
}
q = x * x2 * C3 + x2 * x2 * (C4 + x * (C5 + x * (C6 +
x * (C7 + x * (C8 + x * (C9 + x * (C10 +
x * (C11 + x * (C12 + x * (C13 +
dx * (C14 + dx * (C15 + dx * (C16 +
dx * (C17 + dx * C18))))))))))))));
} else {
q = x * x2 * D3 + x2 * x2 * (D4 + x * (D5 + x * (D6 +
x * (D7 + x * (D8 + x * (D9 + x * (D10 +
x * (D11 + x * (D12 + x * (D13 +
dx * (D14 + dx * (D15 + dx * (D16 +
dx * D17)))))))))))));
}
x_hi = (float)x;
x_lo = x - x_hi;
hx2_hi = x_hi * x_hi / 2;
hx2_lo = x_lo * (x + x_hi) / 2;
if (ix >= BIAS - 7)
RETURN2PI(hx2_hi + x_hi, hx2_lo + x_lo + q);
else
RETURN2PI(x, hx2_lo + q + hx2_hi);
}
/* Reduce x to (k*ln2 + endpoint[n2] + r1 + r2). */
fn = rnint((double)x * INV_L);
n = irint(fn);
n2 = (unsigned)n % INTERVALS;
k = n >> LOG2_INTERVALS;
r1 = x - fn * L1;
r2 = fn * -L2;
r = r1 + r2;
/* Prepare scale factor. */
v.e = 1;
v.xbits.expsign = BIAS + k;
twopk = v.e;
/*
* Evaluate lower terms of
* expl(endpoint[n2] + r1 + r2) = tbl[n2] * expl(r1 + r2).
*/
dr = r;
q = r2 + r * r * (A2 + r * (A3 + r * (A4 + r * (A5 + r * (A6 +
dr * (A7 + dr * (A8 + dr * (A9 + dr * A10))))))));
t = tbl[n2].lo + tbl[n2].hi;
if (k == 0) {
t = SUM2P(tbl[n2].hi - 1, tbl[n2].lo * (r1 + 1) + t * q +
tbl[n2].hi * r1);
RETURNI(t);
}
if (k == -1) {
t = SUM2P(tbl[n2].hi - 2, tbl[n2].lo * (r1 + 1) + t * q +
tbl[n2].hi * r1);
RETURNI(t / 2);
}
if (k < -7) {
t = SUM2P(tbl[n2].hi, tbl[n2].lo + t * (q + r1));
RETURNI(t * twopk - 1);
}
if (k > 2 * LDBL_MANT_DIG - 1) {
t = SUM2P(tbl[n2].hi, tbl[n2].lo + t * (q + r1));
if (k == LDBL_MAX_EXP)
RETURNI(t * 2 * 0x1p16383L - 1);
RETURNI(t * twopk - 1);
}
v.xbits.expsign = BIAS - k;
twomk = v.e;
if (k > LDBL_MANT_DIG - 1)
t = SUM2P(tbl[n2].hi, tbl[n2].lo - twomk + t * (q + r1));
else
t = SUM2P(tbl[n2].hi - twomk, tbl[n2].lo + t * (q + r1));
RETURNI(t * twopk);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -1,103 +1,152 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Optimized Routines FreeBSD lib/msun/src/s_expm1f.c
Copyright (c) 1999-2022, Arm Limited.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/hornerf.internal.h" #include "libc/tinymath/freebsd.internal.h"
#include "libc/tinymath/internal.h"
#include "third_party/libcxx/math.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Optimized Routines (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2022 ARM Limited\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
#define Shift (0x1.8p23f) static const float
#define InvLn2 (0x1.715476p+0f) one = 1.0,
#define Ln2hi (0x1.62e4p-1f) tiny = 1.0e-30,
#define Ln2lo (0x1.7f7d1cp-20f) o_threshold = 8.8721679688e+01,/* 0x42b17180 */
#define AbsMask (0x7fffffff) ln2_hi = 6.9313812256e-01,/* 0x3f317180 */
#define InfLimit \ ln2_lo = 9.0580006145e-06,/* 0x3717f7d1 */
(0x1.644716p6) /* Smallest value of x for which expm1(x) overflows. */ invln2 = 1.4426950216e+00,/* 0x3fb8aa3b */
#define NegLimit \ /*
(-0x1.9bbabcp+6) /* Largest value of x for which expm1(x) rounds to 1. */ * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
*/
Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
#define C(i) __expm1f_poly[i] static volatile float huge = 1.0e+30;
/* Generated using fpminimax, see tools/expm1f.sollya for details. */ /**
const float __expm1f_poly[] = {0x1.fffffep-2, 0x1.5554aep-3, 0x1.555736p-5, * Returns 𝑒^𝑥-𝟷.
0x1.12287cp-7, 0x1.6b55a2p-10}; */
/* Approximation for exp(x) - 1 using polynomial on a reduced interval.
The maximum error is 1.51 ULP:
expm1f(0x1.8baa96p-2) got 0x1.e2fb9p-2
want 0x1.e2fb94p-2. */
float float
expm1f(float x) expm1f(float x)
{ {
uint32_t ix = asuint (x); float y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
uint32_t ax = ix & AbsMask; int32_t k,xsb;
uint32_t hx;
/* Tiny: |x| < 0x1p-23. expm1(x) is closely approximated by x. GET_FLOAT_WORD(hx,x);
Inf: x == +Inf => expm1(x) = x. */ xsb = hx&0x80000000; /* sign bit of x */
if (ax <= 0x34000000 || (ix == 0x7f800000)) hx &= 0x7fffffff; /* high word of |x| */
return x;
/* +/-NaN. */ /* filter out huge and non-finite argument */
if (ax > 0x7f800000) if(hx >= 0x4195b844) { /* if |x|>=27*ln2 */
return __math_invalidf (x); if(hx >= 0x42b17218) { /* if |x|>=88.721... */
if(hx>0x7f800000)
if (x >= InfLimit) return x+x; /* NaN */
return __math_oflowf (0); if(hx==0x7f800000)
return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
if (x <= NegLimit || ix == 0xff800000) if(x > o_threshold) return huge*huge; /* overflow */
return -1; }
if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */
/* Reduce argument to smaller range: if(x+tiny<(float)0.0) /* raise inexact */
Let i = round(x / ln2) return tiny-one; /* return -1 */
and f = x - i * ln2, then f is in [-ln2/2, ln2/2]. }
exp(x) - 1 = 2^i * (expm1(f) + 1) - 1 }
where 2^i is exact because i is an integer. */
float j = fmaf (InvLn2, x, Shift) - Shift; /* argument reduction */
int32_t i = j; if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
float f = fmaf (j, -Ln2hi, x); if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */
f = fmaf (j, -Ln2lo, f); if(xsb==0)
{hi = x - ln2_hi; lo = ln2_lo; k = 1;}
/* Approximate expm1(f) using polynomial. else
Taylor expansion for expm1(x) has the form: {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
x + ax^2 + bx^3 + cx^4 .... } else {
So we calculate the polynomial P(f) = a + bf + cf^2 + ... k = invln2*x+((xsb==0)?(float)0.5:(float)-0.5);
and assemble the approximation expm1(f) ~= f + f^2 * P(f). */ t = k;
float p = fmaf (f * f, HORNER_4 (f, C), f); hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
/* Assemble the result, using a slight rearrangement to achieve acceptable lo = t*ln2_lo;
accuracy. }
expm1(x) ~= 2^i * (p + 1) - 1 STRICT_ASSIGN(float, x, hi - lo);
Let t = 2^(i - 1). */ c = (hi-x)-lo;
float t = ldexpf (0.5f, i); }
/* expm1(x) ~= 2 * (p * t + (t - 1/2)). */ else if(hx < 0x33000000) { /* when |x|<2**-25, return x */
return 2 * fmaf (p, t, t - 0.5f); t = huge+x; /* return x with inexact flags when x!=0 */
return x - (t-(huge+x));
}
else k = 0;
/* x is now in primary range */
hfx = (float)0.5*x;
hxs = x*hfx;
r1 = one+hxs*(Q1+hxs*Q2);
t = (float)3.0-r1*hfx;
e = hxs*((r1-t)/((float)6.0 - x*t));
if(k==0) return x - (x*e-hxs); /* c is 0 */
else {
SET_FLOAT_WORD(twopk,((uint32_t)(0x7f+k))<<23); /* 2^k */
e = (x*(e-c)-c);
e -= hxs;
if(k== -1) return (float)0.5*(x-e)-(float)0.5;
if(k==1) {
if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5));
else return one+(float)2.0*(x-e);
}
if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
y = one-(e-x);
if (k == 128) y = y*2.0F*0x1p127F;
else y = y*twopk;
return y-one;
}
t = one;
if(k<23) {
SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */
y = t-(e-x);
y = y*twopk;
} else {
SET_FLOAT_WORD(t,((0x7f-k)<<23)); /* 2^-k */
y = x-(e+t);
y += one;
y = y*twopk;
}
}
return y;
} }

View file

@ -1,41 +1,19 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/internal.h" #include "libc/tinymath/internal.h"
// clang-format off
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double expm1l(long double x) {
return expm1(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ /* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */
/* /*
@ -53,6 +31,7 @@ asm(".include \"libc/disclaimer.inc\"");
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/* /*
* Exponential function, minus 1 * Exponential function, minus 1
* Long double precision * Long double precision
@ -86,13 +65,6 @@ asm(".include \"libc/disclaimer.inc\"");
* IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double expm1l(long double x)
{
return expm1(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) /* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x)
-.5 ln 2 < x < .5 ln 2 -.5 ln 2 < x < .5 ln 2
Theoretical peak relative error = 3.4e-22 */ Theoretical peak relative error = 3.4e-22 */
@ -151,12 +123,11 @@ long double expm1l(long double x)
x = px * qx + (px - 1.0); x = px * qx + (px - 1.0);
return x; return x;
} }
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double expm1l(long double x) // see expl.c
{
return expm1(x);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -38,9 +38,12 @@ asm(".include \"libc/disclaimer.inc\"");
/** /**
* Returns largest integral value not greater than 𝑥. * Returns largest integral value not greater than 𝑥.
*/ */
long double floorl(long double x) { long double floorl(long double x)
{
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return floor(x); return floor(x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
static const long double toint = 1/LDBL_EPSILON; static const long double toint = 1/LDBL_EPSILON;
@ -63,6 +66,7 @@ long double floorl(long double x) {
if (y > 0) if (y > 0)
return x + y - 1; return x + y - 1;
return x + y; return x + y;
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -2,63 +2,65 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
Copyright © 2005-2014 Rich Felker, et al. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining Redistribution and use in source and binary forms, with or without
a copy of this software and associated documentation files (the modification, are permitted provided that the following conditions
"Software"), to deal in the Software without restriction, including are met:
without limitation the rights to use, copy, modify, merge, publish, 1. Redistributions of source code must retain the above copyright
distribute, sublicense, and/or sell copies of the Software, and to notice, this list of conditions and the following disclaimer.
permit persons to whom the Software is furnished to do so, subject to 2. Redistributions in binary form must reproduce the above copyright
the following conditions: notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
The above copyright notice and this permission notice shall be THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
included in all copies or substantial portions of the Software. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/ */
#include "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/ldshape.internal.h" #include "libc/tinymath/freebsd.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
/** /**
* Splits number normalized fraction and exponent. * Splits number normalized fraction and exponent.
*/ */
long double frexpl(long double x, int *e) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 frexpl(long double x, int *ex)
return frexp(x, e); {
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 union IEEEl2bits u;
union ldshape u = {x};
int ee = u.i.se & 0x7fff;
if (!ee) { u.e = x;
if (x) { switch (u.bits.exp) {
x = frexpl(x*0x1p120, e); case 0: /* 0 or subnormal */
*e -= 120; if ((u.bits.manl | u.bits.manh) == 0) {
} else *e = 0; *ex = 0;
return x; } else {
} else if (ee == 0x7fff) { u.e *= 0x1.0p514;
return x; *ex = u.bits.exp - 0x4200;
u.bits.exp = 0x3ffe;
} }
break;
*e = ee - 0x3ffe; case 0x7fff: /* infinity or NaN; value of *ex is unspecified */
u.i.se &= 0x8000; break;
u.i.se |= 0x3ffe; default: /* normal */
return u.f; *ex = u.bits.exp - 0x3ffe;
#else u.bits.exp = 0x3ffe;
#error "architecture unsupported" break;
#endif }
return (u.e);
} }

View file

@ -142,6 +142,9 @@ S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
/**
* Returns Bessel function of 𝑥 of first kind of order 0.
*/
double j0(double x) double j0(double x)
{ {
double z,r,s; double z,r,s;
@ -190,6 +193,9 @@ v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
/**
* Returns Bessel function of 𝑥 of second kind of order 0.
*/
double y0(double x) double y0(double x)
{ {
double z,u,v; double z,u,v;

View file

@ -144,6 +144,9 @@ s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
/**
* Returns Bessel function of 𝑥 of first kind of order 1.
*/
double j1(double x) double j1(double x)
{ {
double z,r,s; double z,r,s;
@ -183,6 +186,9 @@ static const double V0[5] = {
1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
}; };
/**
* Returns Bessel function of 𝑥 of second kind of order 1.
*/
double y1(double x) double y1(double x)
{ {
double z,u,v; double z,u,v;

View file

@ -72,6 +72,9 @@ asm(".include \"libc/disclaimer.inc\"");
static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */
/**
* Returns Bessel function of 𝑥 of first kind of order 𝑛.
*/
double jn(int n, double x) double jn(int n, double x)
{ {
uint32_t ix, lx; uint32_t ix, lx;
@ -245,7 +248,9 @@ double jn(int n, double x)
return sign ? -b : b; return sign ? -b : b;
} }
/**
* Returns Bessel function of 𝑥 of second kind of order 𝑛.
*/
double yn(int n, double x) double yn(int n, double x)
{ {
uint32_t ix, lx, ib; uint32_t ix, lx, ib;

View file

@ -49,6 +49,9 @@ asm(".include \"libc/disclaimer.inc\"");
* ==================================================== * ====================================================
*/ */
/**
* Returns Bessel function of 𝑥 of first kind of order 𝑛.
*/
float jnf(int n, float x) float jnf(int n, float x)
{ {
uint32_t ix; uint32_t ix;
@ -192,6 +195,9 @@ float jnf(int n, float x)
return sign ? -b : b; return sign ? -b : b;
} }
/**
* Returns Bessel function of 𝑥 of second kind of order 𝑛.
*/
float ynf(int n, float x) float ynf(int n, float x)
{ {
uint32_t ix, ib; uint32_t ix, ib;

View file

@ -35,8 +35,8 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/* clang-format off */
/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ /* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
/* /*
* ==================================================== * ====================================================

View file

@ -35,8 +35,8 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/* clang-format off */
/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ /* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */
/* /*
* ==================================================== * ====================================================

View file

@ -35,7 +35,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ /* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */
/* /*

View file

@ -2,8 +2,8 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc Optimized Routines
Copyright © 2005-2014 Rich Felker, et al. Copyright (c) 1999-2022, Arm Limited.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
@ -31,10 +31,10 @@
#include "libc/tinymath/log_data.internal.h" #include "libc/tinymath/log_data.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Double-precision math functions (MIT License)\\n\ Optimized Routines (MIT License)\\n\
Copyright 2018 ARM Limited\""); Copyright 2022 ARM Limited\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* /*
* Double-precision log(x) function. * Double-precision log(x) function.
@ -52,12 +52,6 @@ asm(".include \"libc/disclaimer.inc\"");
#define N (1 << LOG_TABLE_BITS) #define N (1 << LOG_TABLE_BITS)
#define OFF 0x3fe6000000000000 #define OFF 0x3fe6000000000000
/* Top 16 bits of a double. */
static inline uint32_t top16(double x)
{
return asuint64(x) >> 48;
}
/** /**
* Returns natural logarithm of 𝑥. * Returns natural logarithm of 𝑥.
*/ */
@ -69,7 +63,7 @@ double log(double x)
int k, i; int k, i;
ix = asuint64(x); ix = asuint64(x);
top = top16(x); top = ix >> 48;
#define LO asuint64(1.0 - 0x1p-4) #define LO asuint64(1.0 - 0x1p-4)
#define HI asuint64(1.0 + 0x1.09p-4) #define HI asuint64(1.0 + 0x1.09p-4)
if (UNLIKELY(ix - LO < HI - LO)) { if (UNLIKELY(ix - LO < HI - LO)) {

View file

@ -38,7 +38,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ /* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */
/* /*

View file

@ -29,7 +29,7 @@
#include "libc/tinymath/internal.h" #include "libc/tinymath/internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
@ -96,12 +96,6 @@ asm(".include \"libc/disclaimer.inc\"");
* log domain: x < 0; returns MINLOG * log domain: x < 0; returns MINLOG
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double log10l(long double x)
{
return log10(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) /* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
* 1/sqrt(2) <= x < sqrt(2) * 1/sqrt(2) <= x < sqrt(2)
* Theoretical peak relative error = 6.2e-22 * Theoretical peak relative error = 6.2e-22
@ -159,6 +153,8 @@ long double log10l(long double x)
{ {
#ifdef __x86__ #ifdef __x86__
// asm improves performance 41ns → 21ns
// measurement made on an intel core i9
long double lg2; long double lg2;
asm("fldlg2" : "=t"(lg2)); asm("fldlg2" : "=t"(lg2));
asm("fyl2x" asm("fyl2x"
@ -167,7 +163,11 @@ long double log10l(long double x)
: "st(1)"); : "st(1)");
return x; return x;
#else #elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return log10(x);
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
long double y, z; long double y, z;
int e; int e;
@ -234,15 +234,12 @@ done:
z += e * (L102A); z += e * (L102A);
return z; return z;
#endif /* __x86__ */
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double log10l(long double x) long double __log10lq(long double);
{ return __log10lq(x);
return log10(x);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif
}

View file

@ -34,7 +34,7 @@ asm(".ident\t\"\\n\\n\
Double-precision math functions (MIT License)\\n\ Double-precision math functions (MIT License)\\n\
Copyright 2018 ARM Limited\""); Copyright 2018 ARM Limited\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ /* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */
/* /*

View file

@ -30,7 +30,7 @@
#include "libc/tinymath/complex.internal.h" #include "libc/tinymath/complex.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
@ -88,12 +88,6 @@ asm(".include \"libc/disclaimer.inc\"");
* IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double log1pl(long double x)
{
return log1p(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) /* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x)
* 1/sqrt(2) <= x < sqrt(2) * 1/sqrt(2) <= x < sqrt(2)
* Theoretical peak relative error = 2.32e-20 * Theoretical peak relative error = 2.32e-20
@ -144,6 +138,12 @@ static const long double C2 = 1.4286068203094172321215E-6L;
*/ */
long double log1pl(long double xm1) long double log1pl(long double xm1)
{ {
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return log1p(xm1);
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
long double x, y, z; long double x, y, z;
int e; int e;
@ -208,13 +208,13 @@ long double log1pl(long double xm1)
z = z + x; z = z + x;
z = z + e * C1; z = z + e * C1;
return z; return z;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double log1pl(long double x) long double __log1plq(long double);
{ return __log1plq(xm1);
return log1p(x);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif
}

View file

@ -30,7 +30,7 @@
#include "libc/tinymath/complex.internal.h" #include "libc/tinymath/complex.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
@ -92,12 +92,6 @@ asm(".include \"libc/disclaimer.inc\"");
* [-10000, +10000]. * [-10000, +10000].
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double log2l(long double x)
{
return log2(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) /* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
* 1/sqrt(2) <= x < sqrt(2) * 1/sqrt(2) <= x < sqrt(2)
* Theoretical peak relative error = 6.2e-22 * Theoretical peak relative error = 6.2e-22
@ -144,8 +138,29 @@ static const long double S[4] = {
#define SQRTH 0.70710678118654752440L #define SQRTH 0.70710678118654752440L
/**
* Calculates log𝑥.
*/
long double log2l(long double x) long double log2l(long double x)
{ {
#ifdef __x86__
// asm improves performance 39ns → 21ns
// measurement made on an intel core i9
long double one;
asm("fld1" : "=t"(one));
asm("fyl2x"
: "=t"(x)
: "0"(x), "u"(one)
: "st(1)");
return x;
#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return log2(x);
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
long double y, z; long double y, z;
int e; int e;
@ -210,13 +225,13 @@ done:
z += x; z += x;
z += e; z += e;
return z; return z;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double log2l(long double x) long double __log2lq(long double);
{ return __log2lq(x);
return log2(x);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif
}

View file

@ -34,7 +34,7 @@ asm(".ident\t\"\\n\\n\
Optimized Routines (MIT License)\\n\ Optimized Routines (MIT License)\\n\
Copyright 2022 ARM Limited\""); Copyright 2022 ARM Limited\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* /*
* Single-precision log function. * Single-precision log function.
@ -57,6 +57,9 @@ Relative error: 1.957 * 2^-26 (before rounding.)
#define N (1 << LOGF_TABLE_BITS) #define N (1 << LOGF_TABLE_BITS)
#define OFF 0x3f330000 #define OFF 0x3f330000
/**
* Returns natural logarithm of 𝑥.
*/
float logf(float x) float logf(float x)
{ {
double_t z, r, r2, y, y0, invc, logc; double_t z, r, r2, y, y0, invc, logc;

View file

@ -29,13 +29,13 @@
#include "libc/tinymath/internal.h" #include "libc/tinymath/internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */ /* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */
/* /*
@ -91,12 +91,6 @@ asm(".include \"libc/disclaimer.inc\"");
* [-10000, +10000]. * [-10000, +10000].
*/ */
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double logl(long double x)
{
return log(x);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) /* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
* 1/sqrt(2) <= x < sqrt(2) * 1/sqrt(2) <= x < sqrt(2)
* Theoretical peak relative error = 2.32e-20 * Theoretical peak relative error = 2.32e-20
@ -142,8 +136,27 @@ static const long double C2 = 1.4286068203094172321215E-6L;
#define SQRTH 0.70710678118654752440L #define SQRTH 0.70710678118654752440L
/**
* Returns natural logarithm of 𝑥.
*/
long double logl(long double x) long double logl(long double x)
{ {
#ifdef __x86__
long double ln2;
asm("fldln2" : "=t"(ln2));
asm("fyl2x"
: "=t"(x)
: "0"(x), "u"(ln2)
: "st(1)");
return x;
#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return log(x);
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
long double y, z; long double y, z;
int e; int e;
@ -202,13 +215,13 @@ long double logl(long double x)
z = z + x; z = z + x;
z = z + e * C1; /* This sum has an error of 1/2 lsb. */ z = z + e * C1; /* This sum has an error of 1/2 lsb. */
return z; return z;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double logl(long double x) long double __loglq(long double);
{ return __loglq(x);
return log(x);
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif
}

741
libc/tinymath/loglq.c Normal file
View file

@ -0,0 +1,741 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Copyright (c) 2007-2013 Bruce D. Evans
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice unmodified, this list of conditions, and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libc/math.h"
#include "libc/tinymath/freebsd.internal.h"
#if LDBL_MANT_DIG == 113
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/**
* Implementation of the natural logarithm of x for 128-bit format.
*
* First decompose x into its base 2 representation:
*
* log(x) = log(X * 2**k), where X is in [1, 2)
* = log(X) + k * log(2).
*
* Let X = X_i + e, where X_i is the center of one of the intervals
* [-1.0/256, 1.0/256), [1.0/256, 3.0/256), .... [2.0-1.0/256, 2.0+1.0/256)
* and X is in this interval. Then
*
* log(X) = log(X_i + e)
* = log(X_i * (1 + e / X_i))
* = log(X_i) + log(1 + e / X_i).
*
* The values log(X_i) are tabulated below. Let d = e / X_i and use
*
* log(1 + d) = p(d)
*
* where p(d) = d - 0.5*d*d + ... is a special minimax polynomial of
* suitably high degree.
*
* To get sufficiently small roundoff errors, k * log(2), log(X_i), and
* sometimes (if |k| is not large) the first term in p(d) must be evaluated
* and added up in extra precision. Extra precision is not needed for the
* rest of p(d). In the worst case when k = 0 and log(X_i) is 0, the final
* error is controlled mainly by the error in the second term in p(d). The
* error in this term itself is at most 0.5 ulps from the d*d operation in
* it. The error in this term relative to the first term is thus at most
* 0.5 * |-0.5| * |d| < 1.0/1024 ulps. We aim for an accumulated error of
* at most twice this at the point of the final rounding step. Thus the
* final error should be at most 0.5 + 1.0/512 = 0.5020 ulps. Exhaustive
* testing of a float variant of this function showed a maximum final error
* of 0.5008 ulps. Non-exhaustive testing of a double variant of this
* function showed a maximum final error of 0.5078 ulps (near 1+1.0/256).
*
* We made the maximum of |d| (and thus the total relative error and the
* degree of p(d)) small by using a large number of intervals. Using
* centers of intervals instead of endpoints reduces this maximum by a
* factor of 2 for a given number of intervals. p(d) is special only
* in beginning with the Taylor coefficients 0 + 1*d, which tends to happen
* naturally. The most accurate minimax polynomial of a given degree might
* be different, but then we wouldn't want it since we would have to do
* extra work to avoid roundoff error (especially for P0*d instead of d).
*/
#ifndef NO_STRUCT_RETURN
#define STRUCT_RETURN
#endif
#if !defined(NO_UTAB) && !defined(NO_UTABL)
#define USE_UTAB
#endif
/*
* Domain [-0.005280, 0.004838], range ~[-1.1577e-37, 1.1582e-37]:
* |log(1 + d)/d - p(d)| < 2**-122.7
*/
static const long double
P2 = -0.5L,
P3 = 3.33333333333333333333333333333233795e-1L, /* 0x15555555555555555555555554d42.0p-114L */
P4 = -2.49999999999999999999999999941139296e-1L, /* -0x1ffffffffffffffffffffffdab14e.0p-115L */
P5 = 2.00000000000000000000000085468039943e-1L, /* 0x19999999999999999999a6d3567f4.0p-115L */
P6 = -1.66666666666666666666696142372698408e-1L, /* -0x15555555555555555567267a58e13.0p-115L */
P7 = 1.42857142857142857119522943477166120e-1L, /* 0x1249249249249248ed79a0ae434de.0p-115L */
P8 = -1.24999999999999994863289015033581301e-1L; /* -0x1fffffffffffffa13e91765e46140.0p-116L */
/* Double precision gives ~ 53 + log2(P9 * max(|d|)**8) ~= 120 bits. */
static const double
P9 = 1.1111111111111401e-1, /* 0x1c71c71c71c7ed.0p-56 */
P10 = -1.0000000000040135e-1, /* -0x199999999a0a92.0p-56 */
P11 = 9.0909090728136258e-2, /* 0x1745d173962111.0p-56 */
P12 = -8.3333318851855284e-2, /* -0x1555551722c7a3.0p-56 */
P13 = 7.6928634666404178e-2, /* 0x13b1985204a4ae.0p-56 */
P14 = -7.1626810078462499e-2; /* -0x12562276cdc5d0.0p-56 */
static volatile const double zero = 0;
#define INTERVALS 128
#define LOG2_INTERVALS 7
#define TSIZE (INTERVALS + 1)
#define G(i) (T[(i)].G)
#define F_hi(i) (T[(i)].F_hi)
#define F_lo(i) (T[(i)].F_lo)
#define ln2_hi F_hi(TSIZE - 1)
#define ln2_lo F_lo(TSIZE - 1)
#define E(i) (U[(i)].E)
#define H(i) (U[(i)].H)
static const struct {
float G; /* 1/(1 + i/128) rounded to 8/9 bits */
float F_hi; /* log(1 / G_i) rounded (see below) */
/* The compiler will insert 8 bytes of padding here. */
long double F_lo; /* next 113 bits for log(1 / G_i) */
} T[TSIZE] = {
/*
* ln2_hi and each F_hi(i) are rounded to a number of bits that
* makes F_hi(i) + dk*ln2_hi exact for all i and all dk.
*
* The last entry (for X just below 2) is used to define ln2_hi
* and ln2_lo, to ensure that F_hi(i) and F_lo(i) cancel exactly
* with dk*ln2_hi and dk*ln2_lo, respectively, when dk = -1.
* This is needed for accuracy when x is just below 1. (To avoid
* special cases, such x are "reduced" strangely to X just below
* 2 and dk = -1, and then the exact cancellation is needed
* because any the error from any non-exactness would be too
* large).
*
* The relevant range of dk is [-16445, 16383]. The maximum number
* of bits in F_hi(i) that works is very dependent on i but has
* a minimum of 93. We only need about 12 bits in F_hi(i) for
* it to provide enough extra precision.
*
* We round F_hi(i) to 24 bits so that it can have type float,
* mainly to minimize the size of the table. Using all 24 bits
* in a float for it automatically satisfies the above constraints.
*/
{0x800000.0p-23, 0, 0},
{0xfe0000.0p-24, 0x8080ac.0p-30, -0x14ee431dae6674afa0c4bfe16e8fd.0p-144L},
{0xfc0000.0p-24, 0x8102b3.0p-29, -0x1db29ee2d83717be918e1119642ab.0p-144L},
{0xfa0000.0p-24, 0xc24929.0p-29, 0x1191957d173697cf302cc9476f561.0p-143L},
{0xf80000.0p-24, 0x820aec.0p-28, 0x13ce8888e02e78eba9b1113bc1c18.0p-142L},
{0xf60000.0p-24, 0xa33577.0p-28, -0x17a4382ce6eb7bfa509bec8da5f22.0p-142L},
{0xf48000.0p-24, 0xbc42cb.0p-28, -0x172a21161a107674986dcdca6709c.0p-143L},
{0xf30000.0p-24, 0xd57797.0p-28, -0x1e09de07cb958897a3ea46e84abb3.0p-142L},
{0xf10000.0p-24, 0xf7518e.0p-28, 0x1ae1eec1b036c484993c549c4bf40.0p-151L},
{0xef0000.0p-24, 0x8cb9df.0p-27, -0x1d7355325d560d9e9ab3d6ebab580.0p-141L},
{0xed8000.0p-24, 0x999ec0.0p-27, -0x1f9f02d256d5037108f4ec21e48cd.0p-142L},
{0xec0000.0p-24, 0xa6988b.0p-27, -0x16fc0a9d12c17a70f7a684c596b12.0p-143L},
{0xea0000.0p-24, 0xb80698.0p-27, 0x15d581c1e8da99ded322fb08b8462.0p-141L},
{0xe80000.0p-24, 0xc99af3.0p-27, -0x1535b3ba8f150ae09996d7bb4653e.0p-143L},
{0xe70000.0p-24, 0xd273b2.0p-27, 0x163786f5251aefe0ded34c8318f52.0p-145L},
{0xe50000.0p-24, 0xe442c0.0p-27, 0x1bc4b2368e32d56699c1799a244d4.0p-144L},
{0xe38000.0p-24, 0xf1b83f.0p-27, 0x1c6090f684e6766abceccab1d7174.0p-141L},
{0xe20000.0p-24, 0xff448a.0p-27, -0x1890aa69ac9f4215f93936b709efb.0p-142L},
{0xe08000.0p-24, 0x8673f6.0p-26, 0x1b9985194b6affd511b534b72a28e.0p-140L},
{0xdf0000.0p-24, 0x8d515c.0p-26, -0x1dc08d61c6ef1d9b2ef7e68680598.0p-143L},
{0xdd8000.0p-24, 0x943a9e.0p-26, -0x1f72a2dac729b3f46662238a9425a.0p-142L},
{0xdc0000.0p-24, 0x9b2fe6.0p-26, -0x1fd4dfd3a0afb9691aed4d5e3df94.0p-140L},
{0xda8000.0p-24, 0xa2315d.0p-26, -0x11b26121629c46c186384993e1c93.0p-142L},
{0xd90000.0p-24, 0xa93f2f.0p-26, 0x1286d633e8e5697dc6a402a56fce1.0p-141L},
{0xd78000.0p-24, 0xb05988.0p-26, 0x16128eba9367707ebfa540e45350c.0p-144L},
{0xd60000.0p-24, 0xb78094.0p-26, 0x16ead577390d31ef0f4c9d43f79b2.0p-140L},
{0xd50000.0p-24, 0xbc4c6c.0p-26, 0x151131ccf7c7b75e7d900b521c48d.0p-141L},
{0xd38000.0p-24, 0xc3890a.0p-26, -0x115e2cd714bd06508aeb00d2ae3e9.0p-140L},
{0xd20000.0p-24, 0xcad2d7.0p-26, -0x1847f406ebd3af80485c2f409633c.0p-142L},
{0xd10000.0p-24, 0xcfb620.0p-26, 0x1c2259904d686581799fbce0b5f19.0p-141L},
{0xcf8000.0p-24, 0xd71653.0p-26, 0x1ece57a8d5ae54f550444ecf8b995.0p-140L},
{0xce0000.0p-24, 0xde843a.0p-26, -0x1f109d4bc4595412b5d2517aaac13.0p-141L},
{0xcd0000.0p-24, 0xe37fde.0p-26, 0x1bc03dc271a74d3a85b5b43c0e727.0p-141L},
{0xcb8000.0p-24, 0xeb050c.0p-26, -0x1bf2badc0df841a71b79dd5645b46.0p-145L},
{0xca0000.0p-24, 0xf29878.0p-26, -0x18efededd89fbe0bcfbe6d6db9f66.0p-147L},
{0xc90000.0p-24, 0xf7ad6f.0p-26, 0x1373ff977baa6911c7bafcb4d84fb.0p-141L},
{0xc80000.0p-24, 0xfcc8e3.0p-26, 0x196766f2fb328337cc050c6d83b22.0p-140L},
{0xc68000.0p-24, 0x823f30.0p-25, 0x19bd076f7c434e5fcf1a212e2a91e.0p-139L},
{0xc58000.0p-24, 0x84d52c.0p-25, -0x1a327257af0f465e5ecab5f2a6f81.0p-139L},
{0xc40000.0p-24, 0x88bc74.0p-25, 0x113f23def19c5a0fe396f40f1dda9.0p-141L},
{0xc30000.0p-24, 0x8b5ae6.0p-25, 0x1759f6e6b37de945a049a962e66c6.0p-139L},
{0xc20000.0p-24, 0x8dfccb.0p-25, 0x1ad35ca6ed5147bdb6ddcaf59c425.0p-141L},
{0xc10000.0p-24, 0x90a22b.0p-25, 0x1a1d71a87deba46bae9827221dc98.0p-139L},
{0xbf8000.0p-24, 0x94a0d8.0p-25, -0x139e5210c2b730e28aba001a9b5e0.0p-140L},
{0xbe8000.0p-24, 0x974f16.0p-25, -0x18f6ebcff3ed72e23e13431adc4a5.0p-141L},
{0xbd8000.0p-24, 0x9a00f1.0p-25, -0x1aa268be39aab7148e8d80caa10b7.0p-139L},
{0xbc8000.0p-24, 0x9cb672.0p-25, -0x14c8815839c5663663d15faed7771.0p-139L},
{0xbb0000.0p-24, 0xa0cda1.0p-25, 0x1eaf46390dbb2438273918db7df5c.0p-141L},
{0xba0000.0p-24, 0xa38c6e.0p-25, 0x138e20d831f698298adddd7f32686.0p-141L},
{0xb90000.0p-24, 0xa64f05.0p-25, -0x1e8d3c41123615b147a5d47bc208f.0p-142L},
{0xb80000.0p-24, 0xa91570.0p-25, 0x1ce28f5f3840b263acb4351104631.0p-140L},
{0xb70000.0p-24, 0xabdfbb.0p-25, -0x186e5c0a42423457e22d8c650b355.0p-139L},
{0xb60000.0p-24, 0xaeadef.0p-25, -0x14d41a0b2a08a465dc513b13f567d.0p-143L},
{0xb50000.0p-24, 0xb18018.0p-25, 0x16755892770633947ffe651e7352f.0p-139L},
{0xb40000.0p-24, 0xb45642.0p-25, -0x16395ebe59b15228bfe8798d10ff0.0p-142L},
{0xb30000.0p-24, 0xb73077.0p-25, 0x1abc65c8595f088b61a335f5b688c.0p-140L},
{0xb20000.0p-24, 0xba0ec4.0p-25, -0x1273089d3dad88e7d353e9967d548.0p-139L},
{0xb10000.0p-24, 0xbcf133.0p-25, 0x10f9f67b1f4bbf45de06ecebfaf6d.0p-139L},
{0xb00000.0p-24, 0xbfd7d2.0p-25, -0x109fab904864092b34edda19a831e.0p-140L},
{0xaf0000.0p-24, 0xc2c2ac.0p-25, -0x1124680aa43333221d8a9b475a6ba.0p-139L},
{0xae8000.0p-24, 0xc439b3.0p-25, -0x1f360cc4710fbfe24b633f4e8d84d.0p-140L},
{0xad8000.0p-24, 0xc72afd.0p-25, -0x132d91f21d89c89c45003fc5d7807.0p-140L},
{0xac8000.0p-24, 0xca20a2.0p-25, -0x16bf9b4d1f8da8002f2449e174504.0p-139L},
{0xab8000.0p-24, 0xcd1aae.0p-25, 0x19deb5ce6a6a8717d5626e16acc7d.0p-141L},
{0xaa8000.0p-24, 0xd0192f.0p-25, 0x1a29fb48f7d3ca87dabf351aa41f4.0p-139L},
{0xaa0000.0p-24, 0xd19a20.0p-25, 0x1127d3c6457f9d79f51dcc73014c9.0p-141L},
{0xa90000.0p-24, 0xd49f6a.0p-25, -0x1ba930e486a0ac42d1bf9199188e7.0p-141L},
{0xa80000.0p-24, 0xd7a94b.0p-25, -0x1b6e645f31549dd1160bcc45c7e2c.0p-139L},
{0xa70000.0p-24, 0xdab7d0.0p-25, 0x1118a425494b610665377f15625b6.0p-140L},
{0xa68000.0p-24, 0xdc40d5.0p-25, 0x1966f24d29d3a2d1b2176010478be.0p-140L},
{0xa58000.0p-24, 0xdf566d.0p-25, -0x1d8e52eb2248f0c95dd83626d7333.0p-142L},
{0xa48000.0p-24, 0xe270ce.0p-25, -0x1ee370f96e6b67ccb006a5b9890ea.0p-140L},
{0xa40000.0p-24, 0xe3ffce.0p-25, 0x1d155324911f56db28da4d629d00a.0p-140L},
{0xa30000.0p-24, 0xe72179.0p-25, -0x1fe6e2f2f867d8f4d60c713346641.0p-140L},
{0xa20000.0p-24, 0xea4812.0p-25, 0x1b7be9add7f4d3b3d406b6cbf3ce5.0p-140L},
{0xa18000.0p-24, 0xebdd3d.0p-25, 0x1b3cfb3f7511dd73692609040ccc2.0p-139L},
{0xa08000.0p-24, 0xef0b5b.0p-25, -0x1220de1f7301901b8ad85c25afd09.0p-139L},
{0xa00000.0p-24, 0xf0a451.0p-25, -0x176364c9ac81cc8a4dfb804de6867.0p-140L},
{0x9f0000.0p-24, 0xf3da16.0p-25, 0x1eed6b9aafac8d42f78d3e65d3727.0p-141L},
{0x9e8000.0p-24, 0xf576e9.0p-25, 0x1d593218675af269647b783d88999.0p-139L},
{0x9d8000.0p-24, 0xf8b47c.0p-25, -0x13e8eb7da053e063714615f7cc91d.0p-144L},
{0x9d0000.0p-24, 0xfa553f.0p-25, 0x1c063259bcade02951686d5373aec.0p-139L},
{0x9c0000.0p-24, 0xfd9ac5.0p-25, 0x1ef491085fa3c1649349630531502.0p-139L},
{0x9b8000.0p-24, 0xff3f8c.0p-25, 0x1d607a7c2b8c5320619fb9433d841.0p-139L},
{0x9a8000.0p-24, 0x814697.0p-24, -0x12ad3817004f3f0bdff99f932b273.0p-138L},
{0x9a0000.0p-24, 0x821b06.0p-24, -0x189fc53117f9e54e78103a2bc1767.0p-141L},
{0x990000.0p-24, 0x83c5f8.0p-24, 0x14cf15a048907b7d7f47ddb45c5a3.0p-139L},
{0x988000.0p-24, 0x849c7d.0p-24, 0x1cbb1d35fb82873b04a9af1dd692c.0p-138L},
{0x978000.0p-24, 0x864ba6.0p-24, 0x1128639b814f9b9770d8cb6573540.0p-138L},
{0x970000.0p-24, 0x87244c.0p-24, 0x184733853300f002e836dfd47bd41.0p-139L},
{0x968000.0p-24, 0x87fdaa.0p-24, 0x109d23aef77dd5cd7cc94306fb3ff.0p-140L},
{0x958000.0p-24, 0x89b293.0p-24, -0x1a81ef367a59de2b41eeebd550702.0p-138L},
{0x950000.0p-24, 0x8a8e20.0p-24, -0x121ad3dbb2f45275c917a30df4ac9.0p-138L},
{0x948000.0p-24, 0x8b6a6a.0p-24, -0x1cfb981628af71a89df4e6df2e93b.0p-139L},
{0x938000.0p-24, 0x8d253a.0p-24, -0x1d21730ea76cfdec367828734cae5.0p-139L},
{0x930000.0p-24, 0x8e03c2.0p-24, 0x135cc00e566f76b87333891e0dec4.0p-138L},
{0x928000.0p-24, 0x8ee30d.0p-24, -0x10fcb5df257a263e3bf446c6e3f69.0p-140L},
{0x918000.0p-24, 0x90a3ee.0p-24, -0x16e171b15433d723a4c7380a448d8.0p-139L},
{0x910000.0p-24, 0x918587.0p-24, -0x1d050da07f3236f330972da2a7a87.0p-139L},
{0x908000.0p-24, 0x9267e7.0p-24, 0x1be03669a5268d21148c6002becd3.0p-139L},
{0x8f8000.0p-24, 0x942f04.0p-24, 0x10b28e0e26c336af90e00533323ba.0p-139L},
{0x8f0000.0p-24, 0x9513c3.0p-24, 0x1a1d820da57cf2f105a89060046aa.0p-138L},
{0x8e8000.0p-24, 0x95f950.0p-24, -0x19ef8f13ae3cf162409d8ea99d4c0.0p-139L},
{0x8e0000.0p-24, 0x96dfab.0p-24, -0x109e417a6e507b9dc10dac743ad7a.0p-138L},
{0x8d0000.0p-24, 0x98aed2.0p-24, 0x10d01a2c5b0e97c4990b23d9ac1f5.0p-139L},
{0x8c8000.0p-24, 0x9997a2.0p-24, -0x1d6a50d4b61ea74540bdd2aa99a42.0p-138L},
{0x8c0000.0p-24, 0x9a8145.0p-24, 0x1b3b190b83f9527e6aba8f2d783c1.0p-138L},
{0x8b8000.0p-24, 0x9b6bbf.0p-24, 0x13a69fad7e7abe7ba81c664c107e0.0p-138L},
{0x8b0000.0p-24, 0x9c5711.0p-24, -0x11cd12316f576aad348ae79867223.0p-138L},
{0x8a8000.0p-24, 0x9d433b.0p-24, 0x1c95c444b807a246726b304ccae56.0p-139L},
{0x898000.0p-24, 0x9f1e22.0p-24, -0x1b9c224ea698c2f9b47466d6123fe.0p-139L},
{0x890000.0p-24, 0xa00ce1.0p-24, 0x125ca93186cf0f38b4619a2483399.0p-141L},
{0x888000.0p-24, 0xa0fc80.0p-24, -0x1ee38a7bc228b3597043be78eaf49.0p-139L},
{0x880000.0p-24, 0xa1ed00.0p-24, -0x1a0db876613d204147dc69a07a649.0p-138L},
{0x878000.0p-24, 0xa2de62.0p-24, 0x193224e8516c008d3602a7b41c6e8.0p-139L},
{0x870000.0p-24, 0xa3d0a9.0p-24, 0x1fa28b4d2541aca7d5844606b2421.0p-139L},
{0x868000.0p-24, 0xa4c3d6.0p-24, 0x1c1b5760fb4571acbcfb03f16daf4.0p-138L},
{0x858000.0p-24, 0xa6acea.0p-24, 0x1fed5d0f65949c0a345ad743ae1ae.0p-140L},
{0x850000.0p-24, 0xa7a2d4.0p-24, 0x1ad270c9d749362382a7688479e24.0p-140L},
{0x848000.0p-24, 0xa899ab.0p-24, 0x199ff15ce532661ea9643a3a2d378.0p-139L},
{0x840000.0p-24, 0xa99171.0p-24, 0x1a19e15ccc45d257530a682b80490.0p-139L},
{0x838000.0p-24, 0xaa8a28.0p-24, -0x121a14ec532b35ba3e1f868fd0b5e.0p-140L},
{0x830000.0p-24, 0xab83d1.0p-24, 0x1aee319980bff3303dd481779df69.0p-139L},
{0x828000.0p-24, 0xac7e6f.0p-24, -0x18ffd9e3900345a85d2d86161742e.0p-140L},
{0x820000.0p-24, 0xad7a03.0p-24, -0x1e4db102ce29f79b026b64b42caa1.0p-140L},
{0x818000.0p-24, 0xae768f.0p-24, 0x17c35c55a04a82ab19f77652d977a.0p-141L},
{0x810000.0p-24, 0xaf7415.0p-24, 0x1448324047019b48d7b98c1cf7234.0p-138L},
{0x808000.0p-24, 0xb07298.0p-24, -0x1750ee3915a197e9c7359dd94152f.0p-138L},
{0x800000.0p-24, 0xb17218.0p-24, -0x105c610ca86c3898cff81a12a17e2.0p-141L},
};
#ifdef USE_UTAB
static const struct {
float H; /* 1 + i/INTERVALS (exact) */
float E; /* H(i) * G(i) - 1 (exact) */
} U[TSIZE] = {
{0x800000.0p-23, 0},
{0x810000.0p-23, -0x800000.0p-37},
{0x820000.0p-23, -0x800000.0p-35},
{0x830000.0p-23, -0x900000.0p-34},
{0x840000.0p-23, -0x800000.0p-33},
{0x850000.0p-23, -0xc80000.0p-33},
{0x860000.0p-23, -0xa00000.0p-36},
{0x870000.0p-23, 0x940000.0p-33},
{0x880000.0p-23, 0x800000.0p-35},
{0x890000.0p-23, -0xc80000.0p-34},
{0x8a0000.0p-23, 0xe00000.0p-36},
{0x8b0000.0p-23, 0x900000.0p-33},
{0x8c0000.0p-23, -0x800000.0p-35},
{0x8d0000.0p-23, -0xe00000.0p-33},
{0x8e0000.0p-23, 0x880000.0p-33},
{0x8f0000.0p-23, -0xa80000.0p-34},
{0x900000.0p-23, -0x800000.0p-35},
{0x910000.0p-23, 0x800000.0p-37},
{0x920000.0p-23, 0x900000.0p-35},
{0x930000.0p-23, 0xd00000.0p-35},
{0x940000.0p-23, 0xe00000.0p-35},
{0x950000.0p-23, 0xc00000.0p-35},
{0x960000.0p-23, 0xe00000.0p-36},
{0x970000.0p-23, -0x800000.0p-38},
{0x980000.0p-23, -0xc00000.0p-35},
{0x990000.0p-23, -0xd00000.0p-34},
{0x9a0000.0p-23, 0x880000.0p-33},
{0x9b0000.0p-23, 0xe80000.0p-35},
{0x9c0000.0p-23, -0x800000.0p-35},
{0x9d0000.0p-23, 0xb40000.0p-33},
{0x9e0000.0p-23, 0x880000.0p-34},
{0x9f0000.0p-23, -0xe00000.0p-35},
{0xa00000.0p-23, 0x800000.0p-33},
{0xa10000.0p-23, -0x900000.0p-36},
{0xa20000.0p-23, -0xb00000.0p-33},
{0xa30000.0p-23, -0xa00000.0p-36},
{0xa40000.0p-23, 0x800000.0p-33},
{0xa50000.0p-23, -0xf80000.0p-35},
{0xa60000.0p-23, 0x880000.0p-34},
{0xa70000.0p-23, -0x900000.0p-33},
{0xa80000.0p-23, -0x800000.0p-35},
{0xa90000.0p-23, 0x900000.0p-34},
{0xaa0000.0p-23, 0xa80000.0p-33},
{0xab0000.0p-23, -0xac0000.0p-34},
{0xac0000.0p-23, -0x800000.0p-37},
{0xad0000.0p-23, 0xf80000.0p-35},
{0xae0000.0p-23, 0xf80000.0p-34},
{0xaf0000.0p-23, -0xac0000.0p-33},
{0xb00000.0p-23, -0x800000.0p-33},
{0xb10000.0p-23, -0xb80000.0p-34},
{0xb20000.0p-23, -0x800000.0p-34},
{0xb30000.0p-23, -0xb00000.0p-35},
{0xb40000.0p-23, -0x800000.0p-35},
{0xb50000.0p-23, -0xe00000.0p-36},
{0xb60000.0p-23, -0x800000.0p-35},
{0xb70000.0p-23, -0xb00000.0p-35},
{0xb80000.0p-23, -0x800000.0p-34},
{0xb90000.0p-23, -0xb80000.0p-34},
{0xba0000.0p-23, -0x800000.0p-33},
{0xbb0000.0p-23, -0xac0000.0p-33},
{0xbc0000.0p-23, 0x980000.0p-33},
{0xbd0000.0p-23, 0xbc0000.0p-34},
{0xbe0000.0p-23, 0xe00000.0p-36},
{0xbf0000.0p-23, -0xb80000.0p-35},
{0xc00000.0p-23, -0x800000.0p-33},
{0xc10000.0p-23, 0xa80000.0p-33},
{0xc20000.0p-23, 0x900000.0p-34},
{0xc30000.0p-23, -0x800000.0p-35},
{0xc40000.0p-23, -0x900000.0p-33},
{0xc50000.0p-23, 0x820000.0p-33},
{0xc60000.0p-23, 0x800000.0p-38},
{0xc70000.0p-23, -0x820000.0p-33},
{0xc80000.0p-23, 0x800000.0p-33},
{0xc90000.0p-23, -0xa00000.0p-36},
{0xca0000.0p-23, -0xb00000.0p-33},
{0xcb0000.0p-23, 0x840000.0p-34},
{0xcc0000.0p-23, -0xd00000.0p-34},
{0xcd0000.0p-23, 0x800000.0p-33},
{0xce0000.0p-23, -0xe00000.0p-35},
{0xcf0000.0p-23, 0xa60000.0p-33},
{0xd00000.0p-23, -0x800000.0p-35},
{0xd10000.0p-23, 0xb40000.0p-33},
{0xd20000.0p-23, -0x800000.0p-35},
{0xd30000.0p-23, 0xaa0000.0p-33},
{0xd40000.0p-23, -0xe00000.0p-35},
{0xd50000.0p-23, 0x880000.0p-33},
{0xd60000.0p-23, -0xd00000.0p-34},
{0xd70000.0p-23, 0x9c0000.0p-34},
{0xd80000.0p-23, -0xb00000.0p-33},
{0xd90000.0p-23, -0x800000.0p-38},
{0xda0000.0p-23, 0xa40000.0p-33},
{0xdb0000.0p-23, -0xdc0000.0p-34},
{0xdc0000.0p-23, 0xc00000.0p-35},
{0xdd0000.0p-23, 0xca0000.0p-33},
{0xde0000.0p-23, -0xb80000.0p-34},
{0xdf0000.0p-23, 0xd00000.0p-35},
{0xe00000.0p-23, 0xc00000.0p-33},
{0xe10000.0p-23, -0xf40000.0p-34},
{0xe20000.0p-23, 0x800000.0p-37},
{0xe30000.0p-23, 0x860000.0p-33},
{0xe40000.0p-23, -0xc80000.0p-33},
{0xe50000.0p-23, -0xa80000.0p-34},
{0xe60000.0p-23, 0xe00000.0p-36},
{0xe70000.0p-23, 0x880000.0p-33},
{0xe80000.0p-23, -0xe00000.0p-33},
{0xe90000.0p-23, -0xfc0000.0p-34},
{0xea0000.0p-23, -0x800000.0p-35},
{0xeb0000.0p-23, 0xe80000.0p-35},
{0xec0000.0p-23, 0x900000.0p-33},
{0xed0000.0p-23, 0xe20000.0p-33},
{0xee0000.0p-23, -0xac0000.0p-33},
{0xef0000.0p-23, -0xc80000.0p-34},
{0xf00000.0p-23, -0x800000.0p-35},
{0xf10000.0p-23, 0x800000.0p-35},
{0xf20000.0p-23, 0xb80000.0p-34},
{0xf30000.0p-23, 0x940000.0p-33},
{0xf40000.0p-23, 0xc80000.0p-33},
{0xf50000.0p-23, -0xf20000.0p-33},
{0xf60000.0p-23, -0xc80000.0p-33},
{0xf70000.0p-23, -0xa20000.0p-33},
{0xf80000.0p-23, -0x800000.0p-33},
{0xf90000.0p-23, -0xc40000.0p-34},
{0xfa0000.0p-23, -0x900000.0p-34},
{0xfb0000.0p-23, -0xc80000.0p-35},
{0xfc0000.0p-23, -0x800000.0p-35},
{0xfd0000.0p-23, -0x900000.0p-36},
{0xfe0000.0p-23, -0x800000.0p-37},
{0xff0000.0p-23, -0x800000.0p-39},
{0x800000.0p-22, 0},
};
#endif /* USE_UTAB */
#ifdef STRUCT_RETURN
#define RETURN1(rp, v) do { \
(rp)->hi = (v); \
(rp)->lo_set = 0; \
return; \
} while (0)
#define RETURN2(rp, h, l) do { \
(rp)->hi = (h); \
(rp)->lo = (l); \
(rp)->lo_set = 1; \
return; \
} while (0)
struct ld {
long double hi;
long double lo;
int lo_set;
};
#else
#define RETURN1(rp, v) RETURNF(v)
#define RETURN2(rp, h, l) RETURNI((h) + (l))
#endif
#ifdef STRUCT_RETURN
forceinline void
k_logl(long double x, struct ld *rp)
#else
long double
logl(long double x)
#endif
{
long double d, val_hi, val_lo;
double dd, dk;
uint64_t lx, llx;
int i, k;
uint16_t hx;
EXTRACT_LDBL128_WORDS(hx, lx, llx, x);
k = -16383;
#if 0 /* Hard to do efficiently. Don't do it until we support all modes. */
if (x == 1)
RETURN1(rp, 0); /* log(1) = +0 in all rounding modes */
#endif
if (hx == 0 || hx >= 0x8000) { /* zero, negative or subnormal? */
if (((hx & 0x7fff) | lx | llx) == 0)
RETURN1(rp, -1 / zero); /* log(+-0) = -Inf */
if (hx != 0)
/* log(neg or NaN) = qNaN: */
RETURN1(rp, (x - x) / zero);
x *= 0x1.0p113; /* subnormal; scale up x */
EXTRACT_LDBL128_WORDS(hx, lx, llx, x);
k = -16383 - 113;
} else if (hx >= 0x7fff)
RETURN1(rp, x + x); /* log(Inf or NaN) = Inf or qNaN */
#ifndef STRUCT_RETURN
ENTERI();
#endif
k += hx;
dk = k;
/* Scale x to be in [1, 2). */
SET_LDBL_EXPSIGN(x, 0x3fff);
/* 0 <= i <= INTERVALS: */
#define L2I (49 - LOG2_INTERVALS)
i = (lx + (1LL << (L2I - 2))) >> (L2I - 1);
/*
* -0.005280 < d < 0.004838. In particular, the infinite-
* precision |d| is <= 2**-7. Rounding of G(i) to 8 bits
* ensures that d is representable without extra precision for
* this bound on |d| (since when this calculation is expressed
* as x*G(i)-1, the multiplication needs as many extra bits as
* G(i) has and the subtraction cancels 8 bits). But for
* most i (107 cases out of 129), the infinite-precision |d|
* is <= 2**-8. G(i) is rounded to 9 bits for such i to give
* better accuracy (this works by improving the bound on |d|,
* which in turn allows rounding to 9 bits in more cases).
* This is only important when the original x is near 1 -- it
* lets us avoid using a special method to give the desired
* accuracy for such x.
*/
if (0)
d = x * G(i) - 1;
else {
#ifdef USE_UTAB
d = (x - H(i)) * G(i) + E(i);
#else
long double x_hi;
double x_lo;
/*
* Split x into x_hi + x_lo to calculate x*G(i)-1 exactly.
* G(i) has at most 9 bits, so the splitting point is not
* critical.
*/
INSERT_LDBL128_WORDS(x_hi, 0x3fff, lx,
llx & 0xffffffffff000000ULL);
x_lo = x - x_hi;
d = x_hi * G(i) - 1 + x_lo * G(i);
#endif
}
/*
* Our algorithm depends on exact cancellation of F_lo(i) and
* F_hi(i) with dk*ln_2_lo and dk*ln2_hi when k is -1 and i is
* at the end of the table. This and other technical complications
* make it difficult to avoid the double scaling in (dk*ln2) *
* log(base) for base != e without losing more accuracy and/or
* efficiency than is gained.
*/
/*
* Use double precision operations wherever possible, since
* long double operations are emulated and were very slow on
* the old sparc64 and unknown on the newer aarch64 and riscv
* machines. Also, don't try to improve parallelism by
* increasing the number of operations, since any parallelism
* on such machines is needed for the emulation. Horner's
* method is good for this, and is also good for accuracy.
* Horner's method doesn't handle the `lo' term well, either
* for efficiency or accuracy. However, for accuracy we
* evaluate d * d * P2 separately to take advantage of by P2
* being exact, and this gives a good place to sum the 'lo'
* term too.
*/
dd = (double)d;
val_lo = d * d * d * (P3 +
d * (P4 + d * (P5 + d * (P6 + d * (P7 + d * (P8 +
dd * (P9 + dd * (P10 + dd * (P11 + dd * (P12 + dd * (P13 +
dd * P14))))))))))) + (F_lo(i) + dk * ln2_lo) + d * d * P2;
val_hi = d;
#ifdef DEBUG
if (fetestexcept(FE_UNDERFLOW))
breakpoint();
#endif
_3sumF(val_hi, val_lo, F_hi(i) + dk * ln2_hi);
RETURN2(rp, val_hi, val_lo);
}
long double
__log1plq(long double x)
{
long double d, d_hi, f_lo, val_hi, val_lo;
long double f_hi, twopminusk;
double d_lo, dd, dk;
uint64_t lx, llx;
int i, k;
int16_t ax, hx;
DOPRINT_START(&x);
EXTRACT_LDBL128_WORDS(hx, lx, llx, x);
if (hx < 0x3fff) { /* x < 1, or x neg NaN */
ax = hx & 0x7fff;
if (ax >= 0x3fff) { /* x <= -1, or x neg NaN */
if (ax == 0x3fff && (lx | llx) == 0)
RETURNP(-1 / zero); /* log1p(-1) = -Inf */
/* log1p(x < 1, or x NaN) = qNaN: */
RETURNP((x - x) / (x - x));
}
if (ax <= 0x3f8d) { /* |x| < 2**-113 */
if ((int)x == 0)
RETURNP(x); /* x with inexact if x != 0 */
}
f_hi = 1;
f_lo = x;
} else if (hx >= 0x7fff) { /* x +Inf or non-neg NaN */
RETURNP(x + x); /* log1p(Inf or NaN) = Inf or qNaN */
} else if (hx < 0x40e1) { /* 1 <= x < 2**226 */
f_hi = x;
f_lo = 1;
} else { /* 2**226 <= x < +Inf */
f_hi = x;
f_lo = 0; /* avoid underflow of the P3 term */
}
ENTERI();
x = f_hi + f_lo;
f_lo = (f_hi - x) + f_lo;
EXTRACT_LDBL128_WORDS(hx, lx, llx, x);
k = -16383;
k += hx;
dk = k;
SET_LDBL_EXPSIGN(x, 0x3fff);
twopminusk = 1;
SET_LDBL_EXPSIGN(twopminusk, 0x7ffe - (hx & 0x7fff));
f_lo *= twopminusk;
i = (lx + (1LL << (L2I - 2))) >> (L2I - 1);
/*
* x*G(i)-1 (with a reduced x) can be represented exactly, as
* above, but now we need to evaluate the polynomial on d =
* (x+f_lo)*G(i)-1 and extra precision is needed for that.
* Since x+x_lo is a hi+lo decomposition and subtracting 1
* doesn't lose too many bits, an inexact calculation for
* f_lo*G(i) is good enough.
*/
if (0)
d_hi = x * G(i) - 1;
else {
#ifdef USE_UTAB
d_hi = (x - H(i)) * G(i) + E(i);
#else
long double x_hi;
double x_lo;
INSERT_LDBL128_WORDS(x_hi, 0x3fff, lx,
llx & 0xffffffffff000000ULL);
x_lo = x - x_hi;
d_hi = x_hi * G(i) - 1 + x_lo * G(i);
#endif
}
d_lo = f_lo * G(i);
/*
* This is _2sumF(d_hi, d_lo) inlined. The condition
* (d_hi == 0 || |d_hi| >= |d_lo|) for using _2sumF() is not
* always satisifed, so it is not clear that this works, but
* it works in practice. It works even if it gives a wrong
* normalized d_lo, since |d_lo| > |d_hi| implies that i is
* nonzero and d is tiny, so the F(i) term dominates d_lo.
* In float precision:
* (By exhaustive testing, the worst case is d_hi = 0x1.bp-25.
* And if d is only a little tinier than that, we would have
* another underflow problem for the P3 term; this is also ruled
* out by exhaustive testing.)
*/
d = d_hi + d_lo;
d_lo = d_hi - d + d_lo;
d_hi = d;
dd = (double)d;
val_lo = d * d * d * (P3 +
d * (P4 + d * (P5 + d * (P6 + d * (P7 + d * (P8 +
dd * (P9 + dd * (P10 + dd * (P11 + dd * (P12 + dd * (P13 +
dd * P14))))))))))) + (F_lo(i) + dk * ln2_lo + d_lo) + d * d * P2;
val_hi = d_hi;
#ifdef DEBUG
if (fetestexcept(FE_UNDERFLOW))
breakpoint();
#endif
_3sumF(val_hi, val_lo, F_hi(i) + dk * ln2_hi);
RETURN2PI(val_hi, val_lo);
}
#ifdef STRUCT_RETURN
long double
__loglq(long double x)
{
struct ld r;
ENTERI();
DOPRINT_START(&x);
k_logl(x, &r);
RETURNSPI(&r);
}
/*
* 29+113 bit decompositions. The bits are distributed so that the products
* of the hi terms are exact in double precision. The types are chosen so
* that the products of the hi terms are done in at least double precision,
* without any explicit conversions. More natural choices would require a
* slow long double precision multiplication.
*/
static const double
invln10_hi = 4.3429448176175356e-1, /* 0x1bcb7b15000000.0p-54 */
invln2_hi = 1.4426950402557850e0; /* 0x17154765000000.0p-52 */
static const long double
invln10_lo = 1.41498268538580090791605082294397000e-10L, /* 0x137287195355baaafad33dc323ee3.0p-145L */
invln2_lo = 6.33178418956604368501892137426645911e-10L, /* 0x15c17f0bbbe87fed0691d3e88eb57.0p-143L */
invln10_lo_plus_hi = invln10_lo + invln10_hi,
invln2_lo_plus_hi = invln2_lo + invln2_hi;
long double
__log10lq(long double x)
{
struct ld r;
long double hi, lo;
ENTERI();
DOPRINT_START(&x);
k_logl(x, &r);
if (!r.lo_set)
RETURNPI(r.hi);
_2sumF(r.hi, r.lo);
hi = (float)r.hi;
lo = r.lo + (r.hi - hi);
RETURN2PI(invln10_hi * hi,
invln10_lo_plus_hi * lo + invln10_lo * hi);
}
long double
__log2lq(long double x)
{
struct ld r;
long double hi, lo;
ENTERI();
DOPRINT_START(&x);
k_logl(x, &r);
if (!r.lo_set)
RETURNPI(r.hi);
_2sumF(r.hi, r.lo);
hi = (float)r.hi;
lo = r.lo + (r.hi - hi);
RETURN2PI(invln2_hi * hi,
invln2_lo_plus_hi * lo + invln2_lo * hi);
}
#endif /* STRUCT_RETURN */
#endif /* LDBL_MANT_DIG == 113 */

View file

@ -31,7 +31,7 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ /* clang-format off */

View file

@ -96,7 +96,7 @@ long double powl(long double x, long double y) {
#else #else
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
OpenBSD libm (MIT License)\\n\ OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\""); Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
@ -618,11 +618,448 @@ static long double powil(long double x, int nn)
return y; return y;
} }
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile #include "libc/tinymath/freebsd.internal.h"
long double powl(long double x, long double y)
asm(".ident\t\"\\n\\n\
OpenBSD libm (ISC License)\\n\
Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>\"");
/*-
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/*
* Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* powl(x,y) return x**y
*
* n
* Method: Let x = 2 * (1+f)
* 1. Compute and return log2(x) in two pieces:
* log2(x) = w1 + w2,
* where w1 has 113-53 = 60 bit trailing zeros.
* 2. Perform y*log2(x) = n+y' by simulating multi-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
*
*/
static const long double bp[] = {
1.0L,
1.5L,
};
/* log_2(1.5) */
static const long double dp_h[] = {
0.0,
5.8496250072115607565592654282227158546448E-1L
};
/* Low part of log_2(1.5) */
static const long double dp_l[] = {
0.0,
1.0579781240112554492329533686862998106046E-16L
};
static const long double zero = 0.0L,
one = 1.0L,
two = 2.0L,
two113 = 1.0384593717069655257060992658440192E34L,
huge = 1.0e3000L,
tiny = 1.0e-3000L;
/* 3/2 log x = 3 z + z^3 + z^3 (z^2 R(z^2))
z = (x-1)/(x+1)
1 <= x <= 1.25
Peak relative error 2.3e-37 */
static const long double LN[] =
{ {
return pow(x, y); -3.0779177200290054398792536829702930623200E1L,
6.5135778082209159921251824580292116201640E1L,
-4.6312921812152436921591152809994014413540E1L,
1.2510208195629420304615674658258363295208E1L,
-9.9266909031921425609179910128531667336670E-1L
};
static const long double LD[] =
{
-5.129862866715009066465422805058933131960E1L,
1.452015077564081884387441590064272782044E2L,
-1.524043275549860505277434040464085593165E2L,
7.236063513651544224319663428634139768808E1L,
-1.494198912340228235853027849917095580053E1L
/* 1.0E0 */
};
/* exp(x) = 1 + x - x / (1 - 2 / (x - x^2 R(x^2)))
0 <= x <= 0.5
Peak relative error 5.7e-38 */
static const long double PN[] =
{
5.081801691915377692446852383385968225675E8L,
9.360895299872484512023336636427675327355E6L,
4.213701282274196030811629773097579432957E4L,
5.201006511142748908655720086041570288182E1L,
9.088368420359444263703202925095675982530E-3L,
};
static const long double PD[] =
{
3.049081015149226615468111430031590411682E9L,
1.069833887183886839966085436512368982758E8L,
8.259257717868875207333991924545445705394E5L,
1.872583833284143212651746812884298360922E3L,
/* 1.0E0 */
};
static const long double
/* ln 2 */
lg2 = 6.9314718055994530941723212145817656807550E-1L,
lg2_h = 6.9314718055994528622676398299518041312695E-1L,
lg2_l = 2.3190468138462996154948554638754786504121E-17L,
ovt = 8.0085662595372944372e-0017L,
/* 2/(3*log(2)) */
cp = 9.6179669392597560490661645400126142495110E-1L,
cp_h = 9.6179669392597555432899980587535537779331E-1L,
cp_l = 5.0577616648125906047157785230014751039424E-17L;
long double
powl(long double x, long double y)
{
long double z, ax, z_h, z_l, p_h, p_l;
long double yy1, t1, t2, r, s, t, u, v, w;
long double s2, s_h, s_l, t_h, t_l;
int32_t i, j, k, yisint, n;
uint32_t ix, iy;
int32_t hx, hy;
ieee_quad_shape_type o, p, q;
p.value = x;
hx = p.parts32.mswhi;
ix = hx & 0x7fffffff;
q.value = y;
hy = q.parts32.mswhi;
iy = hy & 0x7fffffff;
/* y==zero: x**0 = 1 */
if ((iy | q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
return one;
/* 1.0**y = 1; -1.0**+-Inf = 1 */
if (x == one)
return one;
if (x == -1.0L && iy == 0x7fff0000
&& (q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
return one;
/* +-NaN return x+y */
if ((ix > 0x7fff0000)
|| ((ix == 0x7fff0000)
&& ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) != 0))
|| (iy > 0x7fff0000)
|| ((iy == 0x7fff0000)
&& ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) != 0)))
return nan_mix(x, y);
/* determine if y is an odd int when x < 0
* yisint = 0 ... y is not an integer
* yisint = 1 ... y is an odd int
* yisint = 2 ... y is an even int
*/
yisint = 0;
if (hx < 0)
{
if (iy >= 0x40700000) /* 2^113 */
yisint = 2; /* even integer y */
else if (iy >= 0x3fff0000) /* 1.0 */
{
if (floorl (y) == y)
{
z = 0.5 * y;
if (floorl (z) == z)
yisint = 2;
else
yisint = 1;
} }
}
}
/* special value of y */
if ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0)
{
if (iy == 0x7fff0000) /* y is +-inf */
{
if (((ix - 0x3fff0000) | p.parts32.mswlo | p.parts32.lswhi |
p.parts32.lswlo) == 0)
return y - y; /* +-1**inf is NaN */
else if (ix >= 0x3fff0000) /* (|x|>1)**+-inf = inf,0 */
return (hy >= 0) ? y : zero;
else /* (|x|<1)**-,+inf = inf,0 */
return (hy < 0) ? -y : zero;
}
if (iy == 0x3fff0000)
{ /* y is +-1 */
if (hy < 0)
return one / x;
else
return x;
}
if (hy == 0x40000000)
return x * x; /* y is 2 */
if (hy == 0x3ffe0000)
{ /* y is 0.5 */
if (hx >= 0) /* x >= +0 */
return sqrtl (x);
}
}
ax = fabsl (x);
/* special value of x */
if ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) == 0)
{
if (ix == 0x7fff0000 || ix == 0 || ix == 0x3fff0000)
{
z = ax; /*x is +-0,+-inf,+-1 */
if (hy < 0)
z = one / z; /* z = (1/|x|) */
if (hx < 0)
{
if (((ix - 0x3fff0000) | yisint) == 0)
{
z = (z - z) / (z - z); /* (-1)**non-int is NaN */
}
else if (yisint == 1)
z = -z; /* (x<0)**odd = -(|x|**odd) */
}
return z;
}
}
/* (x<0)**(non-int) is NaN */
if (((((uint32_t) hx >> 31) - 1) | yisint) == 0)
return (x - x) / (x - x);
/* |y| is huge.
2^-16495 = 1/2 of smallest representable value.
If (1 - 1/131072)^y underflows, y > 1.4986e9 */
if (iy > 0x401d654b)
{
/* if (1 - 2^-113)^y underflows, y > 1.1873e38 */
if (iy > 0x407d654b)
{
if (ix <= 0x3ffeffff)
return (hy < 0) ? huge * huge : tiny * tiny;
if (ix >= 0x3fff0000)
return (hy > 0) ? huge * huge : tiny * tiny;
}
/* over/underflow if x is not close to one */
if (ix < 0x3ffeffff)
return (hy < 0) ? huge * huge : tiny * tiny;
if (ix > 0x3fff0000)
return (hy > 0) ? huge * huge : tiny * tiny;
}
n = 0;
/* take care subnormal number */
if (ix < 0x00010000)
{
ax *= two113;
n -= 113;
o.value = ax;
ix = o.parts32.mswhi;
}
n += ((ix) >> 16) - 0x3fff;
j = ix & 0x0000ffff;
/* determine interval */
ix = j | 0x3fff0000; /* normalize ix */
if (j <= 0x3988)
k = 0; /* |x|<sqrt(3/2) */
else if (j < 0xbb67)
k = 1; /* |x|<sqrt(3) */
else
{
k = 0;
n += 1;
ix -= 0x00010000;
}
o.value = ax;
o.parts32.mswhi = ix;
ax = o.value;
/* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
u = ax - bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
v = one / (ax + bp[k]);
s = u * v;
s_h = s;
o.value = s_h;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
s_h = o.value;
/* t_h=ax+bp[k] High */
t_h = ax + bp[k];
o.value = t_h;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
t_h = o.value;
t_l = ax - (t_h - bp[k]);
s_l = v * ((u - s_h * t_h) - s_h * t_l);
/* compute log(ax) */
s2 = s * s;
u = LN[0] + s2 * (LN[1] + s2 * (LN[2] + s2 * (LN[3] + s2 * LN[4])));
v = LD[0] + s2 * (LD[1] + s2 * (LD[2] + s2 * (LD[3] + s2 * (LD[4] + s2))));
r = s2 * s2 * u / v;
r += s_l * (s_h + s);
s2 = s_h * s_h;
t_h = 3.0 + s2 + r;
o.value = t_h;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
t_h = o.value;
t_l = r - ((t_h - 3.0) - s2);
/* u+v = s*(1+...) */
u = s_h * t_h;
v = s_l * t_h + t_l * s;
/* 2/(3log2)*(s+...) */
p_h = u + v;
o.value = p_h;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
p_h = o.value;
p_l = v - (p_h - u);
z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */
z_l = cp_l * p_h + p_l * cp + dp_l[k];
/* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
t = (long double) n;
t1 = (((z_h + z_l) + dp_h[k]) + t);
o.value = t1;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
t1 = o.value;
t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
/* s (sign of result -ve**odd) = -1 else = 1 */
s = one;
if (((((uint32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
s = -one; /* (-ve)**(odd int) */
/* split up y into yy1+y2 and compute (yy1+y2)*(t1+t2) */
yy1 = y;
o.value = yy1;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
yy1 = o.value;
p_l = (y - yy1) * t1 + y * t2;
p_h = yy1 * t1;
z = p_l + p_h;
o.value = z;
j = o.parts32.mswhi;
if (j >= 0x400d0000) /* z >= 16384 */
{
/* if z > 16384 */
if (((j - 0x400d0000) | o.parts32.mswlo | o.parts32.lswhi |
o.parts32.lswlo) != 0)
return s * huge * huge; /* overflow */
else
{
if (p_l + ovt > z - p_h)
return s * huge * huge; /* overflow */
}
}
else if ((j & 0x7fffffff) >= 0x400d01b9) /* z <= -16495 */
{
/* z < -16495 */
if (((j - 0xc00d01bc) | o.parts32.mswlo | o.parts32.lswhi |
o.parts32.lswlo)
!= 0)
return s * tiny * tiny; /* underflow */
else
{
if (p_l <= z - p_h)
return s * tiny * tiny; /* underflow */
}
}
/* compute 2**(p_h+p_l) */
i = j & 0x7fffffff;
k = (i >> 16) - 0x3fff;
n = 0;
if (i > 0x3ffe0000)
{ /* if |z| > 0.5, set n = [z+0.5] */
n = floorl (z + 0.5L);
t = n;
p_h -= t;
}
t = p_l + p_h;
o.value = t;
o.parts32.lswlo = 0;
o.parts32.lswhi &= 0xf8000000;
t = o.value;
u = t * lg2_h;
v = (p_l - (t - p_h)) * lg2 + t * lg2_l;
z = u + v;
w = v - (z - u);
/* exp(z) */
t = z * z;
u = PN[0] + t * (PN[1] + t * (PN[2] + t * (PN[3] + t * PN[4])));
v = PD[0] + t * (PD[1] + t * (PD[2] + t * (PD[3] + t)));
t1 = z - t * u / v;
r = (z * t1) / (t1 - two) - (w + z * w);
z = one - (r - z);
o.value = z;
j = o.parts32.mswhi;
j += (n << 16);
if ((j >> 16) <= 0)
z = scalbnl (z, n); /* subnormal output */
else
{
o.parts32.mswhi = j;
z = o.value;
}
return s * z;
}
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -39,13 +39,17 @@ asm(".include \"libc/disclaimer.inc\"");
/** /**
* Returns sine and cosine of 𝑥. * Returns sine and cosine of 𝑥.
*/ */
void sincosl(long double x, long double *sin, long double *cos) { void sincosl(long double x, long double *sin, long double *cos)
{
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
double sind, cosd; double sind, cosd;
sincos(x, &sind, &cosd); sincos(x, &sind, &cosd);
*sin = sind; *sin = sind;
*cos = cosd; *cos = cosd;
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
union ldshape u = {x}; union ldshape u = {x};
unsigned n; unsigned n;
long double y[2], s, c; long double y[2], s, c;
@ -90,6 +94,7 @@ void sincosl(long double x, long double *sin, long double *cos) {
*cos = s; *cos = s;
break; break;
} }
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -2,79 +2,154 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/e_sinhl.c
Copyright © 2005-2014 Rich Felker, et al. Converted to long double by Bruce D. Evans
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/intrin/likely.h"
#include "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/expo.internal.h" #include "libc/tinymath/freebsd.internal.h"
#include "libc/tinymath/ldshape.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
#if LDBL_MAX_EXP != 0x4000
/* We also require the usual expsign encoding. */
#error "Unsupported long double format"
#endif
#define BIAS (LDBL_MAX_EXP - 1)
static const long double shuge = 0x1p16383L;
#if LDBL_MANT_DIG == 64
/*
* Domain [-1, 1], range ~[-6.6749e-22, 6.6749e-22]:
* |sinh(x)/x - s(x)| < 2**-70.3
*/
static const union IEEEl2bits
S3u = LD80C(0xaaaaaaaaaaaaaaaa, -3, 1.66666666666666666658e-1L);
#define S3 S3u.e
static const double
S5 = 8.3333333333333332e-3, /* 0x11111111111111.0p-59 */
S7 = 1.9841269841270074e-4, /* 0x1a01a01a01a070.0p-65 */
S9 = 2.7557319223873889e-6, /* 0x171de3a5565fe6.0p-71 */
S11 = 2.5052108406704084e-8, /* 0x1ae6456857530f.0p-78 */
S13 = 1.6059042748655297e-10, /* 0x161245fa910697.0p-85 */
S15 = 7.6470006914396920e-13, /* 0x1ae7ce4eff2792.0p-93 */
S17 = 2.8346142308424267e-15; /* 0x19882ce789ffc6.0p-101 */
#elif LDBL_MANT_DIG == 113
/*
* Domain [-1, 1], range ~[-2.9673e-36, 2.9673e-36]:
* |sinh(x)/x - s(x)| < 2**-118.0
*/
static const long double
S3 = 1.66666666666666666666666666666666033e-1L, /* 0x1555555555555555555555555553b.0p-115L */
S5 = 8.33333333333333333333333333337643193e-3L, /* 0x111111111111111111111111180f5.0p-119L */
S7 = 1.98412698412698412698412697391263199e-4L, /* 0x1a01a01a01a01a01a01a0176aad11.0p-125L */
S9 = 2.75573192239858906525574406205464218e-6L, /* 0x171de3a556c7338faac243aaa9592.0p-131L */
S11 = 2.50521083854417187749675637460977997e-8L, /* 0x1ae64567f544e38fe59b3380d7413.0p-138L */
S13 = 1.60590438368216146368737762431552702e-10L, /* 0x16124613a86d098059c7620850fc2.0p-145L */
S15 = 7.64716373181980539786802470969096440e-13L, /* 0x1ae7f3e733b814193af09ce723043.0p-153L */
S17 = 2.81145725434775409870584280722701574e-15L; /* 0x1952c77030c36898c3fd0b6dfc562.0p-161L */
static const double
S19= 8.2206352435411005e-18, /* 0x12f49b4662b86d.0p-109 */
S21= 1.9572943931418891e-20, /* 0x171b8f2fab9628.0p-118 */
S23 = 3.8679983530666939e-23, /* 0x17617002b73afc.0p-127 */
S25 = 6.5067867911512749e-26; /* 0x1423352626048a.0p-136 */
#else
#error "Unsupported long double format"
#endif /* LDBL_MANT_DIG == 64 */
/* log(2**16385 - 0.5) rounded up: */
static const float
o_threshold = 1.13572168e4; /* 0xb174de.0p-10 */
/** /**
* Returns hyperbolic sine of 𝑥. * Returns hyperbolic sine of 𝑥.
*
* sinh(x) = (exp(x) - 1/exp(x))/2
* = (exp(x)-1 + (exp(x)-1)/exp(x))/2
* = x + x^3/6 + o(x^5)
*/ */
long double sinhl(long double x) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 sinhl(long double x)
return sinh(x); {
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 long double hi,lo,x2,x4;
union ldshape u = {x}; #if LDBL_MANT_DIG == 113
unsigned ex = u.i.se & 0x7fff; double dx2;
long double h, t, absx; #endif
double s;
int16_t ix,jx;
h = 0.5; GET_LDBL_EXPSIGN(jx,x);
if (u.i.se & 0x8000) ix = jx&0x7fff;
h = -h;
/* |x| */
u.i.se = ex;
absx = u.f;
/* |x| < log(LDBL_MAX) */ /* x is INF or NaN */
if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) { if(ix>=0x7fff) return x+x;
t = expm1l(absx);
if (ex < 0x3fff) {
if (ex < 0x3fff-32)
return x;
return h*(2*t - t*t/(1+t));
}
return h*(t + t/(t+1));
}
/* |x| > log(LDBL_MAX) or nan */ ENTERI();
t = expl(0.5*absx);
return h*t*t; s = 1;
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 if (jx<0) s = -1;
// TODO: broken implementation to make things compile
return sinh(x); /* |x| < 64, return x, s(x), or accurate s*(exp(|x|)/2-1/exp(|x|)/2) */
#else if (ix<0x4005) { /* |x|<64 */
#error "architecture unsupported" if (ix<BIAS-(LDBL_MANT_DIG+1)/2) /* |x|<TINY */
if(shuge+x>1) RETURNI(x); /* sinh(tiny) = tiny with inexact */
if (ix<0x3fff) { /* |x|<1 */
x2 = x*x;
#if LDBL_MANT_DIG == 64
x4 = x2*x2;
RETURNI(((S17*x2 + S15)*x4 + (S13*x2 + S11))*(x2*x*x4*x4) +
((S9*x2 + S7)*x2 + S5)*(x2*x*x2) + S3*(x2*x) + x);
#elif LDBL_MANT_DIG == 113
dx2 = x2;
RETURNI(((((((((((S25*dx2 + S23)*dx2 +
S21)*x2 + S19)*x2 +
S17)*x2 + S15)*x2 + S13)*x2 + S11)*x2 + S9)*x2 + S7)*x2 +
S5)* (x2*x*x2) +
S3*(x2*x) + x);
#endif #endif
} }
k_hexpl(fabsl(x), &hi, &lo);
RETURNI(s*(lo - 0.25/(hi + lo) + hi));
}
/* |x| in [64, o_threshold], return correctly-overflowing s*exp(|x|)/2 */
if (fabsl(x) <= o_threshold)
RETURNI(s*hexpl(fabsl(x)));
/* |x| > o_threshold, sinh(x) overflow */
return x*shuge;
}

View file

@ -32,14 +32,10 @@ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
/** /**
* Returns hyperbolic tangent of 𝑥. * Returns hyperbolic tangent of 𝑥.
*
* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x))
* = (exp(2*x) - 1)/(exp(2*x) - 1 + 2)
* = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2)
*/ */
double tanh(double x) double tanh(double x)
{ {

View file

@ -2,79 +2,87 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/s_tanhf.c
Copyright © 2005-2014 Rich Felker, et al. Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/feval.internal.h" #include "libc/tinymath/freebsd.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
static const volatile float tiny = 1.0e-30;
static const float one=1.0, two=2.0, huge = 1.0e30;
/** /**
* Returns hyperbolic tangent of 𝑥. * Returns hyperbolic tangent of 𝑥.
*
* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x))
* = (exp(2*x) - 1)/(exp(2*x) - 1 + 2)
* = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2)
*/ */
float tanhf(float x) float
tanhf(float x)
{ {
union {float f; uint32_t i;} u = {.f = x}; float t,z;
uint32_t w; int32_t jx,ix;
int sign;
float t;
/* x = |x| */ GET_FLOAT_WORD(jx,x);
sign = u.i >> 31; ix = jx&0x7fffffff;
u.i &= 0x7fffffff;
x = u.f;
w = u.i;
if (w > 0x3f0c9f54) { /* x is INF or NaN */
/* |x| > log(3)/2 ~= 0.5493 or nan */ if(ix>=0x7f800000) {
if (w > 0x41200000) { if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
/* |x| > 10 */ else return one/x-one; /* tanh(NaN) = NaN */
t = 1 + 0/x; }
/* |x| < 9 */
if (ix < 0x41100000) { /* |x|<9 */
if (ix<0x39800000) { /* |x|<2**-12 */
if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */
}
if (ix>=0x3f800000) { /* |x|>=1 */
t = expm1f(two*fabsf(x));
z = one - two/(t+two);
} else { } else {
t = expm1f(2*x); t = expm1f(-two*fabsf(x));
t = 1 - 2/(t+2); z= -t/(t+two);
} }
} else if (w > 0x3e82c578) { /* |x| >= 9, return +-1 */
/* |x| > log(5/3)/2 ~= 0.2554 */
t = expm1f(2*x);
t = t/(t+2);
} else if (w >= 0x00800000) {
/* |x| >= 0x1p-126 */
t = expm1f(-2*x);
t = -t/(t+2);
} else { } else {
/* |x| is subnormal */ z = one - tiny; /* raise inexact flag */
fevalf(x*x);
t = x;
} }
return sign ? -t : t; return (jx>=0)? z: -z;
} }

View file

@ -2,83 +2,185 @@
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc FreeBSD lib/msun/src/s_tanhl.c
Copyright © 2005-2014 Rich Felker, et al. Converted to long double by Bruce D. Evans
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 1992-2023 The FreeBSD Project.
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Redistribution and use in source and binary forms, with or without
included in all copies or substantial portions of the Software. modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
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 "libc/intrin/likely.h"
#include "libc/math.h" #include "libc/math.h"
#include "libc/tinymath/ldshape.internal.h" #include "libc/tinymath/freebsd.internal.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\ FreeBSD libm (BSD-2 License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\""); Copyright (c) 2005-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.\"");
asm(".ident\t\"\\n\\n\
fdlibm (fdlibm license)\\n\
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
/* clang-format off */ // clang-format off
#if LDBL_MAX_EXP != 0x4000
/* We also require the usual expsign encoding. */
#error "Unsupported long double format"
#endif
#define BIAS (LDBL_MAX_EXP - 1)
static const volatile double tiny = 1.0e-300;
static const double one = 1.0;
#if LDBL_MANT_DIG == 64
/*
* Domain [-0.25, 0.25], range ~[-1.6304e-22, 1.6304e-22]:
* |tanh(x)/x - t(x)| < 2**-72.3
*/
static const union IEEEl2bits
T3u = LD80C(0xaaaaaaaaaaaaaa9f, -2, -3.33333333333333333017e-1L);
#define T3 T3u.e
static const double
T5 = 1.3333333333333314e-1, /* 0x1111111111110a.0p-55 */
T7 = -5.3968253968210485e-2, /* -0x1ba1ba1ba1a1a1.0p-57 */
T9 = 2.1869488531393817e-2, /* 0x1664f488172022.0p-58 */
T11 = -8.8632352345964591e-3, /* -0x1226e34bc138d5.0p-59 */
T13 = 3.5921169709993771e-3, /* 0x1d6d371d3e400f.0p-61 */
T15 = -1.4555786415756001e-3, /* -0x17d923aa63814d.0p-62 */
T17 = 5.8645267876296793e-4, /* 0x13378589b85aa7.0p-63 */
T19 = -2.1121033571392224e-4; /* -0x1baf0af80c4090.0p-65 */
#elif LDBL_MANT_DIG == 113
/*
* Domain [-0.25, 0.25], range ~[-2.4211e-37, 2.4211e-37]:
* |tanh(x)/x - t(x)| < 2**121.6
*/
static const long double
T3 = -3.33333333333333333333333333333332980e-1L, /* -0x1555555555555555555555555554e.0p-114L */
T5 = 1.33333333333333333333333333332707260e-1L, /* 0x1111111111111111111111110ab7b.0p-115L */
T7 = -5.39682539682539682539682535723482314e-2L, /* -0x1ba1ba1ba1ba1ba1ba1ba17b5fc98.0p-117L */
T9 = 2.18694885361552028218693591149061717e-2L, /* 0x1664f4882c10f9f32d6b1a12a25e5.0p-118L */
T11 = -8.86323552990219656883762347736381851e-3L, /* -0x1226e355e6c23c8f5a5a0f386cb4d.0p-119L */
T13 = 3.59212803657248101358314398220822722e-3L, /* 0x1d6d3d0e157ddfb403ad3637442c6.0p-121L */
T15 = -1.45583438705131796512568010348874662e-3L; /* -0x17da36452b75e150c44cc34253b34.0p-122L */
static const double
T17 = 5.9002744094556621e-4, /* 0x1355824803668e.0p-63 */
T19 = -2.3912911424260516e-4, /* -0x1f57d7734c8dde.0p-65 */
T21 = 9.6915379535512898e-5, /* 0x1967e18ad6a6ca.0p-66 */
T23 = -3.9278322983156353e-5, /* -0x1497d8e6b75729.0p-67 */
T25 = 1.5918887220143869e-5, /* 0x10b1319998cafa.0p-68 */
T27 = -6.4514295231630956e-6, /* -0x1b0f2b71b218eb.0p-70 */
T29 = 2.6120754043964365e-6, /* 0x15e963a3cf3a39.0p-71 */
T31 = -1.0407567231003314e-6, /* -0x1176041e656869.0p-72 */
T33 = 3.4744117554063574e-7; /* 0x1750fe732cab9c.0p-74 */
#endif /* LDBL_MANT_DIG == 64 */
static inline long double
divl(long double a, long double b, long double c, long double d,
long double e, long double f)
{
long double inv, r;
float fr, fw;
_2sumF(a, c);
b = b + c;
_2sumF(d, f);
e = e + f;
inv = 1 / (d + e);
r = (a + b) * inv;
fr = r;
r = fr;
fw = d + e;
e = d - fw + e;
d = fw;
r = r + (a - d * r + b - e * r) * inv;
return r;
}
/** /**
* Returns hyperbolic tangent of 𝑥. * Returns hyperbolic tangent of 𝑥.
*
* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x))
* = (exp(2*x) - 1)/(exp(2*x) - 1 + 2)
* = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2)
*/ */
long double tanhl(long double x) { long double
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 tanhl(long double x)
return tanh(x); {
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 long double hi,lo,s,x2,x4,z;
union ldshape u = {x}; #if LDBL_MANT_DIG == 113
unsigned ex = u.i.se & 0x7fff; double dx2;
unsigned sign = u.i.se & 0x8000; #endif
uint32_t w; int16_t jx,ix;
long double t;
/* x = |x| */ GET_LDBL_EXPSIGN(jx,x);
u.i.se = ex; ix = jx&0x7fff;
x = u.f;
w = u.i.m >> 32;
if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { /* x is INF or NaN */
/* |x| > log(3)/2 ~= 0.5493 or nan */ if(ix>=0x7fff) {
if (ex >= 0x3fff+5) { if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
/* |x| >= 32 */ else return one/x-one; /* tanh(NaN) = NaN */
t = 1 + 0/(x + 0x1p-120f);
} else {
t = expm1l(2*x);
t = 1 - 2/(t+2);
} }
} else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) {
/* |x| > log(5/3)/2 ~= 0.2554 */ ENTERI();
t = expm1l(2*x);
t = t/(t+2); /* |x| < 40 */
} else { if (ix < 0x4004 || fabsl(x) < 40) { /* |x|<40 */
/* |x| is small */ if (UNLIKELY(ix<BIAS-(LDBL_MANT_DIG+1)/2)) { /* |x|<TINY */
t = expm1l(-2*x); /* tanh(+-0) = +0; tanh(tiny) = tiny(-+) with inexact: */
t = -t/(t+2); return (x == 0 ? x : (0x1p200 * x - x) * 0x1p-200);
} }
return sign ? -t : t; if (ix<0x3ffd) { /* |x|<0.25 */
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 x2 = x*x;
// TODO: broken implementation to make things compile #if LDBL_MANT_DIG == 64
return tanh(x); x4 = x2*x2;
#else RETURNI(((T19*x2 + T17)*x4 + (T15*x2 + T13))*(x2*x*x2*x4*x4) +
#error "architecture unsupported" ((T11*x2 + T9)*x4 + (T7*x2 + T5))*(x2*x*x2) +
T3*(x2*x) + x);
#elif LDBL_MANT_DIG == 113
dx2 = x2;
long double q = ((((((((((((((T33*dx2 + T31)*dx2 + T29)*dx2 + T27)*dx2 +
T25)*x2 + T23)*x2 + T21)*x2 + T19)*x2 + T17)*x2 +
T15)*x2 + T13)*x2 + T11)*x2 + T9)*x2 + T7)*x2 + T5)*
(x2*x*x2);
RETURNI(q + T3*(x2*x) + x);
#endif #endif
} }
k_hexpl(2*fabsl(x), &hi, &lo);
if (ix<0x4001 && fabsl(x) < 1.5) /* |x|<1.5 */
z = divl(hi, lo, -0.5, hi, lo, 0.5);
else
z = one - one/(lo+0.5+hi);
/* |x| >= 40, return +-1 */
} else {
z = one - tiny; /* raise inexact flag */
}
s = 1;
if (jx<0) s = -1;
RETURNI(s*z);
}

View file

@ -36,10 +36,17 @@ Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
long double tanl(long double x) { /**
* Returns tangent of x.
*/
long double tanl(long double x)
{
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return tan(x); return tan(x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
union ldshape u = {x}; union ldshape u = {x};
long double y[2]; long double y[2];
unsigned n; unsigned n;
@ -57,6 +64,7 @@ long double tanl(long double x) {
} }
n = __rem_pio2l(x, y); n = __rem_pio2l(x, y);
return __tanl(y[0], y[1], n&1); return __tanl(y[0], y[1], n&1);
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -55,6 +55,11 @@ o/$(MODE)/libc/tinymath/lroundl.o : private \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-fno-builtin -fno-builtin
o/$(MODE)/libc/tinymath/expl.o \
o/$(MODE)/libc/tinymath/loglq.o: private \
OVERRIDE_CFLAGS += \
-ffunction-sections
LIBC_TINYMATH_LIBS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x))) LIBC_TINYMATH_LIBS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x)))
LIBC_TINYMATH_HDRS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x)_HDRS)) LIBC_TINYMATH_HDRS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x)_HDRS))
LIBC_TINYMATH_SRCS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x)_SRCS)) LIBC_TINYMATH_SRCS = $(foreach x,$(LIBC_TINYMATH_ARTIFACTS),$($(x)_SRCS))

View file

@ -35,9 +35,15 @@ Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // clang-format off
long double truncl(long double x) { /**
* Rounds to integer, towards zero.
*/
long double truncl(long double x)
{
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return trunc(x); return trunc(x);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
static const long double toint = 1/LDBL_EPSILON; static const long double toint = 1/LDBL_EPSILON;
@ -60,6 +66,7 @@ long double truncl(long double x) {
y -= 1; y -= 1;
x += y; x += y;
return s ? -x : x; return s ? -x : x;
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif #endif

View file

@ -22,12 +22,18 @@
#include "third_party/gdtoa/gdtoa.h" #include "third_party/gdtoa/gdtoa.h"
/** /**
* Converts double to string the easy way. * Converts long double to string the easy way.
* *
* @return string that needs to be free'd * @return string that needs to be free'd
*/ */
char *xdtoal(long double d) { char *xdtoal(long double d) {
char *p = xmalloc(32); char *p;
#if LDBL_MANT_DIG == 113
p = xmalloc(64);
g_Qfmt_p(p, &d, 16, 64, NIK(2, 0, 0));
#else
p = xmalloc(32);
g_xfmt_p(p, &d, 16, 32, NIK(2, 0, 0)); g_xfmt_p(p, &d, 16, 32, NIK(2, 0, 0));
#endif
return p; return p;
} }

View file

@ -21,8 +21,8 @@
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/stdio/rand.h"
#include "libc/runtime/buffer.internal.h" #include "libc/runtime/buffer.internal.h"
#include "libc/stdio/rand.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -644,13 +644,9 @@ BENCH(palandprintf, bench) {
EZBENCH2("23 %x", donothing, Format("%x", VEIL("r", 23))); EZBENCH2("23 %x", donothing, Format("%x", VEIL("r", 23)));
EZBENCH2("23 %d", donothing, Format("%d", VEIL("r", 23))); EZBENCH2("23 %d", donothing, Format("%d", VEIL("r", 23)));
EZBENCH2("%f M_PI", donothing, Format("%f", VEIL("x", M_PI))); EZBENCH2("%f M_PI", donothing, Format("%f", VEIL("x", M_PI)));
EZBENCH2("%Lf M_PI", donothing, Format("%Lf", VEIL("t", M_PI)));
EZBENCH2("%g M_PI", donothing, Format("%g", VEIL("x", M_PI))); EZBENCH2("%g M_PI", donothing, Format("%g", VEIL("x", M_PI)));
EZBENCH2("%Lg M_PI", donothing, Format("%Lg", VEIL("t", M_PI)));
EZBENCH2("%a M_PI", donothing, Format("%a", VEIL("x", M_PI))); EZBENCH2("%a M_PI", donothing, Format("%a", VEIL("x", M_PI)));
EZBENCH2("%La M_PI", donothing, Format("%La", VEIL("t", M_PI)));
EZBENCH2("%e M_PI", donothing, Format("%e", VEIL("x", M_PI))); EZBENCH2("%e M_PI", donothing, Format("%e", VEIL("x", M_PI)));
EZBENCH2("%Le M_PI", donothing, Format("%Le", VEIL("t", M_PI)));
EZBENCH2("ULONG_MAX %lo", donothing, Format("%lo", VEIL("r", ULONG_MAX))); EZBENCH2("ULONG_MAX %lo", donothing, Format("%lo", VEIL("r", ULONG_MAX)));
EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN))); EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN)));
EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN))); EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN)));
@ -662,4 +658,10 @@ BENCH(palandprintf, bench) {
EZBENCH2("INT128_MIN %jjx", donothing, Format("%jjx", INT128_MIN)); EZBENCH2("INT128_MIN %jjx", donothing, Format("%jjx", INT128_MIN));
EZBENCH2("int64toarray 23", donothing, FormatInt64(buffer, 23)); EZBENCH2("int64toarray 23", donothing, FormatInt64(buffer, 23));
EZBENCH2("int64toarray min", donothing, FormatInt64(buffer, INT_MIN)); EZBENCH2("int64toarray min", donothing, FormatInt64(buffer, INT_MIN));
#ifdef __x86__
EZBENCH2("%Lf M_PI", donothing, Format("%Lf", VEIL("t", M_PI)));
EZBENCH2("%Lg M_PI", donothing, Format("%Lg", VEIL("t", M_PI)));
EZBENCH2("%La M_PI", donothing, Format("%La", VEIL("t", M_PI)));
EZBENCH2("%Le M_PI", donothing, Format("%Le", VEIL("t", M_PI)));
#endif
} }

View file

@ -24,6 +24,7 @@
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#ifdef __x86_64__
int StackOverflow(int f(), int n) { int StackOverflow(int f(), int n) {
if (n < INT_MAX) { if (n < INT_MAX) {
@ -131,3 +132,5 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
} }
#endif /* __x86_64__ */

View file

@ -40,6 +40,7 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/xasprintf.h" #include "libc/x/xasprintf.h"
#include "net/http/escape.h" #include "net/http/escape.h"
#ifdef __x86_64__
STATIC_YOINK("backtrace.com"); STATIC_YOINK("backtrace.com");
STATIC_YOINK("backtrace.com.dbg"); STATIC_YOINK("backtrace.com.dbg");
@ -303,7 +304,7 @@ TEST(ShowCrashReports, testDivideByZero) {
ASSERT_NE(-1, wait(&ws)); ASSERT_NE(-1, wait(&ws));
EXPECT_TRUE(WIFEXITED(ws)); EXPECT_TRUE(WIFEXITED(ws));
assert(128 + SIGFPE == WEXITSTATUS(ws) || 77 == WEXITSTATUS(ws)); assert(128 + SIGFPE == WEXITSTATUS(ws) || 77 == WEXITSTATUS(ws));
/* NULL is stopgap until we can copy symbol tablces into binary */ /* NULL is stopgap until we can copy symbol tables into binary */
#ifdef __FNO_OMIT_FRAME_POINTER__ #ifdef __FNO_OMIT_FRAME_POINTER__
if (!OutputHasSymbol(output, "FpuCrash")) { if (!OutputHasSymbol(output, "FpuCrash")) {
fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n", fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n",
@ -706,3 +707,5 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
#endif #endif
free(output); free(output);
} }
#endif /* __x86_64__ */

View file

@ -17,11 +17,11 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/nexgen32e.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -29,6 +29,8 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/thread/spawn.h" #include "libc/thread/spawn.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#ifdef __x86_64__
// TODO(jart): get garbage collector working properly on aarch64
#define GC(x) _defer(Free, x) #define GC(x) _defer(Free, x)
@ -136,3 +138,5 @@ BENCH(gc, bench) {
EZBENCH2("gc(malloc(16))", donothing, F1p()); EZBENCH2("gc(malloc(16))", donothing, F1p());
EZBENCH2("free(malloc(16))", donothing, F2p()); EZBENCH2("free(malloc(16))", donothing, F2p());
} }
#endif /* __x86_64__ */

View file

@ -1,6 +1,8 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ #───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
ifeq ($(ARCH), x86_64)
o/$(MODE)/test/libc/release/cosmopolitan.zip: private .UNSANDBOXED = 1 o/$(MODE)/test/libc/release/cosmopolitan.zip: private .UNSANDBOXED = 1
o/$(MODE)/test/libc/release/cosmopolitan.zip: \ o/$(MODE)/test/libc/release/cosmopolitan.zip: \
o/cosmopolitan.h \ o/cosmopolitan.h \
@ -194,3 +196,8 @@ o/$(MODE)/test/libc/release: \
o/$(MODE)/test/libc/release/smokecxx.com.runs \ o/$(MODE)/test/libc/release/smokecxx.com.runs \
o/$(MODE)/test/libc/release/smokeansi.com \ o/$(MODE)/test/libc/release/smokeansi.com \
o/$(MODE)/test/libc/release/smokeansi.com.runs o/$(MODE)/test/libc/release/smokeansi.com.runs
endif
.PHONY: o/$(MODE)/test/libc/release
o/$(MODE)/test/libc/release:

View file

@ -24,11 +24,12 @@
#include "libc/intrin/fsgsbase.h" #include "libc/intrin/fsgsbase.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/segmentation.h" #include "libc/intrin/segmentation.h"
#include "libc/thread/tls.h"
#include "libc/nt/version.h" #include "libc/nt/version.h"
#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
void SetUpOnce(void) { void SetUpOnce(void) {
__tls_enabled = false; __tls_enabled = false;
@ -126,3 +127,5 @@ TEST(fsgsbase, gs) {
TriggerSignal(); TriggerSignal();
ASSERT_EQ(0xdeadbeef, gs((int64_t *)0)); ASSERT_EQ(0xdeadbeef, gs((int64_t *)0));
} }
#endif /* __x86_64__ */

View file

@ -52,6 +52,8 @@ TEST(sbrk, underflowsEnd_returnsEinval) {
ASSERT_SYS(EINVAL, MAP_FAILED, sbrk(-GUARDSIZE)); ASSERT_SYS(EINVAL, MAP_FAILED, sbrk(-GUARDSIZE));
} }
#ifndef __aarch64__
// not sure if qemu-aarch64 supports this
TEST(sbrk, giantDelta_returnsEnomem) { TEST(sbrk, giantDelta_returnsEnomem) {
if (IsXnu()) return; // mmap polyfills this but brk doesn't right now if (IsXnu()) return; // mmap polyfills this but brk doesn't right now
if (IsWsl1()) return; // WSL1 setrlimit() is busted if (IsWsl1()) return; // WSL1 setrlimit() is busted
@ -61,6 +63,7 @@ TEST(sbrk, giantDelta_returnsEnomem) {
ASSERT_SYS(ENOMEM, MAP_FAILED, sbrk(1024 * 1024 * 4)); ASSERT_SYS(ENOMEM, MAP_FAILED, sbrk(1024 * 1024 * 4));
EXITS(0); EXITS(0);
} }
#endif
TEST(sbrk, overlapsExistingMapping_failsWithEexist) { TEST(sbrk, overlapsExistingMapping_failsWithEexist) {
char *p = (char *)ROUNDUP((intptr_t)_end, FRAMESIZE); char *p = (char *)ROUNDUP((intptr_t)_end, FRAMESIZE);

View file

@ -95,25 +95,25 @@ atomic_int sysbarrier;
int CloneTestSys(void *arg, int tid) { int CloneTestSys(void *arg, int tid) {
int i, id = (intptr_t)arg; int i, id = (intptr_t)arg;
CheckStackIsAligned(); CheckStackIsAligned();
while (!sysbarrier) asm("pause"); while (!sysbarrier) donothing;
for (i = 0; i < 20; ++i) { for (i = 0; i < 20; ++i) {
switch (id % 3) { switch (id % 3) {
case 0: case 0:
errno = 123; errno = 123;
open(0, 0); open(0, 0);
asm("pause"); donothing;
ASSERT_EQ(EFAULT, errno); ASSERT_EQ(EFAULT, errno);
break; break;
case 1: case 1:
errno = 123; errno = 123;
dup(-1); dup(-1);
asm("pause"); donothing;
ASSERT_EQ(EBADF, errno); ASSERT_EQ(EBADF, errno);
break; break;
case 2: case 2:
errno = 123; errno = 123;
dup3(0, 0, 0); dup3(0, 0, 0);
asm("pause"); donothing;
ASSERT_EQ(EINVAL, errno); ASSERT_EQ(EINVAL, errno);
break; break;
default: default:

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pushpop.h" #include "libc/intrin/pushpop.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
@ -95,6 +96,5 @@ TEST(grow, testOverflow_returnsFalseAndDoesNotFree) {
EXPECT_EQ(1, p[0]); EXPECT_EQ(1, p[0]);
EXPECT_EQ(2, p[1]); EXPECT_EQ(2, p[1]);
EXPECT_EQ(3, p[2]); EXPECT_EQ(3, p[2]);
free(p);
} }
} }

Some files were not shown because too many files have changed in this diff Show more