diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..61e0467 --- /dev/null +++ b/.clang-format @@ -0,0 +1,14 @@ +--- +Language: Cpp +BasedOnStyle: WebKit +SpaceAfterTemplateKeyword: false +AlignEscapedNewlines: Left +AlignTrailingComments: true +BreakBeforeInheritanceComma: true +BreakConstructorInitializers: BeforeComma +IndentPPDirectives: AfterHash +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +NamespaceIndentation: None +QualifierAlignment: Right diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf4cd05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +build/ +src/openlibm/*.o +src/openlibm/*~ +src/openlibm/*.a +src/openlibm/*.dll* +src/openlibm/*.so* +src/openlibm/*.dylib* +src/openlibm/*.pc +src/openlibm/openlibm-test +src/openlibm/cov-html/ +src/openlibm/*.gcda +src/openlibm/*.gcno +src/openlibm/amd64/*.o +src/openlibm/bsdsrc/*.o +src/openlibm/ld80/*.o +src/openlibm/src/*.o +src/mujs/build/ +src/mujs/SpecialCasing.txt +src/mujs/UnicodeData.txt +src/mujs/one.c diff --git a/.kdev4/mujs.kdev4 b/.kdev4/mujs.kdev4 new file mode 100644 index 0000000..2e1bcfd --- /dev/null +++ b/.kdev4/mujs.kdev4 @@ -0,0 +1,47 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00m\x00u\x00j\x00s) + +[CustomBuildSystem] +CurrentConfiguration=BuildConfig0 + +[CustomBuildSystem][BuildConfig0] +BuildDir=file:///home/alec/repos/mujs +Title= + +[CustomBuildSystem][BuildConfig0][ToolBuild] +Arguments=/home/alec/repos/mujs +Enabled=true +Environment= +Executable=file:///home/alec/repos/mujs/scripts/build-all +Type=0 + +[CustomBuildSystem][BuildConfig0][ToolClean] +Arguments= +Enabled=false +Environment= +Executable= +Type=3 + +[CustomBuildSystem][BuildConfig0][ToolConfigure] +Arguments= +Enabled=false +Environment= +Executable= +Type=1 + +[CustomBuildSystem][BuildConfig0][ToolInstall] +Arguments= +Enabled=false +Environment= +Executable= +Type=2 + +[CustomBuildSystem][BuildConfig0][ToolPrune] +Arguments= +Enabled=false +Environment= +Executable= +Type=4 + +[Project] +VersionControlSupport=kdevgit diff --git a/MuJS.HC b/MuJS.HC new file mode 100644 index 0000000..a4d6b6d --- /dev/null +++ b/MuJS.HC @@ -0,0 +1,23 @@ +load_elf("M:/build/bin/mujs"); + +U0 mujs(U8* filename = NULL) +{ + I64 _argc = 1 + (filename != NULL); + U8** _argv = CAlloc(sizeof(U8*) * _argc); + + _argv[0] = "mujs"; + if (filename) + _argv[1] = filename; + + U64 reg RDI rdi = _argc; + U64 reg RSI rsi = _argv; + no_warn rdi, rsi; + asm { + MOV RAX, MUJS_MAIN + CALL RAX + } + + Free(_argv); +} + +@patch_jmp_rel32(MUJS_EXIT, &UserTaskCont); diff --git a/Run.HC b/Run.HC new file mode 100644 index 0000000..c9808e0 --- /dev/null +++ b/Run.HC @@ -0,0 +1,7 @@ +XTalkWait(Fs, "Cd(\"M:/System/\");\n"); +XTalkWait(Fs, "#include \"M:/System/MakeSystem\";\n"); +XTalkWait(Fs, "#include \"M:/MuJS\";\n"); + +XTalkWait(Fs, "Cd(\"M:/\");\n"); +XTalkWait(Fs, "mujs(\"examples/hello.js\");\n"); + diff --git a/System/FFI/Base.HC b/System/FFI/Base.HC new file mode 100644 index 0000000..0211c44 --- /dev/null +++ b/System/FFI/Base.HC @@ -0,0 +1,51 @@ +#define PUSH_SYSV_REGS \ + asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \ + R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15} +#define POP_SYSV_REGS \ + p0 = p0; \ + p1 = p1; \ + p2 = p2; \ + p3 = p3; \ + p4 = p4; \ + p5 = p5; \ + asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \ + RSI POP RBP POP RBX POP RDX POP RCX} +#define GET_SYSV_ARGS \ + asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \ + I64 reg RDI p0; \ + I64 reg RSI p1; \ + I64 reg RDX p2; \ + I64 reg RCX p3; \ + I64 reg R8 p4; \ + I64 reg R9 p5; \ + asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9} + +#define MOV_ANS_RAX asm { MOV[&ans], RAX } +#define MOV_PARAM0_RDI asm {MOV [¶m0], RDI} + +I64 param0; +I64 elf_argc; +U8** elf_argv; + +asm { +_ELF_CALL:: + PUSH RBP + MOV RBP,RSP + MOV RAX,U64 SF_ARG1[RBP] + MOV RDI,U64 SF_ARG2[RBP] + MOV RSI,U64 SF_ARG3[RBP] + TEST RAX,RAX + JZ @@05 + CALL RAX +@@05: POP RBP + RET1 8 +} + +U0 _main() +{ + MOV_PARAM0_RDI + CallInd(_ELF_CALL, param0, elf_argc, elf_argv); + UserTaskCont; +} + +//U0 _exit() { UserTaskCont; } diff --git a/System/FFI/ELF64.HC b/System/FFI/ELF64.HC new file mode 100644 index 0000000..87af9fd --- /dev/null +++ b/System/FFI/ELF64.HC @@ -0,0 +1,300 @@ +#define EI_NIDENT 16 +#define EM_X86_64 0x3E +#define ET_EXEC 2 +#define ET_DYN 3 + +U0 @elf64_debug_print(U8 fmt, ...) +{ + // FIXME: Remove unnecessary debug_print statements and PrintErr for errors. + no_warn fmt, argc, argv; +} + +class Elf64_Ehdr { + U8 e_ident[EI_NIDENT]; /* Magic number and other info */ + U16 e_type; /* Object file type */ + U16 e_machine; /* Architecture */ + U32 e_version; /* Object file version */ + U64 e_entry; /* Entry point virtual address */ + U64 e_phoff; /* Program header table file offset */ + U64 e_shoff; /* Section header table file offset */ + U32 e_flags; /* Processor-specific flags */ + U16 e_ehsize; /* ELF header size in bytes */ + U16 e_phentsize; /* Program header table entry size */ + U16 e_phnum; /* Program header table entry count */ + U16 e_shentsize; /* Section header table entry size */ + U16 e_shnum; /* Section header table entry count */ + U16 e_shstrndx; /* Section header string table index */ +}; + +class Elf64_Shdr { + U32 sh_name; /* Section name (string tbl index) */ + U32 sh_type; /* Section type */ + U64 sh_flags; /* Section flags */ + U64 sh_addr; /* Section virtual addr at execution */ + U64 sh_offset; /* Section file offset */ + U64 sh_size; /* Section size in bytes */ + U32 sh_link; /* Link to another section */ + U32 sh_info; /* Additional section information */ + U64 sh_addralign; /* Section alignment */ + U64 sh_entsize; /* Entry size if section holds table */ +}; + +class Elf64_Sym { + U32 st_name; /* Symbol name (string tbl index) */ + U8 st_info; /* Symbol type and binding */ + U8 st_other; /* Symbol visibility */ + U16 st_shndx; /* Section index */ + U64 st_value; /* Symbol value */ + U64 st_size; /* Symbol size */ +}; + +class PLT_entry { + U8 pad[0x10]; +}; + +class RELA_entry { + U64 r_offset; + U64 r_info; + I64 r_addend; +}; + +class Elf { + union { + U8* u8; + Elf64_Ehdr* ehdr; + } I64 size; + U8* dynstr; + Elf64_Sym* dynsym; + PLT_entry* plt; + RELA_entry* rela_dyn; + RELA_entry* rela_plt; + Elf64_Sym* strtab; + Elf64_Sym* symtab; + I64 rela_dyn_size; + I64 rela_plt_size; + I64 strtab_size; + I64 symtab_size; +}; + +U0 (*_start)(); + +U0 unimplemented_symbol() +{ + I32 s = 0xDEADF00D; + PrintWarn("Unimplemented symbol: %s\n", s); + Dbg; + while (1) + Sleep(1); +} + +Bool is_valid_elf(Elf* elf) +{ + Bool res = TRUE; + if (MemCmp(elf->u8 + 1, "ELF", 3)) { + @elf64_debug_print("Invalid signature (not ELF).\n"); + res = FALSE; + } + if (elf->ehdr->e_type != ET_EXEC && elf->ehdr->e_type != ET_DYN) { + @elf64_debug_print("Invalid object file type.\n"); + res = FALSE; + } + if (elf->ehdr->e_machine != EM_X86_64) { + @elf64_debug_print("Invalid architecture.\n"); + res = FALSE; + } + return res; +} + +U0 process_elf_section_header_table(Elf* elf) +{ + Elf64_Shdr* shdr = elf->u8 + elf->ehdr->e_shoff; + Elf64_Shdr* shdr_shstrtab = shdr + elf->ehdr->e_shstrndx; + U8* shstrtab = elf->u8 + shdr_shstrtab->sh_offset; + I64 i = 0; + while (i < elf->ehdr->e_shnum) { + if (!StrCmp(shstrtab + shdr->sh_name, ".symtab")) { + @elf64_debug_print("found symtab at 0x%08x, size = %d\n", shdr->sh_offset, + shdr->sh_size); + elf->symtab = elf->u8 + shdr->sh_offset; + elf->symtab_size = shdr->sh_size; + } + if (!StrCmp(shstrtab + shdr->sh_name, ".strtab")) { + @elf64_debug_print("found strtab at 0x%08x, size = %d\n", shdr->sh_offset, + shdr->sh_size); + elf->strtab = elf->u8 + shdr->sh_offset; + elf->strtab_size = shdr->sh_size; + } + if (shdr->sh_addr) { + MemCpy(shdr->sh_addr, elf->u8 + shdr->sh_offset, shdr->sh_size); + if (!StrCmp(shstrtab + shdr->sh_name, ".dynstr")) + elf->dynstr = shdr->sh_addr; + if (!StrCmp(shstrtab + shdr->sh_name, ".dynsym")) + elf->dynsym = shdr->sh_addr; + if (!StrCmp(shstrtab + shdr->sh_name, ".plt")) + elf->plt = shdr->sh_addr; + if (!StrCmp(shstrtab + shdr->sh_name, ".rela.dyn")) { + elf->rela_dyn = shdr->sh_addr; + elf->rela_dyn_size = shdr->sh_size / shdr->sh_entsize; + } + if (!StrCmp(shstrtab + shdr->sh_name, ".rela.plt")) { + elf->rela_plt = shdr->sh_addr; + elf->rela_plt_size = shdr->sh_size / shdr->sh_entsize; + } + if (!StrCmp(shstrtab + shdr->sh_name, ".bss") || !StrCmp(shstrtab + shdr->sh_name, ".tbss")) { + MemSet(shdr->sh_addr, NULL, shdr->sh_size); + @elf64_debug_print( + "Zeroed out section '%s' at physical address 0x%06x, size = %d bytes\n", + shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size); + } else + @elf64_debug_print( + "MemCpy section '%s' to physical address 0x%06x, size = %d bytes\n", + shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size); + if (!StrCmp(shstrtab + shdr->sh_name, ".bss")) { + MemSet(shdr->sh_addr, NULL, shdr->sh_size); + @elf64_debug_print("MemSet section '%s' at physical address 0x%06x to NULL, " + "size = %d bytes\n", + shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size); + } + } + shdr++; + i++; + } +} + +U0 process_elf_rela_dyn_entries(Elf* elf) +{ + I64 i; + U8* entry_name; + RELA_entry* rela_dyn = elf->rela_dyn; + for (i = 0; i < elf->rela_dyn_size; i++) { + entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name; + @elf64_debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset); + @elf64_debug_print("entry name = '%s'\n", entry_name); + if (!StrCmp(entry_name, "__libc_start_main")) { + *(rela_dyn->r_offset)(U64*) = &_main; + @elf64_debug_print("Set value for .rela.dyn entry '%s' to: &_main\n", + entry_name); + } + if (!StrCmp(entry_name, "stdin")) { + *(rela_dyn->r_offset)(U64*) = 0; + @elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0); + } + if (!StrCmp(entry_name, "stdout")) { + *(rela_dyn->r_offset)(U64*) = 1; + @elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 1); + } + if (!StrCmp(entry_name, "stderr")) { + *(rela_dyn->r_offset)(U64*) = 2; + @elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 2); + } + rela_dyn++; + } +} + +CHashClass* get_symbol_hash_entry(U8* entry_name) +{ + I64 i; + CHashSrcSym* sym; + CHashTable* tbl = Fs->hash_table; + while (tbl) { + for (i = 0; i < tbl->mask; i++) { + sym = tbl->body[i]; + while (sym) { + if (sym->type == HTT_CLASS) + if (!StrCmp(sym->str, entry_name)) + return sym; + sym = sym->next; + } + } + tbl = tbl->next; + } + return NULL; +} + +U64 get_symbol_address(U8* entry_name) +{ + CHash* h = HashFind(entry_name, Fs->hash_table, Fs->hash_table->mask); + if (!h) + return NULL; + switch (h->type) { + case HTT_GLBL_VAR: + return h(CHashGlblVar*)->data_addr; + break; + case HTT_FUN: + return h(CHashFun*)->exe_addr; + break; + default: + return NULL; + break; + } + return NULL; +} + +U0 process_elf_rela_plt_entries(Elf* elf) +{ + I64 i; + U32 handler; + U32* patch; + U8* entry_name; + Bool symbol_exists; + PLT_entry* plt = elf->plt; + RELA_entry* rela_plt = elf->rela_plt; + plt++; + for (i = 0; i < elf->rela_plt_size; i++) { + symbol_exists = FALSE; + entry_name = elf->dynstr + elf->dynsym[(rela_plt->r_info >> 32)].st_name; + handler = MAlloc(sizeof(unimplemented_symbol), adam_task->code_heap); + MemCpy(handler, &unimplemented_symbol, sizeof(unimplemented_symbol)); + patch = handler + 0x0A; + *patch = entry_name; + @patch_jmp_rel32(plt, handler); + @patch_call_rel32(handler + 0x16, &PrintErr); + //@patch_call_rel32(handler + 0x21, &_exit); + if (!StrCmp(entry_name, "__libc_start_main")) { + symbol_exists = TRUE; + @patch_jmp_rel32(plt, &_main); + @elf64_debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name); + } + if (get_symbol_address(entry_name)) { + symbol_exists = TRUE; + @patch_jmp_rel32(plt, get_symbol_address(entry_name)); + @elf64_debug_print("Set value for .rela.plt entry '%s' to &%s\n", entry_name, + entry_name); + } + if (!symbol_exists) + @elf64_debug_print( + "Set value for .rela.plt entry '%s' to &unimplemented_symbol\n", + entry_name); + rela_plt++; + plt++; + } +} + +U0 load_elf(...) +{ + if (argc < 1) { + PrintErr("Not enough arguments.\n"); + return; + } + if (!FileFind(argv[0])) { + PrintErr("File not found: %s\n", argv[0]); + return; + } + + Elf elf; + elf.u8 = FileRead(argv[0], &elf.size); + @elf64_debug_print("Load file '%s', size = %d bytes\n", argv[0], elf.size); + + if (!is_valid_elf(&elf)) { + PrintErr("File is not a valid ELF x86-64 executable.\n"); + return; + } + + process_elf_section_header_table(&elf); + process_elf_rela_dyn_entries(&elf); + process_elf_rela_plt_entries(&elf); + + _start = elf.ehdr->e_entry; + elf_argc = argc; + elf_argv = argv; +} diff --git a/System/FFI/LibC.HC b/System/FFI/LibC.HC new file mode 100644 index 0000000..230fef1 --- /dev/null +++ b/System/FFI/LibC.HC @@ -0,0 +1,373 @@ +asm { +_SETJMP:: + MOV [RDI], RBX // Store caller saved registers + MOV [RDI+8], RBP // ^ + MOV [RDI+16], R12 // ^ + MOV [RDI+24], R13 // ^ + MOV [RDI+32], R14 // ^ + MOV [RDI+40], R15 // ^ + LEA RDX, [RSP+8] // go one value up (as if setjmp wasn't called) + MOV [RDI+48], RDX // Store the new rsp pointer in env[7] + MOV RDX, [RSP] // go one value up (as if setjmp wasn't called) + MOV [RDI+56], RDX // Store the address we will resume at in env[8] + XOR EAX, EAX // Always return 0 + RET +_LONGJMP:: + XOR EAX, EAX + CMP ESI, 1 + ADC EAX, ESI + MOV RBX, [RDI] + MOV RBP, [RDI + 8] + MOV R12, [RDI + 16] + MOV R13, [RDI + 24] + MOV R14, [RDI + 32] + MOV R15, [RDI + 40] + MOV RSP, [RDI + 48] + JMP U64 [RDI + 56] +} + +_extern _SETJMP U64 _setjmp(U64 jmp_buf); +_extern _LONGJMP U64 longjmp(U64 jmp_buf, U64 ret); + +U0 free() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + Free(p0); + POP_SYSV_REGS +} + +U0 putchar() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + PutChars(p0); + POP_SYSV_REGS +} + +U64 @localtime(U64 p0) +{ + // FIXME: implement this? + no_warn p0; + return 0; +} + +U0 localtime() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @localtime(p0); + POP_SYSV_REGS +} + +I64 @strncmp(U8* s1, U8* s2, I32 n) +{ + U64 u1, u2; + + while (n-- > 0) { + u1 = *s1++; + u2 = *s2++; + u1 = u1 & 0xff; + u2 = u2 & 0xff; + if (u1 != u2) + return u1 - u2; + if (u1 == '\0') + return 0; + } + return 0; +} + +U0 strncmp() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @strncmp(p0, p1, p2); + POP_SYSV_REGS +} + +U0 strcpy() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + StrCpy(p0, p1); + POP_SYSV_REGS +} + +U0 fprintf() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + Print(p1, p2, p3, p4, p5); + POP_SYSV_REGS +} + + +U0 printf() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + Print(p0, p1, p2, p3, p4, p5); + POP_SYSV_REGS +} + +U0 puts() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + PutS(p0); + "\n"; + POP_SYSV_REGS +} + +U0 fputs() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + PutS(p0); + POP_SYSV_REGS +} + +U0 fputc() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + PutChars(p0); + POP_SYSV_REGS +} + +U64 @fwrite(U8* buffer, I64 size, I64 count, U64 stream) +{ + if (!buffer || !size || !count || !stream) + return NULL; + I64 bytes = size * count; + switch (stream) { + case 1...2: + U8* s = CAlloc(bytes + 1); + MemCpy(s, buffer, bytes); + "%s", s; + Free(s); + break; + default: + break; + } + return bytes; +} + +U0 fwrite() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @fwrite(p0, p1, p2, p3); + POP_SYSV_REGS +} + +U0 strerror() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + "strerror: %d\n", p0; + PressAKey; + POP_SYSV_REGS +} + +U0 strlen() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + StrLen(p0); + POP_SYSV_REGS +} + +U8 *@strchr(U8 *str, I64 chr) { + while (*str) { + if (*str == chr) { + return str; + } + str++; + } + return NULL; +} + +U0 strchr() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @strchr(p0, p1); + POP_SYSV_REGS +} + +U8* @strrchr(U8 *str, I64 chr) { + U8* str2 = str + (StrLen(str) - 1); + while (str2 > str - 1) { + if (*str2 == chr) { + return str2; + } + str2--; + } + return NULL; +} + +U0 strrchr() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @strrchr(p0, p1); + POP_SYSV_REGS +} + +U0 strcmp() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + //"strcmp: '%s', '%s'\n", p0, p1; + StrCmp(p0, p1); + POP_SYSV_REGS +} + +U0 memcpy() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + MemCpy(p0, p1, p2); + POP_SYSV_REGS +} + +U0 memset() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + MemSet(p0, p1, p2); + POP_SYSV_REGS +} + +U0 malloc() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + MAlloc(p0); + POP_SYSV_REGS +} + +U8* @realloc(U8* ptr, I64 size) +{ + U8* new; + if (!ptr) { + new = MAlloc(size); + } else { + new = MAlloc(size); + MemCpy(new, ptr, size); + Free(ptr); + } + return new; +} + +U0 realloc() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @realloc(p0, p1); + POP_SYSV_REGS +} + +#define MY_TIME_OFFSET 9488 + +public +I64 CDate2Unix(CDate dt) +{ // TempleOS datetime to Unix timestamp. + return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ) - MY_TIME_OFFSET; +} + +I64 @time(I64* ptr) +{ + no_warn ptr; + return CDate2Unix(Now); +} + +U0 time() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @time(p0); + POP_SYSV_REGS +} + +U64 @gettimeofday(U64* tv) +{ + if (!tv) + return 0; + U64 seconds = CDate2Unix(Now); + tv[0] = seconds; + tv[1] = NULL; + return 0; +} + +U0 gettimeofday() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @gettimeofday(p0); + POP_SYSV_REGS +} + +U0 @fgets(U8* p0, I64 p1) +{ + GetS(p0, p1); + while (*p0) { + if (*p0 == 0x1f) + *p0 = 0x20; + ++p0; + } + Print(""); +} + +U0 fgets() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @fgets(p0, p1); + POP_SYSV_REGS +} + +U64 @ferror() +{ + return 0; +} + +U0 ferror() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @ferror; + POP_SYSV_REGS +} + +U64 @strcat(U8* dst, U8* src) +{ + StrCpy(dst + StrLen(dst), src); + return 0; +} + +U0 strcat() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @strcat(p0, p1); + POP_SYSV_REGS +} + +U0 strstr() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + StrFind(p1, p0); + POP_SYSV_REGS + +} + +U0 sprintf() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + StrPrint(p0, p1, p2, p3, p4, p5); + POP_SYSV_REGS +} diff --git a/System/LibTemple/OS.HC b/System/LibTemple/OS.HC new file mode 100644 index 0000000..0b105f0 --- /dev/null +++ b/System/LibTemple/OS.HC @@ -0,0 +1,60 @@ +U0 os_call_ext_str() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0); + POP_SYSV_REGS +} + +U0 os_call_ext_str_1() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0, p1); + POP_SYSV_REGS +} + +U0 os_call_ext_str_2() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0, p1, p2); + POP_SYSV_REGS +} + +U0 os_call_ext_str_3() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0, p1, p2, p3); + POP_SYSV_REGS +} + +U0 os_call_ext_str_4() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0, p1, p2, p3, p4); + POP_SYSV_REGS +} + +U0 os_call_ext_str_5() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + CallExtStr(p0, p1, p2, p3, p4, p5); + POP_SYSV_REGS +} + +U64 @os_jiffies() +{ + return cnts.jiffies; +} + +U0 os_jiffies() +{ + PUSH_SYSV_REGS + GET_SYSV_ARGS + @os_jiffies(); + POP_SYSV_REGS +} diff --git a/System/MakeSystem.HC b/System/MakeSystem.HC new file mode 100644 index 0000000..54ed209 --- /dev/null +++ b/System/MakeSystem.HC @@ -0,0 +1,44 @@ +/* clang-format off */ + +WinMax; +AutoComplete(0); + +U0 @patch_call_rel32(U32 from, U32 to) +{ + *(from(U8*)) = 0xE8; + *((from + 1)(I32*)) = to - from - 5; +} + +U0 @patch_jmp_rel32(U32 from, U32 to) +{ + *(from(U8*)) = 0xE9; + *((from + 1)(I32*)) = to - from - 5; +} + +U0 @sse_enable() +{ + /* clang-format off */ + asm + { + MOV_EAX_CR0 + AND AX, 0xFFFB // clear coprocessor emulation CR0.EM + OR AX, 0x2 // set coprocessor monitoring CR0.MP + MOV_CR0_EAX + MOV_EAX_CR4 + OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + MOV_CR4_EAX + } + /* clang-format on */ +} + +@sse_enable; + +// FFI support files +#include "FFI/Base"; +#include "FFI/LibC"; +#include "FFI/ELF64"; + +// LibTemple support files +#include "LibTemple/OS"; + +/* clang-format on */ diff --git a/examples/hello.js b/examples/hello.js new file mode 100644 index 0000000..90d3b5e --- /dev/null +++ b/examples/hello.js @@ -0,0 +1,3 @@ +print("Hello, TempleOS, from MuJS!") +print("Current date and time is: " + JSON.stringify(new Date())) +print("Type mujs; with no arguments for a REPL, or mujs(\"path/to/file.js\"); to run a program.") diff --git a/examples/mandelbrot.js b/examples/mandelbrot.js new file mode 100644 index 0000000..562bc53 --- /dev/null +++ b/examples/mandelbrot.js @@ -0,0 +1,60 @@ +/** + * autor: foqc + * github: foqc + */ +// noprotect + +function mandelbrot(c) { + var MAX_ITERATION = 80 + var z = { x: 0, y: 0 }, n = 0, p, d + do { + p = { + x: Math.pow(z.x, 2) - Math.pow(z.y, 2), + y: 2 * z.x * z.y + } + z = { + x: p.x + c.x, + y: p.y + c.y + } + d = Math.sqrt(Math.pow(z.x, 2) + Math.pow(z.y, 2)) + n += 1 + } while (d <= 2 && n < MAX_ITERATION) + isMandelbrotSet = d <= 2 + return n +} + +function draw() { + var ctx = DC.alias() + var isMandelbrotSet = false + var colors = [] + for (var i = 0; i < 16; i++) + colors[i] = i === 0 ? 0 : Math.random() * 16 + + var WIDTH = 320 + var HEIGHT = 240 + + var REAL_SET = { start: -2, end: 1 } + var IMAGINARY_SET = { start: -1, end: 1 } + + var ox = 640 - WIDTH - 8 + var oy = 480 - HEIGHT - 8 + for (var i = 0; i < WIDTH; i++) { + for (var j = 0; j < HEIGHT; j++) { + complex = { + x: REAL_SET.start + (i / WIDTH) * (REAL_SET.end - REAL_SET.start), + y: IMAGINARY_SET.start + (j / HEIGHT) * (IMAGINARY_SET.end - IMAGINARY_SET.start) + } + + m = mandelbrot(complex) + + DC.set_color(ctx, colors[isMandelbrotSet ? 0 : (m % colors.length - 1) + 1]) + Gr.plot(ctx, ox + i, oy + j) + OS.sleep(0) + } + } +} + +draw() + +print("Hello, TempleOS, from MuJS!") +alert("This is an alert!") diff --git a/mujs.kdev4 b/mujs.kdev4 new file mode 100644 index 0000000..f2226bc --- /dev/null +++ b/mujs.kdev4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom= +Manager=KDevCustomBuildSystem +Name=mujs diff --git a/scripts/build-all b/scripts/build-all new file mode 100755 index 0000000..d3a1c68 --- /dev/null +++ b/scripts/build-all @@ -0,0 +1,152 @@ +#!/usr/bin/python3 -u +from pathlib import Path +import glob +import os +import subprocess +import sys +import time + +if len(sys.argv) < 2: + raise ValueError('wrong number of arguments') + +project_path = sys.argv[1] + '/' +project_name = project_path.rsplit('/')[-2] + +isoc_file = project_path + 'build/isoc/MuJS.ISO.C' +redsea_path = project_path + 'build/redsea' + +home_path = str(Path.home()) + '/' + +qemu_slipstream_iso_file = project_path + 'build/isoc/bootable.iso' + +qemu_bin_path = "qemu-system-x86_64" +qemu_display = "-display sdl,grab-mod=rctrl" + +templeos_iso_file = home_path + 'iso/TempleOS.ISO' + +qemu_run_cmd = qemu_bin_path + ' ' + qemu_display + ' -enable-kvm -m 1024 -cdrom ' + qemu_slipstream_iso_file + ' -audiodev pa,id=snd0 -machine pcspk-audiodev=snd0 -debugcon stdio -boot d' + +def clang_format_src_files(): + print("build-all: clang-format-src-files") + exclude_paths = ["mujs", "openlibm", ".iso.c"] + format_file_extensions = [".c", ".cpp", ".h", ".hc"] + for src_file in glob.glob(project_path + "**", recursive=True): + exclude_file = False + for exclude_path in exclude_paths: + if src_file.lower().find(exclude_path) > 0: + exclude_file = True + if exclude_file: + continue + for format_file_extension in format_file_extensions: + if src_file.lower().endswith(format_file_extension): + print(src_file) + res = os.system('clang-format -i --style=file:' + project_path + '.clang-format ' + src_file) + if res: + raise ValueError("build-all: step 'clang-format-src-files' failed, error code " + str(res)) + +def refresh_build_path(): + print("build-all: refresh-build-path") + res = os.system('rm -rf ' + project_path + 'build && mkdir -p ' + project_path + 'build/bin && mkdir -p ' + project_path + 'build/isoc && mkdir -p ' + project_path + 'build/lib && mkdir -p ' + project_path + 'build/redsea') + if res: + raise ValueError("build-all: step 'refresh-build-path' failed, error code " + str(res)) + +def build_image(): + print("build-all: build-image") + build_specific_options = '-Wl,--section-start=.text=0x1004000 -Wl,--section-start=.plt=0x1002020 -no-pie' + res = os.system('cd ' + project_path + '&& cd src/image && gcc -o ../../build/bin/image ' + build_specific_options + ' -O0 -mno-mmx -mno-red-zone image.c') + if res: + raise ValueError("build-all: step 'build-image' failed, error code " + str(res)) + +def build_libtemple(): + print("build-all: build-libtemple") + res = os.system('cd ' + project_path + 'src/libtemple && gcc -c -o ../../build/libtemple.o libtemple.c && gcc -shared -o ../../build/lib/libtemple.so ../../build/libtemple.o && rm ' + project_path + 'build/libtemple.o') + if res: + raise ValueError("build-all: step 'build-libtemple' failed, error code " + str(res)) + +def build_openlibm(): + print("build-all: build-openlibm") + res = os.system('cd ' + project_path + '&& cd src/openlibm && make clean && make ARCH=amd64') + if res: + raise ValueError("build-all: step 'build-image' failed, error code " + str(res)) + +def build_mujs(): + print("build-all: build-mujs") + #build_specific_options = '-Wl,--section-start=.text=0x1004000 -Wl,--section-start=.plt=0x1002020 -no-pie' + res = os.system('cd ' + project_path + '&& cd src/mujs && rm -f one.c && make && cp build/debug/mujs ../../build/bin/mujs') + if res: + raise ValueError("build-all: step 'build-mujs' failed, error code " + str(res)) + +def address_string_for_symbol(file, symbol): + p = subprocess.Popen('readelf -s --wide "' + file + '" | grep \'' + symbol + '$\' | awk \'{sub("000000000", "0x", $2); print $2}\'', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + return str(p.communicate()[0][:-1].decode(encoding='utf-8')) + +def hc_fixup(macro, symbol, bin_path, hc_path): + os.system('echo -e "#define ' + macro + ' ' + address_string_for_symbol(bin_path, symbol) + '\n" | cat - ' + hc_path + ' | sponge ' + hc_path) + return + +def exit_address_for_bin(file): + p = subprocess.Popen('objdump -d "' + file + '" | grep exit@plt\\>: | awk \'{sub("000000000", "0x", $1); print $1}\'', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + return str(p.communicate()[0][:-1].decode(encoding='utf-8')) + +def exit_fixup(bin_path, hc_path): + os.system('echo -e "#define MUJS_EXIT ' + exit_address_for_bin(bin_path) + '\n" | cat - ' + hc_path + ' | sponge ' + hc_path) + +def generate_iso_c_file(): + print("build-all: generate-iso-c-file") + step_error_message = "build-all: step 'generate-iso-c-file' failed, error code " + + res = os.system('isoc-mount --rw ' + isoc_file + ' ' + redsea_path) + if res: + raise ValueError(step_error_message + str(res)) + time.sleep(0.25) + + copy_files_cmd_line = 'rsync -av --inplace --progress ' + project_path + ' ' + redsea_path + copy_files_cmd_line += ' --exclude .clang-format' + copy_files_cmd_line += ' --exclude .git' + copy_files_cmd_line += ' --exclude .gitignore' + copy_files_cmd_line += ' --exclude build/isoc' + copy_files_cmd_line += ' --exclude build/lib' + copy_files_cmd_line += ' --exclude build/redsea' + copy_files_cmd_line += ' --exclude scripts' + copy_files_cmd_line += ' --exclude src' + res = os.system(copy_files_cmd_line) + if res: + raise ValueError(step_error_message + str(res)) + + # Fixup addresses for MuJS + mujs_bin_path = redsea_path + '/build/bin/mujs' + mujs_hc_path = redsea_path + '/MuJS.HC' + + hc_fixup('MUJS_MAIN', 'main', mujs_bin_path, mujs_hc_path) + exit_fixup(mujs_bin_path, mujs_hc_path) + + time.sleep(0.25) + + res = os.system('sync && fusermount -u ' + redsea_path) + if res: + raise ValueError(step_error_message + str(res)) + time.sleep(0.25) + +def generate_slipstream_iso_file(): + print("build-all: generate-slipstream-iso-file") + res = os.system('templeos-slipstream ' + templeos_iso_file + ' ' + isoc_file + ' ' + qemu_slipstream_iso_file) + if res: + raise ValueError("build-all: step 'generate-slipstream-iso-file' failed, error code " + str(res)) + +def run(): + print("build-all: run") + res = os.system(qemu_run_cmd) + if res: + raise ValueError("build-all: step 'run' failed, error code " + str(res)) + +def build_all(): + clang_format_src_files() + refresh_build_path() + build_libtemple() + build_openlibm() + build_mujs() + generate_iso_c_file() + generate_slipstream_iso_file() + run() + +build_all() diff --git a/src/libtemple/libtemple.c b/src/libtemple/libtemple.c new file mode 100644 index 0000000..5dad194 --- /dev/null +++ b/src/libtemple/libtemple.c @@ -0,0 +1,13 @@ +unsigned long os_call_ext_str(char const* func) { return 0; } + +unsigned long os_call_ext_str_1(char const* func, unsigned long arg1) { return 0; } + +unsigned long os_call_ext_str_2(char const* func, unsigned long arg1, unsigned long arg2) { return 0; } + +unsigned long os_call_ext_str_3(char const* func, unsigned long arg1, unsigned long arg2, unsigned long arg3) { return 0; } + +unsigned long os_call_ext_str_4(char const* func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) { return 0; } + +unsigned long os_call_ext_str_5(char const* func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { return 0; } + +unsigned long os_jiffies() { return 0; } diff --git a/src/libtemple/os.h b/src/libtemple/os.h new file mode 100644 index 0000000..1306a18 --- /dev/null +++ b/src/libtemple/os.h @@ -0,0 +1,7 @@ +uint64_t os_call_ext_str(char const* func); +uint64_t os_call_ext_str_1(char const* func, uint64_t arg1); +uint64_t os_call_ext_str_2(char const* func, uint64_t arg1, uint64_t arg2); +uint64_t os_call_ext_str_3(char const* func, uint64_t arg1, uint64_t arg2, uint64_t arg3); +uint64_t os_call_ext_str_4(char const* func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); +uint64_t os_call_ext_str_5(char const* func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5); +unsigned long os_jiffies(); diff --git a/src/mujs/.gitattributes b/src/mujs/.gitattributes new file mode 100644 index 0000000..46fe0b3 --- /dev/null +++ b/src/mujs/.gitattributes @@ -0,0 +1,7 @@ +# Define macro for whitespace settings: +[attr]tabs whitespace=trailing-space,space-before-tab,indent-with-non-tab + +* text=auto +Makefile tabs +*.[ch] tabs +*.js tabs diff --git a/src/mujs/AUTHORS b/src/mujs/AUTHORS new file mode 100644 index 0000000..593c93f --- /dev/null +++ b/src/mujs/AUTHORS @@ -0,0 +1 @@ +Tor Andersson diff --git a/src/mujs/COPYING b/src/mujs/COPYING new file mode 100644 index 0000000..aa8805f --- /dev/null +++ b/src/mujs/COPYING @@ -0,0 +1,16 @@ +ISC License + +Copyright (c) 2013-2020 Artifex Software, Inc. + +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. + diff --git a/src/mujs/Makefile b/src/mujs/Makefile new file mode 100644 index 0000000..14afbd1 --- /dev/null +++ b/src/mujs/Makefile @@ -0,0 +1,168 @@ +# Makefile for building MuJS libraries, shell, and pretty-printer. +# +# Useful targets are: release, install, uninstall. + +default: build/debug/mujs build/debug/mujs-pp + +CFLAGS = -O0 -mno-mmx -mno-red-zone -std=c99 -pedantic -Wall -Wextra -Wno-unused-parameter + +OPTIM = + +prefix = /usr/local +bindir = $(prefix)/bin +incdir = $(prefix)/include +libdir = $(prefix)/lib + +ifeq ($(wildcard .git),.git) + VERSION = $(shell git describe --tags --always) +else + VERSION = $(patsubst mujs-%,%,$(notdir $(CURDIR))) +endif + +ifeq ($(shell uname),Darwin) + SO = dylib +else + SO = so +endif + +ifeq ($(shell uname),FreeBSD) + CFLAGS += -I/usr/local/include -L/usr/local/lib +endif + +HDRS = mujs.h jsi.h regexp.h utf.h astnames.h opnames.h utfdata.h + +SRCS = \ + jsarray.c \ + jsboolean.c \ + jsbuiltin.c \ + jscompile.c \ + jsdate.c \ + jsdtoa.c \ + jserror.c \ + jsfunction.c \ + jsgc.c \ + jsintern.c \ + jslex.c \ + jslibtemple.c \ + jsmath.c \ + jsnumber.c \ + jsobject.c \ + json.c \ + jsparse.c \ + jsproperty.c \ + jsregexp.c \ + jsrepr.c \ + jsrun.c \ + jsstate.c \ + jsstring.c \ + jsvalue.c \ + regexp.c \ + utf.c + +one.c: + for F in $(SRCS); do echo "#include \"$$F\""; done > $@ + +astnames.h: jsi.h + grep -E '\<(AST|EXP|STM)_' jsi.h | sed 's/^[^A-Z]*\(AST_\)*/"/;s/,.*/",/' | tr A-Z a-z > $@ + +opnames.h: jsi.h + grep -E '\ $@ + +UnicodeData.txt: + curl -s -o $@ https://www.unicode.org/Public/16.0.0/ucd/UnicodeData.txt +SpecialCasing.txt: + curl -s -o $@ https://www.unicode.org/Public/16.0.0/ucd/SpecialCasing.txt + +utfdata.h: genucd.py UnicodeData.txt SpecialCasing.txt + python3 genucd.py UnicodeData.txt SpecialCasing.txt >$@ + +build/sanitize/mujs: main.c one.c $(SRCS) $(HDRS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) -g -fsanitize=address -fno-omit-frame-pointer -o $@ main.c one.c ../openlibm/libopenlibm.a $(READLINE_CFLAGS) $(READLINE_LIBS) + +build/debug/libmujs.$(SO): one.c $(SRCS) $(HDRS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) -g -fPIC -shared -o $@ one.c ../openlibm/libopenlibm.a ../../build/lib/libtemple.so +build/debug/libmujs.o: one.c $(SRCS) $(HDRS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) -g -c -o $@ one.c ../../build/lib/libtemple.so +build/debug/libmujs.a: build/debug/libmujs.o + $(AR) cr $@ $^ +build/debug/mujs: main.c build/debug/libmujs.o + $(CC) $(CFLAGS) -g -o $@ $^ ../openlibm/libopenlibm.a ../../build/lib/libtemple.so $(READLINE_CFLAGS) $(READLINE_LIBS) +build/debug/mujs-pp: pp.c build/debug/libmujs.o + $(CC) $(CFLAGS) -g -o $@ $^ ../openlibm/libopenlibm.a ../../build/lib/libtemple.so + +build/release/libmujs.$(SO): one.c $(SRCS) $(HDRS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(OPTIM) -fPIC -shared -o $@ one.c ../openlibm/libopenlibm.a ../../build/lib/libtemple.so +build/release/libmujs.o: one.c $(SRCS) $(HDRS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(OPTIM) -c -o $@ one.c +build/release/libmujs.a: build/release/libmujs.o + $(AR) cr $@ $^ +build/release/mujs: main.c build/release/libmujs.o + $(CC) $(CFLAGS) $(OPTIM) -o $@ $^ ../openlibm/libopenlibm.a $(READLINE_CFLAGS) $(READLINE_LIBS) +build/release/mujs-pp: pp.c build/release/libmujs.o + $(CC) $(CFLAGS) $(OPTIM) -o $@ $^ ../openlibm/libopenlibm.a + +build/release/mujs.pc: + @mkdir -p $(@D) + echo > $@ Name: mujs + echo >> $@ Description: MuJS embeddable Javascript interpreter + echo >> $@ Version: $(VERSION) + echo >> $@ Cflags: -I$(incdir) + echo >> $@ Libs: -L$(libdir) -lmujs + echo >> $@ Libs.private: ../openlibm/libopenlibm.a + +install-common: build/release/mujs build/release/mujs-pp build/release/mujs.pc + install -d $(DESTDIR)$(incdir) + install -d $(DESTDIR)$(libdir) + install -d $(DESTDIR)$(libdir)/pkgconfig + install -d $(DESTDIR)$(bindir) + install -m 644 mujs.h $(DESTDIR)$(incdir) + install -m 644 build/release/mujs.pc $(DESTDIR)$(libdir)/pkgconfig + install -m 755 build/release/mujs $(DESTDIR)$(bindir) + install -m 755 build/release/mujs-pp $(DESTDIR)$(bindir) + +install-static: install-common build/release/libmujs.a + install -m 644 build/release/libmujs.a $(DESTDIR)$(libdir) + +install-shared: install-common build/release/libmujs.$(SO) + install -m 755 build/release/libmujs.$(SO) $(DESTDIR)$(libdir) + +install: install-static + +uninstall: + rm -f $(DESTDIR)$(bindir)/mujs + rm -f $(DESTDIR)$(bindir)/mujs-pp + rm -f $(DESTDIR)$(incdir)/mujs.h + rm -f $(DESTDIR)$(libdir)/pkgconfig/mujs.pc + rm -f $(DESTDIR)$(libdir)/libmujs.a + rm -f $(DESTDIR)$(libdir)/libmujs.$(SO) + +tarball: + git archive --format=zip --prefix=mujs-$(VERSION)/ HEAD > mujs-$(VERSION).zip + git archive --format=tar --prefix=mujs-$(VERSION)/ HEAD | gzip > mujs-$(VERSION).tar.gz + +tags: $(SRCS) $(HDRS) main.c pp.c + ctags $^ + +clean: + rm -rf build + +nuke: clean + rm -f one.c astnames.h opnames.h + +sanitize: build/sanitize/mujs + +debug: build/debug/libmujs.a +debug: build/debug/libmujs.$(SO) +debug: build/debug/mujs +debug: build/debug/mujs-pp + +release: build/release/mujs.pc +release: build/release/libmujs.a +release: build/release/libmujs.$(SO) +release: build/release/mujs +release: build/release/mujs-pp diff --git a/src/mujs/README b/src/mujs/README new file mode 100644 index 0000000..467bc41 --- /dev/null +++ b/src/mujs/README @@ -0,0 +1,50 @@ +MuJS: an embeddable Javascript interpreter in C. + +ABOUT + +MuJS is a lightweight Javascript interpreter designed for embedding in +other software to extend them with scripting capabilities. + +LICENSE + +MuJS is Copyright 2013-2017 Artifex Software, Inc. + +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. + +COMPILING + +If you are building from source you can either use the provided Unix Makefile: + + make release + +Or compile the source with your preferred compiler: + + cc -O2 -c one.c -o libmujs.o + +INSTALLING + +To install the MuJS command line interpreter, static library and header file: + + make prefix=/usr/local install + +DOWNLOAD + +The latest development source is available directly from the git repository: + + git clone http://git.ghostscript.com/mujs.git + +REPORTING BUGS AND PROBLEMS + +Report bugs on the ghostscript bugzilla, with MuJS as the selected component. + + http://bugs.ghostscript.com/ diff --git a/src/mujs/astnames.h b/src/mujs/astnames.h new file mode 100644 index 0000000..aa19557 --- /dev/null +++ b/src/mujs/astnames.h @@ -0,0 +1,92 @@ +"list", +"fundec", +"identifier", +"exp_identifier", +"exp_number", +"exp_string", +"exp_regexp", +"exp_elision", +"exp_null", +"exp_true", +"exp_false", +"exp_this", +"exp_array", +"exp_object", +"exp_prop_val", +"exp_prop_get", +"exp_prop_set", +"exp_fun", +"exp_index", +"exp_member", +"exp_call", +"exp_new", +"exp_postinc", +"exp_postdec", +"exp_delete", +"exp_void", +"exp_typeof", +"exp_preinc", +"exp_predec", +"exp_pos", +"exp_neg", +"exp_bitnot", +"exp_lognot", +"exp_mod", +"exp_div", +"exp_mul", +"exp_sub", +"exp_add", +"exp_ushr", +"exp_shr", +"exp_shl", +"exp_in", +"exp_instanceof", +"exp_ge", +"exp_le", +"exp_gt", +"exp_lt", +"exp_strictne", +"exp_stricteq", +"exp_ne", +"exp_eq", +"exp_bitand", +"exp_bitxor", +"exp_bitor", +"exp_logand", +"exp_logor", +"exp_cond", +"exp_ass", +"exp_ass_mul", +"exp_ass_div", +"exp_ass_mod", +"exp_ass_add", +"exp_ass_sub", +"exp_ass_shl", +"exp_ass_shr", +"exp_ass_ushr", +"exp_ass_bitand", +"exp_ass_bitxor", +"exp_ass_bitor", +"exp_comma", +"exp_var", +"stm_block", +"stm_empty", +"stm_var", +"stm_if", +"stm_do", +"stm_while", +"stm_for", +"stm_for_var", +"stm_for_in", +"stm_for_in_var", +"stm_continue", +"stm_break", +"stm_return", +"stm_with", +"stm_switch", +"stm_throw", +"stm_try", +"stm_debugger", +"stm_label", +"stm_case", +"stm_default", diff --git a/src/mujs/docs/artifex-logo.png b/src/mujs/docs/artifex-logo.png new file mode 100755 index 0000000..af610a0 Binary files /dev/null and b/src/mujs/docs/artifex-logo.png differ diff --git a/src/mujs/docs/examples.html b/src/mujs/docs/examples.html new file mode 100644 index 0000000..30304b1 --- /dev/null +++ b/src/mujs/docs/examples.html @@ -0,0 +1,224 @@ + + + + +MuJS Examples + + + + +
+

MuJS Examples

+
+ + + +
+ +

A stand-alone interpreter

+ +
+#include <stdio.h>
+#include <mujs.h>
+
+int main(int argc, char **argv)
+{
+	char line[256];
+	js_State *J = js_newstate(NULL, NULL, JS_STRICT);
+	while (fgets(line, sizeof line, stdin))
+		js_dostring(J, line);
+	js_freestate(J);
+}
+
+ +

Hello, world!

+ +
+#include <stdio.h>
+#include <mujs.h>
+
+static void hello(js_State *J)
+{
+	const char *name = js_tostring(J, 1);
+	printf("Hello, %s!\n", name);
+	js_pushundefined(J);
+}
+
+int main(int argc, char **argv)
+{
+	js_State *J = js_newstate(NULL, NULL, JS_STRICT);
+
+	js_newcfunction(J, hello, "hello", 1);
+	js_setglobal(J, "hello");
+
+	js_dostring(J, "hello('world');");
+
+	js_freestate(J);
+}
+
+ +

Configuration file

+ +
+js_dofile(J, "config.js")
+
+js_getglobal(J, "foo");
+foo = js_tonumber(J, -1);
+js_pop(J, 1);
+
+ +

Object manipulation

+ +
+// t = { foo: 42, bar: true }
+
+js_newobject(J);
+{
+	js_pushnumber(J, 42);
+	js_setproperty(J, -2, "foo");
+	js_pushboolean(J, 1);
+	js_setproperty(J, -2, "bar");
+}
+js_setglobal(J, "t");
+
+ +

Callbacks from C to JS (by name)

+ +
+static int call_callback(js_State *J, const char *arg1, int arg2)
+{
+	int result;
+
+	/* Find the function to call. */
+	js_getglobal(J, "my_callback");
+
+	/* Push arguments to function. */
+	js_pushnull(J); /* the 'this' object to use */
+	js_pushstring(J, arg1);
+	js_pushnumber(J, arg2);
+
+	/* Call function and check for exceptions. */
+	if (js_pcall(J, 2)) {
+		fprintf(stderr, "an exception occurred in the javascript callback\n");
+		js_pop(J, 1);
+		return -1;
+	}
+
+	/* Retrieve return value. */
+	result = js_tonumber(J, -1);
+	js_pop(J, 1);
+
+	return result;
+}
+
+ +

Callbacks from C to JS

+ +
+const char *handle = NULL; /* handle to stowed away js function */
+
+static void set_callback(js_State *J)
+{
+	if (handle)
+		js_unref(J, handle); /* delete old function */
+	js_copy(J, 1);
+	handle = js_ref(J); /* stow the js function in the registry */
+}
+
+static void call_callback(js_State *J, int arg1, int arg2)
+{
+	js_getregistry(J, handle); /* retrieve the js function from the registry */
+	js_pushnull(J);
+	js_pushnumber(J, arg1);
+	js_pushnumber(J, arg2);
+	js_pcall(J, 2);
+	js_pop(J, 1);
+}
+
+ +

Complete userdata example

+ +
+#include <stdio.h>
+#include <mujs.h>
+
+#define TAG "File"
+
+static void new_File(js_State *J)
+{
+	FILE *file;
+
+	if (js_isundefined(J, 1)) {
+		file = stdin;
+	} else {
+		const char *filename = js_tostring(J, 1);
+		file = fopen(filename, "r");
+		if (!file)
+			js_error(J, "cannot open file: '%s'", filename);
+	}
+
+	js_currentfunction(J);
+	js_getproperty(J, -1, "prototype");
+	js_newuserdata(J, TAG, file);
+}
+
+static void File_prototype_readByte(js_State *J)
+{
+	FILE *file = js_touserdata(J, 0, TAG);
+	js_pushnumber(J, getc(file));
+}
+
+static void File_prototype_readLine(js_State *J)
+{
+	char line[256], *s;
+	FILE *file = js_touserdata(J, 0, TAG);
+	s = fgets(line, sizeof line, file);
+	if (s)
+		js_pushstring(J, line);
+	else
+		js_pushnull(J);
+}
+
+static void File_prototype_close(js_State *J)
+{
+	FILE *file = js_touserdata(J, 0, TAG);
+	fclose(file);
+	js_pushundefined(J);
+}
+
+void initfile(js_State *J)
+{
+	js_getglobal(J, "Object");
+	js_getproperty(J, -1, "prototype");	// File.prototype.[[Prototype]] = Object.prototype
+	js_newuserdata(J, TAG, stdin);		// File.prototype.[[Userdata]] = stdin
+	{
+		js_newcfunction(J, File_prototype_readByte, "File.prototype.readByte", 0);
+		js_defproperty(J, -2, "readByte", JS_DONTENUM);
+
+		js_newcfunction(J, File_prototype_readLine, "File.prototype.readLine", 0);
+		js_defproperty(J, -2, "readLine", JS_DONTENUM);
+
+		js_newcfunction(J, File_prototype_close, "File.prototype.close", 0);
+		js_defproperty(J, -2, "close", JS_DONTENUM);
+	}
+	js_newcconstructor(J, new_File, new_File, "File", 1);
+	js_defglobal(J, "File", JS_DONTENUM);
+}
+
+ +
+ +
+ +Copyright © 2013-2017 Artifex Software Inc. +
+ + + diff --git a/src/mujs/docs/index.html b/src/mujs/docs/index.html new file mode 100644 index 0000000..fa046bc --- /dev/null +++ b/src/mujs/docs/index.html @@ -0,0 +1,58 @@ + + + + +MuJS + + + + +
+

MuJS

+
+ + + +
+ +

+MuJS is a lightweight Javascript interpreter designed for embedding in other +software to extend them with scripting capabilities. + +

+MuJS was designed with a focus on small size, correctness, and simplicity. +It is written in portable C and implements ECMAScript as specified by ECMA-262. +The interface for binding with native code is designed to be as simple as +possible to use, and is very similar to Lua. There is no need to interact with +byzantine C++ template mechanisms, or worry about marking and unmarking garbage +collection roots, or wrestle with obscure build systems. + +

+MuJS is developed and maintained by Artifex Software. +It was originally developed for use with the MuPDF viewer, but is designed to be useful as an independent component. + +

+The primary meeting place for the MuJS community is the +#mupdf +IRC channel on freenode. + +

+MuJS is free open source software distributed under the +ISC license. + +

+ +
+ +Copyright © 2013-2017 Artifex Software Inc. +
+ + + diff --git a/src/mujs/docs/introduction.html b/src/mujs/docs/introduction.html new file mode 100644 index 0000000..7096669 --- /dev/null +++ b/src/mujs/docs/introduction.html @@ -0,0 +1,108 @@ + + + + +MuJS Introduction + + + + +
+

MuJS Introduction

+
+ + + +
+ +

Why choose MuJS?

+ +

Javascript is a proven scripting language

+ +

+Javascript is one of the most popular programming languages in the world. +It is a powerful extension language, used everywhere on the web — both as +a way to add interactivity to web pages in the browser, and on the server side +with platforms like node.js. + +

+With MuJS you can bring this power to your application as well! + +

MuJS is standards compliant

+ +

+MuJS implements ES5. +There are no non-standard extensions, so you can remain confident that +Javascript code that runs on MuJS will also run on any other standards +compliant Javascript implementation. + +

MuJS is portable

+ +

+MuJS is written in portable C and can be built by compiling a single C file using any standard C compiler. +There is no need for configuration or fancy build systems. +MuJS runs on all flavors of Unix and Windows, on mobile devices (such as Android and iOS), +embedded microprocessors (such as the Beagle board and Raspberry Pi), etc. + +

MuJS is embeddable

+ +

+MuJS is a simple language engine with a small footprint that you can easily embed into your application. +The API is simple and well documented and allows strong integration with code written in other languages. +You don't need to work with byzantine C++ templating mechanisms, or manually manage garbage collection roots. +It is easy to extend MuJS with libraries written in other languages. +It is also easy to extend programs written in other languages with MuJS. + +

MuJS is small

+ +

+Adding MuJS to an application does not bloat it. +The source contains around 15'000 lines of C. +Under 64-bit Linux, the compiled library takes 180kB if optimized for size, +and 260kB if optimized for speed. + +Compare this with V8, SpiderMonkey or JavaScriptCore, +which are all several hundred thousand lines of code, +take several megabytes of space, +and require the C++ runtime. + +

MuJS is reasonably fast and secure

+ +

+It is a bytecode interpreter with a very fast mechanism to call-out to C. +The default build is sandboxed with very restricted access to resources. +Due to the nature of bytecode, MuJS is not as fast as JIT compiling +implementations but starts up faster and uses fewer resources. +If you implement heavy lifting in C code, controlled by Javascript, +you can get the best of both worlds. + +

MuJS is free software

+ +

+MuJS is free open source software distributed under the +ISC license. + +

MuJS is developed by a stable company

+ +

+Artifex Software has long experience in +interpreters and page description languages, and has a history with open source +that goes back to 1993 when it was created to facilitate licensing Ghostscript +to OEMs. + +

+ +
+ +Copyright © 2013-2017 Artifex Software Inc. +
+ + + diff --git a/src/mujs/docs/license.html b/src/mujs/docs/license.html new file mode 100644 index 0000000..d4e7056 --- /dev/null +++ b/src/mujs/docs/license.html @@ -0,0 +1,50 @@ + + + + +MuJS License + + + + +
+

MuJS License

+
+ + + +
+ +

+MuJS is Copyright © 2013-2017 Artifex Software, Inc. + +

+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. + +

+ +
+ +Copyright © 2013-2017 Artifex Software Inc. +
+ + + diff --git a/src/mujs/docs/logo.ps b/src/mujs/docs/logo.ps new file mode 100644 index 0000000..2b8347f --- /dev/null +++ b/src/mujs/docs/logo.ps @@ -0,0 +1,47 @@ +%! +<>setpagedevice + +% #323330 = 50 51 48 +% #F0DB4F = 240 219 79 +% #4386b5 = 67 134 181 + +/cG { 50 255 div 51 255 div 48 255 div setrgbcolor } def +/cY { 240 255 div 219 255 div 79 255 div setrgbcolor } def +/cB { 67 255 div 134 255 div 181 255 div setrgbcolor } def + +% fill background with yellow +cY +0 0 moveto 512 0 lineto 512 512 lineto 0 512 lineto closepath fill + +% move logo to lower right corner +512 0.2 mul 0 translate +0.8 0.8 scale + +% center logo +0.875 0.875 scale +32 32 translate + +% draw electrons and nucleus +cG +gsave + 256 256 translate + + 16 setlinewidth + gsave 0 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore + gsave 60 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore + gsave 120 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore + + 0 0 96 0 360 arc fill +grestore + +% draw yellow 'JS' text in center of nucleus +cY +gsave + /SourceSansPro-Bold findfont 128 scalefont setfont + 256 256 moveto + (JS) + dup stringwidth pop -2 div -44 rmoveto + show +grestore + +showpage diff --git a/src/mujs/docs/mujs-logo.png b/src/mujs/docs/mujs-logo.png new file mode 100644 index 0000000..f1ad1a3 Binary files /dev/null and b/src/mujs/docs/mujs-logo.png differ diff --git a/src/mujs/docs/reference.html b/src/mujs/docs/reference.html new file mode 100644 index 0000000..74a7932 --- /dev/null +++ b/src/mujs/docs/reference.html @@ -0,0 +1,719 @@ + + + + +MuJS Reference + + + + +
+

MuJS Reference

+
+ + + +
+ +

Introduction

+ +

+MuJS is a library, written in clean and simple C. +Being an extension library, MuJS has no notion of a main program: it only works embedded in a host client program. +The host program can invoke functions to execute Javascript code, read and write Javascript variables, and register C functions to be called by Javascript. + +

+The MuJS distribution includes a sample host program called "mujs", which uses the MuJS library to offer a standalone Javascript interpreter for interactive or batch use. + +

+This reference manual assumes that you are already familiar with the Javascript language, in particular the type system and object prototype mechanisms. + +

Basic Concepts

+ +

Values and Types

+ +

+There are six basic types in Javascript: undefined, null, boolean, number, string and object. + +

+Each object also has a class: object, array, function, userdata, regular expression, etc. + +

+Javascript can call functions written in C provided by the host program, as well as other Javascript functions. + +

+Objects with the userdata class are provided to allow arbitrary C data to be attached to Javascript objects. +A userdata object has a pointer to a block of raw memory, which is managed by the host. +Userdata values cannot be created or modified in Javascript, only through the C API. +This guarantees the integrity of data owned by the host program. + +

+Custom properties on userdata objects can be implemented using getter and setter property accessor functions. + +

+Numbers are represented using double precision floating point values. + +

+Strings in the C interface are zero-terminated byte arrays in WTF-8 encoding. +This allows both arbitrary 16-bit values (as required by Javascript) and also +extended code points for the full 21-bit Unicode range. +These extended characters will mostly work as expected in Javascript. + +

+If you have Javascript code that expects to work with UTF-16 surrogate pairs, +you will need to manually convert any extended characters to surrogate pairs +and back when passing strings between C and Javascript. + +

+The U+0000 character is encoded as the two-byte sequence , same as in +modified UTF-8. + +

Environments

+ +

+Each function executes within an environment which defines which variables are accessible. +This is a chain of all environment records in scope, with the global environment at the top. +Each environment record in MuJS is represented as an object with the null prototype, including the global environment object. + +

+The registry is a hidden environment record which is only accessible to C. +This is where Javascript values and objects that should only be accessible to C functions may be stored. + +

Error Handling

+ +

+All Javascript actions start from C code in the host program calling a function from the MuJS library. +Whenever an exception is thrown during the compilation or execution of Javascript, control returns to the host, which can take appropriate measures (such as printing an error message). +C code can also throw exceptions by calling functions to create an error object and return control to Javascript. + +

+Internally, MuJS uses the C longjmp facility to handle errors. +A protected environment uses setjmp to set a recovery point. +The try statement in Javascript creates such a recovery point, as does calling js_dostring, js_dofile, js_ploadstring, js_ploadfile, +js_pcall and js_pconstruct. + +

+When an error occurs or an exception is thrown from Javascript, it does a long jump to the most recent active recovery point. + +

+If an error occurs outside any protected environment, MuJS first calls the panic function and then calls abort, thus exiting the host application. +Your panic function can avoid this exit by never returning (for example by doing a long jump to your own recovery point outside MuJS). + +

Garbage Collection

+ +

+MuJS performs automatic memory management using a basic mark-and-sweep collector. +Collection is automatically triggered when enough allocations have accumulated. +You can also force a collection pass from C. + +

+Userdata objects have an associated C finalizer function that is called when +the corresponding object is freed. + +

The Stack

+ +

+MuJS uses a virtual stack to pass values to and from C. +Each element in this stack represents a Javascript value (null, number, string, etc). + +

+Whenever Javascript calls C, the called function gets a new stack. +This stack initially contains the this value and any arguments passed to the function. +When the C function returns, the top value on the stack is passed back to the caller as the return value. + +

+The stack values are accessed using stack indices. +Index 0 always contains the this value, and function arguments are index 1 and up. +Negative indices count down from the top of the stack, so index -1 is the top of the index and index -2 is the one below that. + +

The Application Program Interface

+ +

State

+ +
+typedef struct js_State js_State;
+
+ +

+The interpreter state is bundled up in the opaque struct js_State. +This state contains the value stacks, protected environments, and environment records. + +

+js_State *js_newstate(js_Alloc alloc, void *context, int flags);
+
+ +

+Create a new state using the allocator function and allocator context. +Pass NULL to use the default allocator. + +

+The available flags: + +

    +
  • JS_STRICT: compile and run code using ES5 strict mode. +
+ +
+void js_freestate(js_State *J);
+
+ +

+Destroy the state and free all dynamic memory used by the state. + +

Allocator

+ +

+The interpreter uses a host provided function for all memory allocation needs: + +

+typedef void *(*js_Alloc)(void *memctx, void *ptr, int size);
+
+ +

+When size is zero, the allocator should behave like free and return NULL. +When size is not zero, the allocator should behave like realloc. +The allocator should return NULL if it cannot fulfill the request. +The default allocator uses malloc, realloc and free. + +

Panic

+ +
+typedef void (*js_Panic)(js_State *J);
+
+js_Panic js_atpanic(js_State *J, js_Panic panic);
+
+ +Set a new panic function, and return the old one. + +

Report

+ +
+typedef void (*js_Report)(js_State *J, const char *message);
+
+void js_setreport(js_State *J, js_Report report);
+
+ +

+Set a callback function for reporting various warnings +and garbage collection statistics. + +

+The report function must not throw an exception +or call any other MuJS function except js_getcontext(). + +

Garbage collection

+ +
+js_gc(js_State *J, int report);
+
+ +

+Force a garbage collection pass. +If the report argument is non-zero, send a summary of garbage collection statistics to +the report callback function. + +

Loading and compiling scripts

+ +

+A script is compiled by calling js_loadstring or js_loadfile. +The result of a successful compilation is a function on the top of the stack. +This function can then be executed with js_call. + +

+void js_loadstring(js_State *J, const char *filename, const char *source);
+void js_loadfile(js_State *J, const char *filename);
+
+ +

+Compile the script and push the resulting function. + +

+int js_ploadstring(js_State *J, const char *filename, const char *source);
+int js_ploadfile(js_State *J, const char *filename);
+
+ +Like js_loadstring/js_loadfile but in a protected environment. +In case of success, return 0 with the result as a function on the stack. +In case of failure, return 1 with the error object on the stack. + +

Calling functions

+ +
+void js_call(js_State *J, int n);
+
+ +

+To call a function, you must use the following protocol: +1) push the function to call onto the stack, +2) push the this value to be used by the function, +3) push the arguments to the function in order, +4) finally, call js_call with the number of arguments pushed in step 3. + +

+Pop the function, the this value, and all arguments; +execute the function; +then push the return value from the function. + +

+void js_construct(js_State *J, int n);
+
+ +

+The construct function implements the 'new' expression in Javascript. +This is similar to js_call, but without pushing a this value: +1) push the constructor function to call onto the stack, +2) push the arguments to the constructor function in order, +3) finally, call js_construct with the number of arguments pushed in step 2. + +

+int js_pcall(js_State *J, int n);
+int js_pconstruct(js_State *J, int n);
+
+ +

+Like js_call and js_construct but in a protected environment. +In case of success, return 0 with the result on the stack. +In case of failure, return 1 with the error object on the stack. + +

Script helpers

+ +

+There are two convenience functions for loading and executing code. + +

+int js_dostring(js_State *J, const char *source);
+
+ +

+Compile and execute the script in the zero-terminated string in source argument. +If any errors occur, call the report callback function and return 1. +Return 0 on success. + +

+int js_dofile(js_State *J, const char *filename);
+
+ +

+Load the script from the file with the given filename, then compile and execute it. +If any errors occur, call the report callback function and return 1. +Return 0 on success. + +

Protected environments

+ +

+The js_try macro pushes a new protected environment and calls setjmp. +If it returns true, an error has occurred. The protected environment has been popped +and the error object is located on the top of the stack. + +

+At the end of the code you want to run in the protected environment you must call +js_endtry in order to pop the protected environment. Note: you should not call +js_endtry when an error has occurred and you are in the true-branch of js_try. + +

+Since the macro is a wrapper around setjmp, the usual +restrictions apply. +Use the following example as a guide for how to use js_try: + +

+if (js_try(J)) {
+	fprintf(stderr, "error: %s", js_trystring(J, -1, "Error"));
+	js_pop(J, 1);
+	return;
+}
+do_some_stuff();
+js_endtry(J);
+
+ +

+Most of the time you shouldn't need to worry about protected environments. +The functions prefixed with 'p' (js_pcall, js_ploadstring, etc) handle setting +up the protected environment and return simple error codes. + +

Errors

+ +
+void js_throw(js_State *J);
+
+ +

+Pop the error object on the top of the stack and return control flow to the most recent protected environment. + +

+void js_newerror(js_State *J, const char *message);
+void js_newevalerror(js_State *J, const char *message);
+void js_newrangeerror(js_State *J, const char *message);
+void js_newreferenceerror(js_State *J, const char *message);
+void js_newsyntaxerror(js_State *J, const char *message);
+void js_newtypeerror(js_State *J, const char *message);
+void js_newurierror(js_State *J, const char *message);
+
+ +

+Push a new error object on the stack. + +

+void js_error(js_State *J, const char *fmt, ...);
+void js_evalerror(js_State *J, const char *fmt, ...);
+void js_rangeerror(js_State *J, const char *fmt, ...);
+void js_referenceerror(js_State *J, const char *fmt, ...);
+void js_syntaxerror(js_State *J, const char *fmt, ...);
+void js_typeerror(js_State *J, const char *fmt, ...);
+void js_urierror(js_State *J, const char *fmt, ...);
+
+ +

+Wrapper to push a new error object on the stack using a printf formatting string and call js_throw. + +

Stack manipulation

+ +
+int js_gettop(js_State *J);
+void js_pop(js_State *J, int n);
+void js_rot(js_State *J, int n);
+void js_copy(js_State *J, int idx);
+void js_remove(js_State *J, int idx);
+void js_insert(js_State *J, int idx);
+void js_replace(js_State* J, int idx);
+
+ +

Comparisons and arithmetic

+ +
+void js_concat(js_State *J);
+int js_compare(js_State *J, int *okay);
+int js_equal(js_State *J);
+int js_strictequal(js_State *J);
+int js_instanceof(js_State *J);
+
+ +

+The equivalent of the '+', comparison, and instanceof operators. +The okay argument to js_compare is set to 0 if any of the values are NaN, otherwise it is set to 1. + + + +

Primitive values

+ +
+void js_pushundefined(js_State *J);
+void js_pushnull(js_State *J);
+void js_pushboolean(js_State *J, int v);
+void js_pushnumber(js_State *J, double v);
+void js_pushstring(js_State *J, const char *v);
+void js_pushliteral(js_State *J, const char *v);
+
+ +

+Push primitive values. +js_pushstring makes a copy of the string, so it may be freed or changed after passing it in. +js_pushliteral keeps a pointer to the string, so it must not be changed or freed after passing it in. + +

+int js_isdefined(js_State *J, int idx);
+int js_isundefined(js_State *J, int idx);
+int js_isnull(js_State *J, int idx);
+int js_isboolean(js_State *J, int idx);
+int js_isnumber(js_State *J, int idx);
+int js_isstring(js_State *J, int idx);
+int js_isprimitive(js_State *J, int idx);
+
+ +

+Test if a primitive value is of a given type. + +

+int js_toboolean(js_State *J, int idx);
+double js_tonumber(js_State *J, int idx);
+int js_tointeger(js_State *J, int idx);
+int js_toint32(js_State *J, int idx);
+unsigned int js_touint32(js_State *J, int idx);
+short js_toint16(js_State *J, int idx);
+unsigned short js_touint16(js_State *J, int idx);
+const char *js_tostring(js_State *J, int idx);
+
+ +

+Convert the value at the given index into a C value. +If the value is an object, invoke the toString and/or valueOf methods to do the conversion. + +

+The conversion may change the actual value in the stack! + +

+There is no guarantee that the pointer returned by js_tostring will be valid after +the corresponding value is removed from the stack. + +

+Note that the toString and valueOf methods that may be invoked by these functions +can throw exceptions. If you want to catch and ignore exceptions, use the following +functions instead. The 'error' argument is the default value that will be returned +if a toString/valueOf method throws an exception. + +

+int js_tryboolean(js_State *J, int idx, int error);
+double js_trynumber(js_State *J, int idx, double error);
+int js_tryinteger(js_State *J, int idx, int error);
+const char *js_trystring(js_State *J, int idx, const char *error);
+
+ +

Objects

+ +
+enum {
+	JS_REGEXP_G = 1,
+	JS_REGEXP_I = 2,
+	JS_REGEXP_M = 4,
+};
+
+void js_newobject(js_State *J);
+void js_newarray(js_State *J);
+void js_newboolean(js_State *J, int v);
+void js_newnumber(js_State *J, double v);
+void js_newstring(js_State *J, const char *v);
+void js_newregexp(js_State *J, const char *pattern, int flags);
+
+ +

+Create and push objects on the stack. + +

+int js_isobject(js_State *J, int idx);
+int js_isarray(js_State *J, int idx);
+int js_iscallable(js_State *J, int idx);
+int js_isregexp(js_State *J, int idx);
+
+ +

+Test the type and class of an object on the stack. + +

Properties

+ +

+The property functions all work on an object. +If the stack slot referenced by the index does not contain an object, they will throw an error. + +

+enum {
+	JS_READONLY = 1,
+	JS_DONTENUM = 2,
+	JS_DONTCONF = 4,
+};
+
+ +

+Property attribute bit-mask values. + +

+int js_hasproperty(js_State *J, int idx, const char *name);
+
+ +

+If the object has a property with the given name, return 1 and push the value of the property; otherwise return 0 and leave the stack untouched. + +

+void js_getproperty(js_State *J, int idx, const char *name);
+
+ +

+Push the value of the named property of the object. +If the object does not have the named property, push undefined instead. + +

+void js_setproperty(js_State *J, int idx, const char *name);
+
+ +

+Pop a value from the top of the stack and set the value of the named property of the object. + +

+void js_defproperty(js_State *J, int idx, const char *name, int atts);
+
+ +

+Pop a value from the top of the stack and set the value of the named property of the object. +Also define the property attributes. + +

+void js_defaccessor(js_State *J, int idx, const char *name, int atts);
+
+ +

+Define the getter and setter attributes of a property on the object. +Pop the two getter and setter functions from the stack. +Use null instead of a function object if you want to leave any of the functions unset. + +

+void js_delproperty(js_State *J, int idx, const char *name);
+
+ +

+Delete the named property from the object. + +

Array properties

+ +
+int js_getlength(js_State *J, int idx);
+void js_setlength(js_State *J, int idx, int len);
+
+ +

+Wrappers to get and set the "length" property of an object. + +

+int js_hasindex(js_State *J, int idx, int i);
+void js_getindex(js_State *J, int idx, int i);
+void js_setindex(js_State *J, int idx, int i);
+void js_delindex(js_State *J, int idx, int i);
+
+ +

+These array index functions functions are simple wrappers around the equivalent property functions. +They convert the numeric index to a string to use as the property name. + +

Globals

+ +
+void js_pushglobal(js_State *J);
+
+ +

+Push the object representing the global environment record. + +

+void js_getglobal(js_State *J, const char *name);
+void js_setglobal(js_State *J, const char *name);
+void js_defglobal(js_State *J, const char *name, int atts);
+
+ +

+Wrappers around js_pushglobal and js_get/set/defproperty to read and write the values of global variables. + +

C Functions

+ +
+void js_newcfunction(js_State *J, js_CFunction fun, const char *name, int length);
+
+ +

+Push a function object wrapping a C function pointer. + +

+The length argument is the number of arguments to the function. +If the function is called with fewer arguments, the argument list will be padded with undefined. + +

+void js_newcconstructor(js_State *J,
+	js_CFunction fun, js_CFunction con,
+	const char *name, int length);
+
+ +

+Pop the object to set as the "prototype" property for the constructor function object. +Push a function object wrapping a C function pointer, allowing for separate function pointers for regular calls and 'new' operator calls. + +

+void js_currentfunction(js_State *J);
+
+ +

+Push the currently executing function object. + +

Userdata

+ +
+typedef void (*js_Finalize)(js_State *J, void *data);
+typedef int (*js_HasProperty)(js_State *J, void *data, const char *name);
+typedef int (*js_Put)(js_State *J, void *data, const char *name);
+typedef int (*js_Delete)(js_State *J, void *data, const char *name);
+
+void js_newuserdata(js_State *J, const char *tag, void *data,
+	js_Finalize finalize);
+
+void js_newuserdatax(js_State *J, const char *tag, void *data,
+	js_HasProperty has,
+	js_Put put,
+	js_Delete delete,
+	js_Finalize finalize);
+
+ +

+Pop an object from the top of the stack to use as the internal prototype property for the new object. +Push a new userdata object wrapping a pointer to C memory. +The userdata object is tagged using a string, to represent the type of the C memory. + +

+The finalize callback, if it is not NULL, will be called when the object is +freed by the garbage collector. + +

+The extended function also has callback functions for overriding property accesses. +If these are set, they can be used to override accesses to certain properties. +Any property accesses that are not overridden will be handled as usual in the runtime. +The "HasProperty" callback should push a value and return true if it wants to +handle the property, otherwise it should do nothing and return false. "Put" +should read the top value and return true if it wants to handle the property. +Likewise, "Delete" should return true if it wants to handle the property. + +

+int js_isuserdata(js_State *J, int idx, const char *tag);
+
+ +

+Test if an object is a userdata object with the given type tag string. + +

+void *js_touserdata(js_State *J, int idx, const char *tag);
+
+ +

+Return the wrapped pointer from a userdata object. +If the object is undefined or null, return NULL. +If the object is not a userdata object with the given type tag string, throw a type error. + +

Registry

+ +

+The registry can be used to store references to Javascript objects accessible from C, +but hidden from Javascript to prevent tampering. + +

+void js_getregistry(js_State *J, const char *name);
+void js_setregistry(js_State *J, const char *name);
+void js_delregistry(js_State *J, const char *name);
+
+ +

+Access properties on the hidden registry object. + +

+const char *js_ref(js_State *J);
+
+ +

+WIP: Pop a value from the stack and store it in the registry using a new unique property name. +Return the property name. + +

+void js_unref(js_State *J, const char *ref);
+
+ +

+WIP: Delete the reference from the registry. + +

+ +
+ +Copyright © 2013-2017 Artifex Software Inc. +
+ + + diff --git a/src/mujs/docs/style.css b/src/mujs/docs/style.css new file mode 100644 index 0000000..525f34b --- /dev/null +++ b/src/mujs/docs/style.css @@ -0,0 +1,40 @@ +h1, nav, footer { font-family: sans-serif; } + +a { text-decoration: none; } +a:hover { text-decoration: underline; } +h2 { font-size: 1.25rem; } +h3 { font-size: 1.12rem; } +ul li { list-style-type: circle; } +pre, table, ol, dl { margin-left: 2rem; } +li { margin: 0; } +th, td { text-align: left; vertical-align: top; } + +body { margin: 0; } +h1 { + font-weight: normal; + margin: 0; + padding: 1rem 2rem; +} +header{ + color: white; + background: no-repeat; + background-color: #36648b; + background-image: url("mujs-logo.png"); + background-position: top right; + min-height: 72px; +} +nav { + padding: 0.75rem 2rem; + background-color: #ddd; + no-text-transform: uppercase; +} +nav a { color: #303030; padding-right: 2rem; } +article { + max-width: 50rem; + margin: 2rem; +} +footer { + background-color: #ddd; + color: #303030; + padding: 1rem 2rem; +} diff --git a/src/mujs/genucd.py b/src/mujs/genucd.py new file mode 100644 index 0000000..8625f8c --- /dev/null +++ b/src/mujs/genucd.py @@ -0,0 +1,117 @@ +# Create utfdata.h from UnicodeData.txt and SpecialCasing.txt + +import sys + +tolower = [] +toupper = [] +tolower_full = [] +toupper_full = [] +isalpha = [] + +for line in open(sys.argv[1]).readlines(): + line = line.split(";") + code = int(line[0],16) + # if code > 65535: continue # skip non-BMP codepoints + if line[2][0] == 'L': + isalpha.append(code) + if line[12]: + toupper.append((code,int(line[12],16))) + if line[13]: + tolower.append((code,int(line[13],16))) + +for line in open(sys.argv[2]).readlines(): + # SpecialCasing.txt -- code; lower; title; upper; (condition;)? # comment + line = line.strip() + if len(line) == 0: + continue + if line[0] == "#": + continue + line = line.split(";") + code = int(line[0],16) + lower = line[1].strip() + upper = line[3].strip() + if len(lower) == 0 or len(upper) == 0: + continue + condition = line[4].split("#")[0].strip() + if len(condition) > 0: + continue + lower = list(map(lambda x: int(x,16), lower.split(" "))) + upper = list(map(lambda x: int(x,16), upper.split(" "))) + if lower[0] != code: + tolower_full.append([code] + lower) + if upper[0] != code: + toupper_full.append([code] + upper) + +tolower_full.sort() +toupper_full.sort() + +def dumpalpha(): + table = [] + prev = 0 + start = 0 + for code in isalpha: + if code != prev+1: + if start: + table.append((start,prev)) + start = code + prev = code + table.append((start,prev)) + + print("") + print("static const Rune ucd_alpha2[] = {") + for a, b in table: + if b - a > 0: + print(hex(a)+","+hex(b)+",") + print("};"); + + print("") + print("static const Rune ucd_alpha1[] = {") + for a, b in table: + if b - a == 0: + print(hex(a)+",") + print("};"); + +def dumpmap(name, input): + table = [] + prev_a = 0 + prev_b = 0 + start_a = 0 + start_b = 0 + for a, b in input: + if a != prev_a+1 or b != prev_b+1: + if start_a: + table.append((start_a,prev_a,start_b)) + start_a = a + start_b = b + prev_a = a + prev_b = b + table.append((start_a,prev_a,start_b)) + + print("") + print("static const Rune " + name + "2[] = {") + for a, b, n in table: + if b - a > 0: + print(hex(a)+","+hex(b)+","+str(n-a)+",") + print("};"); + + print("") + print("static const Rune " + name + "1[] = {") + for a, b, n in table: + if b - a == 0: + print(hex(a)+","+str(n-a)+",") + print("};"); + +def dumpmultimap(name, table, w): + print("") + print("static const Rune " + name + "[] = {") + for list in table: + list += [0] * (w - len(list)) + print(",".join(map(hex, list)) + ",") + print("};") + +print("/* This file was automatically created from " + sys.argv[1] + " */") +dumpalpha() +dumpmap("ucd_tolower", tolower) +dumpmap("ucd_toupper", toupper) +dumpmultimap("ucd_tolower_full", tolower_full, 4) +dumpmultimap("ucd_toupper_full", toupper_full, 5) diff --git a/src/mujs/jsarray.c b/src/mujs/jsarray.c new file mode 100644 index 0000000..962d59f --- /dev/null +++ b/src/mujs/jsarray.c @@ -0,0 +1,832 @@ +#include "jsi.h" + +#ifndef JS_HEAPSORT +#define JS_HEAPSORT 0 +#endif + +int js_getlength(js_State *J, int idx) +{ + int len; + js_getproperty(J, idx, "length"); + len = js_tointeger(J, -1); + js_pop(J, 1); + return len; +} + +void js_setlength(js_State *J, int idx, int len) +{ + js_pushnumber(J, len); + js_setproperty(J, idx < 0 ? idx - 1 : idx, "length"); +} + +static void jsB_new_Array(js_State *J) +{ + int i, top = js_gettop(J); + + js_newarray(J); + + if (top == 2) { + if (js_isnumber(J, 1)) { + js_copy(J, 1); + js_setproperty(J, -2, "length"); + } else { + js_copy(J, 1); + js_setindex(J, -2, 0); + } + } else { + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, -2, i - 1); + } + } +} + +static void Ap_concat(js_State *J) +{ + int i, top = js_gettop(J); + int n, k, len; + + js_newarray(J); + n = 0; + + for (i = 0; i < top; ++i) { + js_copy(J, i); + if (js_isarray(J, -1)) { + len = js_getlength(J, -1); + for (k = 0; k < len; ++k) + if (js_hasindex(J, -1, k)) + js_setindex(J, -3, n++); + js_pop(J, 1); + } else { + js_setindex(J, -2, n++); + } + } +} + +static void Ap_join(js_State *J) +{ + char * volatile out = NULL; + const char * volatile r = NULL; + const char *sep; + int seplen; + int k, n, len, rlen; + + len = js_getlength(J, 0); + + if (js_isdefined(J, 1)) { + sep = js_tostring(J, 1); + seplen = strlen(sep); + } else { + sep = ","; + seplen = 1; + } + + if (len <= 0) { + js_pushliteral(J, ""); + return; + } + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + n = 0; + for (k = 0; k < len; ++k) { + js_getindex(J, 0, k); + if (js_iscoercible(J, -1)) { + r = js_tostring(J, -1); + rlen = strlen(r); + } else { + rlen = 0; + } + + if (k == 0) { + out = js_malloc(J, rlen + 1); + if (rlen > 0) { + memcpy(out, r, rlen); + n += rlen; + } + } else { + if (n + seplen + rlen > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + out = js_realloc(J, out, n + seplen + rlen + 1); + if (seplen > 0) { + memcpy(out + n, sep, seplen); + n += seplen; + } + if (rlen > 0) { + memcpy(out + n, r, rlen); + n += rlen; + } + } + + js_pop(J, 1); + } + + js_pushlstring(J, out, n); + js_endtry(J); + js_free(J, out); +} + +static void Ap_pop(js_State *J) +{ + int n; + + n = js_getlength(J, 0); + + if (n > 0) { + js_getindex(J, 0, n - 1); + js_delindex(J, 0, n - 1); + js_setlength(J, 0, n - 1); + } else { + js_setlength(J, 0, 0); + js_pushundefined(J); + } +} + +static void Ap_push(js_State *J) +{ + int i, top = js_gettop(J); + int n; + + n = js_getlength(J, 0); + + for (i = 1; i < top; ++i, ++n) { + js_copy(J, i); + js_setindex(J, 0, n); + } + + js_setlength(J, 0, n); + + js_pushnumber(J, n); +} + +static void Ap_reverse(js_State *J) +{ + int len, middle, lower; + + len = js_getlength(J, 0); + middle = len / 2; + lower = 0; + + while (lower != middle) { + int upper = len - lower - 1; + int haslower = js_hasindex(J, 0, lower); + int hasupper = js_hasindex(J, 0, upper); + if (haslower && hasupper) { + js_setindex(J, 0, lower); + js_setindex(J, 0, upper); + } else if (hasupper) { + js_setindex(J, 0, lower); + js_delindex(J, 0, upper); + } else if (haslower) { + js_setindex(J, 0, upper); + js_delindex(J, 0, lower); + } + ++lower; + } + + js_copy(J, 0); +} + +static void Ap_shift(js_State *J) +{ + int k, len; + + len = js_getlength(J, 0); + + if (len == 0) { + js_setlength(J, 0, 0); + js_pushundefined(J); + return; + } + + js_getindex(J, 0, 0); + + for (k = 1; k < len; ++k) { + if (js_hasindex(J, 0, k)) + js_setindex(J, 0, k - 1); + else + js_delindex(J, 0, k - 1); + } + + js_delindex(J, 0, len - 1); + js_setlength(J, 0, len - 1); +} + +static void Ap_slice(js_State *J) +{ + int len, s, e, n; + double sv, ev; + + js_newarray(J); + + len = js_getlength(J, 0); + sv = js_tointeger(J, 1); + ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + if (sv < 0) sv = sv + len; + if (ev < 0) ev = ev + len; + + s = sv < 0 ? 0 : sv > len ? len : sv; + e = ev < 0 ? 0 : ev > len ? len : ev; + + for (n = 0; s < e; ++s, ++n) + if (js_hasindex(J, 0, s)) + js_setindex(J, -2, n); +} + +static int Ap_sort_cmp(js_State *J, int idx_a, int idx_b) +{ + js_Object *obj = js_tovalue(J, 0)->u.object; + if (obj->u.a.simple) { + js_Value *val_a = &obj->u.a.array[idx_a]; + js_Value *val_b = &obj->u.a.array[idx_b]; + int und_a = val_a->t.type == JS_TUNDEFINED; + int und_b = val_b->t.type == JS_TUNDEFINED; + if (und_a) return und_b; + if (und_b) return -1; + if (js_iscallable(J, 1)) { + double v; + js_copy(J, 1); /* copy function */ + js_pushundefined(J); /* no 'this' binding */ + js_pushvalue(J, *val_a); + js_pushvalue(J, *val_b); + js_call(J, 2); + v = js_tonumber(J, -1); + js_pop(J, 1); + if (isnan(v)) + return 0; + if (v == 0) + return 0; + return v < 0 ? -1 : 1; + } else { + const char *str_a, *str_b; + int c; + js_pushvalue(J, *val_a); + js_pushvalue(J, *val_b); + str_a = js_tostring(J, -2); + str_b = js_tostring(J, -1); + c = strcmp(str_a, str_b); + js_pop(J, 2); + return c; + } + } else { + int und_a, und_b; + int has_a = js_hasindex(J, 0, idx_a); + int has_b = js_hasindex(J, 0, idx_b); + if (!has_a && !has_b) { + return 0; + } + if (has_a && !has_b) { + js_pop(J, 1); + return -1; + } + if (!has_a && has_b) { + js_pop(J, 1); + return 1; + } + + und_a = js_isundefined(J, -2); + und_b = js_isundefined(J, -1); + if (und_a) { + js_pop(J, 2); + return und_b; + } + if (und_b) { + js_pop(J, 2); + return -1; + } + + if (js_iscallable(J, 1)) { + double v; + js_copy(J, 1); /* copy function */ + js_pushundefined(J); /* no 'this' binding */ + js_copy(J, -4); + js_copy(J, -4); + js_call(J, 2); + v = js_tonumber(J, -1); + js_pop(J, 3); + if (isnan(v)) + return 0; + if (v == 0) + return 0; + return v < 0 ? -1 : 1; + } else { + const char *str_a = js_tostring(J, -2); + const char *str_b = js_tostring(J, -1); + int c = strcmp(str_a, str_b); + js_pop(J, 2); + return c; + } + } +} + +static void Ap_sort_swap(js_State *J, int idx_a, int idx_b) +{ + js_Object *obj = js_tovalue(J, 0)->u.object; + if (obj->u.a.simple) { + js_Value tmp = obj->u.a.array[idx_a]; + obj->u.a.array[idx_a] = obj->u.a.array[idx_b]; + obj->u.a.array[idx_b] = tmp; + } else { + int has_a = js_hasindex(J, 0, idx_a); + int has_b = js_hasindex(J, 0, idx_b); + if (has_a && has_b) { + js_setindex(J, 0, idx_a); + js_setindex(J, 0, idx_b); + } else if (has_a && !has_b) { + js_delindex(J, 0, idx_a); + js_setindex(J, 0, idx_b); + } else if (!has_a && has_b) { + js_delindex(J, 0, idx_b); + js_setindex(J, 0, idx_a); + } + } +} + +/* A bottom-up/bouncing heapsort implementation */ + +static int Ap_sort_leaf(js_State *J, int i, int end) +{ + int j = i; + int lc = (j << 1) + 1; /* left child */ + int rc = (j << 1) + 2; /* right child */ + while (rc < end) { + if (Ap_sort_cmp(J, rc, lc) > 0) + j = rc; + else + j = lc; + lc = (j << 1) + 1; + rc = (j << 1) + 2; + } + if (lc < end) + j = lc; + return j; +} + +static void Ap_sort_sift(js_State *J, int i, int end) +{ + int j = Ap_sort_leaf(J, i, end); + while (Ap_sort_cmp(J, i, j) > 0) + j = (j - 1) >> 1; /* parent */ + while (j > i) { + Ap_sort_swap(J, i, j); + j = (j - 1) >> 1; /* parent */ + } +} + +static void Ap_sort_heapsort(js_State *J, int n) +{ + int i; + for (i = n / 2 - 1; i >= 0; --i) + Ap_sort_sift(J, i, n); + for (i = n - 1; i > 0; --i) { + Ap_sort_swap(J, 0, i); + Ap_sort_sift(J, 0, i); + } +} + +static void Ap_sort(js_State *J) +{ + int len; + + len = js_getlength(J, 0); + if (len <= 1) { + js_copy(J, 0); + return; + } + + if (!js_iscallable(J, 1) && !js_isundefined(J, 1)) + js_typeerror(J, "comparison function must be a function or undefined"); + + if (len >= INT_MAX) + js_rangeerror(J, "array is too large to sort"); + + Ap_sort_heapsort(J, len); + + js_copy(J, 0); +} + +static void Ap_splice(js_State *J) +{ + int top = js_gettop(J); + int len, start, del, add, k; + + len = js_getlength(J, 0); + start = js_tointeger(J, 1); + if (start < 0) + start = (len + start) > 0 ? len + start : 0; + else if (start > len) + start = len; + + if (js_isdefined(J, 2)) + del = js_tointeger(J, 2); + else + del = len - start; + if (del > len - start) + del = len - start; + if (del < 0) + del = 0; + + js_newarray(J); + + /* copy deleted items to return array */ + for (k = 0; k < del; ++k) + if (js_hasindex(J, 0, start + k)) + js_setindex(J, -2, k); + js_setlength(J, -1, del); + + /* shift the tail to resize the hole left by deleted items */ + add = top - 3; + if (add < del) { + for (k = start; k < len - del; ++k) { + if (js_hasindex(J, 0, k + del)) + js_setindex(J, 0, k + add); + else + js_delindex(J, 0, k + add); + } + for (k = len; k > len - del + add; --k) + js_delindex(J, 0, k - 1); + } else if (add > del) { + for (k = len - del; k > start; --k) { + if (js_hasindex(J, 0, k + del - 1)) + js_setindex(J, 0, k + add - 1); + else + js_delindex(J, 0, k + add - 1); + } + } + + /* copy new items into the hole */ + for (k = 0; k < add; ++k) { + js_copy(J, 3 + k); + js_setindex(J, 0, start + k); + } + + js_setlength(J, 0, len - del + add); +} + +static void Ap_unshift(js_State *J) +{ + int i, top = js_gettop(J); + int k, len; + + len = js_getlength(J, 0); + + for (k = len; k > 0; --k) { + int from = k - 1; + int to = k + top - 2; + if (js_hasindex(J, 0, from)) + js_setindex(J, 0, to); + else + js_delindex(J, 0, to); + } + + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, 0, i - 1); + } + + js_setlength(J, 0, len + top - 1); + + js_pushnumber(J, len + top - 1); +} + +static void Ap_toString(js_State *J) +{ + if (!js_iscoercible(J, 0)) + js_typeerror(J, "'this' is not an object"); + js_getproperty(J, 0, "join"); + if (!js_iscallable(J, -1)) { + js_pop(J, 1); + /* TODO: call Object.prototype.toString implementation directly */ + js_getglobal(J, "Object"); + js_getproperty(J, -1, "prototype"); + js_rot2pop1(J); + js_getproperty(J, -1, "toString"); + js_rot2pop1(J); + } + js_copy(J, 0); + js_call(J, 0); +} + +static void Ap_indexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0; + if (from < 0) from = len + from; + if (from < 0) from = 0; + + js_copy(J, 1); + for (k = from; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_lastIndexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1; + if (from > len - 1) from = len - 1; + if (from < 0) from = len + from; + + js_copy(J, 1); + for (k = from; k >= 0; --k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_every(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (!js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 1); +} + +static void Ap_some(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 0); +} + +static void Ap_forEach(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_pop(J, 2); + } + } + + js_pushundefined(J); +} + +static void Ap_map(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_setindex(J, -3, k); + js_pop(J, 1); + } + } + js_setlength(J, -1, len); +} + +static void Ap_filter(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, to, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + to = 0; + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) { + js_pop(J, 1); + js_setindex(J, -2, to++); + } else { + js_pop(J, 2); + } + } + } +} + +static void Ap_reduce(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = 0; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k < len) + if (js_hasindex(J, 0, k++)) + break; + if (k == len) + js_typeerror(J, "no initial value"); + } + + while (k < len) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + ++k; + } + + /* return accumulator */ +} + +static void Ap_reduceRight(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = len - 1; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k >= 0) + if (js_hasindex(J, 0, k--)) + break; + if (k < 0) + js_typeerror(J, "no initial value"); + } + + while (k >= 0) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + --k; + } + + /* return accumulator */ +} + +static void A_isArray(js_State *J) +{ + if (js_isobject(J, 1)) { + js_Object *T = js_toobject(J, 1); + js_pushboolean(J, T->type == JS_CARRAY); + } else { + js_pushboolean(J, 0); + } +} + +void jsB_initarray(js_State *J) +{ + js_pushobject(J, J->Array_prototype); + { + jsB_propf(J, "Array.prototype.toString", Ap_toString, 0); + jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */ + jsB_propf(J, "Array.prototype.join", Ap_join, 1); + jsB_propf(J, "Array.prototype.pop", Ap_pop, 0); + jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */ + jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0); + jsB_propf(J, "Array.prototype.shift", Ap_shift, 0); + jsB_propf(J, "Array.prototype.slice", Ap_slice, 2); + jsB_propf(J, "Array.prototype.sort", Ap_sort, 1); + jsB_propf(J, "Array.prototype.splice", Ap_splice, 2); + jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */ + + /* ES5 */ + jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1); + jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1); + jsB_propf(J, "Array.prototype.every", Ap_every, 1); + jsB_propf(J, "Array.prototype.some", Ap_some, 1); + jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1); + jsB_propf(J, "Array.prototype.map", Ap_map, 1); + jsB_propf(J, "Array.prototype.filter", Ap_filter, 1); + jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1); + jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1); + } + js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */ + { + /* ES5 */ + jsB_propf(J, "Array.isArray", A_isArray, 1); + } + js_defglobal(J, "Array", JS_DONTENUM); +} diff --git a/src/mujs/jsboolean.c b/src/mujs/jsboolean.c new file mode 100644 index 0000000..dd9df76 --- /dev/null +++ b/src/mujs/jsboolean.c @@ -0,0 +1,38 @@ +#include "jsi.h" + +static void jsB_new_Boolean(js_State *J) +{ + js_newboolean(J, js_toboolean(J, 1)); +} + +static void jsB_Boolean(js_State *J) +{ + js_pushboolean(J, js_toboolean(J, 1)); +} + +static void Bp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean"); + js_pushliteral(J, self->u.boolean ? "true" : "false"); +} + +static void Bp_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean"); + js_pushboolean(J, self->u.boolean); +} + +void jsB_initboolean(js_State *J) +{ + J->Boolean_prototype->u.boolean = 0; + + js_pushobject(J, J->Boolean_prototype); + { + jsB_propf(J, "Boolean.prototype.toString", Bp_toString, 0); + jsB_propf(J, "Boolean.prototype.valueOf", Bp_valueOf, 0); + } + js_newcconstructor(J, jsB_Boolean, jsB_new_Boolean, "Boolean", 1); + js_defglobal(J, "Boolean", JS_DONTENUM); +} diff --git a/src/mujs/jsbuiltin.c b/src/mujs/jsbuiltin.c new file mode 100644 index 0000000..23ed11f --- /dev/null +++ b/src/mujs/jsbuiltin.c @@ -0,0 +1,249 @@ +#include "jsi.h" +#include "regexp.h" + +static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n) +{ + js_newcfunction(J, cfun, name, n); + js_defglobal(J, name, JS_DONTENUM); +} + +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n) +{ + const char *pname = strrchr(name, '.'); + pname = pname ? pname + 1 : name; + js_newcfunction(J, cfun, name, n); + js_defproperty(J, -2, pname, JS_DONTENUM); +} + +void jsB_propn(js_State *J, const char *name, double number) +{ + js_pushnumber(J, number); + js_defproperty(J, -2, name, JS_READONLY | JS_DONTENUM | JS_DONTCONF); +} + +void jsB_props(js_State *J, const char *name, const char *string) +{ + js_pushliteral(J, string); + js_defproperty(J, -2, name, JS_DONTENUM); +} + +static void jsB_parseInt(js_State *J) +{ + const char *s = js_tostring(J, 1); + int radix = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0; + double sign = 1; + double n; + char *e; + + while (jsY_iswhite(*s) || jsY_isnewline(*s)) + ++s; + if (*s == '-') { + ++s; + sign = -1; + } else if (*s == '+') { + ++s; + } + if (radix == 0) { + radix = 10; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + radix = 16; + } + } else if (radix < 2 || radix > 36) { + js_pushnumber(J, NAN); + return; + } + n = js_strtol(s, &e, radix); + if (s == e) + js_pushnumber(J, NAN); + else + js_pushnumber(J, n * sign); +} + +static void jsB_parseFloat(js_State *J) +{ + const char *s = js_tostring(J, 1); + char *e; + double n; + + while (jsY_iswhite(*s) || jsY_isnewline(*s)) ++s; + if (!strncmp(s, "Infinity", 8)) + js_pushnumber(J, INFINITY); + else if (!strncmp(s, "+Infinity", 9)) + js_pushnumber(J, INFINITY); + else if (!strncmp(s, "-Infinity", 9)) + js_pushnumber(J, -INFINITY); + else { + n = js_stringtofloat(s, &e); + if (e == s) + js_pushnumber(J, NAN); + else + js_pushnumber(J, n); + } +} + +static void jsB_isNaN(js_State *J) +{ + double n = js_tonumber(J, 1); + js_pushboolean(J, isnan(n)); +} + +static void jsB_isFinite(js_State *J) +{ + double n = js_tonumber(J, 1); + js_pushboolean(J, isfinite(n)); +} + +static void Encode(js_State *J, const char *str_, const char *unescaped) +{ + /* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */ + const char * volatile str = str_; + js_Buffer *sb = NULL; + + static const char *HEX = "0123456789ABCDEF"; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + while (*str) { + int c = (unsigned char) *str++; + if (strchr(unescaped, c)) + js_putc(J, &sb, c); + else { + js_putc(J, &sb, '%'); + js_putc(J, &sb, HEX[(c >> 4) & 0xf]); + js_putc(J, &sb, HEX[c & 0xf]); + } + } + js_putc(J, &sb, 0); + + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Decode(js_State *J, const char *str_, const char *reserved) +{ + /* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */ + const char * volatile str = str_; + js_Buffer *sb = NULL; + int a, b; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + while (*str) { + int c = (unsigned char) *str++; + if (c != '%') + js_putc(J, &sb, c); + else { + if (!str[0] || !str[1]) + js_urierror(J, "truncated escape sequence"); + a = *str++; + b = *str++; + if (!jsY_ishex(a) || !jsY_ishex(b)) + js_urierror(J, "invalid escape sequence"); + c = jsY_tohex(a) << 4 | jsY_tohex(b); + if (!strchr(reserved, c)) + js_putc(J, &sb, c); + else { + js_putc(J, &sb, '%'); + js_putc(J, &sb, a); + js_putc(J, &sb, b); + } + } + } + js_putc(J, &sb, 0); + + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +#define URIRESERVED ";/?:@&=+$," +#define URIALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define URIDIGIT "0123456789" +#define URIMARK "-_.!~*'()" +#define URIUNESCAPED URIALPHA URIDIGIT URIMARK + +static void jsB_decodeURI(js_State *J) +{ + Decode(J, js_tostring(J, 1), URIRESERVED "#"); +} + +static void jsB_decodeURIComponent(js_State *J) +{ + Decode(J, js_tostring(J, 1), ""); +} + +static void jsB_encodeURI(js_State *J) +{ + Encode(J, js_tostring(J, 1), URIUNESCAPED URIRESERVED "#"); +} + +static void jsB_encodeURIComponent(js_State *J) +{ + Encode(J, js_tostring(J, 1), URIUNESCAPED); +} + +void jsB_init(js_State *J) +{ + /* Create the prototype objects here, before the constructors */ + J->Object_prototype = jsV_newobject(J, JS_COBJECT, NULL); + J->Array_prototype = jsV_newobject(J, JS_CARRAY, J->Object_prototype); + J->Function_prototype = jsV_newobject(J, JS_CCFUNCTION, J->Object_prototype); + J->Boolean_prototype = jsV_newobject(J, JS_CBOOLEAN, J->Object_prototype); + J->Number_prototype = jsV_newobject(J, JS_CNUMBER, J->Object_prototype); + J->String_prototype = jsV_newobject(J, JS_CSTRING, J->Object_prototype); + J->Date_prototype = jsV_newobject(J, JS_CDATE, J->Object_prototype); + + J->RegExp_prototype = jsV_newobject(J, JS_CREGEXP, J->Object_prototype); + J->RegExp_prototype->u.r.prog = js_regcompx(J->alloc, J->actx, "(?:)", 0, NULL); + J->RegExp_prototype->u.r.source = js_strdup(J, "(?:)"); + + /* All the native error types */ + J->Error_prototype = jsV_newobject(J, JS_CERROR, J->Object_prototype); + J->EvalError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->RangeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->ReferenceError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->SyntaxError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->TypeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->URIError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + + /* Create the constructors and fill out the prototype objects */ + jsB_initobject(J); + jsB_initarray(J); + jsB_initfunction(J); + jsB_initboolean(J); + jsB_initnumber(J); + jsB_initstring(J); + jsB_initregexp(J); + jsB_initdate(J); + jsB_initerror(J); + jsB_initmath(J); + jsB_initjson(J); + + /* Initialize the global object */ + js_pushnumber(J, NAN); + js_defglobal(J, "NaN", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + js_pushnumber(J, INFINITY); + js_defglobal(J, "Infinity", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + js_pushundefined(J); + js_defglobal(J, "undefined", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + jsB_globalf(J, "parseInt", jsB_parseInt, 1); + jsB_globalf(J, "parseFloat", jsB_parseFloat, 1); + jsB_globalf(J, "isNaN", jsB_isNaN, 1); + jsB_globalf(J, "isFinite", jsB_isFinite, 1); + + jsB_globalf(J, "decodeURI", jsB_decodeURI, 1); + jsB_globalf(J, "decodeURIComponent", jsB_decodeURIComponent, 1); + jsB_globalf(J, "encodeURI", jsB_encodeURI, 1); + jsB_globalf(J, "encodeURIComponent", jsB_encodeURIComponent, 1); +} diff --git a/src/mujs/jscompile.c b/src/mujs/jscompile.c new file mode 100644 index 0000000..3676ca2 --- /dev/null +++ b/src/mujs/jscompile.c @@ -0,0 +1,1431 @@ +#include "jsi.h" + +#define cexp jsC_cexp /* collision with math.h */ + +#define JF js_State *J, js_Function *F + +#define NANOPRINTF_IMPLEMENTATION +#include "nanoprintf.h" + +JS_NORETURN void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) JS_PRINTFLIKE(3,4); + +static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body, int is_fun_exp); +static void cexp(JF, js_Ast *exp); +static void cstmlist(JF, js_Ast *list); +static void cstm(JF, js_Ast *stm); + +void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + npf_vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + npf_snprintf(buf, 256, "%s:%d: ", J->filename, node->line); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static const char *futurewords[] = { + "class", "const", "enum", "export", "extends", "import", "super", +}; + +static const char *strictfuturewords[] = { + "implements", "interface", "let", "package", "private", "protected", + "public", "static", "yield", +}; + +static void checkfutureword(JF, js_Ast *exp) +{ + if (jsY_findword(exp->string, futurewords, nelem(futurewords)) >= 0) + jsC_error(J, exp, "'%s' is a future reserved word", exp->string); + if (F->strict) { + if (jsY_findword(exp->string, strictfuturewords, nelem(strictfuturewords)) >= 0) + jsC_error(J, exp, "'%s' is a strict mode future reserved word", exp->string); + } +} + +static js_Function *newfun(js_State *J, int line, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict, int is_fun_exp) +{ + js_Function *F = js_malloc(J, sizeof *F); + memset(F, 0, sizeof *F); + F->gcmark = 0; + F->gcnext = J->gcfun; + J->gcfun = F; + ++J->gccounter; + + F->filename = js_intern(J, J->filename); + F->line = line; + F->script = script; + F->strict = default_strict; + F->name = name ? name->string : ""; + + cfunbody(J, F, name, params, body, is_fun_exp); + + return F; +} + +/* Emit opcodes, constants and jumps */ + +static void emitraw(JF, int value) +{ + if (value != (js_Instruction)value) + js_syntaxerror(J, "integer overflow in instruction coding"); + if (F->codelen >= F->codecap) { + F->codecap = F->codecap ? F->codecap * 2 : 64; + F->code = js_realloc(J, F->code, F->codecap * sizeof *F->code); + } + F->code[F->codelen++] = value; +} + +static void emit(JF, int value) +{ + emitraw(J, F, F->lastline); + emitraw(J, F, value); +} + +static void emitarg(JF, int value) +{ + emitraw(J, F, value); +} + +static void emitline(JF, js_Ast *node) +{ + F->lastline = node->line; +} + +static int addfunction(JF, js_Function *value) +{ + if (F->funlen >= F->funcap) { + F->funcap = F->funcap ? F->funcap * 2 : 16; + F->funtab = js_realloc(J, F->funtab, F->funcap * sizeof *F->funtab); + } + F->funtab[F->funlen] = value; + return F->funlen++; +} + +static int addlocal(JF, js_Ast *ident, int reuse) +{ + const char *name = ident->string; + if (F->strict) { + if (!strcmp(name, "arguments")) + jsC_error(J, ident, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(name, "eval")) + jsC_error(J, ident, "redefining 'eval' is not allowed in strict mode"); + } else { + if (!strcmp(name, "eval")) + js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line); + } + if (reuse || F->strict) { + int i; + for (i = 0; i < F->varlen; ++i) { + if (!strcmp(F->vartab[i], name)) { + if (reuse) + return i+1; + if (F->strict) + jsC_error(J, ident, "duplicate formal parameter '%s'", name); + } + } + } + if (F->varlen >= F->varcap) { + F->varcap = F->varcap ? F->varcap * 2 : 16; + F->vartab = js_realloc(J, F->vartab, F->varcap * sizeof *F->vartab); + } + F->vartab[F->varlen] = name; + return ++F->varlen; +} + +static int findlocal(JF, const char *name) +{ + int i; + for (i = F->varlen; i > 0; --i) + if (!strcmp(F->vartab[i-1], name)) + return i; + return -1; +} + +static void emitfunction(JF, js_Function *fun) +{ + F->lightweight = 0; + emit(J, F, OP_CLOSURE); + emitarg(J, F, addfunction(J, F, fun)); +} + +static void emitnumber(JF, double num) +{ + if (num == 0) { + emit(J, F, OP_INTEGER); + emitarg(J, F, 32768); + if (signbit(num)) + emit(J, F, OP_NEG); + } else if (num >= SHRT_MIN && num <= SHRT_MAX && num == (int)num) { + emit(J, F, OP_INTEGER); + emitarg(J, F, num + 32768); + } else { +#define N (sizeof(num) / sizeof(js_Instruction)) + js_Instruction x[N]; + size_t i; + emit(J, F, OP_NUMBER); + memcpy(x, &num, sizeof(num)); + for (i = 0; i < N; ++i) + emitarg(J, F, x[i]); +#undef N + } +} + +static void emitstring(JF, int opcode, const char *str) +{ +#define N (sizeof(str) / sizeof(js_Instruction)) + js_Instruction x[N]; + size_t i; + emit(J, F, opcode); + memcpy(x, &str, sizeof(str)); + for (i = 0; i < N; ++i) + emitarg(J, F, x[i]); +#undef N +} + +static void emitlocal(JF, int oploc, int opvar, js_Ast *ident) +{ + int is_arguments = !strcmp(ident->string, "arguments"); + int is_eval = !strcmp(ident->string, "eval"); + int i; + + if (is_arguments) { + F->lightweight = 0; + F->arguments = 1; + } + + checkfutureword(J, F, ident); + if (F->strict && oploc == OP_SETLOCAL) { + if (is_arguments) + jsC_error(J, ident, "'arguments' is read-only in strict mode"); + if (is_eval) + jsC_error(J, ident, "'eval' is read-only in strict mode"); + } + if (is_eval) + js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line); + + i = findlocal(J, F, ident->string); + if (i < 0) { + emitstring(J, F, opvar, ident->string); + } else { + emit(J, F, oploc); + emitarg(J, F, i); + } +} + +static int here(JF) +{ + return F->codelen; +} + +static int emitjump(JF, int opcode) +{ + int inst; + emit(J, F, opcode); + inst = F->codelen; + emitarg(J, F, 0); + return inst; +} + +static void emitjumpto(JF, int opcode, int dest) +{ + emit(J, F, opcode); + if (dest != (js_Instruction)dest) + js_syntaxerror(J, "jump address integer overflow"); + emitarg(J, F, dest); +} + +static void labelto(JF, int inst, int addr) +{ + if (addr != (js_Instruction)addr) + js_syntaxerror(J, "jump address integer overflow"); + F->code[inst] = addr; +} + +static void label(JF, int inst) +{ + labelto(J, F, inst, F->codelen); +} + +/* Expressions */ + +static void ctypeof(JF, js_Ast *exp) +{ + if (exp->a->type == EXP_IDENTIFIER) { + emitline(J, F, exp->a); + emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a); + } else { + cexp(J, F, exp->a); + } + emitline(J, F, exp); + emit(J, F, OP_TYPEOF); +} + +static void cunary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, opcode); +} + +static void cbinary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, opcode); +} + +static void carray(JF, js_Ast *list) +{ + while (list) { + emitline(J, F, list->a); + if (list->a->type == EXP_ELISION) { + emit(J, F, OP_SKIPARRAY); + } else { + cexp(J, F, list->a); + emit(J, F, OP_INITARRAY); + } + list = list->b; + } +} + +static void checkdup(JF, js_Ast *list, js_Ast *end) +{ + char nbuf[32], sbuf[32]; + const char *needle, *straw; + + if (end->a->type == EXP_NUMBER) + needle = jsV_numbertostring(J, nbuf, end->a->number); + else + needle = end->a->string; + + while (list->a != end) { + if (list->a->type == end->type) { + js_Ast *prop = list->a->a; + if (prop->type == EXP_NUMBER) + straw = jsV_numbertostring(J, sbuf, prop->number); + else + straw = prop->string; + if (!strcmp(needle, straw)) + jsC_error(J, list, "duplicate property '%s' in object literal", needle); + } + list = list->b; + } +} + +static void cobject(JF, js_Ast *list) +{ + js_Ast *head = list; + + while (list) { + js_Ast *kv = list->a; + js_Ast *prop = kv->a; + + if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) { + emitline(J, F, prop); + emitstring(J, F, OP_STRING, prop->string); + } else if (prop->type == EXP_NUMBER) { + emitline(J, F, prop); + emitnumber(J, F, prop->number); + } else { + jsC_error(J, prop, "invalid property name in object initializer"); + } + + if (F->strict) + checkdup(J, F, head, kv); + + switch (kv->type) { + default: /* impossible */ break; + case EXP_PROP_VAL: + cexp(J, F, kv->b); + emitline(J, F, kv); + emit(J, F, OP_INITPROP); + break; + case EXP_PROP_GET: + emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict, 1)); + emitline(J, F, kv); + emit(J, F, OP_INITGETTER); + break; + case EXP_PROP_SET: + emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict, 1)); + emitline(J, F, kv); + emit(J, F, OP_INITSETTER); + break; + } + + list = list->b; + } +} + +static int cargs(JF, js_Ast *list) +{ + int n = 0; + while (list) { + cexp(J, F, list->a); + list = list->b; + ++n; + } + return n; +} + +static void cassign(JF, js_Ast *exp) +{ + js_Ast *lhs = exp->a; + js_Ast *rhs = exp->b; + switch (lhs->type) { + case EXP_IDENTIFIER: + cexp(J, F, rhs); + emitline(J, F, exp); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + cexp(J, F, rhs); + emitline(J, F, exp); + emit(J, F, OP_SETPROP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + cexp(J, F, rhs); + emitline(J, F, exp); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignforin(JF, js_Ast *stm) +{ + js_Ast *lhs = stm->a; + + if (stm->type == STM_FOR_IN_VAR) { + if (lhs->b) + jsC_error(J, lhs->b, "more than one loop variable in for-in statement"); + emitline(J, F, lhs->a); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs->a->a); /* list(var-init(ident)) */ + emit(J, F, OP_POP); + return; + } + + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + emit(J, F, OP_POP); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + emitline(J, F, lhs); + emit(J, F, OP_ROT3); + emit(J, F, OP_SETPROP); + emit(J, F, OP_POP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + emitline(J, F, lhs); + emit(J, F, OP_ROT2); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + emit(J, F, OP_POP); + break; + default: + jsC_error(J, lhs, "invalid l-value in for-in loop assignment"); + } +} + +static void cassignop1(JF, js_Ast *lhs) +{ + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + emitline(J, F, lhs); + emit(J, F, OP_DUP2); + emit(J, F, OP_GETPROP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + emitline(J, F, lhs); + emit(J, F, OP_DUP); + emitstring(J, F, OP_GETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignop2(JF, js_Ast *lhs, int postfix) +{ + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT2); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + break; + case EXP_INDEX: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT4); + emit(J, F, OP_SETPROP); + break; + case EXP_MEMBER: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT3); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignop(JF, js_Ast *exp, int opcode) +{ + js_Ast *lhs = exp->a; + js_Ast *rhs = exp->b; + cassignop1(J, F, lhs); + cexp(J, F, rhs); + emitline(J, F, exp); + emit(J, F, opcode); + cassignop2(J, F, lhs, 0); +} + +static void cdelete(JF, js_Ast *exp) +{ + js_Ast *arg = exp->a; + switch (arg->type) { + case EXP_IDENTIFIER: + if (F->strict) + jsC_error(J, exp, "delete on an unqualified name is not allowed in strict mode"); + emitline(J, F, exp); + emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, arg); + break; + case EXP_INDEX: + cexp(J, F, arg->a); + cexp(J, F, arg->b); + emitline(J, F, exp); + emit(J, F, OP_DELPROP); + break; + case EXP_MEMBER: + cexp(J, F, arg->a); + emitline(J, F, exp); + emitstring(J, F, OP_DELPROP_S, arg->b->string); + break; + default: + jsC_error(J, exp, "invalid l-value in delete expression"); + } +} + +static void ceval(JF, js_Ast *fun, js_Ast *args) +{ + int n = cargs(J, F, args); + F->lightweight = 0; + F->arguments = 1; + if (n == 0) + emit(J, F, OP_UNDEF); + else while (n-- > 1) + emit(J, F, OP_POP); + emit(J, F, OP_EVAL); +} + +static void ccall(JF, js_Ast *fun, js_Ast *args) +{ + int n; + switch (fun->type) { + case EXP_INDEX: + cexp(J, F, fun->a); + emit(J, F, OP_DUP); + cexp(J, F, fun->b); + emit(J, F, OP_GETPROP); + emit(J, F, OP_ROT2); + break; + case EXP_MEMBER: + cexp(J, F, fun->a); + emit(J, F, OP_DUP); + emitstring(J, F, OP_GETPROP_S, fun->b->string); + emit(J, F, OP_ROT2); + break; + case EXP_IDENTIFIER: + if (!strcmp(fun->string, "eval")) { + ceval(J, F, fun, args); + return; + } + /* fallthrough */ + default: + cexp(J, F, fun); + emit(J, F, OP_UNDEF); + break; + } + n = cargs(J, F, args); + emit(J, F, OP_CALL); + emitarg(J, F, n); +} + +static void cexp(JF, js_Ast *exp) +{ + int then, end; + int n; + + switch (exp->type) { + case EXP_STRING: + emitline(J, F, exp); + emitstring(J, F, OP_STRING, exp->string); + break; + case EXP_NUMBER: + emitline(J, F, exp); + emitnumber(J, F, exp->number); + break; + case EXP_ELISION: + break; + case EXP_NULL: + emitline(J, F, exp); + emit(J, F, OP_NULL); + break; + case EXP_TRUE: + emitline(J, F, exp); + emit(J, F, OP_TRUE); + break; + case EXP_FALSE: + emitline(J, F, exp); + emit(J, F, OP_FALSE); + break; + case EXP_THIS: + emitline(J, F, exp); + emit(J, F, OP_THIS); + break; + + case EXP_REGEXP: + emitline(J, F, exp); + emitstring(J, F, OP_NEWREGEXP, exp->string); + emitarg(J, F, exp->number); + break; + + case EXP_OBJECT: + emitline(J, F, exp); + emit(J, F, OP_NEWOBJECT); + cobject(J, F, exp->a); + break; + + case EXP_ARRAY: + emitline(J, F, exp); + emit(J, F, OP_NEWARRAY); + carray(J, F, exp->a); + break; + + case EXP_FUN: + emitline(J, F, exp); + emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict, 1)); + break; + + case EXP_IDENTIFIER: + emitline(J, F, exp); + emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp); + break; + + case EXP_INDEX: + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, OP_GETPROP); + break; + + case EXP_MEMBER: + cexp(J, F, exp->a); + emitline(J, F, exp); + emitstring(J, F, OP_GETPROP_S, exp->b->string); + break; + + case EXP_CALL: + ccall(J, F, exp->a, exp->b); + break; + + case EXP_NEW: + cexp(J, F, exp->a); + n = cargs(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, OP_NEW); + emitarg(J, F, n); + break; + + case EXP_DELETE: + cdelete(J, F, exp); + break; + + case EXP_PREINC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_INC); + cassignop2(J, F, exp->a, 0); + break; + + case EXP_PREDEC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DEC); + cassignop2(J, F, exp->a, 0); + break; + + case EXP_POSTINC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POSTINC); + cassignop2(J, F, exp->a, 1); + emit(J, F, OP_POP); + break; + + case EXP_POSTDEC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POSTDEC); + cassignop2(J, F, exp->a, 1); + emit(J, F, OP_POP); + break; + + case EXP_VOID: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POP); + emit(J, F, OP_UNDEF); + break; + + case EXP_TYPEOF: ctypeof(J, F, exp); break; + case EXP_POS: cunary(J, F, exp, OP_POS); break; + case EXP_NEG: cunary(J, F, exp, OP_NEG); break; + case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break; + case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break; + + case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break; + case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break; + case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break; + case EXP_EQ: cbinary(J, F, exp, OP_EQ); break; + case EXP_NE: cbinary(J, F, exp, OP_NE); break; + case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break; + case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break; + case EXP_LT: cbinary(J, F, exp, OP_LT); break; + case EXP_GT: cbinary(J, F, exp, OP_GT); break; + case EXP_LE: cbinary(J, F, exp, OP_LE); break; + case EXP_GE: cbinary(J, F, exp, OP_GE); break; + case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break; + case EXP_IN: cbinary(J, F, exp, OP_IN); break; + case EXP_SHL: cbinary(J, F, exp, OP_SHL); break; + case EXP_SHR: cbinary(J, F, exp, OP_SHR); break; + case EXP_USHR: cbinary(J, F, exp, OP_USHR); break; + case EXP_ADD: cbinary(J, F, exp, OP_ADD); break; + case EXP_SUB: cbinary(J, F, exp, OP_SUB); break; + case EXP_MUL: cbinary(J, F, exp, OP_MUL); break; + case EXP_DIV: cbinary(J, F, exp, OP_DIV); break; + case EXP_MOD: cbinary(J, F, exp, OP_MOD); break; + + case EXP_ASS: cassign(J, F, exp); break; + case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break; + case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break; + case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break; + case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break; + case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break; + case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break; + case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break; + case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break; + case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break; + case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break; + case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break; + + case EXP_COMMA: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + break; + + case EXP_LOGOR: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DUP); + end = emitjump(J, F, OP_JTRUE); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + label(J, F, end); + break; + + case EXP_LOGAND: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DUP); + end = emitjump(J, F, OP_JFALSE); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + label(J, F, end); + break; + + case EXP_COND: + cexp(J, F, exp->a); + emitline(J, F, exp); + then = emitjump(J, F, OP_JTRUE); + cexp(J, F, exp->c); + end = emitjump(J, F, OP_JUMP); + label(J, F, then); + cexp(J, F, exp->b); + label(J, F, end); + break; + + default: + jsC_error(J, exp, "unknown expression type"); + } +} + +/* Patch break and continue statements */ + +static void addjump(JF, enum js_AstType type, js_Ast *target, int inst) +{ + js_JumpList *jump = js_malloc(J, sizeof *jump); + jump->type = type; + jump->inst = inst; + jump->next = target->jumps; + target->jumps = jump; +} + +static void labeljumps(JF, js_Ast *stm, int baddr, int caddr) +{ + js_JumpList *jump = stm->jumps; + while (jump) { + js_JumpList *next = jump->next; + if (jump->type == STM_BREAK) + labelto(J, F, jump->inst, baddr); + if (jump->type == STM_CONTINUE) + labelto(J, F, jump->inst, caddr); + js_free(J, jump); + jump = next; + } + stm->jumps = NULL; +} + +static int isloop(enum js_AstType T) +{ + return T == STM_DO || T == STM_WHILE || + T == STM_FOR || T == STM_FOR_VAR || + T == STM_FOR_IN || T == STM_FOR_IN_VAR; +} + +static int isfun(enum js_AstType T) +{ + return T == AST_FUNDEC || T == EXP_FUN || T == EXP_PROP_GET || T == EXP_PROP_SET; +} + +static int matchlabel(js_Ast *node, const char *label) +{ + while (node && node->type == STM_LABEL) { + if (!strcmp(node->a->string, label)) + return 1; + node = node->parent; + } + return 0; +} + +static js_Ast *breaktarget(JF, js_Ast *node, const char *label) +{ + while (node) { + if (isfun(node->type)) + break; + if (!label) { + if (isloop(node->type) || node->type == STM_SWITCH) + return node; + } else { + if (matchlabel(node->parent, label)) + return node; + } + node = node->parent; + } + return NULL; +} + +static js_Ast *continuetarget(JF, js_Ast *node, const char *label) +{ + while (node) { + if (isfun(node->type)) + break; + if (isloop(node->type)) { + if (!label) + return node; + else if (matchlabel(node->parent, label)) + return node; + } + node = node->parent; + } + return NULL; +} + +static js_Ast *returntarget(JF, js_Ast *node) +{ + while (node) { + if (isfun(node->type)) + return node; + node = node->parent; + } + return NULL; +} + +/* Emit code to rebalance stack and scopes during an abrupt exit */ + +static void cexit(JF, enum js_AstType T, js_Ast *node, js_Ast *target) +{ + js_Ast *prev; + do { + prev = node, node = node->parent; + switch (node->type) { + default: + /* impossible */ + break; + case STM_WITH: + emitline(J, F, node); + emit(J, F, OP_ENDWITH); + break; + case STM_FOR_IN: + case STM_FOR_IN_VAR: + emitline(J, F, node); + /* pop the iterator if leaving the loop */ + if (F->script) { + if (T == STM_RETURN || T == STM_BREAK || (T == STM_CONTINUE && target != node)) { + /* pop the iterator, save the return or exp value */ + emit(J, F, OP_ROT2); + emit(J, F, OP_POP); + } + if (T == STM_CONTINUE) + emit(J, F, OP_ROT2); /* put the iterator back on top */ + } else { + if (T == STM_RETURN) { + /* pop the iterator, save the return value */ + emit(J, F, OP_ROT2); + emit(J, F, OP_POP); + } + if (T == STM_BREAK || (T == STM_CONTINUE && target != node)) + emit(J, F, OP_POP); /* pop the iterator */ + } + break; + case STM_TRY: + emitline(J, F, node); + /* came from try block */ + if (prev == node->a) { + emit(J, F, OP_ENDTRY); + if (node->d) cstm(J, F, node->d); /* finally */ + } + /* came from catch block */ + if (prev == node->c) { + /* ... with finally */ + if (node->d) { + emit(J, F, OP_ENDCATCH); + emit(J, F, OP_ENDTRY); + cstm(J, F, node->d); /* finally */ + } else { + emit(J, F, OP_ENDCATCH); + } + } + break; + } + } while (node != target); +} + +/* Try/catch/finally */ + +static void ctryfinally(JF, js_Ast *trystm, js_Ast *finallystm) +{ + int L1; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + cstm(J, F, finallystm); /* inline finally block */ + emit(J, F, OP_THROW); /* rethrow exception */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + cstm(J, F, finallystm); +} + +static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm) +{ + int L1, L2; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + checkfutureword(J, F, catchvar); + if (F->strict) { + if (!strcmp(catchvar->string, "arguments")) + jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(catchvar->string, "eval")) + jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); + } + emitline(J, F, catchvar); + emitstring(J, F, OP_CATCH, catchvar->string); + cstm(J, F, catchstm); + emit(J, F, OP_ENDCATCH); + L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + label(J, F, L2); +} + +static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm) +{ + int L1, L2, L3; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + L2 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the catch block */ + cstm(J, F, finallystm); /* inline finally block */ + emit(J, F, OP_THROW); /* rethrow exception */ + } + label(J, F, L2); + if (F->strict) { + checkfutureword(J, F, catchvar); + if (!strcmp(catchvar->string, "arguments")) + jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(catchvar->string, "eval")) + jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); + } + emitline(J, F, catchvar); + emitstring(J, F, OP_CATCH, catchvar->string); + cstm(J, F, catchstm); + emit(J, F, OP_ENDCATCH); + emit(J, F, OP_ENDTRY); + L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + label(J, F, L3); + cstm(J, F, finallystm); +} + +/* Switch */ + +static void cswitch(JF, js_Ast *ref, js_Ast *head) +{ + js_Ast *node, *clause, *def = NULL; + int end; + + cexp(J, F, ref); + + /* emit an if-else chain of tests for the case clause expressions */ + for (node = head; node; node = node->b) { + clause = node->a; + if (clause->type == STM_DEFAULT) { + if (def) + jsC_error(J, clause, "more than one default label in switch"); + def = clause; + } else { + cexp(J, F, clause->a); + emitline(J, F, clause); + clause->casejump = emitjump(J, F, OP_JCASE); + } + } + emit(J, F, OP_POP); + if (def) { + emitline(J, F, def); + def->casejump = emitjump(J, F, OP_JUMP); + end = 0; + } else { + end = emitjump(J, F, OP_JUMP); + } + + /* emit the case clause bodies */ + for (node = head; node; node = node->b) { + clause = node->a; + label(J, F, clause->casejump); + if (clause->type == STM_DEFAULT) + cstmlist(J, F, clause->a); + else + cstmlist(J, F, clause->b); + } + + if (end) + label(J, F, end); +} + +/* Statements */ + +static void cvarinit(JF, js_Ast *list) +{ + while (list) { + js_Ast *var = list->a; + if (var->b) { + cexp(J, F, var->b); + emitline(J, F, var); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, var->a); + emit(J, F, OP_POP); + } + list = list->b; + } +} + +static void cstm(JF, js_Ast *stm) +{ + js_Ast *target; + int loop, cont, then, end; + + emitline(J, F, stm); + + switch (stm->type) { + case AST_FUNDEC: + break; + + case STM_BLOCK: + cstmlist(J, F, stm->a); + break; + + case STM_EMPTY: + if (F->script) { + emitline(J, F, stm); + emit(J, F, OP_POP); + emit(J, F, OP_UNDEF); + } + break; + + case STM_VAR: + cvarinit(J, F, stm->a); + break; + + case STM_IF: + if (stm->c) { + cexp(J, F, stm->a); + emitline(J, F, stm); + then = emitjump(J, F, OP_JTRUE); + cstm(J, F, stm->c); + emitline(J, F, stm); + end = emitjump(J, F, OP_JUMP); + label(J, F, then); + cstm(J, F, stm->b); + label(J, F, end); + } else { + cexp(J, F, stm->a); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + cstm(J, F, stm->b); + label(J, F, end); + } + break; + + case STM_DO: + loop = here(J, F); + cstm(J, F, stm->a); + cont = here(J, F); + cexp(J, F, stm->b); + emitline(J, F, stm); + emitjumpto(J, F, OP_JTRUE, loop); + labeljumps(J, F, stm, here(J,F), cont); + break; + + case STM_WHILE: + loop = here(J, F); + cexp(J, F, stm->a); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + cstm(J, F, stm->b); + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + label(J, F, end); + labeljumps(J, F, stm, here(J,F), loop); + break; + + case STM_FOR: + case STM_FOR_VAR: + if (stm->type == STM_FOR_VAR) { + cvarinit(J, F, stm->a); + } else { + if (stm->a) { + cexp(J, F, stm->a); + emit(J, F, OP_POP); + } + } + loop = here(J, F); + if (stm->b) { + cexp(J, F, stm->b); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + } else { + end = 0; + } + cstm(J, F, stm->d); + cont = here(J, F); + if (stm->c) { + cexp(J, F, stm->c); + emit(J, F, OP_POP); + } + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + if (end) + label(J, F, end); + labeljumps(J, F, stm, here(J,F), cont); + break; + + case STM_FOR_IN: + case STM_FOR_IN_VAR: + cexp(J, F, stm->b); + emitline(J, F, stm); + emit(J, F, OP_ITERATOR); + loop = here(J, F); + { + emitline(J, F, stm); + emit(J, F, OP_NEXTITER); + end = emitjump(J, F, OP_JFALSE); + cassignforin(J, F, stm); + if (F->script) { + emit(J, F, OP_ROT2); + cstm(J, F, stm->c); + emit(J, F, OP_ROT2); + } else { + cstm(J, F, stm->c); + } + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + } + label(J, F, end); + labeljumps(J, F, stm, here(J,F), loop); + break; + + case STM_SWITCH: + cswitch(J, F, stm->a, stm->b); + labeljumps(J, F, stm, here(J,F), 0); + break; + + case STM_LABEL: + cstm(J, F, stm->b); + /* skip consecutive labels */ + while (stm->type == STM_LABEL) + stm = stm->b; + /* loops and switches have already been labelled */ + if (!isloop(stm->type) && stm->type != STM_SWITCH) + labeljumps(J, F, stm, here(J,F), 0); + break; + + case STM_BREAK: + if (stm->a) { + checkfutureword(J, F, stm->a); + target = breaktarget(J, F, stm->parent, stm->a->string); + if (!target) + jsC_error(J, stm, "break label '%s' not found", stm->a->string); + } else { + target = breaktarget(J, F, stm->parent, NULL); + if (!target) + jsC_error(J, stm, "unlabelled break must be inside loop or switch"); + } + cexit(J, F, STM_BREAK, stm, target); + emitline(J, F, stm); + addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP)); + break; + + case STM_CONTINUE: + if (stm->a) { + checkfutureword(J, F, stm->a); + target = continuetarget(J, F, stm->parent, stm->a->string); + if (!target) + jsC_error(J, stm, "continue label '%s' not found", stm->a->string); + } else { + target = continuetarget(J, F, stm->parent, NULL); + if (!target) + jsC_error(J, stm, "continue must be inside loop"); + } + cexit(J, F, STM_CONTINUE, stm, target); + emitline(J, F, stm); + addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP)); + break; + + case STM_RETURN: + if (stm->a) + cexp(J, F, stm->a); + else + emit(J, F, OP_UNDEF); + target = returntarget(J, F, stm->parent); + if (!target) + jsC_error(J, stm, "return not in function"); + cexit(J, F, STM_RETURN, stm, target); + emitline(J, F, stm); + emit(J, F, OP_RETURN); + break; + + case STM_THROW: + cexp(J, F, stm->a); + emitline(J, F, stm); + emit(J, F, OP_THROW); + break; + + case STM_WITH: + F->lightweight = 0; + if (F->strict) + jsC_error(J, stm->a, "'with' statements are not allowed in strict mode"); + cexp(J, F, stm->a); + emitline(J, F, stm); + emit(J, F, OP_WITH); + cstm(J, F, stm->b); + emitline(J, F, stm); + emit(J, F, OP_ENDWITH); + break; + + case STM_TRY: + emitline(J, F, stm); + if (stm->b && stm->c) { + F->lightweight = 0; + if (stm->d) + ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d); + else + ctrycatch(J, F, stm->a, stm->b, stm->c); + } else { + ctryfinally(J, F, stm->a, stm->d); + } + break; + + case STM_DEBUGGER: + emitline(J, F, stm); + emit(J, F, OP_DEBUGGER); + break; + + default: + if (F->script) { + emitline(J, F, stm); + emit(J, F, OP_POP); + cexp(J, F, stm); + } else { + cexp(J, F, stm); + emitline(J, F, stm); + emit(J, F, OP_POP); + } + break; + } +} + +static void cstmlist(JF, js_Ast *list) +{ + while (list) { + cstm(J, F, list->a); + list = list->b; + } +} + +/* Declarations and programs */ + +static int listlength(js_Ast *list) +{ + int n = 0; + while (list) ++n, list = list->b; + return n; +} + +static void cparams(JF, js_Ast *list, js_Ast *fname) +{ + F->numparams = listlength(list); + while (list) { + checkfutureword(J, F, list->a); + addlocal(J, F, list->a, 0); + list = list->b; + } +} + +static void cvardecs(JF, js_Ast *node) +{ + if (node->type == AST_LIST) { + while (node) { + cvardecs(J, F, node->a); + node = node->b; + } + return; + } + + if (isfun(node->type)) + return; /* stop at inner functions */ + + if (node->type == EXP_VAR) { + checkfutureword(J, F, node->a); + addlocal(J, F, node->a, 1); + } + + if (node->a) cvardecs(J, F, node->a); + if (node->b) cvardecs(J, F, node->b); + if (node->c) cvardecs(J, F, node->c); + if (node->d) cvardecs(J, F, node->d); +} + +static void cfundecs(JF, js_Ast *list) +{ + while (list) { + js_Ast *stm = list->a; + if (stm->type == AST_FUNDEC) { + emitline(J, F, stm); + emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict, 0)); + emitline(J, F, stm); + emit(J, F, OP_SETLOCAL); + emitarg(J, F, addlocal(J, F, stm->a, 1)); + emit(J, F, OP_POP); + } + list = list->b; + } +} + +static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body, int is_fun_exp) +{ + F->lightweight = 1; + F->arguments = 0; + + if (F->script) + F->lightweight = 0; + + /* Check if first statement is 'use strict': */ + if (body && body->type == AST_LIST && body->a && body->a->type == EXP_STRING) + if (!strcmp(body->a->string, "use strict")) + F->strict = 1; + + F->lastline = F->line; + + cparams(J, F, params, name); + + if (body) { + cvardecs(J, F, body); + cfundecs(J, F, body); + } + + if (name) { + checkfutureword(J, F, name); + if (is_fun_exp) { + if (findlocal(J, F, name->string) < 0) { + /* TODO: make this binding immutable! */ + emit(J, F, OP_CURRENT); + emit(J, F, OP_SETLOCAL); + emitarg(J, F, addlocal(J, F, name, 1)); + emit(J, F, OP_POP); + } + } + } + + if (F->script) { + emit(J, F, OP_UNDEF); + cstmlist(J, F, body); + emit(J, F, OP_RETURN); + } else { + cstmlist(J, F, body); + emit(J, F, OP_UNDEF); + emit(J, F, OP_RETURN); + } +} + +js_Function *jsC_compilefunction(js_State *J, js_Ast *prog) +{ + return newfun(J, prog->line, prog->a, prog->b, prog->c, 0, J->default_strict, 1); +} + +js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict) +{ + return newfun(J, prog ? prog->line : 0, NULL, NULL, prog, 1, default_strict, 0); +} diff --git a/src/mujs/jsdate.c b/src/mujs/jsdate.c new file mode 100644 index 0000000..bf1d406 --- /dev/null +++ b/src/mujs/jsdate.c @@ -0,0 +1,861 @@ +#include "jsi.h" + +#include + +#if defined(__unix__) || defined(__APPLE__) +#include +#elif defined(_WIN32) +#include +#endif + +#define js_optnumber(J,I,V) (js_isdefined(J,I) ? js_tonumber(J,I) : V) + +static double Now(void) +{ +#if defined(__unix__) || defined(__APPLE__) + struct timeval tv; + gettimeofday(&tv, NULL); + return floor(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0); +#elif defined(_WIN32) + struct _timeb tv; + _ftime(&tv); + return tv.time * 1000.0 + tv.millitm; +#else + return time(NULL) * 1000.0; +#endif +} + +static double LocalTZA(void) +{ + static int once = 1; + static double tza = 0; + if (once) { + time_t now = time(NULL); + time_t utc = mktime(gmtime(&now)); + time_t loc = mktime(localtime(&now)); + tza = (loc - utc) * 1000; + once = 0; + } + return tza; +} + +static double DaylightSavingTA(double t) +{ + return 0; /* TODO */ +} + +/* Helpers from the ECMA 262 specification */ + +#define HoursPerDay 24.0 +#define MinutesPerDay (HoursPerDay * MinutesPerHour) +#define MinutesPerHour 60.0 +#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) +#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) +#define SecondsPerMinute 60.0 + +#define msPerDay (SecondsPerDay * msPerSecond) +#define msPerHour (SecondsPerHour * msPerSecond) +#define msPerMinute (SecondsPerMinute * msPerSecond) +#define msPerSecond 1000.0 + +static double pmod(double x, double y) +{ + x = fmod(x, y); + if (x < 0) + x += y; + return x; +} + +static int Day(double t) +{ + return floor(t / msPerDay); +} + +static double TimeWithinDay(double t) +{ + return pmod(t, msPerDay); +} + +static int DaysInYear(int y) +{ + return y % 4 == 0 && (y % 100 || (y % 400 == 0)) ? 366 : 365; +} + +static int DayFromYear(int y) +{ + return 365 * (y - 1970) + + floor((y - 1969) / 4.0) - + floor((y - 1901) / 100.0) + + floor((y - 1601) / 400.0); +} + +static double TimeFromYear(int y) +{ + return DayFromYear(y) * msPerDay; +} + +static int YearFromTime(double t) +{ + int y = floor(t / (msPerDay * 365.2425)) + 1970; + double t2 = TimeFromYear(y); + if (t2 > t) + --y; + else if (t2 + msPerDay * DaysInYear(y) <= t) + ++y; + return y; +} + +static int InLeapYear(double t) +{ + return DaysInYear(YearFromTime(t)) == 366; +} + +static int DayWithinYear(double t) +{ + return Day(t) - DayFromYear(YearFromTime(t)); +} + +static int MonthFromTime(double t) +{ + int day = DayWithinYear(t); + int leap = InLeapYear(t); + if (day < 31) return 0; + if (day < 59 + leap) return 1; + if (day < 90 + leap) return 2; + if (day < 120 + leap) return 3; + if (day < 151 + leap) return 4; + if (day < 181 + leap) return 5; + if (day < 212 + leap) return 6; + if (day < 243 + leap) return 7; + if (day < 273 + leap) return 8; + if (day < 304 + leap) return 9; + if (day < 334 + leap) return 10; + return 11; +} + +static int DateFromTime(double t) +{ + int day = DayWithinYear(t); + int leap = InLeapYear(t); + switch (MonthFromTime(t)) { + case 0: return day + 1; + case 1: return day - 30; + case 2: return day - 58 - leap; + case 3: return day - 89 - leap; + case 4: return day - 119 - leap; + case 5: return day - 150 - leap; + case 6: return day - 180 - leap; + case 7: return day - 211 - leap; + case 8: return day - 242 - leap; + case 9: return day - 272 - leap; + case 10: return day - 303 - leap; + default : return day - 333 - leap; + } +} + +static int WeekDay(double t) +{ + return pmod(Day(t) + 4, 7); +} + +static double LocalTime(double utc) +{ + return utc + LocalTZA() + DaylightSavingTA(utc); +} + +static double UTC(double loc) +{ + return loc - LocalTZA() - DaylightSavingTA(loc - LocalTZA()); +} + +static int HourFromTime(double t) +{ + return pmod(floor(t / msPerHour), HoursPerDay); +} + +static int MinFromTime(double t) +{ + return pmod(floor(t / msPerMinute), MinutesPerHour); +} + +static int SecFromTime(double t) +{ + return pmod(floor(t / msPerSecond), SecondsPerMinute); +} + +static int msFromTime(double t) +{ + return pmod(t, msPerSecond); +} + +static double MakeTime(double hour, double min, double sec, double ms) +{ + return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; +} + +static double MakeDay(double y, double m, double date) +{ + /* + * The following array contains the day of year for the first day of + * each month, where index 0 is January, and day 0 is January 1. + */ + static const double firstDayOfMonth[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + + double yd, md; + int im; + + y += floor(m / 12); + m = pmod(m, 12); + + im = (int)m; + if (im < 0 || im >= 12) + return NAN; + + yd = floor(TimeFromYear(y) / msPerDay); + md = firstDayOfMonth[DaysInYear(y) == 366][im]; + + return yd + md + date - 1; +} + +static double MakeDate(double day, double time) +{ + return day * msPerDay + time; +} + +static double TimeClip(double t) +{ + if (!isfinite(t)) + return NAN; + if (fabs(t) > 8.64e15) + return NAN; + return t < 0 ? -floor(-t) : floor(t); +} + +static int toint(const char **sp, int w, int *v) +{ + const char *s = *sp; + *v = 0; + while (w--) { + if (*s < '0' || *s > '9') + return 0; + *v = *v * 10 + (*s++ - '0'); + } + *sp = s; + return 1; +} + +static double parseDateTime(const char *s) +{ + int y = 1970, m = 1, d = 1, H = 0, M = 0, S = 0, ms = 0; + int tza = 0; + double t; + + /* Parse ISO 8601 formatted date and time: */ + /* YYYY("-"MM("-"DD)?)?("T"HH":"mm(":"ss("."sss)?)?("Z"|[+-]HH(":"mm)?)?)? */ + + if (!toint(&s, 4, &y)) return NAN; + if (*s == '-') { + s += 1; + if (!toint(&s, 2, &m)) return NAN; + if (*s == '-') { + s += 1; + if (!toint(&s, 2, &d)) return NAN; + } + } + + if (*s == 'T') { + s += 1; + if (!toint(&s, 2, &H)) return NAN; + if (*s != ':') return NAN; + s += 1; + if (!toint(&s, 2, &M)) return NAN; + if (*s == ':') { + s += 1; + if (!toint(&s, 2, &S)) return NAN; + if (*s == '.') { + s += 1; + if (!toint(&s, 3, &ms)) return NAN; + } + } + if (*s == 'Z') { + s += 1; + tza = 0; + } else if (*s == '+' || *s == '-') { + int tzh = 0, tzm = 0; + int tzs = *s == '+' ? 1 : -1; + s += 1; + if (!toint(&s, 2, &tzh)) return NAN; + if (*s == ':') { + s += 1; + if (!toint(&s, 2, &tzm)) return NAN; + } + if (tzh > 23 || tzm > 59) return NAN; + tza = tzs * (tzh * msPerHour + tzm * msPerMinute); + } else { + tza = LocalTZA(); + } + } + + if (*s) return NAN; + + if (m < 1 || m > 12) return NAN; + if (d < 1 || d > 31) return NAN; + if (H < 0 || H > 24) return NAN; + if (M < 0 || M > 59) return NAN; + if (S < 0 || S > 59) return NAN; + if (ms < 0 || ms > 999) return NAN; + if (H == 24 && (M != 0 || S != 0 || ms != 0)) return NAN; + + /* TODO: DaylightSavingTA on local times */ + t = MakeDate(MakeDay(y, m-1, d), MakeTime(H, M, S, ms)); + return t - tza; +} + +/* date formatting */ + +static char *fmtdate(char *buf, double t) +{ + int y = YearFromTime(t); + int m = MonthFromTime(t); + int d = DateFromTime(t); + if (!isfinite(t)) + return "Invalid Date"; + sprintf(buf, "%04d-%02d-%02d", y, m+1, d); + return buf; +} + +static char *fmttime(char *buf, double t, double tza) +{ + int H = HourFromTime(t); + int M = MinFromTime(t); + int S = SecFromTime(t); + int ms = msFromTime(t); + int tzh = HourFromTime(fabs(tza)); + int tzm = MinFromTime(fabs(tza)); + if (!isfinite(t)) + return "Invalid Date"; + if (tza == 0) + sprintf(buf, "%02d:%02d:%02d.%03dZ", H, M, S, ms); + else if (tza < 0) + sprintf(buf, "%02d:%02d:%02d.%03d-%02d:%02d", H, M, S, ms, tzh, tzm); + else + sprintf(buf, "%02d:%02d:%02d.%03d+%02d:%02d", H, M, S, ms, tzh, tzm); + return buf; +} + +static char *fmtdatetime(char *buf, double t, double tza) +{ + char dbuf[20], tbuf[20]; + if (!isfinite(t)) + return "Invalid Date"; + fmtdate(dbuf, t); + fmttime(tbuf, t, tza); + sprintf(buf, "%sT%s", dbuf, tbuf); + return buf; +} + +/* Date functions */ + +static double js_todate(js_State *J, int idx) +{ + js_Object *self = js_toobject(J, idx); + if (self->type != JS_CDATE) + js_typeerror(J, "not a date"); + return self->u.number; +} + +static void js_setdate(js_State *J, int idx, double t) +{ + js_Object *self = js_toobject(J, idx); + if (self->type != JS_CDATE) + js_typeerror(J, "not a date"); + self->u.number = TimeClip(t); + js_pushnumber(J, self->u.number); +} + +static void D_parse(js_State *J) +{ + double t = parseDateTime(js_tostring(J, 1)); + js_pushnumber(J, t); +} + +static void D_UTC(js_State *J) +{ + double y, m, d, H, M, S, ms, t; + y = js_tonumber(J, 1); + if (y < 100) y += 1900; + m = js_tonumber(J, 2); + d = js_optnumber(J, 3, 1); + H = js_optnumber(J, 4, 0); + M = js_optnumber(J, 5, 0); + S = js_optnumber(J, 6, 0); + ms = js_optnumber(J, 7, 0); + t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); + t = TimeClip(t); + js_pushnumber(J, t); +} + +static void D_now(js_State *J) +{ + js_pushnumber(J, Now()); +} + +static void jsB_Date(js_State *J) +{ + char buf[64]; + js_pushstring(J, fmtdatetime(buf, LocalTime(Now()), LocalTZA())); +} + +static void jsB_new_Date(js_State *J) +{ + int top = js_gettop(J); + js_Object *obj; + double t; + + if (top == 1) + t = Now(); + else if (top == 2) { + js_toprimitive(J, 1, JS_HNONE); + if (js_isstring(J, 1)) + t = parseDateTime(js_tostring(J, 1)); + else + t = TimeClip(js_tonumber(J, 1)); + } else { + double y, m, d, H, M, S, ms; + y = js_tonumber(J, 1); + if (y < 100) y += 1900; + m = js_tonumber(J, 2); + d = js_optnumber(J, 3, 1); + H = js_optnumber(J, 4, 0); + M = js_optnumber(J, 5, 0); + S = js_optnumber(J, 6, 0); + ms = js_optnumber(J, 7, 0); + t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); + t = TimeClip(UTC(t)); + } + + obj = jsV_newobject(J, JS_CDATE, J->Date_prototype); + obj->u.number = t; + + js_pushobject(J, obj); +} + +static void Dp_valueOf(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, t); +} + +static void Dp_toString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdatetime(buf, LocalTime(t), LocalTZA())); +} + +static void Dp_toDateString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdate(buf, LocalTime(t))); +} + +static void Dp_toTimeString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmttime(buf, LocalTime(t), LocalTZA())); +} + +static void Dp_toUTCString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdatetime(buf, t, 0)); +} + +static void Dp_toISOString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + if (!isfinite(t)) + js_rangeerror(J, "invalid date"); + js_pushstring(J, fmtdatetime(buf, t, 0)); +} + +static void Dp_getFullYear(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, YearFromTime(LocalTime(t))); +} + +static void Dp_getMonth(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, MonthFromTime(LocalTime(t))); +} + +static void Dp_getDate(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, DateFromTime(LocalTime(t))); +} + +static void Dp_getDay(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, WeekDay(LocalTime(t))); +} + +static void Dp_getHours(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, HourFromTime(LocalTime(t))); +} + +static void Dp_getMinutes(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, MinFromTime(LocalTime(t))); +} + +static void Dp_getSeconds(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, SecFromTime(LocalTime(t))); +} + +static void Dp_getMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, msFromTime(LocalTime(t))); +} + +static void Dp_getUTCFullYear(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, YearFromTime(t)); +} + +static void Dp_getUTCMonth(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, MonthFromTime(t)); +} + +static void Dp_getUTCDate(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, DateFromTime(t)); +} + +static void Dp_getUTCDay(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, WeekDay(t)); +} + +static void Dp_getUTCHours(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, HourFromTime(t)); +} + +static void Dp_getUTCMinutes(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, MinFromTime(t)); +} + +static void Dp_getUTCSeconds(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, SecFromTime(t)); +} + +static void Dp_getUTCMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, msFromTime(t)); +} + +static void Dp_getTimezoneOffset(js_State *J) +{ + double t = js_todate(J, 0); + if (isnan(t)) + js_pushnumber(J, NAN); + else + js_pushnumber(J, (t - LocalTime(t)) / msPerMinute); +} + +static void Dp_setTime(js_State *J) +{ + js_setdate(J, 0, js_tonumber(J, 1)); +} + +static void Dp_setMilliseconds(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = SecFromTime(t); + double ms = js_tonumber(J, 1); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setSeconds(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = js_tonumber(J, 1); + double ms = js_optnumber(J, 2, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setMinutes(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = js_tonumber(J, 1); + double s = js_optnumber(J, 2, SecFromTime(t)); + double ms = js_optnumber(J, 3, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setHours(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MinFromTime(t)); + double s = js_optnumber(J, 3, SecFromTime(t)); + double ms = js_optnumber(J, 4, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setDate(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = YearFromTime(t); + double m = MonthFromTime(t); + double d = js_tonumber(J, 1); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setMonth(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = YearFromTime(t); + double m = js_tonumber(J, 1); + double d = js_optnumber(J, 2, DateFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setFullYear(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MonthFromTime(t)); + double d = js_optnumber(J, 3, DateFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setUTCMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = SecFromTime(t); + double ms = js_tonumber(J, 1); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCSeconds(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = js_tonumber(J, 1); + double ms = js_optnumber(J, 2, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCMinutes(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = js_tonumber(J, 1); + double s = js_optnumber(J, 2, SecFromTime(t)); + double ms = js_optnumber(J, 3, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCHours(js_State *J) +{ + double t = js_todate(J, 0); + double h = js_tonumber(J, 1); + double m = js_optnumber(J, 2, HourFromTime(t)); + double s = js_optnumber(J, 3, SecFromTime(t)); + double ms = js_optnumber(J, 4, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCDate(js_State *J) +{ + double t = js_todate(J, 0); + double y = YearFromTime(t); + double m = MonthFromTime(t); + double d = js_tonumber(J, 1); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_setUTCMonth(js_State *J) +{ + double t = js_todate(J, 0); + double y = YearFromTime(t); + double m = js_tonumber(J, 1); + double d = js_optnumber(J, 2, DateFromTime(t)); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_setUTCFullYear(js_State *J) +{ + double t = js_todate(J, 0); + double y = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MonthFromTime(t)); + double d = js_optnumber(J, 3, DateFromTime(t)); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_toJSON(js_State *J) +{ + js_copy(J, 0); + js_toprimitive(J, -1, JS_HNUMBER); + if (js_isnumber(J, -1) && !isfinite(js_tonumber(J, -1))) { + js_pushnull(J); + return; + } + js_pop(J, 1); + + js_getproperty(J, 0, "toISOString"); + if (!js_iscallable(J, -1)) + js_typeerror(J, "this.toISOString is not a function"); + js_copy(J, 0); + js_call(J, 0); +} + +void jsB_initdate(js_State *J) +{ + J->Date_prototype->u.number = 0; + + js_pushobject(J, J->Date_prototype); + { + jsB_propf(J, "Date.prototype.valueOf", Dp_valueOf, 0); + jsB_propf(J, "Date.prototype.toString", Dp_toString, 0); + jsB_propf(J, "Date.prototype.toDateString", Dp_toDateString, 0); + jsB_propf(J, "Date.prototype.toTimeString", Dp_toTimeString, 0); + jsB_propf(J, "Date.prototype.toLocaleString", Dp_toString, 0); + jsB_propf(J, "Date.prototype.toLocaleDateString", Dp_toDateString, 0); + jsB_propf(J, "Date.prototype.toLocaleTimeString", Dp_toTimeString, 0); + jsB_propf(J, "Date.prototype.toUTCString", Dp_toUTCString, 0); + + jsB_propf(J, "Date.prototype.getTime", Dp_valueOf, 0); + jsB_propf(J, "Date.prototype.getFullYear", Dp_getFullYear, 0); + jsB_propf(J, "Date.prototype.getUTCFullYear", Dp_getUTCFullYear, 0); + jsB_propf(J, "Date.prototype.getMonth", Dp_getMonth, 0); + jsB_propf(J, "Date.prototype.getUTCMonth", Dp_getUTCMonth, 0); + jsB_propf(J, "Date.prototype.getDate", Dp_getDate, 0); + jsB_propf(J, "Date.prototype.getUTCDate", Dp_getUTCDate, 0); + jsB_propf(J, "Date.prototype.getDay", Dp_getDay, 0); + jsB_propf(J, "Date.prototype.getUTCDay", Dp_getUTCDay, 0); + jsB_propf(J, "Date.prototype.getHours", Dp_getHours, 0); + jsB_propf(J, "Date.prototype.getUTCHours", Dp_getUTCHours, 0); + jsB_propf(J, "Date.prototype.getMinutes", Dp_getMinutes, 0); + jsB_propf(J, "Date.prototype.getUTCMinutes", Dp_getUTCMinutes, 0); + jsB_propf(J, "Date.prototype.getSeconds", Dp_getSeconds, 0); + jsB_propf(J, "Date.prototype.getUTCSeconds", Dp_getUTCSeconds, 0); + jsB_propf(J, "Date.prototype.getMilliseconds", Dp_getMilliseconds, 0); + jsB_propf(J, "Date.prototype.getUTCMilliseconds", Dp_getUTCMilliseconds, 0); + jsB_propf(J, "Date.prototype.getTimezoneOffset", Dp_getTimezoneOffset, 0); + + jsB_propf(J, "Date.prototype.setTime", Dp_setTime, 1); + jsB_propf(J, "Date.prototype.setMilliseconds", Dp_setMilliseconds, 1); + jsB_propf(J, "Date.prototype.setUTCMilliseconds", Dp_setUTCMilliseconds, 1); + jsB_propf(J, "Date.prototype.setSeconds", Dp_setSeconds, 2); + jsB_propf(J, "Date.prototype.setUTCSeconds", Dp_setUTCSeconds, 2); + jsB_propf(J, "Date.prototype.setMinutes", Dp_setMinutes, 3); + jsB_propf(J, "Date.prototype.setUTCMinutes", Dp_setUTCMinutes, 3); + jsB_propf(J, "Date.prototype.setHours", Dp_setHours, 4); + jsB_propf(J, "Date.prototype.setUTCHours", Dp_setUTCHours, 4); + jsB_propf(J, "Date.prototype.setDate", Dp_setDate, 1); + jsB_propf(J, "Date.prototype.setUTCDate", Dp_setUTCDate, 1); + jsB_propf(J, "Date.prototype.setMonth", Dp_setMonth, 2); + jsB_propf(J, "Date.prototype.setUTCMonth", Dp_setUTCMonth, 2); + jsB_propf(J, "Date.prototype.setFullYear", Dp_setFullYear, 3); + jsB_propf(J, "Date.prototype.setUTCFullYear", Dp_setUTCFullYear, 3); + + /* ES5 */ + jsB_propf(J, "Date.prototype.toISOString", Dp_toISOString, 0); + jsB_propf(J, "Date.prototype.toJSON", Dp_toJSON, 1); + } + js_newcconstructor(J, jsB_Date, jsB_new_Date, "Date", 0); /* 1 */ + { + jsB_propf(J, "Date.parse", D_parse, 1); + jsB_propf(J, "Date.UTC", D_UTC, 7); + + /* ES5 */ + jsB_propf(J, "Date.now", D_now, 0); + } + js_defglobal(J, "Date", JS_DONTENUM); +} diff --git a/src/mujs/jsdtoa.c b/src/mujs/jsdtoa.c new file mode 100644 index 0000000..a80cc6a --- /dev/null +++ b/src/mujs/jsdtoa.c @@ -0,0 +1,749 @@ +/* Locale-independent implementations of string <-> double conversions. */ + +#include "jsi.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */ +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#include +#include + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* + * format exponent like sprintf(p, "e%+d", e) + */ +void +js_fmtexp(char *p, int e) +{ + char se[9]; + int i; + + *p++ = 'e'; + if(e < 0) { + *p++ = '-'; + e = -e; + } else + *p++ = '+'; + i = 0; + while(e) { + se[i++] = e % 10 + '0'; + e /= 10; + } + while(i < 1) + se[i++] = '0'; + while(i > 0) + *p++ = se[--i]; + *p++ = '\0'; +} + +/* + * grisu2_59_56.c + * + * Grisu prints the optimal decimal representation of floating-point numbers. + * + * Copyright (c) 2009 Florian Loitsch + * + * 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. + */ + +typedef struct diy_fp_t { + uint64_t f; + int e; +} diy_fp_t; + +#define DIY_SIGNIFICAND_SIZE 64 +#define D_1_LOG2_10 0.30102999566398114 /* 1 / lg(10) */ + +static const uint64_t powers_ten[] = { + 0xbf29dcaba82fdeae, 0xeef453d6923bd65a, 0x9558b4661b6565f8, + 0xbaaee17fa23ebf76, 0xe95a99df8ace6f54, 0x91d8a02bb6c10594, + 0xb64ec836a47146fa, 0xe3e27a444d8d98b8, 0x8e6d8c6ab0787f73, + 0xb208ef855c969f50, 0xde8b2b66b3bc4724, 0x8b16fb203055ac76, + 0xaddcb9e83c6b1794, 0xd953e8624b85dd79, 0x87d4713d6f33aa6c, + 0xa9c98d8ccb009506, 0xd43bf0effdc0ba48, 0x84a57695fe98746d, + 0xa5ced43b7e3e9188, 0xcf42894a5dce35ea, 0x818995ce7aa0e1b2, + 0xa1ebfb4219491a1f, 0xca66fa129f9b60a7, 0xfd00b897478238d1, + 0x9e20735e8cb16382, 0xc5a890362fddbc63, 0xf712b443bbd52b7c, + 0x9a6bb0aa55653b2d, 0xc1069cd4eabe89f9, 0xf148440a256e2c77, + 0x96cd2a865764dbca, 0xbc807527ed3e12bd, 0xeba09271e88d976c, + 0x93445b8731587ea3, 0xb8157268fdae9e4c, 0xe61acf033d1a45df, + 0x8fd0c16206306bac, 0xb3c4f1ba87bc8697, 0xe0b62e2929aba83c, + 0x8c71dcd9ba0b4926, 0xaf8e5410288e1b6f, 0xdb71e91432b1a24b, + 0x892731ac9faf056f, 0xab70fe17c79ac6ca, 0xd64d3d9db981787d, + 0x85f0468293f0eb4e, 0xa76c582338ed2622, 0xd1476e2c07286faa, + 0x82cca4db847945ca, 0xa37fce126597973d, 0xcc5fc196fefd7d0c, + 0xff77b1fcbebcdc4f, 0x9faacf3df73609b1, 0xc795830d75038c1e, + 0xf97ae3d0d2446f25, 0x9becce62836ac577, 0xc2e801fb244576d5, + 0xf3a20279ed56d48a, 0x9845418c345644d7, 0xbe5691ef416bd60c, + 0xedec366b11c6cb8f, 0x94b3a202eb1c3f39, 0xb9e08a83a5e34f08, + 0xe858ad248f5c22ca, 0x91376c36d99995be, 0xb58547448ffffb2e, + 0xe2e69915b3fff9f9, 0x8dd01fad907ffc3c, 0xb1442798f49ffb4b, + 0xdd95317f31c7fa1d, 0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b67, + 0xd863b256369d4a41, 0x873e4f75e2224e68, 0xa90de3535aaae202, + 0xd3515c2831559a83, 0x8412d9991ed58092, 0xa5178fff668ae0b6, + 0xce5d73ff402d98e4, 0x80fa687f881c7f8e, 0xa139029f6a239f72, + 0xc987434744ac874f, 0xfbe9141915d7a922, 0x9d71ac8fada6c9b5, + 0xc4ce17b399107c23, 0xf6019da07f549b2b, 0x99c102844f94e0fb, + 0xc0314325637a193a, 0xf03d93eebc589f88, 0x96267c7535b763b5, + 0xbbb01b9283253ca3, 0xea9c227723ee8bcb, 0x92a1958a7675175f, + 0xb749faed14125d37, 0xe51c79a85916f485, 0x8f31cc0937ae58d3, + 0xb2fe3f0b8599ef08, 0xdfbdcece67006ac9, 0x8bd6a141006042be, + 0xaecc49914078536d, 0xda7f5bf590966849, 0x888f99797a5e012d, + 0xaab37fd7d8f58179, 0xd5605fcdcf32e1d7, 0x855c3be0a17fcd26, + 0xa6b34ad8c9dfc070, 0xd0601d8efc57b08c, 0x823c12795db6ce57, + 0xa2cb1717b52481ed, 0xcb7ddcdda26da269, 0xfe5d54150b090b03, + 0x9efa548d26e5a6e2, 0xc6b8e9b0709f109a, 0xf867241c8cc6d4c1, + 0x9b407691d7fc44f8, 0xc21094364dfb5637, 0xf294b943e17a2bc4, + 0x979cf3ca6cec5b5b, 0xbd8430bd08277231, 0xece53cec4a314ebe, + 0x940f4613ae5ed137, 0xb913179899f68584, 0xe757dd7ec07426e5, + 0x9096ea6f3848984f, 0xb4bca50b065abe63, 0xe1ebce4dc7f16dfc, + 0x8d3360f09cf6e4bd, 0xb080392cc4349ded, 0xdca04777f541c568, + 0x89e42caaf9491b61, 0xac5d37d5b79b6239, 0xd77485cb25823ac7, + 0x86a8d39ef77164bd, 0xa8530886b54dbdec, 0xd267caa862a12d67, + 0x8380dea93da4bc60, 0xa46116538d0deb78, 0xcd795be870516656, + 0x806bd9714632dff6, 0xa086cfcd97bf97f4, 0xc8a883c0fdaf7df0, + 0xfad2a4b13d1b5d6c, 0x9cc3a6eec6311a64, 0xc3f490aa77bd60fd, + 0xf4f1b4d515acb93c, 0x991711052d8bf3c5, 0xbf5cd54678eef0b7, + 0xef340a98172aace5, 0x9580869f0e7aac0f, 0xbae0a846d2195713, + 0xe998d258869facd7, 0x91ff83775423cc06, 0xb67f6455292cbf08, + 0xe41f3d6a7377eeca, 0x8e938662882af53e, 0xb23867fb2a35b28e, + 0xdec681f9f4c31f31, 0x8b3c113c38f9f37f, 0xae0b158b4738705f, + 0xd98ddaee19068c76, 0x87f8a8d4cfa417ca, 0xa9f6d30a038d1dbc, + 0xd47487cc8470652b, 0x84c8d4dfd2c63f3b, 0xa5fb0a17c777cf0a, + 0xcf79cc9db955c2cc, 0x81ac1fe293d599c0, 0xa21727db38cb0030, + 0xca9cf1d206fdc03c, 0xfd442e4688bd304b, 0x9e4a9cec15763e2f, + 0xc5dd44271ad3cdba, 0xf7549530e188c129, 0x9a94dd3e8cf578ba, + 0xc13a148e3032d6e8, 0xf18899b1bc3f8ca2, 0x96f5600f15a7b7e5, + 0xbcb2b812db11a5de, 0xebdf661791d60f56, 0x936b9fcebb25c996, + 0xb84687c269ef3bfb, 0xe65829b3046b0afa, 0x8ff71a0fe2c2e6dc, + 0xb3f4e093db73a093, 0xe0f218b8d25088b8, 0x8c974f7383725573, + 0xafbd2350644eead0, 0xdbac6c247d62a584, 0x894bc396ce5da772, + 0xab9eb47c81f5114f, 0xd686619ba27255a3, 0x8613fd0145877586, + 0xa798fc4196e952e7, 0xd17f3b51fca3a7a1, 0x82ef85133de648c5, + 0xa3ab66580d5fdaf6, 0xcc963fee10b7d1b3, 0xffbbcfe994e5c620, + 0x9fd561f1fd0f9bd4, 0xc7caba6e7c5382c9, 0xf9bd690a1b68637b, + 0x9c1661a651213e2d, 0xc31bfa0fe5698db8, 0xf3e2f893dec3f126, + 0x986ddb5c6b3a76b8, 0xbe89523386091466, 0xee2ba6c0678b597f, + 0x94db483840b717f0, 0xba121a4650e4ddec, 0xe896a0d7e51e1566, + 0x915e2486ef32cd60, 0xb5b5ada8aaff80b8, 0xe3231912d5bf60e6, + 0x8df5efabc5979c90, 0xb1736b96b6fd83b4, 0xddd0467c64bce4a1, + 0x8aa22c0dbef60ee4, 0xad4ab7112eb3929e, 0xd89d64d57a607745, + 0x87625f056c7c4a8b, 0xa93af6c6c79b5d2e, 0xd389b47879823479, + 0x843610cb4bf160cc, 0xa54394fe1eedb8ff, 0xce947a3da6a9273e, + 0x811ccc668829b887, 0xa163ff802a3426a9, 0xc9bcff6034c13053, + 0xfc2c3f3841f17c68, 0x9d9ba7832936edc1, 0xc5029163f384a931, + 0xf64335bcf065d37d, 0x99ea0196163fa42e, 0xc06481fb9bcf8d3a, + 0xf07da27a82c37088, 0x964e858c91ba2655, 0xbbe226efb628afeb, + 0xeadab0aba3b2dbe5, 0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb, + 0xe55990879ddcaabe, 0x8f57fa54c2a9eab7, 0xb32df8e9f3546564, + 0xdff9772470297ebd, 0x8bfbea76c619ef36, 0xaefae51477a06b04, + 0xdab99e59958885c5, 0x88b402f7fd75539b, 0xaae103b5fcd2a882, + 0xd59944a37c0752a2, 0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88f, + 0xd097ad07a71f26b2, 0x825ecc24c8737830, 0xa2f67f2dfa90563b, + 0xcbb41ef979346bca, 0xfea126b7d78186bd, 0x9f24b832e6b0f436, + 0xc6ede63fa05d3144, 0xf8a95fcf88747d94, 0x9b69dbe1b548ce7d, + 0xc24452da229b021c, 0xf2d56790ab41c2a3, 0x97c560ba6b0919a6, + 0xbdb6b8e905cb600f, 0xed246723473e3813, 0x9436c0760c86e30c, + 0xb94470938fa89bcf, 0xe7958cb87392c2c3, 0x90bd77f3483bb9ba, + 0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232, 0x8d590723948a535f, + 0xb0af48ec79ace837, 0xdcdb1b2798182245, 0x8a08f0f8bf0f156b, + 0xac8b2d36eed2dac6, 0xd7adf884aa879177, 0x86ccbb52ea94baeb, + 0xa87fea27a539e9a5, 0xd29fe4b18e88640f, 0x83a3eeeef9153e89, + 0xa48ceaaab75a8e2b, 0xcdb02555653131b6, 0x808e17555f3ebf12, + 0xa0b19d2ab70e6ed6, 0xc8de047564d20a8c, 0xfb158592be068d2f, + 0x9ced737bb6c4183d, 0xc428d05aa4751e4d, 0xf53304714d9265e0, + 0x993fe2c6d07b7fac, 0xbf8fdb78849a5f97, 0xef73d256a5c0f77d, + 0x95a8637627989aae, 0xbb127c53b17ec159, 0xe9d71b689dde71b0, + 0x9226712162ab070e, 0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b06, + 0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c, 0xdf01e85f912e37a3, + 0x8b61313bbabce2c6, 0xae397d8aa96c1b78, 0xd9c7dced53c72256, + 0x881cea14545c7575, 0xaa242499697392d3, 0xd4ad2dbfc3d07788, + 0x84ec3c97da624ab5, 0xa6274bbdd0fadd62, 0xcfb11ead453994ba, + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3e, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e48, 0xc612062576589ddb, + 0xf79687aed3eec551, 0x9abe14cd44753b53, 0xc16d9a0095928a27, + 0xf1c90080baf72cb1, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a5, 0x9392ee8e921d5d07, 0xb877aa3236a4b449, + 0xe69594bec44de15b, 0x901d7cf73ab0acd9, 0xb424dc35095cd80f, + 0xe12e13424bb40e13, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a597, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bc, 0x8637bd05af6c69b6, 0xa7c5ac471b478423, + 0xd1b71758e219652c, 0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, + 0xa18f07d736b90be5, 0xc9f2c9cd04674edf, 0xfc6f7c4045812296, + 0x9dc5ada82b70b59e, 0xc5371912364ce305, 0xf684df56c3e01bc7, + 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, + 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, + 0x92efd1b8d0cf37be, 0xb7abc627050305ae, 0xe596b7b0c643c719, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f, + 0x8c213d9da502de45, 0xaf298d050e4395d7, 0xdaf3f04651d47b4c, + 0x88d8762bf324cd10, 0xab0e93b6efee0054, 0xd5d238a4abe98068, + 0x85a36366eb71f041, 0xa70c3c40a64e6c52, 0xd0cf4b50cfe20766, + 0x82818f1281ed44a0, 0xa321f2d7226895c8, 0xcbea6f8ceb02bb3a, + 0xfee50b7025c36a08, 0x9f4f2726179a2245, 0xc722f0ef9d80aad6, + 0xf8ebad2b84e0d58c, 0x9b934c3b330c8577, 0xc2781f49ffcfa6d5, + 0xf316271c7fc3908b, 0x97edd871cfda3a57, 0xbde94e8e43d0c8ec, + 0xed63a231d4c4fb27, 0x945e455f24fb1cf9, 0xb975d6b6ee39e437, + 0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4b, 0xb51d13aea4a488dd, + 0xe264589a4dcdab15, 0x8d7eb76070a08aed, 0xb0de65388cc8ada8, + 0xdd15fe86affad912, 0x8a2dbf142dfcc7ab, 0xacb92ed9397bf996, + 0xd7e77a8f87daf7fc, 0x86f0ac99b4e8dafd, 0xa8acd7c0222311bd, + 0xd2d80db02aabd62c, 0x83c7088e1aab65db, 0xa4b8cab1a1563f52, + 0xcde6fd5e09abcf27, 0x80b05e5ac60b6178, 0xa0dc75f1778e39d6, + 0xc913936dd571c84c, 0xfb5878494ace3a5f, 0x9d174b2dcec0e47b, + 0xc45d1df942711d9a, 0xf5746577930d6501, 0x9968bf6abbe85f20, + 0xbfc2ef456ae276e9, 0xefb3ab16c59b14a3, 0x95d04aee3b80ece6, + 0xbb445da9ca61281f, 0xea1575143cf97227, 0x924d692ca61be758, + 0xb6e0c377cfa2e12e, 0xe498f455c38b997a, 0x8edf98b59a373fec, + 0xb2977ee300c50fe7, 0xdf3d5e9bc0f653e1, 0x8b865b215899f46d, + 0xae67f1e9aec07188, 0xda01ee641a708dea, 0x884134fe908658b2, + 0xaa51823e34a7eedf, 0xd4e5e2cdc1d1ea96, 0x850fadc09923329e, + 0xa6539930bf6bff46, 0xcfe87f7cef46ff17, 0x81f14fae158c5f6e, + 0xa26da3999aef774a, 0xcb090c8001ab551c, 0xfdcb4fa002162a63, + 0x9e9f11c4014dda7e, 0xc646d63501a1511e, 0xf7d88bc24209a565, + 0x9ae757596946075f, 0xc1a12d2fc3978937, 0xf209787bb47d6b85, + 0x9745eb4d50ce6333, 0xbd176620a501fc00, 0xec5d3fa8ce427b00, + 0x93ba47c980e98ce0, 0xb8a8d9bbe123f018, 0xe6d3102ad96cec1e, + 0x9043ea1ac7e41393, 0xb454e4a179dd1877, 0xe16a1dc9d8545e95, + 0x8ce2529e2734bb1d, 0xb01ae745b101e9e4, 0xdc21a1171d42645d, + 0x899504ae72497eba, 0xabfa45da0edbde69, 0xd6f8d7509292d603, + 0x865b86925b9bc5c2, 0xa7f26836f282b733, 0xd1ef0244af2364ff, + 0x8335616aed761f1f, 0xa402b9c5a8d3a6e7, 0xcd036837130890a1, + 0x802221226be55a65, 0xa02aa96b06deb0fe, 0xc83553c5c8965d3d, + 0xfa42a8b73abbf48d, 0x9c69a97284b578d8, 0xc38413cf25e2d70e, + 0xf46518c2ef5b8cd1, 0x98bf2f79d5993803, 0xbeeefb584aff8604, + 0xeeaaba2e5dbf6785, 0x952ab45cfa97a0b3, 0xba756174393d88e0, + 0xe912b9d1478ceb17, 0x91abb422ccb812ef, 0xb616a12b7fe617aa, + 0xe39c49765fdf9d95, 0x8e41ade9fbebc27d, 0xb1d219647ae6b31c, + 0xde469fbd99a05fe3, 0x8aec23d680043bee, 0xada72ccc20054aea, + 0xd910f7ff28069da4, 0x87aa9aff79042287, 0xa99541bf57452b28, + 0xd3fa922f2d1675f2, 0x847c9b5d7c2e09b7, 0xa59bc234db398c25, + 0xcf02b2c21207ef2f, 0x8161afb94b44f57d, 0xa1ba1ba79e1632dc, + 0xca28a291859bbf93, 0xfcb2cb35e702af78, 0x9defbf01b061adab, + 0xc56baec21c7a1916, 0xf6c69a72a3989f5c, 0x9a3c2087a63f6399, + 0xc0cb28a98fcf3c80, 0xf0fdf2d3f3c30b9f, 0x969eb7c47859e744, + 0xbc4665b596706115, 0xeb57ff22fc0c795a, 0x9316ff75dd87cbd8, + 0xb7dcbf5354e9bece, 0xe5d3ef282a242e82, 0x8fa475791a569d11, + 0xb38d92d760ec4455, 0xe070f78d3927556b, 0x8c469ab843b89563, + 0xaf58416654a6babb, 0xdb2e51bfe9d0696a, 0x88fcf317f22241e2, + 0xab3c2fddeeaad25b, 0xd60b3bd56a5586f2, 0x85c7056562757457, + 0xa738c6bebb12d16d, 0xd106f86e69d785c8, 0x82a45b450226b39d, + 0xa34d721642b06084, 0xcc20ce9bd35c78a5, 0xff290242c83396ce, + 0x9f79a169bd203e41, 0xc75809c42c684dd1, 0xf92e0c3537826146, + 0x9bbcc7a142b17ccc, 0xc2abf989935ddbfe, 0xf356f7ebf83552fe, + 0x98165af37b2153df, 0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c, + 0x9485d4d1c63e8be8, 0xb9a74a0637ce2ee1, 0xe8111c87c5c1ba9a, + 0x910ab1d4db9914a0, 0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a, + 0x8da471a9de737e24, 0xb10d8e1456105dad, 0xdd50f1996b947519, + 0x8a5296ffe33cc930, 0xace73cbfdc0bfb7b, 0xd8210befd30efa5a, + 0x8714a775e3e95c78, 0xa8d9d1535ce3b396, 0xd31045a8341ca07c, + 0x83ea2b892091e44e, 0xa4e4b66b68b65d61, 0xce1de40642e3f4b9, + 0x80d2ae83e9ce78f4, 0xa1075a24e4421731, 0xc94930ae1d529cfd, + 0xfb9b7cd9a4a7443c, 0x9d412e0806e88aa6, 0xc491798a08a2ad4f, + 0xf5b5d7ec8acb58a3, 0x9991a6f3d6bf1766, 0xbff610b0cc6edd3f, + 0xeff394dcff8a948f, 0x95f83d0a1fb69cd9, 0xbb764c4ca7a44410, + 0xea53df5fd18d5514, 0x92746b9be2f8552c, 0xb7118682dbb66a77, + 0xe4d5e82392a40515, 0x8f05b1163ba6832d, 0xb2c71d5bca9023f8, + 0xdf78e4b2bd342cf7, 0x8bab8eefb6409c1a, 0xae9672aba3d0c321, + 0xda3c0f568cc4f3e9, 0x8865899617fb1871, 0xaa7eebfb9df9de8e, + 0xd51ea6fa85785631, 0x8533285c936b35df, 0xa67ff273b8460357, + 0xd01fef10a657842c, 0x8213f56a67f6b29c, 0xa298f2c501f45f43, + 0xcb3f2f7642717713, 0xfe0efb53d30dd4d8, 0x9ec95d1463e8a507, + 0xc67bb4597ce2ce49, 0xf81aa16fdc1b81db, 0x9b10a4e5e9913129, + 0xc1d4ce1f63f57d73, 0xf24a01a73cf2dcd0, 0x976e41088617ca02, + 0xbd49d14aa79dbc82, 0xec9c459d51852ba3, 0x93e1ab8252f33b46, + 0xb8da1662e7b00a17, 0xe7109bfba19c0c9d, 0x906a617d450187e2, + 0xb484f9dc9641e9db, 0xe1a63853bbd26451, 0x8d07e33455637eb3, + 0xb049dc016abc5e60, 0xdc5c5301c56b75f7, 0x89b9b3e11b6329bb, + 0xac2820d9623bf429, 0xd732290fbacaf134, 0x867f59a9d4bed6c0, + 0xa81f301449ee8c70, 0xd226fc195c6a2f8c, 0x83585d8fd9c25db8, + 0xa42e74f3d032f526, 0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85, + 0xa0555e361951c367, 0xc86ab5c39fa63441, 0xfa856334878fc151, + 0x9c935e00d4b9d8d2, 0xc3b8358109e84f07, 0xf4a642e14c6262c9, + 0x98e7e9cccfbd7dbe, 0xbf21e44003acdd2d, 0xeeea5d5004981478, + 0x95527a5202df0ccb, 0xbaa718e68396cffe, 0xe950df20247c83fd, + 0x91d28b7416cdd27e, 0xb6472e511c81471e, 0xe3d8f9e563a198e5, + 0x8e679c2f5e44ff8f, 0xb201833b35d63f73, 0xde81e40a034bcf50, + 0x8b112e86420f6192, 0xadd57a27d29339f6, 0xd94ad8b1c7380874, + 0x87cec76f1c830549, 0xa9c2794ae3a3c69b, 0xd433179d9c8cb841, + 0x849feec281d7f329, 0xa5c7ea73224deff3, 0xcf39e50feae16bf0, + 0x81842f29f2cce376, 0xa1e53af46f801c53, 0xca5e89b18b602368, + 0xfcf62c1dee382c42, 0x9e19db92b4e31ba9, 0xc5a05277621be294, + 0xf70867153aa2db39, 0x9a65406d44a5c903, 0xc0fe908895cf3b44, + 0xf13e34aabb430a15, 0x96c6e0eab509e64d, 0xbc789925624c5fe1, + 0xeb96bf6ebadf77d9, 0x933e37a534cbaae8, 0xb80dc58e81fe95a1, + 0xe61136f2227e3b0a, 0x8fcac257558ee4e6, 0xb3bd72ed2af29e20, + 0xe0accfa875af45a8, 0x8c6c01c9498d8b89, 0xaf87023b9bf0ee6b, + 0xdb68c2ca82ed2a06, 0x892179be91d43a44, 0xab69d82e364948d4 +}; + +static const int powers_ten_e[] = { + -1203, -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, + -1170, -1166, -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, + -1136, -1133, -1130, -1127, -1123, -1120, -1117, -1113, -1110, -1107, + -1103, -1100, -1097, -1093, -1090, -1087, -1083, -1080, -1077, -1073, + -1070, -1067, -1063, -1060, -1057, -1053, -1050, -1047, -1043, -1040, + -1037, -1034, -1030, -1027, -1024, -1020, -1017, -1014, -1010, -1007, + -1004, -1000, -997, -994, -990, -987, -984, -980, -977, -974, -970, + -967, -964, -960, -957, -954, -950, -947, -944, -940, -937, -934, -931, + -927, -924, -921, -917, -914, -911, -907, -904, -901, -897, -894, -891, + -887, -884, -881, -877, -874, -871, -867, -864, -861, -857, -854, -851, + -847, -844, -841, -838, -834, -831, -828, -824, -821, -818, -814, -811, + -808, -804, -801, -798, -794, -791, -788, -784, -781, -778, -774, -771, + -768, -764, -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, + -728, -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, + -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, -651, + -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, -615, -612, + -608, -605, -602, -598, -595, -592, -588, -585, -582, -578, -575, -572, + -568, -565, -562, -558, -555, -552, -549, -545, -542, -539, -535, -532, + -529, -525, -522, -519, -515, -512, -509, -505, -502, -499, -495, -492, + -489, -485, -482, -479, -475, -472, -469, -465, -462, -459, -455, -452, + -449, -446, -442, -439, -436, -432, -429, -426, -422, -419, -416, -412, + -409, -406, -402, -399, -396, -392, -389, -386, -382, -379, -376, -372, + -369, -366, -362, -359, -356, -353, -349, -346, -343, -339, -336, -333, + -329, -326, -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, + -289, -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, + -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, -213, + -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, -176, -173, + -170, -166, -163, -160, -157, -153, -150, -147, -143, -140, -137, -133, + -130, -127, -123, -120, -117, -113, -110, -107, -103, -100, -97, -93, + -90, -87, -83, -80, -77, -73, -70, -67, -63, -60, -57, -54, -50, -47, + -44, -40, -37, -34, -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, 6, + 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, 43, 46, 49, 53, 56, 59, 63, 66, + 69, 73, 76, 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, 116, 119, + 123, 126, 129, 132, 136, 139, 142, 146, 149, 152, 156, 159, 162, 166, + 169, 172, 176, 179, 182, 186, 189, 192, 196, 199, 202, 206, 209, 212, + 216, 219, 222, 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, + 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, 299, 302, 305, + 309, 312, 315, 319, 322, 325, 328, 332, 335, 338, 342, 345, 348, 352, + 355, 358, 362, 365, 368, 372, 375, 378, 382, 385, 388, 392, 395, 398, + 402, 405, 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, 445, + 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, 481, 485, 488, 491, + 495, 498, 501, 505, 508, 511, 515, 518, 521, 524, 528, 531, 534, 538, + 541, 544, 548, 551, 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, + 588, 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, 627, 631, + 634, 637, 641, 644, 647, 651, 654, 657, 661, 664, 667, 671, 674, 677, + 681, 684, 687, 691, 694, 697, 701, 704, 707, 711, 714, 717, 720, 724, + 727, 730, 734, 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, + 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, 810, 813, 817, + 820, 823, 827, 830, 833, 837, 840, 843, 847, 850, 853, 857, 860, 863, + 867, 870, 873, 877, 880, 883, 887, 890, 893, 897, 900, 903, 907, 910, + 913, 916, 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, 956, + 960, 963, 966, 970, 973, 976, 980, 983, 986, 990, 993, 996, 1000, 1003, + 1006, 1009, 1013, 1016, 1019, 1023, 1026, 1029, 1033, 1036, 1039, 1043, + 1046, 1049, 1053, 1056, 1059, 1063, 1066, 1069, 1073, 1076 +}; + +static diy_fp_t cached_power(int k) +{ + diy_fp_t res; + int index = 343 + k; + res.f = powers_ten[index]; + res.e = powers_ten_e[index]; + return res; +} + +static int k_comp(int e, int alpha, int gamma) { + return ceil((alpha-e+63) * D_1_LOG2_10); +} + +static diy_fp_t minus(diy_fp_t x, diy_fp_t y) +{ + diy_fp_t r; + assert(x.e == y.e); + assert(x.f >= y.f); + r.f = x.f - y.f; + r.e = x.e; + return r; +} + +static diy_fp_t multiply(diy_fp_t x, diy_fp_t y) +{ + uint64_t a,b,c,d,ac,bc,ad,bd,tmp; + diy_fp_t r; + uint64_t M32 = 0xFFFFFFFF; + a = x.f >> 32; b = x.f & M32; + c = y.f >> 32; d = y.f & M32; + ac = a*c; bc = b*c; ad = a*d; bd = b*d; + tmp = (bd>>32) + (ad&M32) + (bc&M32); + tmp += 1U << 31; + r.f = ac+(ad>>32)+(bc>>32)+(tmp >>32); + r.e = x.e + y.e + 64; + return r; +} + +static uint64_t double_to_uint64(double d) +{ + uint64_t n; + memcpy(&n, &d, 8); + return n; +} + +#define DP_SIGNIFICAND_SIZE 52 +#define DP_EXPONENT_BIAS (0x3FF + DP_SIGNIFICAND_SIZE) +#define DP_MIN_EXPONENT (-DP_EXPONENT_BIAS) +#define DP_EXPONENT_MASK 0x7FF0000000000000 +#define DP_SIGNIFICAND_MASK 0x000FFFFFFFFFFFFF +#define DP_HIDDEN_BIT 0x0010000000000000 + +static diy_fp_t double2diy_fp(double d) +{ + uint64_t d64 = double_to_uint64(d); + int biased_e = (d64 & DP_EXPONENT_MASK) >> DP_SIGNIFICAND_SIZE; + uint64_t significand = (d64 & DP_SIGNIFICAND_MASK); + diy_fp_t res; + if (biased_e != 0) { + res.f = significand + DP_HIDDEN_BIT; + res.e = biased_e - DP_EXPONENT_BIAS; + } else { + res.f = significand; + res.e = DP_MIN_EXPONENT + 1; + } + return res; +} + +static diy_fp_t normalize_boundary(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (! (res.f & (DP_HIDDEN_BIT << 1))) { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2); + res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2); + return res; +} + +static void normalized_boundaries(double d, diy_fp_t* out_m_minus, diy_fp_t* out_m_plus) +{ + diy_fp_t v = double2diy_fp(d); + diy_fp_t pl, mi; + int significand_is_zero = v.f == DP_HIDDEN_BIT; + pl.f = (v.f << 1) + 1; pl.e = v.e - 1; + pl = normalize_boundary(pl); + if (significand_is_zero) { + mi.f = (v.f << 2) - 1; + mi.e = v.e - 2; + } else { + mi.f = (v.f << 1) - 1; + mi.e = v.e - 1; + } + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *out_m_plus = pl; + *out_m_minus = mi; +} + +#define TEN2 100 +static void digit_gen(diy_fp_t Mp, diy_fp_t delta, char* buffer, int* len, int* K) +{ + uint32_t div, p1; + uint64_t p2; + int d,kappa; + diy_fp_t one; + one.f = ((uint64_t) 1) << -Mp.e; one.e = Mp.e; + p1 = Mp.f >> -one.e; + p2 = Mp.f & (one.f - 1); + *len = 0; kappa = 3; div = TEN2; + while (kappa > 0) { + d = p1 / div; + if (d || *len) buffer[(*len)++] = '0' + d; + p1 %= div; kappa--; div /= 10; + if ((((uint64_t)p1)<<-one.e)+p2 <= delta.f) { + *K += kappa; return; + } + } + do { + p2 *= 10; + d = p2 >> -one.e; + if (d || *len) buffer[(*len)++] = '0' + d; + p2 &= one.f - 1; kappa--; delta.f *= 10; + } while (p2 > delta.f); + *K += kappa; +} + +int +js_grisu2(double v, char *buffer, int *K) +{ + int length, mk; + diy_fp_t w_m, w_p, c_mk, Wp, Wm, delta; + int q = 64, alpha = -59, gamma = -56; + normalized_boundaries(v, &w_m, &w_p); + mk = k_comp(w_p.e + q, alpha, gamma); + c_mk = cached_power(mk); + Wp = multiply(w_p, c_mk); + Wm = multiply(w_m, c_mk); + Wm.f++; Wp.f--; + delta = minus(Wp, Wm); + *K = -mk; + digit_gen(Wp, delta, buffer, &length, K); + return length; +} + +/* + * strtod.c + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies. The University of + * California makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + */ + +/* Largest possible base 10 exponent. Any exponent larger than this will + * already produce underflow or overflow, so there's no need to worry about + * additional digits. + */ +static int maxExponent = 511; + +/* Table giving binary powers of 10. Entry + * is 10^2^i. Used to convert decimal + * exponents into floating-point numbers. + */ +static double powersOf10[] = { + 10., + 100., + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* Parse a decimal ASCII floating-point number, optionally preceded by white + * space. Must have form "-I.FE-X", where I is the integer part of the + * mantissa, F is the fractional part of the mantissa, and X is the exponent. + * Either of the signs may be "+", "-", or omitted. Either I or F may be + * omitted, or both. The decimal point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X may both be omitted (but not just + * one). + */ +double +js_strtod(const char *string, char **endPtr) +{ + int sign, expSign = FALSE; + double fraction, dblExp, *d; + register const char *p; + register int c; + + /* Exponent read from "EX" field. */ + int exp = 0; + + /* Exponent that derives from the fractional part. Under normal + * circumstances, it is the negative of the number of digits in F. + * However, if I is very long, the last digits of I get dropped + * (otherwise a long I with a large negative exponent could cause an + * unnecessary overflow on I alone). In this case, fracExp is + * incremented one for each dropped digit. + */ + int fracExp = 0; + + /* Number of digits in mantissa. */ + int mantSize; + + /* Number of mantissa digits BEFORE decimal point. */ + int decPt; + + /* Temporarily holds location of exponent in string. */ + const char *pExp; + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!(c>='0'&&c<='9')) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while ((*p >= '0') && (*p <= '9') && exp < INT_MAX/100) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + while ((*p >= '0') && (*p <= '9')) + p += 1; + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < -maxExponent) { + exp = maxExponent; + expSign = TRUE; + errno = ERANGE; + } else if (exp > maxExponent) { + exp = maxExponent; + expSign = FALSE; + errno = ERANGE; + } else if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/src/mujs/jserror.c b/src/mujs/jserror.c new file mode 100644 index 0000000..99a1bbc --- /dev/null +++ b/src/mujs/jserror.c @@ -0,0 +1,128 @@ +#include "jsi.h" + +#define QQ(X) #X +#define Q(X) QQ(X) + +static int jsB_stacktrace(js_State *J, int skip) +{ + char buf[256]; + int n = J->tracetop - skip; + if (n <= 0) + return 0; + for (; n > 0; --n) { + const char *name = J->trace[n].name; + const char *file = J->trace[n].file; + int line = J->trace[n].line; + if (line > 0) { + if (name[0]) + npf_snprintf(buf, sizeof buf, "\n\tat %s (%s:%d)", name, file, line); + else + npf_snprintf(buf, sizeof buf, "\n\tat %s:%d", file, line); + } else + npf_snprintf(buf, sizeof buf, "\n\tat %s (%s)", name, file); + js_pushstring(J, buf); + if (n < J->tracetop - skip) + js_concat(J); + } + return 1; +} + +static void Ep_toString(js_State *J) +{ + const char *name = "Error"; + const char *message = ""; + + if (!js_isobject(J, -1)) + js_typeerror(J, "not an object"); + + if (js_hasproperty(J, 0, "name")) + name = js_tostring(J, -1); + if (js_hasproperty(J, 0, "message")) + message = js_tostring(J, -1); + + if (name[0] == 0) + js_pushstring(J, message); + else if (message[0] == 0) + js_pushstring(J, name); + else { + js_pushstring(J, name); + js_pushstring(J, ": "); + js_concat(J); + js_pushstring(J, message); + js_concat(J); + } +} + +static int jsB_ErrorX(js_State *J, js_Object *prototype) +{ + js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype)); + if (js_isdefined(J, 1)) { + js_pushstring(J, js_tostring(J, 1)); + js_defproperty(J, -2, "message", JS_DONTENUM); + } + if (jsB_stacktrace(J, 1)) + js_defproperty(J, -2, "stackTrace", JS_DONTENUM); + return 1; +} + +static void js_newerrorx(js_State *J, const char *message, js_Object *prototype) +{ + js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype)); + js_pushstring(J, message); + js_setproperty(J, -2, "message"); + if (jsB_stacktrace(J, 0)) + js_setproperty(J, -2, "stackTrace"); +} + +#define DERROR(name, Name) \ + static void jsB_##Name(js_State *J) { \ + jsB_ErrorX(J, J->Name##_prototype); \ + } \ + void js_new##name(js_State *J, const char *s) { \ + js_newerrorx(J, s, J->Name##_prototype); \ + } \ + void js_##name(js_State *J, const char *fmt, ...) { \ + va_list ap; \ + char buf[256]; \ + va_start(ap, fmt); \ + npf_vsnprintf(buf, sizeof buf, fmt, ap); \ + va_end(ap); \ + js_newerrorx(J, buf, J->Name##_prototype); \ + js_throw(J); \ + } + +DERROR(error, Error) +DERROR(evalerror, EvalError) +DERROR(rangeerror, RangeError) +DERROR(referenceerror, ReferenceError) +DERROR(syntaxerror, SyntaxError) +DERROR(typeerror, TypeError) +DERROR(urierror, URIError) + +#undef DERROR + +void jsB_initerror(js_State *J) +{ + js_pushobject(J, J->Error_prototype); + { + jsB_props(J, "name", "Error"); + jsB_propf(J, "Error.prototype.toString", Ep_toString, 0); + } + js_newcconstructor(J, jsB_Error, jsB_Error, "Error", 1); + js_defglobal(J, "Error", JS_DONTENUM); + + #define IERROR(NAME) \ + js_pushobject(J, J->NAME##_prototype); \ + jsB_props(J, "name", Q(NAME)); \ + js_newcconstructor(J, jsB_##NAME, jsB_##NAME, Q(NAME), 1); \ + js_defglobal(J, Q(NAME), JS_DONTENUM); + + IERROR(EvalError); + IERROR(RangeError); + IERROR(ReferenceError); + IERROR(SyntaxError); + IERROR(TypeError); + IERROR(URIError); + + #undef IERROR +} diff --git a/src/mujs/jsfunction.c b/src/mujs/jsfunction.c new file mode 100644 index 0000000..dea75ac --- /dev/null +++ b/src/mujs/jsfunction.c @@ -0,0 +1,231 @@ +#include "jsi.h" + +static void jsB_Function(js_State *J) +{ + int i, top = js_gettop(J); + js_Buffer *sb = NULL; + const char *body; + js_Ast *parse; + js_Function *fun; + + if (js_try(J)) { + js_free(J, sb); + jsP_freeparse(J); + js_throw(J); + } + + /* p1, p2, ..., pn */ + if (top > 2) { + for (i = 1; i < top - 1; ++i) { + if (i > 1) + js_putc(J, &sb, ','); + js_puts(J, &sb, js_tostring(J, i)); + } + js_putc(J, &sb, ')'); + js_putc(J, &sb, 0); + } + + /* body */ + body = js_isdefined(J, top - 1) ? js_tostring(J, top - 1) : ""; + + parse = jsP_parsefunction(J, "[string]", sb ? sb->s : NULL, body); + fun = jsC_compilefunction(J, parse); + + js_endtry(J); + js_free(J, sb); + jsP_freeparse(J); + + js_newfunction(J, fun, J->GE); +} + +static void jsB_Function_prototype(js_State *J) +{ + js_pushundefined(J); +} + +static void Fp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + js_Buffer *sb = NULL; + int i; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) { + js_Function *F = self->u.f.function; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_puts(J, &sb, "function "); + js_puts(J, &sb, F->name); + js_putc(J, &sb, '('); + for (i = 0; i < F->numparams; ++i) { + if (i > 0) js_putc(J, &sb, ','); + js_puts(J, &sb, F->vartab[i]); + } + js_puts(J, &sb, ") { [byte code] }"); + js_putc(J, &sb, 0); + + js_pushstring(J, sb->s); + js_endtry(J); + js_free(J, sb); + } else if (self->type == JS_CCFUNCTION) { + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_puts(J, &sb, "function "); + js_puts(J, &sb, self->u.c.name); + js_puts(J, &sb, "() { [native code] }"); + js_putc(J, &sb, 0); + + js_pushstring(J, sb->s); + js_endtry(J); + js_free(J, sb); + } else { + js_pushliteral(J, "function () { }"); + } +} + +static void Fp_apply(js_State *J) +{ + int i, n; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + js_copy(J, 0); + js_copy(J, 1); + + if (js_isnull(J, 2) || js_isundefined(J, 2)) { + n = 0; + } else { + n = js_getlength(J, 2); + if (n < 0) + n = 0; + for (i = 0; i < n; ++i) + js_getindex(J, 2, i); + } + + js_call(J, n); +} + +static void Fp_call(js_State *J) +{ + int i, top = js_gettop(J); + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + for (i = 0; i < top; ++i) + js_copy(J, i); + + js_call(J, top - 2); +} + +static void callbound(js_State *J) +{ + int top = js_gettop(J); + int i, fun, args, n; + + fun = js_gettop(J); + js_currentfunction(J); + js_getproperty(J, fun, "__TargetFunction__"); + js_getproperty(J, fun, "__BoundThis__"); + + args = js_gettop(J); + js_getproperty(J, fun, "__BoundArguments__"); + n = js_getlength(J, args); + if (n < 0) + n = 0; + for (i = 0; i < n; ++i) + js_getindex(J, args, i); + js_remove(J, args); + + for (i = 1; i < top; ++i) + js_copy(J, i); + + js_call(J, n + top - 1); +} + +static void constructbound(js_State *J) +{ + int top = js_gettop(J); + int i, fun, args, n; + + fun = js_gettop(J); + js_currentfunction(J); + js_getproperty(J, fun, "__TargetFunction__"); + + args = js_gettop(J); + js_getproperty(J, fun, "__BoundArguments__"); + n = js_getlength(J, args); + if (n < 0) + n = 0; + for (i = 0; i < n; ++i) + js_getindex(J, args, i); + js_remove(J, args); + + for (i = 1; i < top; ++i) + js_copy(J, i); + + js_construct(J, n + top - 1); +} + +static void Fp_bind(js_State *J) +{ + int i, top = js_gettop(J); + int n; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + n = js_getlength(J, 0); + if (n > top - 2) + n -= top - 2; + else + n = 0; + + /* Reuse target function's prototype for HasInstance check. */ + js_getproperty(J, 0, "prototype"); + js_newcconstructor(J, callbound, constructbound, "[bind]", n); + + /* target function */ + js_copy(J, 0); + js_defproperty(J, -2, "__TargetFunction__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + /* bound this */ + js_copy(J, 1); + js_defproperty(J, -2, "__BoundThis__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + /* bound arguments */ + js_newarray(J); + for (i = 2; i < top; ++i) { + js_copy(J, i); + js_setindex(J, -2, i - 2); + } + js_defproperty(J, -2, "__BoundArguments__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); +} + +void jsB_initfunction(js_State *J) +{ + J->Function_prototype->u.c.name = "Function.prototype"; + J->Function_prototype->u.c.function = jsB_Function_prototype; + J->Function_prototype->u.c.constructor = NULL; + J->Function_prototype->u.c.length = 0; + + js_pushobject(J, J->Function_prototype); + { + jsB_propf(J, "Function.prototype.toString", Fp_toString, 2); + jsB_propf(J, "Function.prototype.apply", Fp_apply, 2); + jsB_propf(J, "Function.prototype.call", Fp_call, 1); + jsB_propf(J, "Function.prototype.bind", Fp_bind, 1); + } + js_newcconstructor(J, jsB_Function, jsB_Function, "Function", 1); + js_defglobal(J, "Function", JS_DONTENUM); +} diff --git a/src/mujs/jsgc.c b/src/mujs/jsgc.c new file mode 100644 index 0000000..3f05be3 --- /dev/null +++ b/src/mujs/jsgc.c @@ -0,0 +1,284 @@ +#include "jsi.h" +#include "regexp.h" + +static void jsG_freeenvironment(js_State *J, js_Environment *env) +{ + js_free(J, env); +} + +static void jsG_freefunction(js_State *J, js_Function *fun) +{ + js_free(J, fun->funtab); + js_free(J, fun->vartab); + js_free(J, fun->code); + js_free(J, fun); +} + +static void jsG_freeproperty(js_State *J, js_Property *node) +{ + if (node->left->level) jsG_freeproperty(J, node->left); + if (node->right->level) jsG_freeproperty(J, node->right); + js_free(J, node); +} + +static void jsG_freeiterator(js_State *J, js_Iterator *node) +{ + while (node) { + js_Iterator *next = node->next; + js_free(J, node); + node = next; + } +} + +static void jsG_freeobject(js_State *J, js_Object *obj) +{ + if (obj->properties->level) + jsG_freeproperty(J, obj->properties); + if (obj->type == JS_CREGEXP) { + js_free(J, obj->u.r.source); + js_regfreex(J->alloc, J->actx, obj->u.r.prog); + } + if (obj->type == JS_CSTRING) { + if (obj->u.s.string != obj->u.s.shrstr) + js_free(J, obj->u.s.string); + } + if (obj->type == JS_CARRAY && obj->u.a.simple) + js_free(J, obj->u.a.array); + if (obj->type == JS_CITERATOR) + jsG_freeiterator(J, obj->u.iter.head); + if (obj->type == JS_CUSERDATA && obj->u.user.finalize) + obj->u.user.finalize(J, obj->u.user.data); + if (obj->type == JS_CCFUNCTION && obj->u.c.finalize) + obj->u.c.finalize(J, obj->u.c.data); + js_free(J, obj); +} + +/* Mark and add object to scan queue */ +static void jsG_markobject(js_State *J, int mark, js_Object *obj) +{ + obj->gcmark = mark; + obj->gcroot = J->gcroot; + J->gcroot = obj; +} + +static void jsG_markfunction(js_State *J, int mark, js_Function *fun) +{ + int i; + fun->gcmark = mark; + for (i = 0; i < fun->funlen; ++i) + if (fun->funtab[i]->gcmark != mark) + jsG_markfunction(J, mark, fun->funtab[i]); +} + +static void jsG_markenvironment(js_State *J, int mark, js_Environment *env) +{ + do { + env->gcmark = mark; + if (env->variables->gcmark != mark) + jsG_markobject(J, mark, env->variables); + env = env->outer; + } while (env && env->gcmark != mark); +} + +static void jsG_markproperty(js_State *J, int mark, js_Property *node) +{ + if (node->left->level) jsG_markproperty(J, mark, node->left); + if (node->right->level) jsG_markproperty(J, mark, node->right); + + if (node->value.t.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark) + node->value.u.memstr->gcmark = mark; + if (node->value.t.type == JS_TOBJECT && node->value.u.object->gcmark != mark) + jsG_markobject(J, mark, node->value.u.object); + if (node->getter && node->getter->gcmark != mark) + jsG_markobject(J, mark, node->getter); + if (node->setter && node->setter->gcmark != mark) + jsG_markobject(J, mark, node->setter); +} + +/* Mark everything the object can reach. */ +static void jsG_scanobject(js_State *J, int mark, js_Object *obj) +{ + if (obj->properties->level) + jsG_markproperty(J, mark, obj->properties); + if (obj->prototype && obj->prototype->gcmark != mark) + jsG_markobject(J, mark, obj->prototype); + if (obj->type == JS_CARRAY && obj->u.a.simple) { + int i; + for (i = 0; i < obj->u.a.flat_length; ++i) { + js_Value *v = &obj->u.a.array[i]; + if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark) + v->u.memstr->gcmark = mark; + if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark) + jsG_markobject(J, mark, v->u.object); + } + } + if (obj->type == JS_CITERATOR && obj->u.iter.target->gcmark != mark) { + jsG_markobject(J, mark, obj->u.iter.target); + } + if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT) { + if (obj->u.f.scope && obj->u.f.scope->gcmark != mark) + jsG_markenvironment(J, mark, obj->u.f.scope); + if (obj->u.f.function && obj->u.f.function->gcmark != mark) + jsG_markfunction(J, mark, obj->u.f.function); + } +} + +static void jsG_markstack(js_State *J, int mark) +{ + js_Value *v = J->stack; + int n = J->top; + while (n--) { + if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark) + v->u.memstr->gcmark = mark; + if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark) + jsG_markobject(J, mark, v->u.object); + ++v; + } +} + +void js_gc(js_State *J, int report) +{ + js_Function *fun, *nextfun, **prevnextfun; + js_Object *obj, *nextobj, **prevnextobj; + js_String *str, *nextstr, **prevnextstr; + js_Environment *env, *nextenv, **prevnextenv; + unsigned int nenv = 0, nfun = 0, nobj = 0, nstr = 0, nprop = 0; + unsigned int genv = 0, gfun = 0, gobj = 0, gstr = 0, gprop = 0; + int mark; + int i; + + mark = J->gcmark = J->gcmark == 1 ? 2 : 1; + + /* Add initial roots. */ + + jsG_markobject(J, mark, J->Object_prototype); + jsG_markobject(J, mark, J->Array_prototype); + jsG_markobject(J, mark, J->Function_prototype); + jsG_markobject(J, mark, J->Boolean_prototype); + jsG_markobject(J, mark, J->Number_prototype); + jsG_markobject(J, mark, J->String_prototype); + jsG_markobject(J, mark, J->RegExp_prototype); + jsG_markobject(J, mark, J->Date_prototype); + + jsG_markobject(J, mark, J->Error_prototype); + jsG_markobject(J, mark, J->EvalError_prototype); + jsG_markobject(J, mark, J->RangeError_prototype); + jsG_markobject(J, mark, J->ReferenceError_prototype); + jsG_markobject(J, mark, J->SyntaxError_prototype); + jsG_markobject(J, mark, J->TypeError_prototype); + jsG_markobject(J, mark, J->URIError_prototype); + + jsG_markobject(J, mark, J->R); + jsG_markobject(J, mark, J->G); + + jsG_markstack(J, mark); + + jsG_markenvironment(J, mark, J->E); + jsG_markenvironment(J, mark, J->GE); + for (i = 0; i < J->envtop; ++i) + jsG_markenvironment(J, mark, J->envstack[i]); + + /* Scan objects until none remain. */ + + while ((obj = J->gcroot) != NULL) { + J->gcroot = obj->gcroot; + obj->gcroot = NULL; + jsG_scanobject(J, mark, obj); + } + + /* Free everything not marked. */ + + prevnextenv = &J->gcenv; + for (env = J->gcenv; env; env = nextenv) { + nextenv = env->gcnext; + if (env->gcmark != mark) { + *prevnextenv = nextenv; + jsG_freeenvironment(J, env); + ++genv; + } else { + prevnextenv = &env->gcnext; + } + ++nenv; + } + + prevnextfun = &J->gcfun; + for (fun = J->gcfun; fun; fun = nextfun) { + nextfun = fun->gcnext; + if (fun->gcmark != mark) { + *prevnextfun = nextfun; + jsG_freefunction(J, fun); + ++gfun; + } else { + prevnextfun = &fun->gcnext; + } + ++nfun; + } + + prevnextobj = &J->gcobj; + for (obj = J->gcobj; obj; obj = nextobj) { + nprop += obj->count; + nextobj = obj->gcnext; + if (obj->gcmark != mark) { + gprop += obj->count; + *prevnextobj = nextobj; + jsG_freeobject(J, obj); + ++gobj; + } else { + prevnextobj = &obj->gcnext; + } + ++nobj; + } + + prevnextstr = &J->gcstr; + for (str = J->gcstr; str; str = nextstr) { + nextstr = str->gcnext; + if (str->gcmark != mark) { + *prevnextstr = nextstr; + js_free(J, str); + ++gstr; + } else { + prevnextstr = &str->gcnext; + } + ++nstr; + } + + unsigned int ntot = nenv + nfun + nobj + nstr + nprop; + unsigned int gtot = genv + gfun + gobj + gstr + gprop; + unsigned int remaining = ntot - gtot; + + J->gccounter = remaining; + J->gcthresh = remaining * JS_GCFACTOR; + + if (report) { + char buf[256]; + npf_snprintf(buf, sizeof buf, "garbage collected (%d%%): %d/%d envs, %d/%d funs, %d/%d objs, %d/%d props, %d/%d strs", + 100*gtot/ntot, genv, nenv, gfun, nfun, gobj, nobj, gprop, nprop, gstr, nstr); + js_report(J, buf); + } +} + +void js_freestate(js_State *J) +{ + js_Function *fun, *nextfun; + js_Object *obj, *nextobj; + js_Environment *env, *nextenv; + js_String *str, *nextstr; + + if (!J) + return; + + for (env = J->gcenv; env; env = nextenv) + nextenv = env->gcnext, jsG_freeenvironment(J, env); + for (fun = J->gcfun; fun; fun = nextfun) + nextfun = fun->gcnext, jsG_freefunction(J, fun); + for (obj = J->gcobj; obj; obj = nextobj) + nextobj = obj->gcnext, jsG_freeobject(J, obj); + for (str = J->gcstr; str; str = nextstr) + nextstr = str->gcnext, js_free(J, str); + + jsS_freestrings(J); + + js_free(J, J->lexbuf.text); + J->alloc(J->actx, J->stack, 0); + J->alloc(J->actx, J, 0); +} diff --git a/src/mujs/jsi.h b/src/mujs/jsi.h new file mode 100644 index 0000000..6956d97 --- /dev/null +++ b/src/mujs/jsi.h @@ -0,0 +1,867 @@ +#ifndef jsi_h +#define jsi_h + +#include "mujs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* NOTE: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103052 */ +#ifdef __GNUC__ +#if (__GNUC__ >= 6) +#pragma GCC optimize ("no-ipa-pure-const") +#endif +#endif + +/* Microsoft Visual C */ +#ifdef _MSC_VER +#pragma warning(disable:4996) /* _CRT_SECURE_NO_WARNINGS */ +#pragma warning(disable:4244) /* implicit conversion from double to int */ +#pragma warning(disable:4267) /* implicit conversion of int to smaller int */ +#pragma warning(disable:4090) /* broken const warnings */ +#define inline __inline +#if _MSC_VER < 1900 /* MSVC 2015 */ +#define snprintf jsW_snprintf +#define vsnprintf jsW_vsnprintf +static int jsW_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) +{ + int n; + n = _vsnprintf(str, size, fmt, ap); + str[size-1] = 0; + return n; +} +static int jsW_snprintf(char *str, size_t size, const char *fmt, ...) +{ + int n; + va_list ap; + va_start(ap, fmt); + n = jsW_vsnprintf(str, size, fmt, ap); + va_end(ap); + return n; +} +#endif +#if _MSC_VER <= 1700 /* <= MSVC 2012 */ +#define isnan(x) _isnan(x) +#define isinf(x) (!_finite(x)) +#define isfinite(x) _finite(x) +static __inline int signbit(double x) { __int64 i; memcpy(&i, &x, 8); return i>>63; } +#define INFINITY (DBL_MAX+DBL_MAX) +#define NAN (INFINITY-INFINITY) +#endif +#endif + +#define soffsetof(x,y) ((int)offsetof(x,y)) +#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) + +void *js_malloc(js_State *J, int size); +void *js_realloc(js_State *J, void *ptr, int size); +void js_free(js_State *J, void *ptr); + +typedef union js_Value js_Value; +typedef struct js_Regexp js_Regexp; +typedef struct js_Object js_Object; +typedef struct js_String js_String; +typedef struct js_Ast js_Ast; +typedef struct js_Function js_Function; +typedef struct js_Environment js_Environment; +typedef struct js_StringNode js_StringNode; +typedef struct js_Jumpbuf js_Jumpbuf; +typedef struct js_StackTrace js_StackTrace; + +/* Limits */ + +#ifndef JS_STACKSIZE +#define JS_STACKSIZE 4096 /* value stack size */ +#endif +#ifndef JS_ENVLIMIT +#define JS_ENVLIMIT 1024 /* environment stack size */ +#endif +#ifndef JS_TRYLIMIT +#define JS_TRYLIMIT 64 /* exception stack size */ +#endif + +#ifndef JS_ARRAYLIMIT +#define JS_ARRAYLIMIT (1<<26) /* limit arrays to 64M entries (1G of flat array data) */ +#endif + +#ifndef JS_GCFACTOR +/* + * GC will try to trigger when memory usage is this value times the minimum + * needed memory. E.g. if there are 100 remaining objects after GC and this + * value is 5.0, then the next GC will trigger when the overall number is 500. + * I.e. a value of 5.0 aims at 80% garbage, 20% remain-used on each GC. + * The bigger the value the less impact GC has on overall performance, but more + * memory is used and individual GC pauses are longer (but fewer). + */ +#define JS_GCFACTOR 5.0 /* memory overhead factor >= 1.0 */ +#endif + +#ifndef JS_ASTLIMIT +#define JS_ASTLIMIT 400 /* max nested expressions */ +#endif + +#ifndef JS_STRLIMIT +#define JS_STRLIMIT (1<<28) /* max string length */ +#endif + +/* instruction size -- change to int if you get integer overflow syntax errors */ + +#ifdef JS_INSTRUCTION +typedef JS_INSTRUCTION js_Instruction; +#else +typedef unsigned short js_Instruction; +#endif + +/* String interning */ + +char *js_strdup(js_State *J, const char *s); +const char *js_intern(js_State *J, const char *s); +void jsS_dumpstrings(js_State *J); +void jsS_freestrings(js_State *J); + +/* Portable strtod and printf float formatting */ + +void js_fmtexp(char *p, int e); +int js_grisu2(double v, char *buffer, int *K); +double js_strtod(const char *as, char **aas); + +double js_strtol(const char *s, char **ep, int radix); + +/* Private stack functions */ + +void js_newarguments(js_State *J); +void js_newfunction(js_State *J, js_Function *function, js_Environment *scope); +void js_newscript(js_State *J, js_Function *function, js_Environment *scope); +void js_loadeval(js_State *J, const char *filename, const char *source); + +js_Regexp *js_toregexp(js_State *J, int idx); +int js_isarrayindex(js_State *J, const char *str, int *idx); +int js_runeat(js_State *J, const char *s, int i); +int js_utflen(const char *s); +int js_utfptrtoidx(const char *s, const char *p); + +void js_dup(js_State *J); +void js_dup2(js_State *J); +void js_rot2(js_State *J); +void js_rot3(js_State *J); +void js_rot4(js_State *J); +void js_rot2pop1(js_State *J); +void js_rot3pop2(js_State *J); +void js_dup1rot3(js_State *J); +void js_dup1rot4(js_State *J); + +void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text); + +void js_trap(js_State *J, int pc); /* dump stack and environment to stdout */ + +struct js_StackTrace +{ + const char *name; + const char *file; + int line; +}; + +/* Exception handling */ + +struct js_Jumpbuf +{ + jmp_buf buf; + js_Environment *E; + int envtop; + int tracetop; + int top, bot; + int strict; + js_Instruction *pc; +}; + +void *js_savetrypc(js_State *J, js_Instruction *pc); + +#define js_trypc(J, PC) \ + setjmp(js_savetrypc(J, PC)) + +/* String buffer */ + +typedef struct js_Buffer { int n, m; char s[64]; } js_Buffer; + +void js_putc(js_State *J, js_Buffer **sbp, int c); +void js_puts(js_State *J, js_Buffer **sb, const char *s); +void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e); + +/* State struct */ + +struct js_State +{ + void *actx; + void *uctx; + js_Alloc alloc; + js_Report report; + js_Panic panic; + + js_StringNode *strings; + + int default_strict; + int strict; + + /* parser input source */ + const char *filename; + const char *source; + int line; + + /* lexer state */ + struct { char *text; int len, cap; } lexbuf; + int lexline; + int lexchar; + int lasttoken; + int newline; + + /* parser state */ + int astdepth; + int lookahead; + const char *text; + double number; + js_Ast *gcast; /* list of allocated nodes to free after parsing */ + + /* runtime environment */ + js_Object *Object_prototype; + js_Object *Array_prototype; + js_Object *Function_prototype; + js_Object *Boolean_prototype; + js_Object *Number_prototype; + js_Object *String_prototype; + js_Object *RegExp_prototype; + js_Object *Date_prototype; + + js_Object *Error_prototype; + js_Object *EvalError_prototype; + js_Object *RangeError_prototype; + js_Object *ReferenceError_prototype; + js_Object *SyntaxError_prototype; + js_Object *TypeError_prototype; + js_Object *URIError_prototype; + + unsigned int seed; /* Math.random seed */ + + char scratch[12]; /* scratch buffer for iterating over array indices */ + + int nextref; /* for js_ref use */ + js_Object *R; /* registry of hidden values */ + js_Object *G; /* the global object */ + js_Environment *E; /* current environment scope */ + js_Environment *GE; /* global environment scope (at the root) */ + + /* execution stack */ + int top, bot; + js_Value *stack; + + /* garbage collector list */ + int gcmark; + unsigned int gccounter, gcthresh; + js_Environment *gcenv; + js_Function *gcfun; + js_Object *gcobj; + js_String *gcstr; + + js_Object *gcroot; /* gc scan list */ + + /* environments on the call stack but currently not in scope */ + int envtop; + js_Environment *envstack[JS_ENVLIMIT]; + + /* debug info stack trace */ + int tracetop; + js_StackTrace trace[JS_ENVLIMIT]; + + /* exception stack */ + int trytop; + js_Jumpbuf trybuf[JS_TRYLIMIT]; +}; + +/* Values */ + +typedef struct js_Property js_Property; +typedef struct js_Iterator js_Iterator; + +/* Hint to ToPrimitive() */ +enum { + JS_HNONE, + JS_HNUMBER, + JS_HSTRING +}; + +enum js_Type { + JS_TSHRSTR, /* type tag doubles as string zero-terminator */ + JS_TUNDEFINED, + JS_TNULL, + JS_TBOOLEAN, + JS_TNUMBER, + JS_TLITSTR, + JS_TMEMSTR, + JS_TOBJECT, +}; + +enum js_Class { + JS_COBJECT, + JS_CARRAY, + JS_CFUNCTION, + JS_CSCRIPT, /* function created from global/eval code */ + JS_CCFUNCTION, /* built-in function */ + JS_CERROR, + JS_CBOOLEAN, + JS_CNUMBER, + JS_CSTRING, + JS_CREGEXP, + JS_CDATE, + JS_CMATH, + JS_CJSON, + JS_CARGUMENTS, + JS_CITERATOR, + JS_CUSERDATA, +}; + +/* + Short strings abuse the js_Value struct. By putting the type tag in the + last byte, and using 0 as the tag for short strings, we can use the + entire js_Value as string storage by letting the type tag serve double + purpose as the string zero terminator. +*/ + +union js_Value +{ + struct { + char pad[15]; + char type; /* type tag overlaps with final byte of shrstr */ + } t; + union { + char shrstr[16]; + int boolean; + double number; + const char *litstr; + js_String *memstr; + js_Object *object; + } u; +}; + +struct js_String +{ + js_String *gcnext; + char gcmark; + char p[1]; +}; + +struct js_Regexp +{ + void *prog; + char *source; + unsigned short flags; + unsigned short last; +}; + +struct js_Object +{ + enum js_Class type; + int extensible; + js_Property *properties; + int count; /* number of properties, for array sparseness check */ + js_Object *prototype; + union { + int boolean; + double number; + struct { + int length; + char *string; + char shrstr[16]; + } s; + struct { + int length; /* actual length */ + int simple; /* true if array has only non-sparse array properties */ + int flat_length; /* used length of simple array part */ + int flat_capacity; /* allocated length of simple array part */ + js_Value *array; + } a; + struct { + js_Function *function; + js_Environment *scope; + } f; + struct { + const char *name; + js_CFunction function; + js_CFunction constructor; + int length; + void *data; + js_Finalize finalize; + } c; + js_Regexp r; + struct { + js_Object *target; + int i, n; /* for array part */ + js_Iterator *head, *current; /* for object part */ + } iter; + struct { + const char *tag; + void *data; + js_HasProperty has; + js_Put put; + js_Delete delete; + js_Finalize finalize; + } user; + } u; + js_Object *gcnext; /* allocation list */ + js_Object *gcroot; /* scan list */ + int gcmark; +}; + +struct js_Property +{ + js_Property *left, *right; + int level; + int atts; + js_Value value; + js_Object *getter; + js_Object *setter; + char name[1]; +}; + +struct js_Iterator +{ + js_Iterator *next; + char name[1]; +}; + +struct js_Environment +{ + js_Environment *outer; + js_Object *variables; + + js_Environment *gcnext; + int gcmark; +}; + +/* jsrun.c */ +js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer); +js_String *jsV_newmemstring(js_State *J, const char *s, int n); +js_Value *js_tovalue(js_State *J, int idx); +void js_toprimitive(js_State *J, int idx, int hint); +js_Object *js_toobject(js_State *J, int idx); +void js_pushvalue(js_State *J, js_Value v); +void js_pushobject(js_State *J, js_Object *v); +void jsR_unflattenarray(js_State *J, js_Object *obj); + +/* jsvalue.c */ +int jsV_toboolean(js_State *J, js_Value *v); +double jsV_tonumber(js_State *J, js_Value *v); +double jsV_tointeger(js_State *J, js_Value *v); +const char *jsV_tostring(js_State *J, js_Value *v); +js_Object *jsV_toobject(js_State *J, js_Value *v); +void jsV_toprimitive(js_State *J, js_Value *v, int preferred); + +const char *js_itoa(char *buf, int a); +double js_stringtofloat(const char *s, char **ep); +int jsV_numbertointeger(double n); +int jsV_numbertoint32(double n); +unsigned int jsV_numbertouint32(double n); +short jsV_numbertoint16(double n); +unsigned short jsV_numbertouint16(double n); +const char *jsV_numbertostring(js_State *J, char buf[32], double number); +double jsV_stringtonumber(js_State *J, const char *string); + +/* jsproperty.c */ +js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype); +js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name); +js_Property *jsV_getpropertyx(js_State *J, js_Object *obj, const char *name, int *own); +js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name); +js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name); +js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name); +void jsV_delproperty(js_State *J, js_Object *obj, const char *name); + +js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own); +const char *jsV_nextiterator(js_State *J, js_Object *iter); + +void jsV_resizearray(js_State *J, js_Object *obj, int newlen); + +void jsV_unflattenarray(js_State *J, js_Object *obj); +void jsV_growarray(js_State *J, js_Object *obj); + +/* Lexer */ + +enum +{ + TK_IDENTIFIER = 256, + TK_NUMBER, + TK_STRING, + TK_REGEXP, + + /* multi-character punctuators */ + TK_LE, + TK_GE, + TK_EQ, + TK_NE, + TK_STRICTEQ, + TK_STRICTNE, + TK_SHL, + TK_SHR, + TK_USHR, + TK_AND, + TK_OR, + TK_ADD_ASS, + TK_SUB_ASS, + TK_MUL_ASS, + TK_DIV_ASS, + TK_MOD_ASS, + TK_SHL_ASS, + TK_SHR_ASS, + TK_USHR_ASS, + TK_AND_ASS, + TK_OR_ASS, + TK_XOR_ASS, + TK_INC, + TK_DEC, + + /* keywords */ + TK_BREAK, + TK_CASE, + TK_CATCH, + TK_CONTINUE, + TK_DEBUGGER, + TK_DEFAULT, + TK_DELETE, + TK_DO, + TK_ELSE, + TK_FALSE, + TK_FINALLY, + TK_FOR, + TK_FUNCTION, + TK_IF, + TK_IN, + TK_INSTANCEOF, + TK_NEW, + TK_NULL, + TK_RETURN, + TK_SWITCH, + TK_THIS, + TK_THROW, + TK_TRUE, + TK_TRY, + TK_TYPEOF, + TK_VAR, + TK_VOID, + TK_WHILE, + TK_WITH, +}; + +int jsY_iswhite(int c); +int jsY_isnewline(int c); +int jsY_ishex(int c); +int jsY_tohex(int c); + +const char *jsY_tokenstring(int token); +int jsY_findword(const char *s, const char **list, int num); + +void jsY_initlex(js_State *J, const char *filename, const char *source); +int jsY_lex(js_State *J); +int jsY_lexjson(js_State *J); + +/* Parser */ + +enum js_AstType +{ + AST_LIST, + AST_FUNDEC, + AST_IDENTIFIER, + + EXP_IDENTIFIER, + EXP_NUMBER, + EXP_STRING, + EXP_REGEXP, + + /* literals */ + EXP_ELISION, /* for array elisions */ + EXP_NULL, + EXP_TRUE, + EXP_FALSE, + EXP_THIS, + + EXP_ARRAY, + EXP_OBJECT, + EXP_PROP_VAL, + EXP_PROP_GET, + EXP_PROP_SET, + + EXP_FUN, + + /* expressions */ + EXP_INDEX, + EXP_MEMBER, + EXP_CALL, + EXP_NEW, + + EXP_POSTINC, + EXP_POSTDEC, + + EXP_DELETE, + EXP_VOID, + EXP_TYPEOF, + EXP_PREINC, + EXP_PREDEC, + EXP_POS, + EXP_NEG, + EXP_BITNOT, + EXP_LOGNOT, + + EXP_MOD, + EXP_DIV, + EXP_MUL, + EXP_SUB, + EXP_ADD, + EXP_USHR, + EXP_SHR, + EXP_SHL, + EXP_IN, + EXP_INSTANCEOF, + EXP_GE, + EXP_LE, + EXP_GT, + EXP_LT, + EXP_STRICTNE, + EXP_STRICTEQ, + EXP_NE, + EXP_EQ, + EXP_BITAND, + EXP_BITXOR, + EXP_BITOR, + EXP_LOGAND, + EXP_LOGOR, + + EXP_COND, + + EXP_ASS, + EXP_ASS_MUL, + EXP_ASS_DIV, + EXP_ASS_MOD, + EXP_ASS_ADD, + EXP_ASS_SUB, + EXP_ASS_SHL, + EXP_ASS_SHR, + EXP_ASS_USHR, + EXP_ASS_BITAND, + EXP_ASS_BITXOR, + EXP_ASS_BITOR, + + EXP_COMMA, + + EXP_VAR, /* var initializer */ + + /* statements */ + STM_BLOCK, + STM_EMPTY, + STM_VAR, + STM_IF, + STM_DO, + STM_WHILE, + STM_FOR, + STM_FOR_VAR, + STM_FOR_IN, + STM_FOR_IN_VAR, + STM_CONTINUE, + STM_BREAK, + STM_RETURN, + STM_WITH, + STM_SWITCH, + STM_THROW, + STM_TRY, + STM_DEBUGGER, + + STM_LABEL, + STM_CASE, + STM_DEFAULT, +}; + +typedef struct js_JumpList js_JumpList; + +struct js_JumpList +{ + enum js_AstType type; + int inst; + js_JumpList *next; +}; + +struct js_Ast +{ + enum js_AstType type; + int line; + js_Ast *parent, *a, *b, *c, *d; + double number; + const char *string; + js_JumpList *jumps; /* list of break/continue jumps to patch */ + int casejump; /* for switch case clauses */ + js_Ast *gcnext; /* next in alloc list */ +}; + +js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body); +js_Ast *jsP_parse(js_State *J, const char *filename, const char *source); +void jsP_freeparse(js_State *J); + +/* Compiler */ + +enum js_OpCode +{ + OP_POP, /* A -- */ + OP_DUP, /* A -- A A */ + OP_DUP2, /* A B -- A B A B */ + OP_ROT2, /* A B -- B A */ + OP_ROT3, /* A B C -- C A B */ + OP_ROT4, /* A B C D -- D A B C */ + + OP_INTEGER, /* -K- (number-32768) */ + OP_NUMBER, /* -N- */ + OP_STRING, /* -S- */ + OP_CLOSURE, /* -F- */ + + OP_NEWARRAY, + OP_NEWOBJECT, + OP_NEWREGEXP, /* -S,opts- */ + + OP_UNDEF, + OP_NULL, + OP_TRUE, + OP_FALSE, + + OP_THIS, + OP_CURRENT, /* currently executing function object */ + + OP_GETLOCAL, /* -K- */ + OP_SETLOCAL, /* -K- */ + OP_DELLOCAL, /* -K- false */ + + OP_HASVAR, /* -S- ( | undefined ) */ + OP_GETVAR, /* -S- */ + OP_SETVAR, /* -S- */ + OP_DELVAR, /* -S- */ + + OP_IN, /* -- */ + + OP_SKIPARRAY, /* -- */ + OP_INITARRAY, /* -- */ + OP_INITPROP, /* -- */ + OP_INITGETTER, /* -- */ + OP_INITSETTER, /* -- */ + + OP_GETPROP, /* -- */ + OP_GETPROP_S, /* -S- */ + OP_SETPROP, /* -- */ + OP_SETPROP_S, /* -S- */ + OP_DELPROP, /* -- */ + OP_DELPROP_S, /* -S- */ + + OP_ITERATOR, /* -- */ + OP_NEXTITER, /* -- ( true | false ) */ + + OP_EVAL, /* -(numargs)- */ + OP_CALL, /* -(numargs)- */ + OP_NEW, /* -(numargs)- */ + + OP_TYPEOF, + OP_POS, + OP_NEG, + OP_BITNOT, + OP_LOGNOT, + OP_INC, /* -- ToNumber(x)+1 */ + OP_DEC, /* -- ToNumber(x)-1 */ + OP_POSTINC, /* -- ToNumber(x)+1 ToNumber(x) */ + OP_POSTDEC, /* -- ToNumber(x)-1 ToNumber(x) */ + + OP_MUL, + OP_DIV, + OP_MOD, + OP_ADD, + OP_SUB, + OP_SHL, + OP_SHR, + OP_USHR, + OP_LT, + OP_GT, + OP_LE, + OP_GE, + OP_EQ, + OP_NE, + OP_STRICTEQ, + OP_STRICTNE, + OP_JCASE, + OP_BITAND, + OP_BITXOR, + OP_BITOR, + + OP_INSTANCEOF, + + OP_THROW, + + OP_TRY, /* -ADDR- /jump/ or -ADDR- */ + OP_ENDTRY, + + OP_CATCH, /* push scope chain with exception variable */ + OP_ENDCATCH, + + OP_WITH, + OP_ENDWITH, + + OP_DEBUGGER, + OP_JUMP, + OP_JTRUE, + OP_JFALSE, + OP_RETURN, +}; + +struct js_Function +{ + const char *name; + int script; + int lightweight; + int strict; + int arguments; + int numparams; + + js_Instruction *code; + int codecap, codelen; + + js_Function **funtab; + int funcap, funlen; + + const char **vartab; + int varcap, varlen; + + const char *filename; + int line, lastline; + + js_Function *gcnext; + int gcmark; +}; + +js_Function *jsC_compilefunction(js_State *J, js_Ast *prog); +js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict); + +/* Builtins */ + +void jsB_init(js_State *J); +void jsB_initobject(js_State *J); +void jsB_initarray(js_State *J); +void jsB_initfunction(js_State *J); +void jsB_initboolean(js_State *J); +void jsB_initnumber(js_State *J); +void jsB_initstring(js_State *J); +void jsB_initregexp(js_State *J); +void jsB_initerror(js_State *J); +void jsB_initmath(js_State *J); +void jsB_initjson(js_State *J); +void jsB_initdate(js_State *J); + +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); +void jsB_propn(js_State *J, const char *name, double number); +void jsB_props(js_State *J, const char *name, const char *string); + +#endif diff --git a/src/mujs/jsintern.c b/src/mujs/jsintern.c new file mode 100644 index 0000000..42e6984 --- /dev/null +++ b/src/mujs/jsintern.c @@ -0,0 +1,137 @@ +#include "jsi.h" + +/* Dynamically grown string buffer */ + +void js_putc(js_State *J, js_Buffer **sbp, int c) +{ + js_Buffer *sb = *sbp; + if (!sb) { + sb = js_malloc(J, sizeof *sb); + sb->n = 0; + sb->m = sizeof sb->s; + *sbp = sb; + } else if (sb->n == sb->m) { + sb = js_realloc(J, sb, (sb->m *= 2) + soffsetof(js_Buffer, s)); + *sbp = sb; + } + sb->s[sb->n++] = c; +} + +void js_puts(js_State *J, js_Buffer **sb, const char *s) +{ + while (*s) + js_putc(J, sb, *s++); +} + +void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e) +{ + while (s < e) + js_putc(J, sb, *s++); +} + +/* Use an AA-tree to quickly look up interned strings. */ + +struct js_StringNode +{ + js_StringNode *left, *right; + int level; + char string[1]; +}; + +static js_StringNode jsS_sentinel = { &jsS_sentinel, &jsS_sentinel, 0, ""}; + +static js_StringNode *jsS_newstringnode(js_State *J, const char *string, const char **result) +{ + size_t n = strlen(string); + if (n > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + js_StringNode *node = js_malloc(J, soffsetof(js_StringNode, string) + n + 1); + node->left = node->right = &jsS_sentinel; + node->level = 1; + memcpy(node->string, string, n + 1); + return *result = node->string, node; +} + +static js_StringNode *jsS_skew(js_StringNode *node) +{ + if (node->left->level == node->level) { + js_StringNode *temp = node; + node = node->left; + temp->left = node->right; + node->right = temp; + } + return node; +} + +static js_StringNode *jsS_split(js_StringNode *node) +{ + if (node->right->right->level == node->level) { + js_StringNode *temp = node; + node = node->right; + temp->right = node->left; + node->left = temp; + ++node->level; + } + return node; +} + +static js_StringNode *jsS_insert(js_State *J, js_StringNode *node, const char *string, const char **result) +{ + if (node != &jsS_sentinel) { + int c = strcmp(string, node->string); + if (c < 0) + node->left = jsS_insert(J, node->left, string, result); + else if (c > 0) + node->right = jsS_insert(J, node->right, string, result); + else + return *result = node->string, node; + node = jsS_skew(node); + node = jsS_split(node); + return node; + } + return jsS_newstringnode(J, string, result); +} + +static void dumpstringnode(js_StringNode *node, int level) +{ + int i; + if (node->left != &jsS_sentinel) + dumpstringnode(node->left, level + 1); + printf("%d: ", node->level); + for (i = 0; i < level; ++i) + putchar('\t'); + printf("'%s'\n", node->string); + if (node->right != &jsS_sentinel) + dumpstringnode(node->right, level + 1); +} + +void jsS_dumpstrings(js_State *J) +{ + js_StringNode *root = J->strings; + printf("interned strings {\n"); + if (root && root != &jsS_sentinel) + dumpstringnode(root, 1); + printf("}\n"); +} + +static void jsS_freestringnode(js_State *J, js_StringNode *node) +{ + if (node->left != &jsS_sentinel) jsS_freestringnode(J, node->left); + if (node->right != &jsS_sentinel) jsS_freestringnode(J, node->right); + js_free(J, node); +} + +void jsS_freestrings(js_State *J) +{ + if (J->strings && J->strings != &jsS_sentinel) + jsS_freestringnode(J, J->strings); +} + +const char *js_intern(js_State *J, const char *s) +{ + const char *result; + if (!J->strings) + J->strings = &jsS_sentinel; + J->strings = jsS_insert(J, J->strings, s, &result); + return result; +} diff --git a/src/mujs/jslex.c b/src/mujs/jslex.c new file mode 100644 index 0000000..8fd9ab6 --- /dev/null +++ b/src/mujs/jslex.c @@ -0,0 +1,878 @@ +#include "jsi.h" +#include "utf.h" + +JS_NORETURN static void jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +static void jsY_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + npf_vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + npf_snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static const char *tokenstring[] = { + "(end-of-file)", + "'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'", + "'\\x08'", "'\\x09'", "'\\x0A'", "'\\x0B'", "'\\x0C'", "'\\x0D'", "'\\x0E'", "'\\x0F'", + "'\\x10'", "'\\x11'", "'\\x12'", "'\\x13'", "'\\x14'", "'\\x15'", "'\\x16'", "'\\x17'", + "'\\x18'", "'\\x19'", "'\\x1A'", "'\\x1B'", "'\\x1C'", "'\\x1D'", "'\\x1E'", "'\\x1F'", + "' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'\\''", + "'('", "')'", "'*'", "'+'", "','", "'-'", "'.'", "'/'", + "'0'", "'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'", + "'8'", "'9'", "':'", "';'", "'<'", "'='", "'>'", "'?'", + "'@'", "'A'", "'B'", "'C'", "'D'", "'E'", "'F'", "'G'", + "'H'", "'I'", "'J'", "'K'", "'L'", "'M'", "'N'", "'O'", + "'P'", "'Q'", "'R'", "'S'", "'T'", "'U'", "'V'", "'W'", + "'X'", "'Y'", "'Z'", "'['", "'\'", "']'", "'^'", "'_'", + "'`'", "'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'", + "'h'", "'i'", "'j'", "'k'", "'l'", "'m'", "'n'", "'o'", + "'p'", "'q'", "'r'", "'s'", "'t'", "'u'", "'v'", "'w'", + "'x'", "'y'", "'z'", "'{'", "'|'", "'}'", "'~'", "'\\x7F'", + + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + + "(identifier)", "(number)", "(string)", "(regexp)", + + "'<='", "'>='", "'=='", "'!='", "'==='", "'!=='", + "'<<'", "'>>'", "'>>>'", "'&&'", "'||'", + "'+='", "'-='", "'*='", "'/='", "'%='", + "'<<='", "'>>='", "'>>>='", "'&='", "'|='", "'^='", + "'++'", "'--'", + + "'break'", "'case'", "'catch'", "'continue'", "'debugger'", + "'default'", "'delete'", "'do'", "'else'", "'false'", "'finally'", "'for'", + "'function'", "'if'", "'in'", "'instanceof'", "'new'", "'null'", "'return'", + "'switch'", "'this'", "'throw'", "'true'", "'try'", "'typeof'", "'var'", + "'void'", "'while'", "'with'", +}; + +const char *jsY_tokenstring(int token) +{ + if (token >= 0 && token < (int)nelem(tokenstring)) + if (tokenstring[token]) + return tokenstring[token]; + return ""; +} + +static const char *keywords[] = { + "break", "case", "catch", "continue", "debugger", "default", "delete", + "do", "else", "false", "finally", "for", "function", "if", "in", + "instanceof", "new", "null", "return", "switch", "this", "throw", + "true", "try", "typeof", "var", "void", "while", "with", +}; + +int jsY_findword(const char *s, const char **list, int num) +{ + int l = 0; + int r = num - 1; + while (l <= r) { + int m = (l + r) >> 1; + int c = strcmp(s, list[m]); + if (c < 0) + r = m - 1; + else if (c > 0) + l = m + 1; + else + return m; + } + return -1; +} + +static int jsY_findkeyword(js_State *J, const char *s) +{ + int i = jsY_findword(s, keywords, nelem(keywords)); + if (i >= 0) { + J->text = keywords[i]; + return TK_BREAK + i; /* first keyword + i */ + } + J->text = js_intern(J, s); + return TK_IDENTIFIER; +} + +int jsY_iswhite(int c) +{ + return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF; +} + +int jsY_isnewline(int c) +{ + return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +#ifndef isalpha +#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +#endif +#ifndef isdigit +#define isdigit(c) (c >= '0' && c <= '9') +#endif +#ifndef ishex +#define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) +#endif + +static int jsY_isidentifierstart(int c) +{ + return isalpha(c) || c == '$' || c == '_' || isalpharune(c); +} + +static int jsY_isidentifierpart(int c) +{ + return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c); +} + +static int jsY_isdec(int c) +{ + return isdigit(c); +} + +int jsY_ishex(int c) +{ + return isdigit(c) || ishex(c); +} + +int jsY_tohex(int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + return 0; +} + +static void jsY_next(js_State *J) +{ + Rune c; + if (*J->source == 0) { + J->lexchar = EOF; + return; + } + J->source += chartorune(&c, J->source); + /* consume CR LF as one unit */ + if (c == '\r' && *J->source == '\n') + ++J->source; + if (jsY_isnewline(c)) { + J->line++; + c = '\n'; + } + J->lexchar = c; +} + +#define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0) + +#define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x) + +static void jsY_unescape(js_State *J) +{ + if (jsY_accept(J, '\\')) { + if (jsY_accept(J, 'u')) { + int x = 0; + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar); + J->lexchar = x; + return; + } +error: + jsY_error(J, "unexpected escape sequence"); + } +} + +static void textinit(js_State *J) +{ + if (!J->lexbuf.text) { + J->lexbuf.cap = 4096; + J->lexbuf.text = js_malloc(J, J->lexbuf.cap); + } + J->lexbuf.len = 0; +} + +static void textpush(js_State *J, Rune c) +{ + int n; + if (c == EOF) + n = 1; + else + n = runelen(c); + if (J->lexbuf.len + n > J->lexbuf.cap) { + J->lexbuf.cap = J->lexbuf.cap * 2; + J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap); + } + if (c == EOF) + J->lexbuf.text[J->lexbuf.len++] = 0; + else + J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c); +} + +static char *textend(js_State *J) +{ + textpush(J, EOF); + return J->lexbuf.text; +} + +static void lexlinecomment(js_State *J) +{ + while (J->lexchar != EOF && J->lexchar != '\n') + jsY_next(J); +} + +static int lexcomment(js_State *J) +{ + /* already consumed initial '/' '*' sequence */ + while (J->lexchar != EOF) { + if (jsY_accept(J, '*')) { + while (J->lexchar == '*') + jsY_next(J); + if (jsY_accept(J, '/')) + return 0; + } + else + jsY_next(J); + } + return -1; +} + +static double lexhex(js_State *J) +{ + double n = 0; + if (!jsY_ishex(J->lexchar)) + jsY_error(J, "malformed hexadecimal number"); + while (jsY_ishex(J->lexchar)) { + n = n * 16 + jsY_tohex(J->lexchar); + jsY_next(J); + } + return n; +} + +#if 0 + +static double lexinteger(js_State *J) +{ + double n = 0; + if (!jsY_isdec(J->lexchar)) + jsY_error(J, "malformed number"); + while (jsY_isdec(J->lexchar)) { + n = n * 10 + (J->lexchar - '0'); + jsY_next(J); + } + return n; +} + +static double lexfraction(js_State *J) +{ + double n = 0; + double d = 1; + while (jsY_isdec(J->lexchar)) { + n = n * 10 + (J->lexchar - '0'); + d = d * 10; + jsY_next(J); + } + return n / d; +} + +static double lexexponent(js_State *J) +{ + double sign; + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (jsY_accept(J, '-')) sign = -1; + else if (jsY_accept(J, '+')) sign = 1; + else sign = 1; + return sign * lexinteger(J); + } + return 0; +} + +static int lexnumber(js_State *J) +{ + double n; + double e; + + if (jsY_accept(J, '0')) { + if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) { + J->number = lexhex(J); + return TK_NUMBER; + } + if (jsY_isdec(J->lexchar)) + jsY_error(J, "number with leading zero"); + n = 0; + if (jsY_accept(J, '.')) + n += lexfraction(J); + } else if (jsY_accept(J, '.')) { + if (!jsY_isdec(J->lexchar)) + return '.'; + n = lexfraction(J); + } else { + n = lexinteger(J); + if (jsY_accept(J, '.')) + n += lexfraction(J); + } + + e = lexexponent(J); + if (e < 0) + n /= pow(10, -e); + else if (e > 0) + n *= pow(10, e); + + if (jsY_isidentifierstart(J->lexchar)) + jsY_error(J, "number with letter suffix"); + + J->number = n; + return TK_NUMBER; +} + +#else + +static int lexnumber(js_State *J) +{ + const char *s = J->source - 1; + + if (jsY_accept(J, '0')) { + if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) { + J->number = lexhex(J); + return TK_NUMBER; + } + if (jsY_isdec(J->lexchar)) + jsY_error(J, "number with leading zero"); + if (jsY_accept(J, '.')) { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } + } else if (jsY_accept(J, '.')) { + if (!jsY_isdec(J->lexchar)) + return '.'; + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } else { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + if (jsY_accept(J, '.')) { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } + } + + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (J->lexchar == '-' || J->lexchar == '+') + jsY_next(J); + if (jsY_isdec(J->lexchar)) + while (jsY_isdec(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing exponent"); + } + + if (jsY_isidentifierstart(J->lexchar)) + jsY_error(J, "number with letter suffix"); + + J->number = js_strtod(s, NULL); + return TK_NUMBER; +} + +#endif + +static int lexescape(js_State *J) +{ + int x = 0; + + /* already consumed '\' */ + + if (jsY_accept(J, '\n')) + return 0; + + switch (J->lexchar) { + case EOF: jsY_error(J, "unterminated escape sequence"); + case 'u': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case 'x': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case '0': textpush(J, 0); jsY_next(J); break; + case '\\': textpush(J, '\\'); jsY_next(J); break; + case '\'': textpush(J, '\''); jsY_next(J); break; + case '"': textpush(J, '"'); jsY_next(J); break; + case 'b': textpush(J, '\b'); jsY_next(J); break; + case 'f': textpush(J, '\f'); jsY_next(J); break; + case 'n': textpush(J, '\n'); jsY_next(J); break; + case 'r': textpush(J, '\r'); jsY_next(J); break; + case 't': textpush(J, '\t'); jsY_next(J); break; + case 'v': textpush(J, '\v'); jsY_next(J); break; + default: textpush(J, J->lexchar); jsY_next(J); break; + } + return 0; +} + +static int lexstring(js_State *J) +{ + const char *s; + + int q = J->lexchar; + jsY_next(J); + + textinit(J); + + while (J->lexchar != q) { + if (J->lexchar == EOF || J->lexchar == '\n') + jsY_error(J, "string not terminated"); + if (jsY_accept(J, '\\')) { + if (lexescape(J)) + jsY_error(J, "malformed escape sequence"); + } else { + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, q); + + s = textend(J); + + J->text = js_intern(J, s); + return TK_STRING; +} + +/* the ugliest language wart ever... */ +static int isregexpcontext(int last) +{ + switch (last) { + case ']': + case ')': + case '}': + case TK_IDENTIFIER: + case TK_NUMBER: + case TK_STRING: + case TK_FALSE: + case TK_NULL: + case TK_THIS: + case TK_TRUE: + return 0; + default: + return 1; + } +} + +static int lexregexp(js_State *J) +{ + const char *s; + int g, m, i; + int inclass = 0; + + /* already consumed initial '/' */ + + textinit(J); + + /* regexp body */ + while (J->lexchar != '/' || inclass) { + if (J->lexchar == EOF || J->lexchar == '\n') { + jsY_error(J, "regular expression not terminated"); + } else if (jsY_accept(J, '\\')) { + if (jsY_accept(J, '/')) { + textpush(J, '/'); + } else { + textpush(J, '\\'); + if (J->lexchar == EOF || J->lexchar == '\n') + jsY_error(J, "regular expression not terminated"); + textpush(J, J->lexchar); + jsY_next(J); + } + } else { + if (J->lexchar == '[' && !inclass) + inclass = 1; + if (J->lexchar == ']' && inclass) + inclass = 0; + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, '/'); + + s = textend(J); + + /* regexp flags */ + g = i = m = 0; + + while (jsY_isidentifierpart(J->lexchar)) { + if (jsY_accept(J, 'g')) ++g; + else if (jsY_accept(J, 'i')) ++i; + else if (jsY_accept(J, 'm')) ++m; + else jsY_error(J, "illegal flag in regular expression: %c", J->lexchar); + } + + if (g > 1 || i > 1 || m > 1) + jsY_error(J, "duplicated flag in regular expression"); + + J->text = js_intern(J, s); + J->number = 0; + if (g) J->number += JS_REGEXP_G; + if (i) J->number += JS_REGEXP_I; + if (m) J->number += JS_REGEXP_M; + return TK_REGEXP; +} + +/* simple "return [no Line Terminator here] ..." contexts */ +static int isnlthcontext(int last) +{ + switch (last) { + case TK_BREAK: + case TK_CONTINUE: + case TK_RETURN: + case TK_THROW: + return 1; + default: + return 0; + } +} + +static int jsY_lexx(js_State *J) +{ + J->newline = 0; + + while (1) { + J->lexline = J->line; /* save location of beginning of token */ + + while (jsY_iswhite(J->lexchar)) + jsY_next(J); + + if (jsY_accept(J, '\n')) { + J->newline = 1; + if (isnlthcontext(J->lasttoken)) + return ';'; + continue; + } + + if (jsY_accept(J, '/')) { + if (jsY_accept(J, '/')) { + lexlinecomment(J); + continue; + } else if (jsY_accept(J, '*')) { + if (lexcomment(J)) + jsY_error(J, "multi-line comment not terminated"); + continue; + } else if (isregexpcontext(J->lasttoken)) { + return lexregexp(J); + } else if (jsY_accept(J, '=')) { + return TK_DIV_ASS; + } else { + return '/'; + } + } + + if (J->lexchar >= '0' && J->lexchar <= '9') { + return lexnumber(J); + } + + switch (J->lexchar) { + case '(': jsY_next(J); return '('; + case ')': jsY_next(J); return ')'; + case ',': jsY_next(J); return ','; + case ':': jsY_next(J); return ':'; + case ';': jsY_next(J); return ';'; + case '?': jsY_next(J); return '?'; + case '[': jsY_next(J); return '['; + case ']': jsY_next(J); return ']'; + case '{': jsY_next(J); return '{'; + case '}': jsY_next(J); return '}'; + case '~': jsY_next(J); return '~'; + + case '\'': + case '"': + return lexstring(J); + + case '.': + return lexnumber(J); + + case '<': + jsY_next(J); + if (jsY_accept(J, '<')) { + if (jsY_accept(J, '=')) + return TK_SHL_ASS; + return TK_SHL; + } + if (jsY_accept(J, '=')) + return TK_LE; + return '<'; + + case '>': + jsY_next(J); + if (jsY_accept(J, '>')) { + if (jsY_accept(J, '>')) { + if (jsY_accept(J, '=')) + return TK_USHR_ASS; + return TK_USHR; + } + if (jsY_accept(J, '=')) + return TK_SHR_ASS; + return TK_SHR; + } + if (jsY_accept(J, '=')) + return TK_GE; + return '>'; + + case '=': + jsY_next(J); + if (jsY_accept(J, '=')) { + if (jsY_accept(J, '=')) + return TK_STRICTEQ; + return TK_EQ; + } + return '='; + + case '!': + jsY_next(J); + if (jsY_accept(J, '=')) { + if (jsY_accept(J, '=')) + return TK_STRICTNE; + return TK_NE; + } + return '!'; + + case '+': + jsY_next(J); + if (jsY_accept(J, '+')) + return TK_INC; + if (jsY_accept(J, '=')) + return TK_ADD_ASS; + return '+'; + + case '-': + jsY_next(J); + if (jsY_accept(J, '-')) + return TK_DEC; + if (jsY_accept(J, '=')) + return TK_SUB_ASS; + return '-'; + + case '*': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_MUL_ASS; + return '*'; + + case '%': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_MOD_ASS; + return '%'; + + case '&': + jsY_next(J); + if (jsY_accept(J, '&')) + return TK_AND; + if (jsY_accept(J, '=')) + return TK_AND_ASS; + return '&'; + + case '|': + jsY_next(J); + if (jsY_accept(J, '|')) + return TK_OR; + if (jsY_accept(J, '=')) + return TK_OR_ASS; + return '|'; + + case '^': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_XOR_ASS; + return '^'; + + case EOF: + return 0; /* EOF */ + } + + /* Handle \uXXXX escapes in identifiers */ + jsY_unescape(J); + if (jsY_isidentifierstart(J->lexchar)) { + textinit(J); + textpush(J, J->lexchar); + + jsY_next(J); + jsY_unescape(J); + while (jsY_isidentifierpart(J->lexchar)) { + textpush(J, J->lexchar); + jsY_next(J); + jsY_unescape(J); + } + + textend(J); + + return jsY_findkeyword(J, J->lexbuf.text); + } + + if (J->lexchar >= 0x20 && J->lexchar <= 0x7E) + jsY_error(J, "unexpected character: '%c'", J->lexchar); + jsY_error(J, "unexpected character: \\u%04X", J->lexchar); + } +} + +void jsY_initlex(js_State *J, const char *filename, const char *source) +{ + J->filename = filename; + J->source = source; + J->line = 1; + J->lasttoken = 0; + jsY_next(J); /* load first lookahead character */ +} + +int jsY_lex(js_State *J) +{ + return J->lasttoken = jsY_lexx(J); +} + +static int lexjsonnumber(js_State *J) +{ + const char *s = J->source - 1; + + if (J->lexchar == '-') + jsY_next(J); + + if (J->lexchar == '0') + jsY_next(J); + else if (J->lexchar >= '1' && J->lexchar <= '9') + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "unexpected non-digit"); + + if (jsY_accept(J, '.')) { + if (isdigit(J->lexchar)) + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing digits after decimal point"); + } + + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (J->lexchar == '-' || J->lexchar == '+') + jsY_next(J); + if (isdigit(J->lexchar)) + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing digits after exponent indicator"); + } + + J->number = js_strtod(s, NULL); + return TK_NUMBER; +} + +static int lexjsonescape(js_State *J) +{ + int x = 0; + + /* already consumed '\' */ + + switch (J->lexchar) { + default: jsY_error(J, "invalid escape sequence"); + case 'u': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case '"': textpush(J, '"'); jsY_next(J); break; + case '\\': textpush(J, '\\'); jsY_next(J); break; + case '/': textpush(J, '/'); jsY_next(J); break; + case 'b': textpush(J, '\b'); jsY_next(J); break; + case 'f': textpush(J, '\f'); jsY_next(J); break; + case 'n': textpush(J, '\n'); jsY_next(J); break; + case 'r': textpush(J, '\r'); jsY_next(J); break; + case 't': textpush(J, '\t'); jsY_next(J); break; + } + return 0; +} + +static int lexjsonstring(js_State *J) +{ + const char *s; + + textinit(J); + + while (J->lexchar != '"') { + if (J->lexchar == EOF) + jsY_error(J, "unterminated string"); + else if (J->lexchar < 32) + jsY_error(J, "invalid control character in string"); + else if (jsY_accept(J, '\\')) + lexjsonescape(J); + else { + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, '"'); + + s = textend(J); + + J->text = js_intern(J, s); + return TK_STRING; +} + +int jsY_lexjson(js_State *J) +{ + while (1) { + J->lexline = J->line; /* save location of beginning of token */ + + while (jsY_iswhite(J->lexchar) || J->lexchar == '\n') + jsY_next(J); + + if ((J->lexchar >= '0' && J->lexchar <= '9') || J->lexchar == '-') + return lexjsonnumber(J); + + switch (J->lexchar) { + case ',': jsY_next(J); return ','; + case ':': jsY_next(J); return ':'; + case '[': jsY_next(J); return '['; + case ']': jsY_next(J); return ']'; + case '{': jsY_next(J); return '{'; + case '}': jsY_next(J); return '}'; + + case '"': + jsY_next(J); + return lexjsonstring(J); + + case 'f': + jsY_next(J); jsY_expect(J, 'a'); jsY_expect(J, 'l'); jsY_expect(J, 's'); jsY_expect(J, 'e'); + return TK_FALSE; + + case 'n': + jsY_next(J); jsY_expect(J, 'u'); jsY_expect(J, 'l'); jsY_expect(J, 'l'); + return TK_NULL; + + case 't': + jsY_next(J); jsY_expect(J, 'r'); jsY_expect(J, 'u'); jsY_expect(J, 'e'); + return TK_TRUE; + + case EOF: + return 0; /* EOF */ + } + + if (J->lexchar >= 0x20 && J->lexchar <= 0x7E) + jsY_error(J, "unexpected character: '%c'", J->lexchar); + jsY_error(J, "unexpected character: \\u%04X", J->lexchar); + } +} diff --git a/src/mujs/jslibtemple.c b/src/mujs/jslibtemple.c new file mode 100644 index 0000000..6448e96 --- /dev/null +++ b/src/mujs/jslibtemple.c @@ -0,0 +1,280 @@ +#include +#include + +#include "../libtemple/os.h" + +#define value_or_number(v, x) js_isundefined(J, x) ? v : js_tonumber(J, x) +#define null_or_number(x) value_or_number(0, x) + +/** DC **/ + +// public CDC *DCAlias(CDC *dc=NULL,CTask *task=NULL) +void DC_alias(js_State *J) +{ + long dc = null_or_number(1); + long task = null_or_number(2); + js_pushnumber(J, os_call_ext_str_2("DCAlias", dc, task)); +} + +// public U0 DCClear(CDC *dc=NULL) +void DC_clear(js_State *J) +{ + long dc = null_or_number(1); + os_call_ext_str_1("DCClear", dc); + js_pushundefined(J); +} + +// public CDC *DCCopy(CDC *dc,CTask *task=NULL) +void DC_copy(js_State *J) +{ + long dc = null_or_number(1); + long task = null_or_number(2); + js_pushnumber(J, os_call_ext_str_2("DCCopy", dc, task)); +} + +// public U0 DCDel(CDC *dc) +void DC_delete(js_State *J) +{ + if (!js_isundefined(J, 1)) { + os_call_ext_str_1("DCDel", js_tonumber(J, 1)); + } + js_pushundefined(J); +} + +// public U0 DCFill(CDC *dc=NULL,CColorROPU32 val=TRANSPARENT) +void DC_fill(js_State *J) +{ + long dc = null_or_number(1); + long color = value_or_number(255, 2); + os_call_ext_str_2("DCFill", dc, color); + js_pushundefined(J); +} + +// public CDC *DCNew(I64 width,I64 height,CTask *task=NULL,Bool null_bitmap=FALSE) +void DC_new(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2)) { + js_pushundefined(J); + return; + } + long width = js_tonumber(J, 1); + long height = js_tonumber(J, 2); + long task = null_or_number(3); + long null_bitmap = null_or_number(4); + js_pushnumber(J, os_call_ext_str_4("DCNew", width, height, task, null_bitmap)); +} + +// public I64 DCColorChg(CDC *dc,I64 src_color,I64 dst_color=TRANSPARENT) +void DC_replace_color(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2)) { + js_pushundefined(J); + return; + } + long dc = js_tonumber(J, 1); + long src_color = js_tonumber(J, 2); + long dst_color = value_or_number(255, 3); + js_pushnumber(J, os_call_ext_str_3("DCColorChg", dc, src_color, dst_color)); +} + +// DC.set_color(dc, color) +void DC_set_color(js_State *J) +{ + if (!js_isundefined(J, 1) && !js_isundefined(J, 2)) { + long dc = js_tonumber(J, 1); + long color = js_tonumber(J, 2); + memset((void*)(dc + 0xa0), color, 1); // offset(CDC.color) == 0xa0 + } + js_pushundefined(J); +} + +void jsLT_initdc(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, -1, J->Object_prototype)); + { + jsB_propf(J, "DC.alias", DC_alias, 1); + jsB_propf(J, "DC.clear", DC_clear, 1); + jsB_propf(J, "DC.copy", DC_copy, 4); + jsB_propf(J, "DC.delete", DC_delete, 1); + jsB_propf(J, "DC.fill", DC_fill, 2); + jsB_propf(J, "DC.new", DC_new, 2); + jsB_propf(J, "DC.replace_color", DC_replace_color, 3); + jsB_propf(J, "DC.set_color", DC_set_color, 2); + } + js_defglobal(J, "DC", JS_DONTENUM); +} + +/** Gr **/ + +// public I64 GrBlot(CDC *dc=gr.dc,I64 x,I64 y,CDC *img) +void Gr_blot(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2) || js_isundefined(J, 3) || js_isundefined(J, 4)) { + js_pushundefined(J); + return; + } + long dc = js_tonumber(J, 1); + long x = js_tonumber(J, 2); + long y = js_tonumber(J, 3); + long img = js_tonumber(J, 4); + js_pushnumber(J, os_call_ext_str_4("GrBlot", dc, x, y, img)); +} + +// public I64 GrPeek(CDC *dc=gr.dc,I64 x,I64 y) +void Gr_peek(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2) || js_isundefined(J, 3)) { + js_pushundefined(J); + return; + } + long dc = js_tonumber(J, 1); + long x = js_tonumber(J, 2); + long y = js_tonumber(J, 3); + js_pushnumber(J, os_call_ext_str_3("GrPeek", dc, x, y)); +} + +// public Bool GrPlot(CDC *dc=gr.dc,I64 x,I64 y) +void Gr_plot(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2) || js_isundefined(J, 3)) { + js_pushundefined(J); + return; + } + long dc = js_tonumber(J, 1); + long x = js_tonumber(J, 2); + long y = js_tonumber(J, 3); + js_pushboolean(J, os_call_ext_str_3("GrPlot", dc, x, y)); +} + +void jsLT_initgr(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, -1, J->Object_prototype)); + { + jsB_propf(J, "Gr.blot", Gr_blot, 4); + jsB_propf(J, "Gr.peek", Gr_peek, 3); + jsB_propf(J, "Gr.plot", Gr_plot, 3); + } + js_defglobal(J, "Gr", JS_DONTENUM); +} + +/** OS **/ + +// U0 Beep(I8 ona=62,Bool busy=FALSE) +void OS_beep(js_State *J) +{ + long ona = value_or_number(62, 1); + long busy = null_or_number(2); + os_call_ext_str_2("Beep", ona, busy); + js_pushundefined(J); +} + +// _extern _MALLOC U8 *MAlloc(I64 size,CTask *mem_task=NULL); +void OS_malloc(js_State *J) +{ + if (js_isundefined(J, 1)) { + js_pushundefined(J); + return; + } + long size = js_tonumber(J, 1); + long mem_task = null_or_number(2); + js_pushnumber(J, os_call_ext_str_2("MAlloc", size, mem_task)); +} + +// U8 *CAlloc(I64 size,CTask *mem_task=NULL) +void OS_calloc(js_State *J) +{ + if (js_isundefined(J, 1)) { + js_pushundefined(J); + return; + } + long size = js_tonumber(J, 1); + long mem_task = null_or_number(2); + js_pushnumber(J, os_call_ext_str_2("CAlloc", size, mem_task)); +} + +// _extern _FREE U0 Free(U8 *addr); //Free MAlloc()ed memory chunk. +void OS_free(js_State *J) +{ + if (!js_isundefined(J, 1)) { + long addr = js_tonumber(J, 1); + os_call_ext_str_1("Free", addr); + } + js_pushundefined(J); +} + +void OS_jiffies(js_State *J) +{ + js_pushnumber(J, os_jiffies()); +} + +void OS_read_file_as_string(js_State *J) +{ + if (js_isundefined(J, 1)) { + js_pushundefined(J); + return; + } + const char* filename = js_tostring(J, 1); + long file_as_string = os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0); + js_pushstring(J, file_as_string ? (char*)file_as_string : ""); +} + +// U0 Reboot() +void OS_reboot(js_State *J) +{ + os_call_ext_str("Reboot"); +} + +// U0 Sleep(I64 mS) +void OS_sleep(js_State *J) +{ + if (!js_isundefined(J, 1)) { + long ms = js_tonumber(J, 1); + os_call_ext_str_1("Sleep", ms); + } + js_pushundefined(J); +} + +// U0 Snd(I8 ona=0) +void OS_snd(js_State *J) +{ + long ona = null_or_number(1); + os_call_ext_str_1("Snd", ona); + js_pushundefined(J); +} + +void OS_write_file_as_string(js_State *J) +{ + if (js_isundefined(J, 1) || js_isundefined(J, 2)) { + js_pushundefined(J); + return; + } + const char* filename = js_tostring(J, 1); + const char* string = js_tostring(J, 2); + long length = strlen(string); + js_pushnumber(J, os_call_ext_str_5("FileWrite", (uint64_t)filename, (uint64_t)string, length, 0, 0)); +} + +void jsLT_initos(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, -1, J->Object_prototype)); + { + jsB_propf(J, "OS.beep", OS_beep, 2); + jsB_propf(J, "OS.malloc", OS_malloc, 2); + jsB_propf(J, "OS.calloc", OS_calloc, 2); + jsB_propf(J, "OS.free", OS_free, 1); + jsB_propf(J, "OS.jiffies", OS_jiffies, 0); + jsB_propf(J, "OS.read_file_as_string", OS_read_file_as_string, 1); + jsB_propf(J, "OS.write_file_as_string", OS_write_file_as_string, 2); + jsB_propf(J, "OS.reboot", OS_reboot, 0); + jsB_propf(J, "OS.sleep", OS_sleep, 1); + jsB_propf(J, "OS.snd", OS_snd, 1); + } + js_defglobal(J, "OS", JS_DONTENUM); +} + +void js_initlibtemple(js_State *J) +{ + jsLT_initdc(J); + jsLT_initgr(J); + jsLT_initos(J); +} diff --git a/src/mujs/jsmath.c b/src/mujs/jsmath.c new file mode 100644 index 0000000..6d33883 --- /dev/null +++ b/src/mujs/jsmath.c @@ -0,0 +1,194 @@ +#include "jsi.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */ +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#include + +static double jsM_round(double x) +{ + if (isnan(x)) return x; + if (isinf(x)) return x; + if (x == 0) return x; + if (x > 0 && x < 0.5) return 0; + if (x < 0 && x >= -0.5) return -0; + return floor(x + 0.5); +} + +static void Math_abs(js_State *J) +{ + js_pushnumber(J, fabs(js_tonumber(J, 1))); +} + +static void Math_acos(js_State *J) +{ + js_pushnumber(J, acos(js_tonumber(J, 1))); +} + +static void Math_asin(js_State *J) +{ + js_pushnumber(J, asin(js_tonumber(J, 1))); +} + +static void Math_atan(js_State *J) +{ + js_pushnumber(J, atan(js_tonumber(J, 1))); +} + +static void Math_atan2(js_State *J) +{ + double y = js_tonumber(J, 1); + double x = js_tonumber(J, 2); + js_pushnumber(J, atan2(y, x)); +} + +static void Math_ceil(js_State *J) +{ + js_pushnumber(J, ceil(js_tonumber(J, 1))); +} + +static void Math_cos(js_State *J) +{ + js_pushnumber(J, cos(js_tonumber(J, 1))); +} + +static void Math_exp(js_State *J) +{ + js_pushnumber(J, exp(js_tonumber(J, 1))); +} + +static void Math_floor(js_State *J) +{ + js_pushnumber(J, floor(js_tonumber(J, 1))); +} + +static void Math_log(js_State *J) +{ + js_pushnumber(J, log(js_tonumber(J, 1))); +} + +static void Math_pow(js_State *J) +{ + double x = js_tonumber(J, 1); + double y = js_tonumber(J, 2); + if (!isfinite(y) && fabs(x) == 1) + js_pushnumber(J, NAN); + else + js_pushnumber(J, pow(x,y)); +} + +static void Math_random(js_State *J) +{ + /* Lehmer generator with a=48271 and m=2^31-1 */ + /* Park & Miller (1988). Random Number Generators: Good ones are hard to find. */ + J->seed = (uint64_t) J->seed * 48271 % 0x7fffffff; + js_pushnumber(J, (double) J->seed / 0x7fffffff); +} + +static void Math_init_random(js_State *J) +{ + /* Pick initial seed by scrambling current time with Xorshift. */ + /* Marsaglia (2003). Xorshift RNGs. */ + J->seed = time(0) + 123; + J->seed ^= J->seed << 13; + J->seed ^= J->seed >> 17; + J->seed ^= J->seed << 5; + J->seed %= 0x7fffffff; +} + +static void Math_round(js_State *J) +{ + double x = js_tonumber(J, 1); + js_pushnumber(J, jsM_round(x)); +} + +static void Math_sin(js_State *J) +{ + js_pushnumber(J, sin(js_tonumber(J, 1))); +} + +static void Math_sqrt(js_State *J) +{ + js_pushnumber(J, sqrt(js_tonumber(J, 1))); +} + +static void Math_tan(js_State *J) +{ + js_pushnumber(J, tan(js_tonumber(J, 1))); +} + +static void Math_max(js_State *J) +{ + int i, n = js_gettop(J); + double x = -INFINITY; + for (i = 1; i < n; ++i) { + double y = js_tonumber(J, i); + if (isnan(y)) { + x = y; + break; + } + if (signbit(x) == signbit(y)) + x = x > y ? x : y; + else if (signbit(x)) + x = y; + } + js_pushnumber(J, x); +} + +static void Math_min(js_State *J) +{ + int i, n = js_gettop(J); + double x = INFINITY; + for (i = 1; i < n; ++i) { + double y = js_tonumber(J, i); + if (isnan(y)) { + x = y; + break; + } + if (signbit(x) == signbit(y)) + x = x < y ? x : y; + else if (signbit(y)) + x = y; + } + js_pushnumber(J, x); +} + +void jsB_initmath(js_State *J) +{ + Math_init_random(J); + js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype)); + { + jsB_propn(J, "E", 2.7182818284590452354); + jsB_propn(J, "LN10", 2.302585092994046); + jsB_propn(J, "LN2", 0.6931471805599453); + jsB_propn(J, "LOG2E", 1.4426950408889634); + jsB_propn(J, "LOG10E", 0.4342944819032518); + jsB_propn(J, "PI", 3.1415926535897932); + jsB_propn(J, "SQRT1_2", 0.7071067811865476); + jsB_propn(J, "SQRT2", 1.4142135623730951); + + jsB_propf(J, "Math.abs", Math_abs, 1); + jsB_propf(J, "Math.acos", Math_acos, 1); + jsB_propf(J, "Math.asin", Math_asin, 1); + jsB_propf(J, "Math.atan", Math_atan, 1); + jsB_propf(J, "Math.atan2", Math_atan2, 2); + jsB_propf(J, "Math.ceil", Math_ceil, 1); + jsB_propf(J, "Math.cos", Math_cos, 1); + jsB_propf(J, "Math.exp", Math_exp, 1); + jsB_propf(J, "Math.floor", Math_floor, 1); + jsB_propf(J, "Math.log", Math_log, 1); + jsB_propf(J, "Math.max", Math_max, 0); /* 2 */ + jsB_propf(J, "Math.min", Math_min, 0); /* 2 */ + jsB_propf(J, "Math.pow", Math_pow, 2); + jsB_propf(J, "Math.random", Math_random, 0); + jsB_propf(J, "Math.round", Math_round, 1); + jsB_propf(J, "Math.sin", Math_sin, 1); + jsB_propf(J, "Math.sqrt", Math_sqrt, 1); + jsB_propf(J, "Math.tan", Math_tan, 1); + } + js_defglobal(J, "Math", JS_DONTENUM); +} diff --git a/src/mujs/jsnumber.c b/src/mujs/jsnumber.c new file mode 100644 index 0000000..8e79d34 --- /dev/null +++ b/src/mujs/jsnumber.c @@ -0,0 +1,198 @@ +#include "jsi.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */ +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +static void jsB_new_Number(js_State *J) +{ + js_newnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0); +} + +static void jsB_Number(js_State *J) +{ + js_pushnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0); +} + +static void Np_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + js_pushnumber(J, self->u.number); +} + +static void Np_toString(js_State *J) +{ + char buf[100]; + js_Object *self = js_toobject(J, 0); + int radix = js_isundefined(J, 1) ? 10 : js_tointeger(J, 1); + double x = 0; + if (self->type != JS_CNUMBER) + js_typeerror(J, "not a number"); + x = self->u.number; + if (radix == 10) { + js_pushstring(J, jsV_numbertostring(J, buf, x)); + return; + } + if (radix < 2 || radix > 36) + js_rangeerror(J, "invalid radix"); + + /* lame number to string conversion for any radix from 2 to 36 */ + { + static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + double number = x; + int sign = x < 0; + js_Buffer *sb = NULL; + uint64_t u, limit = ((uint64_t)1<<52); + + int ndigits, exp, point; + + if (number == 0) { js_pushstring(J, "0"); return; } + if (isnan(number)) { js_pushstring(J, "NaN"); return; } + if (isinf(number)) { js_pushstring(J, sign ? "-Infinity" : "Infinity"); return; } + + if (sign) + number = -number; + + /* fit as many digits as we want in an int */ + exp = 0; + while (number * pow(radix, exp) > limit) + --exp; + while (number * pow(radix, exp+1) < limit) + ++exp; + u = number * pow(radix, exp) + 0.5; + + /* trim trailing zeros */ + while (u > 0 && (u % radix) == 0) { + u /= radix; + --exp; + } + + /* serialize digits */ + ndigits = 0; + while (u > 0) { + buf[ndigits++] = digits[u % radix]; + u /= radix; + } + point = ndigits - exp; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + if (sign) + js_putc(J, &sb, '-'); + + if (point <= 0) { + js_putc(J, &sb, '0'); + js_putc(J, &sb, '.'); + while (point++ < 0) + js_putc(J, &sb, '0'); + while (ndigits-- > 0) + js_putc(J, &sb, buf[ndigits]); + } else { + while (ndigits-- > 0) { + js_putc(J, &sb, buf[ndigits]); + if (--point == 0 && ndigits > 0) + js_putc(J, &sb, '.'); + } + while (point-- > 0) + js_putc(J, &sb, '0'); + } + + js_putc(J, &sb, 0); + js_pushstring(J, sb->s); + + js_endtry(J); + js_free(J, sb); + } +} + +/* Customized ToString() on a number */ +static void numtostr(js_State *J, const char *fmt, int w, double n) +{ + /* buf needs to fit printf("%.20f", 1e20) */ + char buf[50], *e; + sprintf(buf, fmt, w, n); + e = strchr(buf, 'e'); + if (e) { + int exp = atoi(e+1); + sprintf(e, "e%+d", exp); + } + js_pushstring(J, buf); +} + +static void Np_toFixed(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x) || x <= -1e21 || x >= 1e21) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*f", width, x); +} + +static void Np_toExponential(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*e", width, x); +} + +static void Np_toPrecision(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 1) js_rangeerror(J, "precision %d out of range", width); + if (width > 21) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*g", width, x); +} + +void jsB_initnumber(js_State *J) +{ + J->Number_prototype->u.number = 0; + + js_pushobject(J, J->Number_prototype); + { + jsB_propf(J, "Number.prototype.valueOf", Np_valueOf, 0); + jsB_propf(J, "Number.prototype.toString", Np_toString, 1); + jsB_propf(J, "Number.prototype.toLocaleString", Np_toString, 0); + jsB_propf(J, "Number.prototype.toFixed", Np_toFixed, 1); + jsB_propf(J, "Number.prototype.toExponential", Np_toExponential, 1); + jsB_propf(J, "Number.prototype.toPrecision", Np_toPrecision, 1); + } + js_newcconstructor(J, jsB_Number, jsB_new_Number, "Number", 0); /* 1 */ + { + jsB_propn(J, "MAX_VALUE", 1.7976931348623157e+308); + jsB_propn(J, "MIN_VALUE", 5e-324); + jsB_propn(J, "NaN", NAN); + jsB_propn(J, "NEGATIVE_INFINITY", -INFINITY); + jsB_propn(J, "POSITIVE_INFINITY", INFINITY); + } + js_defglobal(J, "Number", JS_DONTENUM); +} diff --git a/src/mujs/jsobject.c b/src/mujs/jsobject.c new file mode 100644 index 0000000..efb571b --- /dev/null +++ b/src/mujs/jsobject.c @@ -0,0 +1,560 @@ +#include "jsi.h" + +static void jsB_new_Object(js_State *J) +{ + if (js_isundefined(J, 1) || js_isnull(J, 1)) + js_newobject(J); + else + js_pushobject(J, js_toobject(J, 1)); +} + +static void jsB_Object(js_State *J) +{ + if (js_isundefined(J, 1) || js_isnull(J, 1)) + js_newobject(J); + else + js_pushobject(J, js_toobject(J, 1)); +} + +static void Op_toString(js_State *J) +{ + if (js_isundefined(J, 0)) + js_pushliteral(J, "[object Undefined]"); + else if (js_isnull(J, 0)) + js_pushliteral(J, "[object Null]"); + else { + js_Object *self = js_toobject(J, 0); + switch (self->type) { + case JS_COBJECT: js_pushliteral(J, "[object Object]"); break; + case JS_CARRAY: js_pushliteral(J, "[object Array]"); break; + case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break; + case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CERROR: js_pushliteral(J, "[object Error]"); break; + case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break; + case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break; + case JS_CSTRING: js_pushliteral(J, "[object String]"); break; + case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break; + case JS_CDATE: js_pushliteral(J, "[object Date]"); break; + case JS_CMATH: js_pushliteral(J, "[object Math]"); break; + case JS_CJSON: js_pushliteral(J, "[object JSON]"); break; + case JS_CARGUMENTS: js_pushliteral(J, "[object Arguments]"); break; + case JS_CITERATOR: js_pushliteral(J, "[object Iterator]"); break; + case JS_CUSERDATA: + js_pushliteral(J, "[object "); + js_pushliteral(J, self->u.user.tag); + js_concat(J); + js_pushliteral(J, "]"); + js_concat(J); + break; + } + } +} + +static void Op_valueOf(js_State *J) +{ + js_copy(J, 0); +} + +static void Op_hasOwnProperty(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref; + int k; + + if (self->type == JS_CSTRING) { + if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.s.length) { + js_pushboolean(J, 1); + return; + } + } + + if (self->type == JS_CARRAY && self->u.a.simple) { + if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.a.flat_length) { + js_pushboolean(J, 1); + return; + } + } + + ref = jsV_getownproperty(J, self, name); + js_pushboolean(J, ref != NULL); +} + +static void Op_isPrototypeOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (js_isobject(J, 1)) { + js_Object *V = js_toobject(J, 1); + do { + V = V->prototype; + if (V == self) { + js_pushboolean(J, 1); + return; + } + } while (V); + } + js_pushboolean(J, 0); +} + +static void Op_propertyIsEnumerable(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref = jsV_getownproperty(J, self, name); + js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM)); +} + +static void O_getPrototypeOf(js_State *J) +{ + js_Object *obj; + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + if (obj->prototype) + js_pushobject(J, obj->prototype); + else + js_pushnull(J); +} + +static void O_getOwnPropertyDescriptor(js_State *J) +{ + js_Object *obj; + js_Property *ref; + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + ref = jsV_getproperty(J, obj, js_tostring(J, 2)); + if (!ref) { + /* TODO: builtin properties (string and array index and length, regexp flags, etc) */ + js_pushundefined(J); + } else { + js_newobject(J); + if (!ref->getter && !ref->setter) { + js_pushvalue(J, ref->value); + js_defproperty(J, -2, "value", 0); + js_pushboolean(J, !(ref->atts & JS_READONLY)); + js_defproperty(J, -2, "writable", 0); + } else { + if (ref->getter) + js_pushobject(J, ref->getter); + else + js_pushundefined(J); + js_defproperty(J, -2, "get", 0); + if (ref->setter) + js_pushobject(J, ref->setter); + else + js_pushundefined(J); + js_defproperty(J, -2, "set", 0); + } + js_pushboolean(J, !(ref->atts & JS_DONTENUM)); + js_defproperty(J, -2, "enumerable", 0); + js_pushboolean(J, !(ref->atts & JS_DONTCONF)); + js_defproperty(J, -2, "configurable", 0); + } +} + +static int O_getOwnPropertyNames_walk(js_State *J, js_Property *ref, int i) +{ + if (ref->left->level) + i = O_getOwnPropertyNames_walk(J, ref->left, i); + js_pushstring(J, ref->name); + js_setindex(J, -2, i++); + if (ref->right->level) + i = O_getOwnPropertyNames_walk(J, ref->right, i); + return i; +} + +static void O_getOwnPropertyNames(js_State *J) +{ + js_Object *obj; + char name[32]; + int k; + int i; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + + js_newarray(J); + + if (obj->properties->level) + i = O_getOwnPropertyNames_walk(J, obj->properties, 0); + else + i = 0; + + if (obj->type == JS_CARRAY) { + js_pushliteral(J, "length"); + js_setindex(J, -2, i++); + if (obj->u.a.simple) { + for (k = 0; k < obj->u.a.flat_length; ++k) { + js_itoa(name, k); + js_pushstring(J, name); + js_setindex(J, -2, i++); + } + } + } + + if (obj->type == JS_CSTRING) { + js_pushliteral(J, "length"); + js_setindex(J, -2, i++); + for (k = 0; k < obj->u.s.length; ++k) { + js_itoa(name, k); + js_pushstring(J, name); + js_setindex(J, -2, i++); + } + } + + if (obj->type == JS_CREGEXP) { + js_pushliteral(J, "source"); + js_setindex(J, -2, i++); + js_pushliteral(J, "global"); + js_setindex(J, -2, i++); + js_pushliteral(J, "ignoreCase"); + js_setindex(J, -2, i++); + js_pushliteral(J, "multiline"); + js_setindex(J, -2, i++); + js_pushliteral(J, "lastIndex"); + js_setindex(J, -2, i++); + } +} + +static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name, js_Object *desc) +{ + int haswritable = 0; + int hasvalue = 0; + int enumerable = 0; + int configurable = 0; + int writable = 0; + int atts = 0; + + js_pushobject(J, obj); + js_pushobject(J, desc); + + if (js_hasproperty(J, -1, "writable")) { + haswritable = 1; + writable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "enumerable")) { + enumerable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "configurable")) { + configurable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "value")) { + hasvalue = 1; + js_defproperty(J, -3, name, 0); + } + + if (!writable) atts |= JS_READONLY; + if (!enumerable) atts |= JS_DONTENUM; + if (!configurable) atts |= JS_DONTCONF; + + if (js_hasproperty(J, -1, "get")) { + if (haswritable || hasvalue) + js_typeerror(J, "value/writable and get/set attributes are exclusive"); + } else { + js_pushundefined(J); + } + + if (js_hasproperty(J, -2, "set")) { + if (haswritable || hasvalue) + js_typeerror(J, "value/writable and get/set attributes are exclusive"); + } else { + js_pushundefined(J); + } + + js_defaccessor(J, -4, name, atts); + + js_pop(J, 2); +} + +static void O_defineProperty(js_State *J) +{ + if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); + if (!js_isobject(J, 3)) js_typeerror(J, "not an object"); + ToPropertyDescriptor(J, js_toobject(J, 1), js_tostring(J, 2), js_toobject(J, 3)); + js_copy(J, 1); +} + +static void O_defineProperties_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_defineProperties_walk(J, ref->left); + if (!(ref->atts & JS_DONTENUM)) { + js_pushvalue(J, ref->value); + ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1)); + js_pop(J, 1); + } + if (ref->right->level) + O_defineProperties_walk(J, ref->right); +} + +static void O_defineProperties(js_State *J) +{ + js_Object *props; + + if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); + if (!js_isobject(J, 2)) js_typeerror(J, "not an object"); + + props = js_toobject(J, 2); + if (props->properties->level) + O_defineProperties_walk(J, props->properties); + + js_copy(J, 1); +} + +static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref) +{ + if (ref->left->level) + O_create_walk(J, obj, ref->left); + if (!(ref->atts & JS_DONTENUM)) { + if (ref->value.t.type != JS_TOBJECT) + js_typeerror(J, "not an object"); + ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object); + } + if (ref->right->level) + O_create_walk(J, obj, ref->right); +} + +static void O_create(js_State *J) +{ + js_Object *obj; + js_Object *proto; + js_Object *props; + + if (js_isobject(J, 1)) + proto = js_toobject(J, 1); + else if (js_isnull(J, 1)) + proto = NULL; + else + js_typeerror(J, "not an object or null"); + + obj = jsV_newobject(J, JS_COBJECT, proto); + js_pushobject(J, obj); + + if (js_isdefined(J, 2)) { + if (!js_isobject(J, 2)) + js_typeerror(J, "not an object"); + props = js_toobject(J, 2); + if (props->properties->level) + O_create_walk(J, obj, props->properties); + } +} + +static int O_keys_walk(js_State *J, js_Property *ref, int i) +{ + if (ref->left->level) + i = O_keys_walk(J, ref->left, i); + if (!(ref->atts & JS_DONTENUM)) { + js_pushstring(J, ref->name); + js_setindex(J, -2, i++); + } + if (ref->right->level) + i = O_keys_walk(J, ref->right, i); + return i; +} + +static void O_keys(js_State *J) +{ + js_Object *obj; + char name[32]; + int i, k; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + + js_newarray(J); + + if (obj->properties->level) + i = O_keys_walk(J, obj->properties, 0); + else + i = 0; + + if (obj->type == JS_CSTRING) { + for (k = 0; k < obj->u.s.length; ++k) { + js_itoa(name, k); + js_pushstring(J, name); + js_setindex(J, -2, i++); + } + } + + if (obj->type == JS_CARRAY && obj->u.a.simple) { + for (k = 0; k < obj->u.a.flat_length; ++k) { + js_itoa(name, k); + js_pushstring(J, name); + js_setindex(J, -2, i++); + } + } +} + +static void O_preventExtensions(js_State *J) +{ + js_Object *obj; + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + jsR_unflattenarray(J, obj); + obj->extensible = 0; + js_copy(J, 1); +} + +static void O_isExtensible(js_State *J) +{ + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + js_pushboolean(J, js_toobject(J, 1)->extensible); +} + +static void O_seal_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_seal_walk(J, ref->left); + ref->atts |= JS_DONTCONF; + if (ref->right->level) + O_seal_walk(J, ref->right); +} + +static void O_seal(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + jsR_unflattenarray(J, obj); + obj->extensible = 0; + + if (obj->properties->level) + O_seal_walk(J, obj->properties); + + js_copy(J, 1); +} + +static int O_isSealed_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + if (!O_isSealed_walk(J, ref->left)) + return 0; + if (!(ref->atts & JS_DONTCONF)) + return 0; + if (ref->right->level) + if (!O_isSealed_walk(J, ref->right)) + return 0; + return 1; +} + +static void O_isSealed(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + if (obj->extensible) { + js_pushboolean(J, 0); + return; + } + + if (obj->properties->level) + js_pushboolean(J, O_isSealed_walk(J, obj->properties)); + else + js_pushboolean(J, 1); +} + +static void O_freeze_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_freeze_walk(J, ref->left); + ref->atts |= JS_READONLY | JS_DONTCONF; + if (ref->right->level) + O_freeze_walk(J, ref->right); +} + +static void O_freeze(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + jsR_unflattenarray(J, obj); + obj->extensible = 0; + + if (obj->properties->level) + O_freeze_walk(J, obj->properties); + + js_copy(J, 1); +} + +static int O_isFrozen_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + if (!O_isFrozen_walk(J, ref->left)) + return 0; + if (!(ref->atts & JS_READONLY)) + return 0; + if (!(ref->atts & JS_DONTCONF)) + return 0; + if (ref->right->level) + if (!O_isFrozen_walk(J, ref->right)) + return 0; + return 1; +} + +static void O_isFrozen(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + + if (obj->properties->level) { + if (!O_isFrozen_walk(J, obj->properties)) { + js_pushboolean(J, 0); + return; + } + } + + js_pushboolean(J, !obj->extensible); +} + +void jsB_initobject(js_State *J) +{ + js_pushobject(J, J->Object_prototype); + { + jsB_propf(J, "Object.prototype.toString", Op_toString, 0); + jsB_propf(J, "Object.prototype.toLocaleString", Op_toString, 0); + jsB_propf(J, "Object.prototype.valueOf", Op_valueOf, 0); + jsB_propf(J, "Object.prototype.hasOwnProperty", Op_hasOwnProperty, 1); + jsB_propf(J, "Object.prototype.isPrototypeOf", Op_isPrototypeOf, 1); + jsB_propf(J, "Object.prototype.propertyIsEnumerable", Op_propertyIsEnumerable, 1); + } + js_newcconstructor(J, jsB_Object, jsB_new_Object, "Object", 1); + { + /* ES5 */ + jsB_propf(J, "Object.getPrototypeOf", O_getPrototypeOf, 1); + jsB_propf(J, "Object.getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2); + jsB_propf(J, "Object.getOwnPropertyNames", O_getOwnPropertyNames, 1); + jsB_propf(J, "Object.create", O_create, 2); + jsB_propf(J, "Object.defineProperty", O_defineProperty, 3); + jsB_propf(J, "Object.defineProperties", O_defineProperties, 2); + jsB_propf(J, "Object.seal", O_seal, 1); + jsB_propf(J, "Object.freeze", O_freeze, 1); + jsB_propf(J, "Object.preventExtensions", O_preventExtensions, 1); + jsB_propf(J, "Object.isSealed", O_isSealed, 1); + jsB_propf(J, "Object.isFrozen", O_isFrozen, 1); + jsB_propf(J, "Object.isExtensible", O_isExtensible, 1); + jsB_propf(J, "Object.keys", O_keys, 1); + } + js_defglobal(J, "Object", JS_DONTENUM); +} diff --git a/src/mujs/json.c b/src/mujs/json.c new file mode 100644 index 0000000..6dd8f09 --- /dev/null +++ b/src/mujs/json.c @@ -0,0 +1,422 @@ +#include "jsi.h" +#include "utf.h" + +int js_isnumberobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CNUMBER; +} + +int js_isstringobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CSTRING; +} + +int js_isbooleanobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CBOOLEAN; +} + +int js_isdateobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CDATE; +} + +static void jsonnext(js_State *J) +{ + J->lookahead = jsY_lexjson(J); +} + +static int jsonaccept(js_State *J, int t) +{ + if (J->lookahead == t) { + jsonnext(J); + return 1; + } + return 0; +} + +static void jsonexpect(js_State *J, int t) +{ + if (!jsonaccept(J, t)) + js_syntaxerror(J, "JSON: unexpected token: %s (expected %s)", + jsY_tokenstring(J->lookahead), jsY_tokenstring(t)); +} + +static void jsonvalue(js_State *J) +{ + int i; + const char *name; + + switch (J->lookahead) { + case TK_STRING: + js_pushstring(J, J->text); + jsonnext(J); + break; + + case TK_NUMBER: + js_pushnumber(J, J->number); + jsonnext(J); + break; + + case '{': + js_newobject(J); + jsonnext(J); + if (jsonaccept(J, '}')) + return; + do { + if (J->lookahead != TK_STRING) + js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead)); + name = J->text; + jsonnext(J); + jsonexpect(J, ':'); + jsonvalue(J); + js_setproperty(J, -2, name); + } while (jsonaccept(J, ',')); + jsonexpect(J, '}'); + break; + + case '[': + js_newarray(J); + jsonnext(J); + i = 0; + if (jsonaccept(J, ']')) + return; + do { + jsonvalue(J); + js_setindex(J, -2, i++); + } while (jsonaccept(J, ',')); + jsonexpect(J, ']'); + break; + + case TK_TRUE: + js_pushboolean(J, 1); + jsonnext(J); + break; + + case TK_FALSE: + js_pushboolean(J, 0); + jsonnext(J); + break; + + case TK_NULL: + js_pushnull(J); + jsonnext(J); + break; + + default: + js_syntaxerror(J, "JSON: unexpected token: %s", jsY_tokenstring(J->lookahead)); + } +} + +static void jsonrevive(js_State *J, const char *name) +{ + const char *key; + char buf[32]; + + /* revive is in 2 */ + /* holder is in -1 */ + + js_getproperty(J, -1, name); /* get value from holder */ + + if (js_isobject(J, -1)) { + if (js_isarray(J, -1)) { + int i = 0; + int n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + jsonrevive(J, js_itoa(buf, i)); + if (js_isundefined(J, -1)) { + js_pop(J, 1); + js_delproperty(J, -1, buf); + } else { + js_setproperty(J, -2, buf); + } + } + } else { + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + js_rot2(J); + jsonrevive(J, key); + if (js_isundefined(J, -1)) { + js_pop(J, 1); + js_delproperty(J, -1, key); + } else { + js_setproperty(J, -2, key); + } + js_rot2(J); + } + js_pop(J, 1); + } + } + + js_copy(J, 2); /* reviver function */ + js_copy(J, -3); /* holder as this */ + js_pushstring(J, name); /* name */ + js_copy(J, -4); /* value */ + js_call(J, 2); + js_rot2pop1(J); /* pop old value, leave new value on stack */ +} + +static void JSON_parse(js_State *J) +{ + const char *source = js_tostring(J, 1); + jsY_initlex(J, "JSON", source); + jsonnext(J); + + if (js_iscallable(J, 2)) { + js_newobject(J); + jsonvalue(J); + js_defproperty(J, -2, "", 0); + jsonrevive(J, ""); + } else { + jsonvalue(J); + } +} + +static void fmtnum(js_State *J, js_Buffer **sb, double n) +{ + if (isnan(n)) js_puts(J, sb, "null"); + else if (isinf(n)) js_puts(J, sb, "null"); + else if (n == 0) js_puts(J, sb, "0"); + else { + char buf[40]; + js_puts(J, sb, jsV_numbertostring(J, buf, n)); + } +} + +static void fmtstr(js_State *J, js_Buffer **sb, const char *s) +{ + static const char *HEX = "0123456789abcdef"; + int i, n; + Rune c; + js_putc(J, sb, '"'); + while (*s) { + n = chartorune(&c, s); + switch (c) { + case '"': js_puts(J, sb, "\\\""); break; + case '\\': js_puts(J, sb, "\\\\"); break; + case '\b': js_puts(J, sb, "\\b"); break; + case '\f': js_puts(J, sb, "\\f"); break; + case '\n': js_puts(J, sb, "\\n"); break; + case '\r': js_puts(J, sb, "\\r"); break; + case '\t': js_puts(J, sb, "\\t"); break; + default: + if (c < ' ' || (c >= 0xd800 && c <= 0xdfff)) { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'u'); + js_putc(J, sb, HEX[(c>>12)&15]); + js_putc(J, sb, HEX[(c>>8)&15]); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else if (c < 128) { + js_putc(J, sb, c); + } else { + for (i = 0; i < n; ++i) + js_putc(J, sb, s[i]); + } + break; + } + s += n; + } + js_putc(J, sb, '"'); +} + +static void fmtindent(js_State *J, js_Buffer **sb, const char *gap, int level) +{ + js_putc(J, sb, '\n'); + while (level--) + js_puts(J, sb, gap); +} + +static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level); + +static int filterprop(js_State *J, const char *key) +{ + int i, n, found; + /* replacer/property-list is in stack slot 2 */ + if (js_isarray(J, 2)) { + found = 0; + n = js_getlength(J, 2); + for (i = 0; i < n && !found; ++i) { + js_getindex(J, 2, i); + if (js_isstring(J, -1) || js_isnumber(J, -1) || + js_isstringobject(J, -1) || js_isnumberobject(J, -1)) + found = !strcmp(key, js_tostring(J, -1)); + js_pop(J, 1); + } + return found; + } + return 1; +} + +static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level) +{ + const char *key; + int save; + int i, n; + + n = js_gettop(J) - 1; + for (i = 4; i < n; ++i) + if (js_isobject(J, i)) + if (js_toobject(J, i) == js_toobject(J, -1)) + js_typeerror(J, "cyclic object value"); + + n = 0; + js_putc(J, sb, '{'); + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + if (filterprop(J, key)) { + save = (*sb)->n; + if (n) js_putc(J, sb, ','); + if (gap) fmtindent(J, sb, gap, level + 1); + fmtstr(J, sb, key); + js_putc(J, sb, ':'); + if (gap) + js_putc(J, sb, ' '); + js_rot2(J); + if (!fmtvalue(J, sb, key, gap, level + 1)) + (*sb)->n = save; + else + ++n; + js_rot2(J); + } + } + js_pop(J, 1); + if (gap && n) fmtindent(J, sb, gap, level); + js_putc(J, sb, '}'); +} + +static void fmtarray(js_State *J, js_Buffer **sb, const char *gap, int level) +{ + int n, i; + char buf[32]; + + n = js_gettop(J) - 1; + for (i = 4; i < n; ++i) + if (js_isobject(J, i)) + if (js_toobject(J, i) == js_toobject(J, -1)) + js_typeerror(J, "cyclic object value"); + + js_putc(J, sb, '['); + n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + if (i) js_putc(J, sb, ','); + if (gap) fmtindent(J, sb, gap, level + 1); + if (!fmtvalue(J, sb, js_itoa(buf, i), gap, level + 1)) + js_puts(J, sb, "null"); + } + if (gap && n) fmtindent(J, sb, gap, level); + js_putc(J, sb, ']'); +} + +static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level) +{ + /* replacer/property-list is in 2 */ + /* holder is in -1 */ + + js_getproperty(J, -1, key); + + if (js_isobject(J, -1)) { + if (js_hasproperty(J, -1, "toJSON")) { + if (js_iscallable(J, -1)) { + js_copy(J, -2); + js_pushstring(J, key); + js_call(J, 1); + js_rot2pop1(J); + } else { + js_pop(J, 1); + } + } + } + + if (js_iscallable(J, 2)) { + js_copy(J, 2); /* replacer function */ + js_copy(J, -3); /* holder as this */ + js_pushstring(J, key); /* name */ + js_copy(J, -4); /* old value */ + js_call(J, 2); + js_rot2pop1(J); /* pop old value, leave new value on stack */ + } + + if (js_isobject(J, -1) && !js_iscallable(J, -1)) { + js_Object *obj = js_toobject(J, -1); + switch (obj->type) { + case JS_CNUMBER: fmtnum(J, sb, obj->u.number); break; + case JS_CSTRING: fmtstr(J, sb, obj->u.s.string); break; + case JS_CBOOLEAN: js_puts(J, sb, obj->u.boolean ? "true" : "false"); break; + case JS_CARRAY: fmtarray(J, sb, gap, level); break; + default: fmtobject(J, sb, obj, gap, level); break; + } + } + else if (js_isboolean(J, -1)) + js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false"); + else if (js_isnumber(J, -1)) + fmtnum(J, sb, js_tonumber(J, -1)); + else if (js_isstring(J, -1)) + fmtstr(J, sb, js_tostring(J, -1)); + else if (js_isnull(J, -1)) + js_puts(J, sb, "null"); + else { + js_pop(J, 1); + return 0; + } + + js_pop(J, 1); + return 1; +} + +static void JSON_stringify(js_State *J) +{ + js_Buffer *sb = NULL; + char buf[12]; + /* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */ + const char * volatile gap; + const char *s; + int n; + + gap = NULL; + + if (js_isnumber(J, 3) || js_isnumberobject(J, 3)) { + n = js_tointeger(J, 3); + if (n < 0) n = 0; + if (n > 10) n = 10; + memset(buf, ' ', n); + buf[n] = 0; + if (n > 0) gap = buf; + } else if (js_isstring(J, 3) || js_isstringobject(J, 3)) { + s = js_tostring(J, 3); + n = strlen(s); + if (n > 10) n = 10; + memcpy(buf, s, n); + buf[n] = 0; + if (n > 0) gap = buf; + } + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_newobject(J); /* wrapper */ + js_copy(J, 1); + js_defproperty(J, -2, "", 0); + if (!fmtvalue(J, &sb, "", gap, 0)) { + js_pushundefined(J); + } else { + js_putc(J, &sb, 0); + js_pushstring(J, sb ? sb->s : ""); + js_rot2pop1(J); + } + + js_endtry(J); + js_free(J, sb); +} + +void jsB_initjson(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_CJSON, J->Object_prototype)); + { + jsB_propf(J, "JSON.parse", JSON_parse, 2); + jsB_propf(J, "JSON.stringify", JSON_stringify, 3); + } + js_defglobal(J, "JSON", JS_DONTENUM); +} diff --git a/src/mujs/jsparse.c b/src/mujs/jsparse.c new file mode 100644 index 0000000..95ebfc1 --- /dev/null +++ b/src/mujs/jsparse.c @@ -0,0 +1,1065 @@ +#include "jsi.h" + +#define LIST(h) jsP_newnode(J, AST_LIST, 0, h, 0, 0, 0) + +#define EXP0(x) jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0) +#define EXP1(x,a) jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0) +#define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0) +#define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, line, a, b, c, 0) + +#define STM0(x) jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0) +#define STM1(x,a) jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0) +#define STM2(x,a,b) jsP_newnode(J, STM_ ## x, line, a, b, 0, 0) +#define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, line, a, b, c, 0) +#define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, line, a, b, c, d) + +static js_Ast *expression(js_State *J, int notin); +static js_Ast *assignment(js_State *J, int notin); +static js_Ast *memberexp(js_State *J); +static js_Ast *statement(js_State *J); +static js_Ast *funbody(js_State *J); + +JS_NORETURN static void jsP_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +#define INCREC() if (++J->astdepth > JS_ASTLIMIT) jsP_error(J, "too much recursion") +#define DECREC() --J->astdepth +#define SAVEREC() int SAVE=J->astdepth +#define POPREC() J->astdepth=SAVE + +static void jsP_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + npf_vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + npf_snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static void jsP_warning(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msg[256]; + + va_start(ap, fmt); + npf_vsnprintf(msg, sizeof msg, fmt, ap); + va_end(ap); + + npf_snprintf(buf, sizeof buf, "%s:%d: warning: %s", J->filename, J->lexline, msg); + js_report(J, buf); +} + +static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) +{ + js_Ast *node = js_malloc(J, sizeof *node); + + node->type = type; + node->line = line; + node->a = a; + node->b = b; + node->c = c; + node->d = d; + node->number = 0; + node->string = NULL; + node->jumps = NULL; + node->casejump = 0; + + node->parent = NULL; + if (a) a->parent = node; + if (b) b->parent = node; + if (c) c->parent = node; + if (d) d->parent = node; + + node->gcnext = J->gcast; + J->gcast = node; + + return node; +} + +static js_Ast *jsP_list(js_Ast *head) +{ + /* set parent pointers in list nodes */ + js_Ast *prev = head, *node = head->b; + while (node) { + node->parent = prev; + prev = node; + node = node->b; + } + return head; +} + +static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s) +{ + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); + node->string = s; + return node; +} + +static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n) +{ + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); + node->number = n; + return node; +} + +static void jsP_freejumps(js_State *J, js_JumpList *node) +{ + while (node) { + js_JumpList *next = node->next; + js_free(J, node); + node = next; + } +} + +void jsP_freeparse(js_State *J) +{ + js_Ast *node = J->gcast; + while (node) { + js_Ast *next = node->gcnext; + jsP_freejumps(J, node->jumps); + js_free(J, node); + node = next; + } + J->gcast = NULL; +} + +/* Lookahead */ + +static void jsP_next(js_State *J) +{ + J->lookahead = jsY_lex(J); +} + +#define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0) + +#define jsP_expect(J,x) if (!jsP_accept(J, x)) jsP_error(J, "unexpected token: %s (expected %s)", jsY_tokenstring(J->lookahead), jsY_tokenstring(x)) + +static void semicolon(js_State *J) +{ + if (J->lookahead == ';') { + jsP_next(J); + return; + } + if (J->newline || J->lookahead == '}' || J->lookahead == 0) + return; + jsP_error(J, "unexpected token: %s (expected ';')", jsY_tokenstring(J->lookahead)); +} + +/* Literals */ + +static js_Ast *identifier(js_State *J) +{ + js_Ast *a; + if (J->lookahead == TK_IDENTIFIER) { + a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + jsP_error(J, "unexpected token: %s (expected identifier)", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *identifieropt(js_State *J) +{ + if (J->lookahead == TK_IDENTIFIER) + return identifier(J); + return NULL; +} + +static js_Ast *identifiername(js_State *J) +{ + if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) { + js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + jsP_error(J, "unexpected token: %s (expected identifier or keyword)", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *arrayelement(js_State *J) +{ + int line = J->lexline; + if (J->lookahead == ',') + return EXP0(ELISION); + return assignment(J, 0); +} + +static js_Ast *arrayliteral(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ']') + return NULL; + head = tail = LIST(arrayelement(J)); + while (jsP_accept(J, ',')) { + if (J->lookahead != ']') + tail = tail->b = LIST(arrayelement(J)); + } + return jsP_list(head); +} + +static js_Ast *propname(js_State *J) +{ + js_Ast *name; + if (J->lookahead == TK_NUMBER) { + name = jsP_newnumnode(J, EXP_NUMBER, J->number); + jsP_next(J); + } else if (J->lookahead == TK_STRING) { + name = jsP_newstrnode(J, EXP_STRING, J->text); + jsP_next(J); + } else { + name = identifiername(J); + } + return name; +} + +static js_Ast *propassign(js_State *J) +{ + js_Ast *name, *value, *arg, *body; + int line = J->lexline; + + name = propname(J); + + if (J->lookahead != ':' && name->type == AST_IDENTIFIER) { + if (!strcmp(name->string, "get")) { + name = propname(J); + jsP_expect(J, '('); + jsP_expect(J, ')'); + body = funbody(J); + return EXP3(PROP_GET, name, NULL, body); + } + if (!strcmp(name->string, "set")) { + name = propname(J); + jsP_expect(J, '('); + arg = identifier(J); + jsP_expect(J, ')'); + body = funbody(J); + return EXP3(PROP_SET, name, LIST(arg), body); + } + } + + jsP_expect(J, ':'); + value = assignment(J, 0); + return EXP2(PROP_VAL, name, value); +} + +static js_Ast *objectliteral(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}') + return NULL; + head = tail = LIST(propassign(J)); + while (jsP_accept(J, ',')) { + if (J->lookahead == '}') + break; + tail = tail->b = LIST(propassign(J)); + } + return jsP_list(head); +} + +/* Functions */ + +static js_Ast *parameters(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ')') + return NULL; + head = tail = LIST(identifier(J)); + while (jsP_accept(J, ',')) { + tail = tail->b = LIST(identifier(J)); + } + return jsP_list(head); +} + +static js_Ast *fundec(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifier(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0); +} + +static js_Ast *funstm(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifier(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + /* rewrite function statement as "var X = function X() {}" */ + return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c)))); +} + +static js_Ast *funexp(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifieropt(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + return EXP3(FUN, a, b, c); +} + +/* Expressions */ + +static js_Ast *primary(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + + if (J->lookahead == TK_IDENTIFIER) { + a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + if (J->lookahead == TK_STRING) { + a = jsP_newstrnode(J, EXP_STRING, J->text); + jsP_next(J); + return a; + } + if (J->lookahead == TK_REGEXP) { + a = jsP_newstrnode(J, EXP_REGEXP, J->text); + a->number = J->number; + jsP_next(J); + return a; + } + if (J->lookahead == TK_NUMBER) { + a = jsP_newnumnode(J, EXP_NUMBER, J->number); + jsP_next(J); + return a; + } + + if (jsP_accept(J, TK_THIS)) return EXP0(THIS); + if (jsP_accept(J, TK_NULL)) return EXP0(NULL); + if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE); + if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE); + if (jsP_accept(J, '{')) { + a = EXP1(OBJECT, objectliteral(J)); + jsP_expect(J, '}'); + return a; + } + if (jsP_accept(J, '[')) { + a = EXP1(ARRAY, arrayliteral(J)); + jsP_expect(J, ']'); + return a; + } + if (jsP_accept(J, '(')) { + a = expression(J, 0); + jsP_expect(J, ')'); + return a; + } + + jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *arguments(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ')') + return NULL; + head = tail = LIST(assignment(J, 0)); + while (jsP_accept(J, ',')) { + tail = tail->b = LIST(assignment(J, 0)); + } + return jsP_list(head); +} + +static js_Ast *newexp(js_State *J) +{ + js_Ast *a, *b; + int line = J->lexline; + + if (jsP_accept(J, TK_NEW)) { + a = memberexp(J); + if (jsP_accept(J, '(')) { + b = arguments(J); + jsP_expect(J, ')'); + return EXP2(NEW, a, b); + } + return EXP1(NEW, a); + } + + if (jsP_accept(J, TK_FUNCTION)) + return funexp(J, line); + + return primary(J); +} + +static js_Ast *memberexp(js_State *J) +{ + js_Ast *a = newexp(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } + if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } + POPREC(); + return a; +} + +static js_Ast *callexp(js_State *J) +{ + js_Ast *a = newexp(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } + if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } + if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; } + POPREC(); + return a; +} + +static js_Ast *postfix(js_State *J) +{ + js_Ast *a = callexp(J); + int line = J->lexline; + if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a); + if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a); + return a; +} + +static js_Ast *unary(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + INCREC(); + if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J)); + else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J)); + else if (jsP_accept(J, TK_TYPEOF)) a = EXP1(TYPEOF, unary(J)); + else if (jsP_accept(J, TK_INC)) a = EXP1(PREINC, unary(J)); + else if (jsP_accept(J, TK_DEC)) a = EXP1(PREDEC, unary(J)); + else if (jsP_accept(J, '+')) a = EXP1(POS, unary(J)); + else if (jsP_accept(J, '-')) a = EXP1(NEG, unary(J)); + else if (jsP_accept(J, '~')) a = EXP1(BITNOT, unary(J)); + else if (jsP_accept(J, '!')) a = EXP1(LOGNOT, unary(J)); + else a = postfix(J); + DECREC(); + return a; +} + +static js_Ast *multiplicative(js_State *J) +{ + js_Ast *a = unary(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; } + if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; } + if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *additive(js_State *J) +{ + js_Ast *a = multiplicative(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; } + if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *shift(js_State *J) +{ + js_Ast *a = additive(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; } + if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; } + if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *relational(js_State *J, int notin) +{ + js_Ast *a = shift(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; } + if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_GE)) { a = EXP2(GE, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_INSTANCEOF)) { a = EXP2(INSTANCEOF, a, shift(J)); goto loop; } + if (!notin && jsP_accept(J, TK_IN)) { a = EXP2(IN, a, shift(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *equality(js_State *J, int notin) +{ + js_Ast *a = relational(J, notin); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *bitand(js_State *J, int notin) +{ + js_Ast *a = equality(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '&')) { + INCREC(); + a = EXP2(BITAND, a, equality(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *bitxor(js_State *J, int notin) +{ + js_Ast *a = bitand(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '^')) { + INCREC(); + a = EXP2(BITXOR, a, bitand(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *bitor(js_State *J, int notin) +{ + js_Ast *a = bitxor(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '|')) { + INCREC(); + a = EXP2(BITOR, a, bitxor(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *logand(js_State *J, int notin) +{ + js_Ast *a = bitor(J, notin); + int line = J->lexline; + if (jsP_accept(J, TK_AND)) { + INCREC(); + a = EXP2(LOGAND, a, logand(J, notin)); + DECREC(); + } + return a; +} + +static js_Ast *logor(js_State *J, int notin) +{ + js_Ast *a = logand(J, notin); + int line = J->lexline; + if (jsP_accept(J, TK_OR)) { + INCREC(); + a = EXP2(LOGOR, a, logor(J, notin)); + DECREC(); + } + return a; +} + +static js_Ast *conditional(js_State *J, int notin) +{ + js_Ast *a = logor(J, notin); + int line = J->lexline; + if (jsP_accept(J, '?')) { + js_Ast *b, *c; + INCREC(); + b = assignment(J, 0); + jsP_expect(J, ':'); + c = assignment(J, notin); + DECREC(); + return EXP3(COND, a, b, c); + } + return a; +} + +static js_Ast *assignment(js_State *J, int notin) +{ + js_Ast *a = conditional(J, notin); + int line = J->lexline; + INCREC(); + if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin)); + else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin)); + else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin)); + else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin)); + else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin)); + else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin)); + DECREC(); + return a; +} + +static js_Ast *expression(js_State *J, int notin) +{ + js_Ast *a = assignment(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, ',')) { + INCREC(); + a = EXP2(COMMA, a, assignment(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +/* Statements */ + +static js_Ast *vardec(js_State *J, int notin) +{ + js_Ast *a = identifier(J); + int line = J->lexline; + if (jsP_accept(J, '=')) + return EXP2(VAR, a, assignment(J, notin)); + return EXP1(VAR, a); +} + +static js_Ast *vardeclist(js_State *J, int notin) +{ + js_Ast *head, *tail; + head = tail = LIST(vardec(J, notin)); + while (jsP_accept(J, ',')) + tail = tail->b = LIST(vardec(J, notin)); + return jsP_list(head); +} + +static js_Ast *statementlist(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}' || J->lookahead == TK_CASE || J->lookahead == TK_DEFAULT) + return NULL; + head = tail = LIST(statement(J)); + while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT) + tail = tail->b = LIST(statement(J)); + return jsP_list(head); +} + +static js_Ast *caseclause(js_State *J) +{ + js_Ast *a, *b; + int line = J->lexline; + + if (jsP_accept(J, TK_CASE)) { + a = expression(J, 0); + jsP_expect(J, ':'); + b = statementlist(J); + return STM2(CASE, a, b); + } + + if (jsP_accept(J, TK_DEFAULT)) { + jsP_expect(J, ':'); + a = statementlist(J); + return STM1(DEFAULT, a); + } + + jsP_error(J, "unexpected token in switch: %s (expected 'case' or 'default')", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *caselist(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}') + return NULL; + head = tail = LIST(caseclause(J)); + while (J->lookahead != '}') + tail = tail->b = LIST(caseclause(J)); + return jsP_list(head); +} + +static js_Ast *block(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + jsP_expect(J, '{'); + a = statementlist(J); + jsP_expect(J, '}'); + return STM1(BLOCK, a); +} + +static js_Ast *forexpression(js_State *J, int end) +{ + js_Ast *a = NULL; + if (J->lookahead != end) + a = expression(J, 0); + jsP_expect(J, end); + return a; +} + +static js_Ast *forstatement(js_State *J, int line) +{ + js_Ast *a, *b, *c, *d; + jsP_expect(J, '('); + if (jsP_accept(J, TK_VAR)) { + a = vardeclist(J, 1); + if (jsP_accept(J, ';')) { + b = forexpression(J, ';'); + c = forexpression(J, ')'); + d = statement(J); + return STM4(FOR_VAR, a, b, c, d); + } + if (jsP_accept(J, TK_IN)) { + b = expression(J, 0); + jsP_expect(J, ')'); + c = statement(J); + return STM3(FOR_IN_VAR, a, b, c); + } + jsP_error(J, "unexpected token in for-var-statement: %s", jsY_tokenstring(J->lookahead)); + } + + if (J->lookahead != ';') + a = expression(J, 1); + else + a = NULL; + if (jsP_accept(J, ';')) { + b = forexpression(J, ';'); + c = forexpression(J, ')'); + d = statement(J); + return STM4(FOR, a, b, c, d); + } + if (jsP_accept(J, TK_IN)) { + b = expression(J, 0); + jsP_expect(J, ')'); + c = statement(J); + return STM3(FOR_IN, a, b, c); + } + jsP_error(J, "unexpected token in for-statement: %s", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *statement(js_State *J) +{ + js_Ast *a, *b, *c, *d; + js_Ast *stm; + int line = J->lexline; + + INCREC(); + + if (J->lookahead == '{') { + stm = block(J); + } + + else if (jsP_accept(J, TK_VAR)) { + a = vardeclist(J, 0); + semicolon(J); + stm = STM1(VAR, a); + } + + /* empty statement */ + else if (jsP_accept(J, ';')) { + stm = STM0(EMPTY); + } + + else if (jsP_accept(J, TK_IF)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + if (jsP_accept(J, TK_ELSE)) + c = statement(J); + else + c = NULL; + stm = STM3(IF, a, b, c); + } + + else if (jsP_accept(J, TK_DO)) { + a = statement(J); + jsP_expect(J, TK_WHILE); + jsP_expect(J, '('); + b = expression(J, 0); + jsP_expect(J, ')'); + semicolon(J); + stm = STM2(DO, a, b); + } + + else if (jsP_accept(J, TK_WHILE)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + stm = STM2(WHILE, a, b); + } + + else if (jsP_accept(J, TK_FOR)) { + stm = forstatement(J, line); + } + + else if (jsP_accept(J, TK_CONTINUE)) { + a = identifieropt(J); + semicolon(J); + stm = STM1(CONTINUE, a); + } + + else if (jsP_accept(J, TK_BREAK)) { + a = identifieropt(J); + semicolon(J); + stm = STM1(BREAK, a); + } + + else if (jsP_accept(J, TK_RETURN)) { + if (J->lookahead != ';' && J->lookahead != '}' && J->lookahead != 0) + a = expression(J, 0); + else + a = NULL; + semicolon(J); + stm = STM1(RETURN, a); + } + + else if (jsP_accept(J, TK_WITH)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + stm = STM2(WITH, a, b); + } + + else if (jsP_accept(J, TK_SWITCH)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + jsP_expect(J, '{'); + b = caselist(J); + jsP_expect(J, '}'); + stm = STM2(SWITCH, a, b); + } + + else if (jsP_accept(J, TK_THROW)) { + a = expression(J, 0); + semicolon(J); + stm = STM1(THROW, a); + } + + else if (jsP_accept(J, TK_TRY)) { + a = block(J); + b = c = d = NULL; + if (jsP_accept(J, TK_CATCH)) { + jsP_expect(J, '('); + b = identifier(J); + jsP_expect(J, ')'); + c = block(J); + } + if (jsP_accept(J, TK_FINALLY)) { + d = block(J); + } + if (!b && !d) + jsP_error(J, "unexpected token in try: %s (expected 'catch' or 'finally')", jsY_tokenstring(J->lookahead)); + stm = STM4(TRY, a, b, c, d); + } + + else if (jsP_accept(J, TK_DEBUGGER)) { + semicolon(J); + stm = STM0(DEBUGGER); + } + + else if (jsP_accept(J, TK_FUNCTION)) { + jsP_warning(J, "function statements are not standard"); + stm = funstm(J, line); + } + + /* labelled statement or expression statement */ + else if (J->lookahead == TK_IDENTIFIER) { + a = expression(J, 0); + if (a->type == EXP_IDENTIFIER && jsP_accept(J, ':')) { + a->type = AST_IDENTIFIER; + b = statement(J); + stm = STM2(LABEL, a, b); + } else { + semicolon(J); + stm = a; + } + } + + /* expression statement */ + else { + stm = expression(J, 0); + semicolon(J); + } + + DECREC(); + return stm; +} + +/* Program */ + +static js_Ast *scriptelement(js_State *J) +{ + int line = J->lexline; + if (jsP_accept(J, TK_FUNCTION)) + return fundec(J, line); + return statement(J); +} + +static js_Ast *script(js_State *J, int terminator) +{ + js_Ast *head, *tail; + if (J->lookahead == terminator) + return NULL; + head = tail = LIST(scriptelement(J)); + while (J->lookahead != terminator) + tail = tail->b = LIST(scriptelement(J)); + return jsP_list(head); +} + +static js_Ast *funbody(js_State *J) +{ + js_Ast *a; + jsP_expect(J, '{'); + a = script(J, '}'); + jsP_expect(J, '}'); + return a; +} + +/* Constant folding */ + +static int toint32(double d) +{ + double two32 = 4294967296.0; + double two31 = 2147483648.0; + + if (!isfinite(d) || d == 0) + return 0; + + d = fmod(d, two32); + d = d >= 0 ? floor(d) : ceil(d) + two32; + if (d >= two31) + return d - two32; + else + return d; +} + +static unsigned int touint32(double d) +{ + return (unsigned int)toint32(d); +} + +static int jsP_setnumnode(js_Ast *node, double x) +{ + node->type = EXP_NUMBER; + node->number = x; + node->a = node->b = node->c = node->d = NULL; + return 1; +} + +static int jsP_foldconst(js_Ast *node) +{ + double x, y; + int a, b; + + if (node->type == AST_LIST) { + while (node) { + jsP_foldconst(node->a); + node = node->b; + } + return 0; + } + + if (node->type == EXP_NUMBER) + return 1; + + a = node->a ? jsP_foldconst(node->a) : 0; + b = node->b ? jsP_foldconst(node->b) : 0; + if (node->c) jsP_foldconst(node->c); + if (node->d) jsP_foldconst(node->d); + + if (a) { + x = node->a->number; + switch (node->type) { + default: break; + case EXP_NEG: return jsP_setnumnode(node, -x); + case EXP_POS: return jsP_setnumnode(node, x); + case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x)); + } + + if (b) { + y = node->b->number; + switch (node->type) { + default: break; + case EXP_MUL: return jsP_setnumnode(node, x * y); + case EXP_DIV: return jsP_setnumnode(node, x / y); + case EXP_MOD: return jsP_setnumnode(node, fmod(x, y)); + case EXP_ADD: return jsP_setnumnode(node, x + y); + case EXP_SUB: return jsP_setnumnode(node, x - y); + case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F)); + case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F)); + case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F)); + case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y)); + case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y)); + case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y)); + } + } + } + + return 0; +} + +/* Main entry point */ + +js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) +{ + js_Ast *p; + + jsY_initlex(J, filename, source); + jsP_next(J); + J->astdepth = 0; + p = script(J, 0); + if (p) + jsP_foldconst(p); + + return p; +} + +js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body) +{ + js_Ast *p = NULL; + int line = 0; + if (params) { + jsY_initlex(J, filename, params); + jsP_next(J); + J->astdepth = 0; + p = parameters(J); + } + return EXP3(FUN, NULL, p, jsP_parse(J, filename, body)); +} diff --git a/src/mujs/jsproperty.c b/src/mujs/jsproperty.c new file mode 100644 index 0000000..7d6e271 --- /dev/null +++ b/src/mujs/jsproperty.c @@ -0,0 +1,341 @@ +#include "jsi.h" + +#include + +/* + Use an AA-tree to quickly look up properties in objects: + + The level of every leaf node is one. + The level of every left child is one less than its parent. + The level of every right child is equal or one less than its parent. + The level of every right grandchild is less than its grandparent. + Every node of level greater than one has two children. + + A link where the child's level is equal to that of its parent is called a horizontal link. + Individual right horizontal links are allowed, but consecutive ones are forbidden. + Left horizontal links are forbidden. + + skew() fixes left horizontal links. + split() fixes consecutive right horizontal links. +*/ + +static js_Property sentinel = { + &sentinel, &sentinel, + 0, 0, + { { {0}, JS_TUNDEFINED } }, + NULL, NULL, "" +}; + +static js_Property *newproperty(js_State *J, js_Object *obj, const char *name) +{ + int n = strlen(name) + 1; + js_Property *node = js_malloc(J, offsetof(js_Property, name) + n); + node->left = node->right = &sentinel; + node->level = 1; + node->atts = 0; + node->value.t.type = JS_TUNDEFINED; + node->value.u.number = 0; + node->getter = NULL; + node->setter = NULL; + memcpy(node->name, name, n); + ++obj->count; + ++J->gccounter; + return node; +} + +static js_Property *lookup(js_Property *node, const char *name) +{ + while (node != &sentinel) { + int c = strcmp(name, node->name); + if (c == 0) + return node; + else if (c < 0) + node = node->left; + else + node = node->right; + } + return NULL; +} + +static js_Property *skew(js_Property *node) +{ + if (node->left->level == node->level) { + js_Property *temp = node; + node = node->left; + temp->left = node->right; + node->right = temp; + } + return node; +} + +static js_Property *split(js_Property *node) +{ + if (node->right->right->level == node->level) { + js_Property *temp = node; + node = node->right; + temp->right = node->left; + node->left = temp; + ++node->level; + } + return node; +} + +static js_Property *insert(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **result) +{ + if (node != &sentinel) { + int c = strcmp(name, node->name); + if (c < 0) + node->left = insert(J, obj, node->left, name, result); + else if (c > 0) + node->right = insert(J, obj, node->right, name, result); + else + return *result = node; + node = skew(node); + node = split(node); + return node; + } + return *result = newproperty(J, obj, name); +} + +static void freeproperty(js_State *J, js_Object *obj, js_Property *node) +{ + js_free(J, node); + --obj->count; +} + +static js_Property *unlinkproperty(js_Property *node, const char *name, js_Property **garbage) +{ + js_Property *temp, *a, *b; + if (node != &sentinel) { + int c = strcmp(name, node->name); + if (c < 0) { + node->left = unlinkproperty(node->left, name, garbage); + } else if (c > 0) { + node->right = unlinkproperty(node->right, name, garbage); + } else { + *garbage = node; + if (node->left == &sentinel && node->right == &sentinel) { + return &sentinel; + } + else if (node->left == &sentinel) { + a = node->right; + while (a->left != &sentinel) + a = a->left; + b = unlinkproperty(node->right, a->name, &temp); + temp->level = node->level; + temp->left = node->left; + temp->right = b; + node = temp; + } + else { + a = node->left; + while (a->right != &sentinel) + a = a->right; + b = unlinkproperty(node->left, a->name, &temp); + temp->level = node->level; + temp->left = b; + temp->right = node->right; + node = temp; + } + } + + if (node->left->level < node->level - 1 || node->right->level < node->level - 1) + { + if (node->right->level > --node->level) + node->right->level = node->level; + node = skew(node); + node->right = skew(node->right); + node->right->right = skew(node->right->right); + node = split(node); + node->right = split(node->right); + } + } + return node; +} + +static js_Property *deleteproperty(js_State *J, js_Object *obj, js_Property *tree, const char *name) +{ + js_Property *garbage = &sentinel; + tree = unlinkproperty(tree, name, &garbage); + if (garbage != &sentinel) + freeproperty(J, obj, garbage); + return tree; +} + +js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype) +{ + js_Object *obj = js_malloc(J, sizeof *obj); + memset(obj, 0, sizeof *obj); + obj->gcmark = 0; + obj->gcnext = J->gcobj; + J->gcobj = obj; + ++J->gccounter; + + obj->type = type; + obj->properties = &sentinel; + obj->prototype = prototype; + obj->extensible = 1; + return obj; +} + +js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name) +{ + return lookup(obj->properties, name); +} + +js_Property *jsV_getpropertyx(js_State *J, js_Object *obj, const char *name, int *own) +{ + *own = 1; + do { + js_Property *ref = lookup(obj->properties, name); + if (ref) + return ref; + obj = obj->prototype; + *own = 0; + } while (obj); + return NULL; +} + +js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name) +{ + do { + js_Property *ref = lookup(obj->properties, name); + if (ref) + return ref; + obj = obj->prototype; + } while (obj); + return NULL; +} + +static js_Property *jsV_getenumproperty(js_State *J, js_Object *obj, const char *name) +{ + do { + js_Property *ref = lookup(obj->properties, name); + if (ref && !(ref->atts & JS_DONTENUM)) + return ref; + obj = obj->prototype; + } while (obj); + return NULL; +} + +js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *result; + + if (!obj->extensible) { + result = lookup(obj->properties, name); + if (J->strict && !result) + js_typeerror(J, "object is non-extensible"); + return result; + } + + obj->properties = insert(J, obj, obj->properties, name, &result); + + return result; +} + +void jsV_delproperty(js_State *J, js_Object *obj, const char *name) +{ + obj->properties = deleteproperty(J, obj, obj->properties, name); +} + +/* Flatten hierarchy of enumerable properties into an iterator object */ + +static js_Iterator *itnewnode(js_State *J, const char *name, js_Iterator *next) { + int n = strlen(name) + 1; + js_Iterator *node = js_malloc(J, offsetof(js_Iterator, name) + n); + node->next = next; + memcpy(node->name, name, n); + return node; +} + +static js_Iterator *itwalk(js_State *J, js_Iterator *iter, js_Property *prop, js_Object *seen) +{ + if (prop->right != &sentinel) + iter = itwalk(J, iter, prop->right, seen); + if (!(prop->atts & JS_DONTENUM)) { + if (!seen || !jsV_getenumproperty(J, seen, prop->name)) { + iter = itnewnode(J, prop->name, iter); + } + } + if (prop->left != &sentinel) + iter = itwalk(J, iter, prop->left, seen); + return iter; +} + +static js_Iterator *itflatten(js_State *J, js_Object *obj) +{ + js_Iterator *iter = NULL; + if (obj->prototype) + iter = itflatten(J, obj->prototype); + if (obj->properties != &sentinel) + iter = itwalk(J, iter, obj->properties, obj->prototype); + return iter; +} + +js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own) +{ + js_Object *io = jsV_newobject(J, JS_CITERATOR, NULL); + io->u.iter.target = obj; + io->u.iter.i = 0; + io->u.iter.n = 0; + if (own) { + io->u.iter.head = NULL; + if (obj->properties != &sentinel) + io->u.iter.head = itwalk(J, io->u.iter.head, obj->properties, NULL); + } else { + io->u.iter.head = itflatten(J, obj); + } + io->u.iter.current = io->u.iter.head; + + if (obj->type == JS_CSTRING) + io->u.iter.n = obj->u.s.length; + + if (obj->type == JS_CARRAY && obj->u.a.simple) + io->u.iter.n = obj->u.a.flat_length; + + return io; +} + +const char *jsV_nextiterator(js_State *J, js_Object *io) +{ + if (io->type != JS_CITERATOR) + js_typeerror(J, "not an iterator"); + if (io->u.iter.i < io->u.iter.n) { + js_itoa(J->scratch, io->u.iter.i); + io->u.iter.i++; + return J->scratch; + } + while (io->u.iter.current) { + const char *name = io->u.iter.current->name; + io->u.iter.current = io->u.iter.current->next; + if (jsV_getproperty(J, io->u.iter.target, name)) + return name; + } + return NULL; +} + +/* Walk all the properties and delete them one by one for arrays */ + +void jsV_resizearray(js_State *J, js_Object *obj, int newlen) +{ + char buf[32]; + const char *s; + int k; + assert(!obj->u.a.simple); + if (newlen < obj->u.a.length) { + if (obj->u.a.length > obj->count * 2) { + js_Object *it = jsV_newiterator(J, obj, 1); + while ((s = jsV_nextiterator(J, it))) { + k = jsV_numbertointeger(jsV_stringtonumber(J, s)); + if (k >= newlen && !strcmp(s, jsV_numbertostring(J, buf, k))) + jsV_delproperty(J, obj, s); + } + } else { + for (k = newlen; k < obj->u.a.length; ++k) { + jsV_delproperty(J, obj, js_itoa(buf, k)); + } + } + } + obj->u.a.length = newlen; +} diff --git a/src/mujs/jsregexp.c b/src/mujs/jsregexp.c new file mode 100644 index 0000000..85c4a0d --- /dev/null +++ b/src/mujs/jsregexp.c @@ -0,0 +1,232 @@ +#include "jsi.h" +#include "regexp.h" + +static char *escaperegexp(js_State *J, const char *pattern) { + char *copy, *p; + const char *s; + int n = 0; + for (s = pattern; *s; ++s) { + if (*s == '/') + ++n; + ++n; + } + copy = p = js_malloc(J, n+1); + for (s = pattern; *s; ++s) { + if (*s == '/') + *p++ = '\\'; + *p++ = *s; + } + *p = 0; + return copy; +} + +static void js_newregexpx(js_State *J, const char *pattern, int flags, int is_clone) +{ + const char *error; + js_Object *obj; + Reprog *prog; + int opts; + + obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype); + + opts = 0; + if (flags & JS_REGEXP_I) opts |= REG_ICASE; + if (flags & JS_REGEXP_M) opts |= REG_NEWLINE; + + prog = js_regcompx(J->alloc, J->actx, pattern, opts, &error); + if (!prog) + js_syntaxerror(J, "regular expression: %s", error); + + obj->u.r.prog = prog; + obj->u.r.source = is_clone ? js_strdup(J, pattern) : escaperegexp(J, pattern); + obj->u.r.flags = flags; + obj->u.r.last = 0; + js_pushobject(J, obj); +} + +void js_newregexp(js_State *J, const char *pattern, int flags) +{ + js_newregexpx(J, pattern, flags, 0); +} + +void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text) +{ + const char *haystack; + int result; + int i; + int opts; + Resub m; + + haystack = text; + opts = 0; + if (re->flags & JS_REGEXP_G) { + if (re->last > strlen(haystack)) { + re->last = 0; + js_pushnull(J); + return; + } + if (re->last > 0) { + haystack = text + re->last; + opts |= REG_NOTBOL; + } + } + + result = js_regexec(re->prog, haystack, &m, opts); + if (result < 0) + js_error(J, "regexec failed"); + if (result == 0) { + js_newarray(J); + js_pushstring(J, text); + js_setproperty(J, -2, "input"); + js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); + js_setproperty(J, -2, "index"); + for (i = 0; i < m.nsub; ++i) { + js_pushlstring(J, m.sub[i].sp, m.sub[i].ep - m.sub[i].sp); + js_setindex(J, -2, i); + } + if (re->flags & JS_REGEXP_G) + re->last = m.sub[0].ep - text; + return; + } + + if (re->flags & JS_REGEXP_G) + re->last = 0; + + js_pushnull(J); +} + +static void Rp_test(js_State *J) +{ + js_Regexp *re; + const char *text; + int result; + int opts; + Resub m; + + re = js_toregexp(J, 0); + text = js_tostring(J, 1); + + opts = 0; + if (re->flags & JS_REGEXP_G) { + if (re->last > strlen(text)) { + re->last = 0; + js_pushboolean(J, 0); + return; + } + if (re->last > 0) { + text += re->last; + opts |= REG_NOTBOL; + } + } + + result = js_regexec(re->prog, text, &m, opts); + if (result < 0) + js_error(J, "regexec failed"); + if (result == 0) { + if (re->flags & JS_REGEXP_G) + re->last = re->last + (m.sub[0].ep - text); + js_pushboolean(J, 1); + return; + } + + if (re->flags & JS_REGEXP_G) + re->last = 0; + + js_pushboolean(J, 0); +} + +static void jsB_new_RegExp(js_State *J) +{ + js_Regexp *old; + const char *pattern; + int flags; + int is_clone = 0; + + if (js_isregexp(J, 1)) { + if (js_isdefined(J, 2)) + js_typeerror(J, "cannot supply flags when creating one RegExp from another"); + old = js_toregexp(J, 1); + pattern = old->source; + flags = old->flags; + is_clone = 1; + } else if (js_isundefined(J, 1)) { + pattern = "(?:)"; + flags = 0; + } else { + pattern = js_tostring(J, 1); + flags = 0; + } + + if (strlen(pattern) == 0) + pattern = "(?:)"; + + if (js_isdefined(J, 2)) { + const char *s = js_tostring(J, 2); + int g = 0, i = 0, m = 0; + while (*s) { + if (*s == 'g') ++g; + else if (*s == 'i') ++i; + else if (*s == 'm') ++m; + else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s); + ++s; + } + if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'"); + if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'"); + if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'"); + if (g) flags |= JS_REGEXP_G; + if (i) flags |= JS_REGEXP_I; + if (m) flags |= JS_REGEXP_M; + } + + js_newregexpx(J, pattern, flags, is_clone); +} + +static void jsB_RegExp(js_State *J) +{ + if (js_isregexp(J, 1)) + return; + jsB_new_RegExp(J); +} + +static void Rp_toString(js_State *J) +{ + js_Regexp *re; + char * volatile out = NULL; + + re = js_toregexp(J, 0); + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + out = js_malloc(J, strlen(re->source) + 6); /* extra space for //gim */ + strcpy(out, "/"); + strcat(out, re->source); + strcat(out, "/"); + if (re->flags & JS_REGEXP_G) strcat(out, "g"); + if (re->flags & JS_REGEXP_I) strcat(out, "i"); + if (re->flags & JS_REGEXP_M) strcat(out, "m"); + + js_pop(J, 0); + js_pushstring(J, out); + js_endtry(J); + js_free(J, out); +} + +static void Rp_exec(js_State *J) +{ + js_RegExp_prototype_exec(J, js_toregexp(J, 0), js_tostring(J, 1)); +} + +void jsB_initregexp(js_State *J) +{ + js_pushobject(J, J->RegExp_prototype); + { + jsB_propf(J, "RegExp.prototype.toString", Rp_toString, 0); + jsB_propf(J, "RegExp.prototype.test", Rp_test, 0); + jsB_propf(J, "RegExp.prototype.exec", Rp_exec, 0); + } + js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, "RegExp", 1); + js_defglobal(J, "RegExp", JS_DONTENUM); +} diff --git a/src/mujs/jsrepr.c b/src/mujs/jsrepr.c new file mode 100644 index 0000000..6d7e4d3 --- /dev/null +++ b/src/mujs/jsrepr.c @@ -0,0 +1,285 @@ +#include "jsi.h" +#include "utf.h" + +static void reprvalue(js_State *J, js_Buffer **sb); + +static void reprnum(js_State *J, js_Buffer **sb, double n) +{ + char buf[40]; + if (n == 0 && signbit(n)) + js_puts(J, sb, "-0"); + else + js_puts(J, sb, jsV_numbertostring(J, buf, n)); +} + +static void reprstr(js_State *J, js_Buffer **sb, const char *s) +{ + static const char *HEX = "0123456789ABCDEF"; + int i, n; + Rune c; + js_putc(J, sb, '"'); + while (*s) { + n = chartorune(&c, s); + switch (c) { + case '"': js_puts(J, sb, "\\\""); break; + case '\\': js_puts(J, sb, "\\\\"); break; + case '\b': js_puts(J, sb, "\\b"); break; + case '\f': js_puts(J, sb, "\\f"); break; + case '\n': js_puts(J, sb, "\\n"); break; + case '\r': js_puts(J, sb, "\\r"); break; + case '\t': js_puts(J, sb, "\\t"); break; + default: + if (c < ' ') { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'x'); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else if (c < 128) { + js_putc(J, sb, c); + } else if (c < 0x10000) { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'u'); + js_putc(J, sb, HEX[(c>>12)&15]); + js_putc(J, sb, HEX[(c>>8)&15]); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else { + for (i = 0; i < n; ++i) + js_putc(J, sb, s[i]); + } + break; + } + s += n; + } + js_putc(J, sb, '"'); +} + +#ifndef isalpha +#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +#endif +#ifndef isdigit +#define isdigit(c) (c >= '0' && c <= '9') +#endif + +static void reprident(js_State *J, js_Buffer **sb, const char *name) +{ + const char *p = name; + if (isdigit(*p)) + while (isdigit(*p)) + ++p; + else if (isalpha(*p) || *p == '_') + while (isdigit(*p) || isalpha(*p) || *p == '_') + ++p; + if (p > name && *p == 0) + js_puts(J, sb, name); + else + reprstr(J, sb, name); +} + +static void reprobject(js_State *J, js_Buffer **sb) +{ + const char *key; + int i, n; + + n = js_gettop(J) - 1; + for (i = 0; i < n; ++i) { + if (js_isobject(J, i)) { + if (js_toobject(J, i) == js_toobject(J, -1)) { + js_puts(J, sb, "{}"); + return; + } + } + } + + n = 0; + js_putc(J, sb, '{'); + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + if (n++ > 0) + js_puts(J, sb, ", "); + reprident(J, sb, key); + js_puts(J, sb, ": "); + js_getproperty(J, -2, key); + reprvalue(J, sb); + js_pop(J, 1); + } + js_pop(J, 1); + js_putc(J, sb, '}'); +} + +static void reprarray(js_State *J, js_Buffer **sb) +{ + int n, i; + + n = js_gettop(J) - 1; + for (i = 0; i < n; ++i) { + if (js_isobject(J, i)) { + if (js_toobject(J, i) == js_toobject(J, -1)) { + js_puts(J, sb, "[]"); + return; + } + } + } + + js_putc(J, sb, '['); + n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + if (i > 0) + js_puts(J, sb, ", "); + if (js_hasindex(J, -1, i)) { + reprvalue(J, sb); + js_pop(J, 1); + } + } + js_putc(J, sb, ']'); +} + +static void reprfun(js_State *J, js_Buffer **sb, js_Function *fun) +{ + int i; + js_puts(J, sb, "function "); + js_puts(J, sb, fun->name); + js_putc(J, sb, '('); + for (i = 0; i < fun->numparams; ++i) { + if (i > 0) + js_puts(J, sb, ", "); + js_puts(J, sb, fun->vartab[i]); + } + js_puts(J, sb, ") { [byte code] }"); +} + +static void reprvalue(js_State *J, js_Buffer **sb) +{ + if (js_isundefined(J, -1)) + js_puts(J, sb, "undefined"); + else if (js_isnull(J, -1)) + js_puts(J, sb, "null"); + else if (js_isboolean(J, -1)) + js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false"); + else if (js_isnumber(J, -1)) + reprnum(J, sb, js_tonumber(J, -1)); + else if (js_isstring(J, -1)) + reprstr(J, sb, js_tostring(J, -1)); + else if (js_isobject(J, -1)) { + js_Object *obj = js_toobject(J, -1); + switch (obj->type) { + default: + reprobject(J, sb); + break; + case JS_CARRAY: + reprarray(J, sb); + break; + case JS_CFUNCTION: + case JS_CSCRIPT: + reprfun(J, sb, obj->u.f.function); + break; + case JS_CCFUNCTION: + js_puts(J, sb, "function "); + js_puts(J, sb, obj->u.c.name); + js_puts(J, sb, "() { [native code] }"); + break; + case JS_CBOOLEAN: + js_puts(J, sb, "(new Boolean("); + js_puts(J, sb, obj->u.boolean ? "true" : "false"); + js_puts(J, sb, "))"); + break; + case JS_CNUMBER: + js_puts(J, sb, "(new Number("); + reprnum(J, sb, obj->u.number); + js_puts(J, sb, "))"); + break; + case JS_CSTRING: + js_puts(J, sb, "(new String("); + reprstr(J, sb, obj->u.s.string); + js_puts(J, sb, "))"); + break; + case JS_CREGEXP: + js_putc(J, sb, '/'); + js_puts(J, sb, obj->u.r.source); + js_putc(J, sb, '/'); + if (obj->u.r.flags & JS_REGEXP_G) js_putc(J, sb, 'g'); + if (obj->u.r.flags & JS_REGEXP_I) js_putc(J, sb, 'i'); + if (obj->u.r.flags & JS_REGEXP_M) js_putc(J, sb, 'm'); + break; + case JS_CDATE: + { + char buf[40]; + js_puts(J, sb, "(new Date("); + js_puts(J, sb, jsV_numbertostring(J, buf, obj->u.number)); + js_puts(J, sb, "))"); + } + break; + case JS_CERROR: + js_puts(J, sb, "(new "); + js_getproperty(J, -1, "name"); + js_puts(J, sb, js_tostring(J, -1)); + js_pop(J, 1); + js_putc(J, sb, '('); + if (js_hasproperty(J, -1, "message")) { + reprvalue(J, sb); + js_pop(J, 1); + } + js_puts(J, sb, "))"); + break; + case JS_CMATH: + js_puts(J, sb, "Math"); + break; + case JS_CJSON: + js_puts(J, sb, "JSON"); + break; + case JS_CITERATOR: + js_puts(J, sb, "[iterator "); + break; + case JS_CUSERDATA: + js_puts(J, sb, "[userdata "); + js_puts(J, sb, obj->u.user.tag); + js_putc(J, sb, ']'); + break; + } + } +} + +void js_repr(js_State *J, int idx) +{ + js_Buffer *sb = NULL; + int savebot; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_copy(J, idx); + + savebot = J->bot; + J->bot = J->top - 1; + reprvalue(J, &sb); + J->bot = savebot; + + js_pop(J, 1); + + js_putc(J, &sb, 0); + js_pushstring(J, sb ? sb->s : "undefined"); + + js_endtry(J); + js_free(J, sb); +} + +const char *js_torepr(js_State *J, int idx) +{ + js_repr(J, idx); + js_replace(J, idx < 0 ? idx-1 : idx); + return js_tostring(J, idx); +} + +const char *js_tryrepr(js_State *J, int idx, const char *error) +{ + const char *s; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + s = js_torepr(J, idx); + js_endtry(J); + return s; +} diff --git a/src/mujs/jsrun.c b/src/mujs/jsrun.c new file mode 100644 index 0000000..b956208 --- /dev/null +++ b/src/mujs/jsrun.c @@ -0,0 +1,2063 @@ +#include "jsi.h" +#include "utf.h" + +#include + +static void jsR_run(js_State *J, js_Function *F); + +/* Push values on stack */ + +#define STACK (J->stack) +#define TOP (J->top) +#define BOT (J->bot) + +static void js_trystackoverflow(js_State *J) +{ + STACK[TOP].t.type = JS_TLITSTR; + STACK[TOP].u.litstr = "exception stack overflow"; + ++TOP; + js_throw(J); +} + +static void js_stackoverflow(js_State *J) +{ + STACK[TOP].t.type = JS_TLITSTR; + STACK[TOP].u.litstr = "stack overflow"; + ++TOP; + js_throw(J); +} + +static void js_outofmemory(js_State *J) +{ + STACK[TOP].t.type = JS_TLITSTR; + STACK[TOP].u.litstr = "out of memory"; + ++TOP; + js_throw(J); +} + +void *js_malloc(js_State *J, int size) +{ + void *ptr = J->alloc(J->actx, NULL, size); + if (!ptr) + js_outofmemory(J); + return ptr; +} + +void *js_realloc(js_State *J, void *ptr, int size) +{ + ptr = J->alloc(J->actx, ptr, size); + if (!ptr) + js_outofmemory(J); + return ptr; +} + +char *js_strdup(js_State *J, const char *s) +{ + int n = strlen(s) + 1; + char *p = js_malloc(J, n); + memcpy(p, s, n); + return p; +} + +void js_free(js_State *J, void *ptr) +{ + J->alloc(J->actx, ptr, 0); +} + +js_String *jsV_newmemstring(js_State *J, const char *s, int n) +{ + js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1); + memcpy(v->p, s, n); + v->p[n] = 0; + v->gcmark = 0; + v->gcnext = J->gcstr; + J->gcstr = v; + ++J->gccounter; + return v; +} + +#define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J) + +void js_pushvalue(js_State *J, js_Value v) +{ + CHECKSTACK(1); + STACK[TOP] = v; + ++TOP; +} + +void js_pushundefined(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TUNDEFINED; + ++TOP; +} + +void js_pushnull(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TNULL; + ++TOP; +} + +void js_pushboolean(js_State *J, int v) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TBOOLEAN; + STACK[TOP].u.boolean = !!v; + ++TOP; +} + +void js_pushnumber(js_State *J, double v) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TNUMBER; + STACK[TOP].u.number = v; + ++TOP; +} + +void js_pushstring(js_State *J, const char *v) +{ + size_t n = strlen(v); + if (n > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + CHECKSTACK(1); + if (n <= soffsetof(js_Value, t.type)) { + char *s = STACK[TOP].u.shrstr; + while (n--) *s++ = *v++; + *s = 0; + STACK[TOP].t.type = JS_TSHRSTR; + } else { + STACK[TOP].t.type = JS_TMEMSTR; + STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); + } + ++TOP; +} + +void js_pushlstring(js_State *J, const char *v, int n) +{ + if (n > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + CHECKSTACK(1); + if (n <= soffsetof(js_Value, t.type)) { + char *s = STACK[TOP].u.shrstr; + while (n--) *s++ = *v++; + *s = 0; + STACK[TOP].t.type = JS_TSHRSTR; + } else { + STACK[TOP].t.type = JS_TMEMSTR; + STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); + } + ++TOP; +} + +void js_pushliteral(js_State *J, const char *v) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TLITSTR; + STACK[TOP].u.litstr = v; + ++TOP; +} + +void js_pushobject(js_State *J, js_Object *v) +{ + CHECKSTACK(1); + STACK[TOP].t.type = JS_TOBJECT; + STACK[TOP].u.object = v; + ++TOP; +} + +void js_pushglobal(js_State *J) +{ + js_pushobject(J, J->G); +} + +void js_currentfunction(js_State *J) +{ + CHECKSTACK(1); + if (BOT > 0) + STACK[TOP] = STACK[BOT-1]; + else + STACK[TOP].t.type = JS_TUNDEFINED; + ++TOP; +} + +void *js_currentfunctiondata(js_State *J) +{ + if (BOT > 0) + return STACK[BOT-1].u.object->u.c.data; + return NULL; +} + +/* Read values from stack */ + +static js_Value *stackidx(js_State *J, int idx) +{ + static js_Value undefined = { { {0}, JS_TUNDEFINED } }; + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < 0 || idx >= TOP) + return &undefined; + return STACK + idx; +} + +js_Value *js_tovalue(js_State *J, int idx) +{ + return stackidx(J, idx); +} + +int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TUNDEFINED; } +int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TUNDEFINED; } +int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNULL; } +int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TBOOLEAN; } +int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNUMBER; } +int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->t.type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; } +int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TOBJECT; } +int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TOBJECT; } +int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->t.type != JS_TUNDEFINED && v->t.type != JS_TNULL; } + +int js_iscallable(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TOBJECT) + return v->u.object->type == JS_CFUNCTION || + v->u.object->type == JS_CSCRIPT || + v->u.object->type == JS_CCFUNCTION; + return 0; +} + +int js_isarray(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->t.type == JS_TOBJECT && v->u.object->type == JS_CARRAY; +} + +int js_isregexp(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP; +} + +int js_isuserdata(js_State *J, int idx, const char *tag) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) + return !strcmp(tag, v->u.object->u.user.tag); + return 0; +} + +int js_iserror(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->t.type == JS_TOBJECT && v->u.object->type == JS_CERROR; +} + +const char *js_typeof(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + switch (v->t.type) { + default: + case JS_TSHRSTR: return "string"; + case JS_TUNDEFINED: return "undefined"; + case JS_TNULL: return "object"; + case JS_TBOOLEAN: return "boolean"; + case JS_TNUMBER: return "number"; + case JS_TLITSTR: return "string"; + case JS_TMEMSTR: return "string"; + case JS_TOBJECT: + if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) + return "function"; + return "object"; + } +} + +int js_type(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + switch (v->t.type) { + default: + case JS_TSHRSTR: return JS_ISSTRING; + case JS_TUNDEFINED: return JS_ISUNDEFINED; + case JS_TNULL: return JS_ISNULL; + case JS_TBOOLEAN: return JS_ISBOOLEAN; + case JS_TNUMBER: return JS_ISNUMBER; + case JS_TLITSTR: return JS_ISSTRING; + case JS_TMEMSTR: return JS_ISSTRING; + case JS_TOBJECT: + if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) + return JS_ISFUNCTION; + return JS_ISOBJECT; + } +} + +int js_toboolean(js_State *J, int idx) +{ + return jsV_toboolean(J, stackidx(J, idx)); +} + +double js_tonumber(js_State *J, int idx) +{ + return jsV_tonumber(J, stackidx(J, idx)); +} + +int js_tointeger(js_State *J, int idx) +{ + return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx))); +} + +int js_toint32(js_State *J, int idx) +{ + return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx))); +} + +unsigned int js_touint32(js_State *J, int idx) +{ + return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx))); +} + +short js_toint16(js_State *J, int idx) +{ + return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx))); +} + +unsigned short js_touint16(js_State *J, int idx) +{ + return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx))); +} + +const char *js_tostring(js_State *J, int idx) +{ + return jsV_tostring(J, stackidx(J, idx)); +} + +js_Object *js_toobject(js_State *J, int idx) +{ + return jsV_toobject(J, stackidx(J, idx)); +} + +void js_toprimitive(js_State *J, int idx, int hint) +{ + jsV_toprimitive(J, stackidx(J, idx), hint); +} + +js_Regexp *js_toregexp(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP) + return &v->u.object->u.r; + js_typeerror(J, "not a regexp"); +} + +void *js_touserdata(js_State *J, int idx, const char *tag) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) + if (!strcmp(tag, v->u.object->u.user.tag)) + return v->u.object->u.user.data; + js_typeerror(J, "not a %s", tag); +} + +static js_Object *jsR_tofunction(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TUNDEFINED || v->t.type == JS_TNULL) + return NULL; + if (v->t.type == JS_TOBJECT) + if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) + return v->u.object; + js_typeerror(J, "not a function"); +} + +/* Stack manipulation */ + +int js_gettop(js_State *J) +{ + return TOP - BOT; +} + +void js_pop(js_State *J, int n) +{ + TOP -= n; + if (TOP < BOT) { + TOP = BOT; + js_error(J, "stack underflow!"); + } +} + +void js_remove(js_State *J, int idx) +{ + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < BOT || idx >= TOP) + js_error(J, "stack error!"); + for (;idx < TOP - 1; ++idx) + STACK[idx] = STACK[idx+1]; + --TOP; +} + +void js_insert(js_State *J, int idx) +{ + js_error(J, "not implemented yet"); +} + +void js_replace(js_State* J, int idx) +{ + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < BOT || idx >= TOP) + js_error(J, "stack error!"); + STACK[idx] = STACK[--TOP]; +} + +void js_copy(js_State *J, int idx) +{ + CHECKSTACK(1); + STACK[TOP] = *stackidx(J, idx); + ++TOP; +} + +void js_dup(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP] = STACK[TOP-1]; + ++TOP; +} + +void js_dup2(js_State *J) +{ + CHECKSTACK(2); + STACK[TOP] = STACK[TOP-2]; + STACK[TOP+1] = STACK[TOP-1]; + TOP += 2; +} + +void js_rot2(js_State *J) +{ + /* A B -> B A */ + js_Value tmp = STACK[TOP-1]; /* A B (B) */ + STACK[TOP-1] = STACK[TOP-2]; /* A A */ + STACK[TOP-2] = tmp; /* B A */ +} + +void js_rot3(js_State *J) +{ + /* A B C -> C A B */ + js_Value tmp = STACK[TOP-1]; /* A B C (C) */ + STACK[TOP-1] = STACK[TOP-2]; /* A B B */ + STACK[TOP-2] = STACK[TOP-3]; /* A A B */ + STACK[TOP-3] = tmp; /* C A B */ +} + +void js_rot4(js_State *J) +{ + /* A B C D -> D A B C */ + js_Value tmp = STACK[TOP-1]; /* A B C D (D) */ + STACK[TOP-1] = STACK[TOP-2]; /* A B C C */ + STACK[TOP-2] = STACK[TOP-3]; /* A B B C */ + STACK[TOP-3] = STACK[TOP-4]; /* A A B C */ + STACK[TOP-4] = tmp; /* D A B C */ +} + +void js_rot2pop1(js_State *J) +{ + /* A B -> B */ + STACK[TOP-2] = STACK[TOP-1]; + --TOP; +} + +void js_rot3pop2(js_State *J) +{ + /* A B C -> C */ + STACK[TOP-3] = STACK[TOP-1]; + TOP -= 2; +} + +void js_rot(js_State *J, int n) +{ + int i; + js_Value tmp = STACK[TOP-1]; + for (i = 1; i < n; ++i) + STACK[TOP-i] = STACK[TOP-i-1]; + STACK[TOP-i] = tmp; +} + +/* Property access that takes care of attributes and getters/setters */ + +int js_isarrayindex(js_State *J, const char *p, int *idx) +{ + int n = 0; + + /* check for empty string */ + if (p[0] == 0) + return 0; + + /* check for '0' and integers with leading zero */ + if (p[0] == '0') + return (p[1] == 0) ? *idx = 0, 1 : 0; + + while (*p) { + int c = *p++; + if (c >= '0' && c <= '9') { + if (n >= INT_MAX / 10) + return 0; + n = n * 10 + (c - '0'); + } else { + return 0; + } + } + return *idx = n, 1; +} + +static void js_pushrune(js_State *J, Rune rune) +{ + char buf[UTFmax + 1]; + if (rune >= 0) { + buf[runetochar(buf, &rune)] = 0; + js_pushstring(J, buf); + } else { + js_pushundefined(J); + } +} + +void jsR_unflattenarray(js_State *J, js_Object *obj) { + if (obj->type == JS_CARRAY && obj->u.a.simple) { + js_Property *ref; + int i; + char name[32]; + if (js_try(J)) { + obj->properties = NULL; + js_throw(J); + } + for (i = 0; i < obj->u.a.flat_length; ++i) { + js_itoa(name, i); + ref = jsV_setproperty(J, obj, name); + ref->value = obj->u.a.array[i]; + } + js_free(J, obj->u.a.array); + obj->u.a.simple = 0; + obj->u.a.flat_length = 0; + obj->u.a.flat_capacity = 0; + obj->u.a.array = NULL; + js_endtry(J); + } +} + +static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) { + js_pushnumber(J, obj->u.a.length); + return 1; + } + if (obj->u.a.simple) { + if (js_isarrayindex(J, name, &k)) { + if (k >= 0 && k < obj->u.a.flat_length) { + js_pushvalue(J, obj->u.a.array[k]); + return 1; + } + return 0; + } + } + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) { + js_pushnumber(J, obj->u.s.length); + return 1; + } + if (js_isarrayindex(J, name, &k)) { + if (k >= 0 && k < obj->u.s.length) { + js_pushrune(J, js_runeat(J, obj->u.s.string, k)); + return 1; + } + } + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) { + js_pushstring(J, obj->u.r.source); + return 1; + } + if (!strcmp(name, "global")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G); + return 1; + } + if (!strcmp(name, "ignoreCase")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I); + return 1; + } + if (!strcmp(name, "multiline")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M); + return 1; + } + if (!strcmp(name, "lastIndex")) { + js_pushnumber(J, obj->u.r.last); + return 1; + } + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.has && obj->u.user.has(J, obj->u.user.data, name)) + return 1; + } + + ref = jsV_getproperty(J, obj, name); + if (ref) { + if (ref->getter) { + js_pushobject(J, ref->getter); + js_pushobject(J, obj); + js_call(J, 0); + } else { + js_pushvalue(J, ref->value); + } + return 1; + } + + return 0; +} + +static void jsR_getproperty(js_State *J, js_Object *obj, const char *name) +{ + if (!jsR_hasproperty(J, obj, name)) + js_pushundefined(J); +} + +static int jsR_hasindex(js_State *J, js_Object *obj, int k) +{ + char buf[32]; + if (obj->type == JS_CARRAY && obj->u.a.simple) { + if (k >= 0 && k < obj->u.a.flat_length) { + js_pushvalue(J, obj->u.a.array[k]); + return 1; + } + return 0; + } + return jsR_hasproperty(J, obj, js_itoa(buf, k)); +} + +static void jsR_getindex(js_State *J, js_Object *obj, int k) +{ + if (!jsR_hasindex(J, obj, k)) + js_pushundefined(J); +} + +static void jsR_setarrayindex(js_State *J, js_Object *obj, int k, js_Value *value) +{ + int newlen = k + 1; + assert(obj->u.a.simple); + assert(k >= 0); + if (newlen > JS_ARRAYLIMIT) + js_rangeerror(J, "array too large"); + if (newlen > obj->u.a.flat_length) { + assert(newlen == obj->u.a.flat_length + 1); + if (newlen > obj->u.a.flat_capacity) { + int newcap = obj->u.a.flat_capacity; + if (newcap == 0) + newcap = 8; + while (newcap < newlen) + newcap <<= 1; + obj->u.a.array = js_realloc(J, obj->u.a.array, newcap * sizeof(js_Value)); + obj->u.a.flat_capacity = newcap; + } + obj->u.a.flat_length = newlen; + } + if (newlen > obj->u.a.length) + obj->u.a.length = newlen; + obj->u.a.array[k] = *value; +} + +static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, int transient) +{ + js_Value *value = stackidx(J, -1); + js_Property *ref; + int k; + int own; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) { + double rawlen = jsV_tonumber(J, value); + int newlen = jsV_numbertointeger(rawlen); + if (newlen != rawlen || newlen < 0) + js_rangeerror(J, "invalid array length"); + if (newlen > JS_ARRAYLIMIT) + js_rangeerror(J, "array too large"); + if (obj->u.a.simple) { + obj->u.a.length = newlen; + if (newlen <= obj->u.a.flat_length) + obj->u.a.flat_length = newlen; + } else { + jsV_resizearray(J, obj, newlen); + } + return; + } + + if (js_isarrayindex(J, name, &k)) { + if (obj->u.a.simple) { + if (k >= 0 && k <= obj->u.a.flat_length) { + jsR_setarrayindex(J, obj, k, value); + } else { + jsR_unflattenarray(J, obj); + if (obj->u.a.length < k + 1) + obj->u.a.length = k + 1; + } + } else { + if (obj->u.a.length < k + 1) + obj->u.a.length = k + 1; + } + } + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto readonly; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto readonly; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto readonly; + if (!strcmp(name, "global")) goto readonly; + if (!strcmp(name, "ignoreCase")) goto readonly; + if (!strcmp(name, "multiline")) goto readonly; + if (!strcmp(name, "lastIndex")) { + obj->u.r.last = jsV_tointeger(J, value); + return; + } + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name)) + return; + } + + /* First try to find a setter in prototype chain */ + ref = jsV_getpropertyx(J, obj, name, &own); + if (ref) { + if (ref->setter) { + js_pushobject(J, ref->setter); + js_pushobject(J, obj); + js_pushvalue(J, *value); + js_call(J, 1); + js_pop(J, 1); + return; + } else { + if (J->strict) + if (ref->getter) + js_typeerror(J, "setting property '%s' that only has a getter", name); + if (ref->atts & JS_READONLY) + goto readonly; + } + } + + /* Property not found on this object, so create one */ + if (!ref || !own) { + if (transient) { + if (J->strict) + js_typeerror(J, "cannot create property '%s' on transient object", name); + return; + } + ref = jsV_setproperty(J, obj, name); + } + + if (ref) { + if (!(ref->atts & JS_READONLY)) + ref->value = *value; + else + goto readonly; + } + + return; + +readonly: + if (J->strict) + js_typeerror(J, "'%s' is read-only", name); +} + +static void jsR_setindex(js_State *J, js_Object *obj, int k, int transient) +{ + char buf[32]; + if (obj->type == JS_CARRAY && obj->u.a.simple && k >= 0 && k <= obj->u.a.flat_length) { + jsR_setarrayindex(J, obj, k, stackidx(J, -1)); + } else { + jsR_setproperty(J, obj, js_itoa(buf, k), transient); + } +} + +static void jsR_defproperty(js_State *J, js_Object *obj, const char *name, + int atts, js_Value *value, js_Object *getter, js_Object *setter, + int throw) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) + goto readonly; + if (obj->u.a.simple) + jsR_unflattenarray(J, obj); + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto readonly; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto readonly; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto readonly; + if (!strcmp(name, "global")) goto readonly; + if (!strcmp(name, "ignoreCase")) goto readonly; + if (!strcmp(name, "multiline")) goto readonly; + if (!strcmp(name, "lastIndex")) goto readonly; + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name)) + return; + } + + ref = jsV_setproperty(J, obj, name); + if (ref) { + if (value) { + if (!(ref->atts & JS_READONLY)) + ref->value = *value; + else if (J->strict) + js_typeerror(J, "'%s' is read-only", name); + } + if (getter) { + if (!(ref->atts & JS_DONTCONF)) + ref->getter = getter; + else if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + } + if (setter) { + if (!(ref->atts & JS_DONTCONF)) + ref->setter = setter; + else if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + } + ref->atts |= atts; + } + + return; + +readonly: + if (J->strict || throw) + js_typeerror(J, "'%s' is read-only or non-configurable", name); +} + +static int jsR_delproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) + goto dontconf; + if (obj->u.a.simple) + jsR_unflattenarray(J, obj); + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto dontconf; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto dontconf; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto dontconf; + if (!strcmp(name, "global")) goto dontconf; + if (!strcmp(name, "ignoreCase")) goto dontconf; + if (!strcmp(name, "multiline")) goto dontconf; + if (!strcmp(name, "lastIndex")) goto dontconf; + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.delete && obj->u.user.delete(J, obj->u.user.data, name)) + return 1; + } + + ref = jsV_getownproperty(J, obj, name); + if (ref) { + if (ref->atts & JS_DONTCONF) + goto dontconf; + jsV_delproperty(J, obj, name); + } + return 1; + +dontconf: + if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + return 0; +} + +static void jsR_delindex(js_State *J, js_Object *obj, int k) +{ + char buf[32]; + /* Allow deleting last element of a simple array without unflattening */ + if (obj->type == JS_CARRAY && obj->u.a.simple && k == obj->u.a.flat_length - 1) + obj->u.a.flat_length = k; + else + jsR_delproperty(J, obj, js_itoa(buf, k)); +} + +/* Registry, global and object property accessors */ + +const char *js_ref(js_State *J) +{ + js_Value *v = stackidx(J, -1); + const char *s; + char buf[32]; + switch (v->t.type) { + case JS_TUNDEFINED: s = "_Undefined"; break; + case JS_TNULL: s = "_Null"; break; + case JS_TBOOLEAN: + s = v->u.boolean ? "_True" : "_False"; + break; + case JS_TOBJECT: + sprintf(buf, "%p", (void*)v->u.object); + s = js_intern(J, buf); + break; + default: + sprintf(buf, "%d", J->nextref++); + s = js_intern(J, buf); + break; + } + js_setregistry(J, s); + return s; +} + +void js_unref(js_State *J, const char *ref) +{ + js_delregistry(J, ref); +} + +void js_getregistry(js_State *J, const char *name) +{ + jsR_getproperty(J, J->R, name); +} + +void js_setregistry(js_State *J, const char *name) +{ + jsR_setproperty(J, J->R, name, 0); + js_pop(J, 1); +} + +void js_delregistry(js_State *J, const char *name) +{ + jsR_delproperty(J, J->R, name); +} + +void js_getglobal(js_State *J, const char *name) +{ + jsR_getproperty(J, J->G, name); +} + +void js_setglobal(js_State *J, const char *name) +{ + jsR_setproperty(J, J->G, name, 0); + js_pop(J, 1); +} + +void js_defglobal(js_State *J, const char *name, int atts) +{ + jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL, 0); + js_pop(J, 1); +} + +void js_delglobal(js_State *J, const char *name) +{ + jsR_delproperty(J, J->G, name); +} + +void js_getproperty(js_State *J, int idx, const char *name) +{ + jsR_getproperty(J, js_toobject(J, idx), name); +} + +void js_setproperty(js_State *J, int idx, const char *name) +{ + jsR_setproperty(J, js_toobject(J, idx), name, !js_isobject(J, idx)); + js_pop(J, 1); +} + +void js_defproperty(js_State *J, int idx, const char *name, int atts) +{ + jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL, 1); + js_pop(J, 1); +} + +void js_delproperty(js_State *J, int idx, const char *name) +{ + jsR_delproperty(J, js_toobject(J, idx), name); +} + +void js_defaccessor(js_State *J, int idx, const char *name, int atts) +{ + jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1), 1); + js_pop(J, 2); +} + +int js_hasproperty(js_State *J, int idx, const char *name) +{ + return jsR_hasproperty(J, js_toobject(J, idx), name); +} + +void js_getindex(js_State *J, int idx, int i) +{ + jsR_getindex(J, js_toobject(J, idx), i); +} + +int js_hasindex(js_State *J, int idx, int i) +{ + return jsR_hasindex(J, js_toobject(J, idx), i); +} + +void js_setindex(js_State *J, int idx, int i) +{ + jsR_setindex(J, js_toobject(J, idx), i, !js_isobject(J, idx)); + js_pop(J, 1); +} + +void js_delindex(js_State *J, int idx, int i) +{ + jsR_delindex(J, js_toobject(J, idx), i); +} + +/* Iterator */ + +void js_pushiterator(js_State *J, int idx, int own) +{ + js_pushobject(J, jsV_newiterator(J, js_toobject(J, idx), own)); +} + +const char *js_nextiterator(js_State *J, int idx) +{ + return jsV_nextiterator(J, js_toobject(J, idx)); +} + +/* Environment records */ + +js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer) +{ + js_Environment *E = js_malloc(J, sizeof *E); + E->gcmark = 0; + E->gcnext = J->gcenv; + J->gcenv = E; + ++J->gccounter; + + E->outer = outer; + E->variables = vars; + return E; +} + +static void js_initvar(js_State *J, const char *name, int idx) +{ + jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL, 0); +} + +static int js_hasvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getproperty(J, E->variables, name); + if (ref) { + if (ref->getter) { + js_pushobject(J, ref->getter); + js_pushobject(J, E->variables); + js_call(J, 0); + } else { + js_pushvalue(J, ref->value); + } + return 1; + } + E = E->outer; + } while (E); + return 0; +} + +static void js_setvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getproperty(J, E->variables, name); + if (ref) { + if (ref->setter) { + js_pushobject(J, ref->setter); + js_pushobject(J, E->variables); + js_copy(J, -3); + js_call(J, 1); + js_pop(J, 1); + return; + } + if (!(ref->atts & JS_READONLY)) + ref->value = *stackidx(J, -1); + else if (J->strict) + js_typeerror(J, "'%s' is read-only", name); + return; + } + E = E->outer; + } while (E); + if (J->strict) + js_referenceerror(J, "assignment to undeclared variable '%s'", name); + jsR_setproperty(J, J->G, name, 0); +} + +static int js_delvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getownproperty(J, E->variables, name); + if (ref) { + if (ref->atts & JS_DONTCONF) { + if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + return 0; + } + jsV_delproperty(J, E->variables, name); + return 1; + } + E = E->outer; + } while (E); + return jsR_delproperty(J, J->G, name); +} + +/* Function calls */ + +static void jsR_savescope(js_State *J, js_Environment *newE) +{ + if (J->envtop + 1 >= JS_ENVLIMIT) + js_stackoverflow(J); + J->envstack[J->envtop++] = J->E; + J->E = newE; +} + +static void jsR_restorescope(js_State *J) +{ + J->E = J->envstack[--J->envtop]; +} + +static void jsR_calllwfunction(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + jsR_savescope(J, scope); + + if (n > F->numparams) { + js_pop(J, n - F->numparams); + n = F->numparams; + } + + for (i = n; i < F->varlen; ++i) + js_pushundefined(J); + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + jsR_restorescope(J); +} + +static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope); + + jsR_savescope(J, scope); + + if (F->arguments) { + js_newarguments(J); + if (!J->strict) { + js_currentfunction(J); + js_defproperty(J, -2, "callee", JS_DONTENUM); + } + js_pushnumber(J, n); + js_defproperty(J, -2, "length", JS_DONTENUM); + for (i = 0; i < n; ++i) { + js_copy(J, i + 1); + js_setindex(J, -2, i); + } + js_initvar(J, "arguments", -1); + js_pop(J, 1); + } + + for (i = 0; i < n && i < F->numparams; ++i) + js_initvar(J, F->vartab[i], i + 1); + js_pop(J, n); + + for (; i < F->varlen; ++i) { + js_pushundefined(J); + js_initvar(J, F->vartab[i], -1); + js_pop(J, 1); + } + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + jsR_restorescope(J); +} + +static void jsR_callscript(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + if (scope) + jsR_savescope(J, scope); + + /* scripts take no arguments */ + js_pop(J, n); + + for (i = 0; i < F->varlen; ++i) { + /* Bug 701886: don't redefine existing vars in eval/scripts */ + if (!js_hasvar(J, F->vartab[i])) { + js_pushundefined(J); + js_initvar(J, F->vartab[i], -1); + js_pop(J, 1); + } + } + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + if (scope) + jsR_restorescope(J); +} + +static void jsR_callcfunction(js_State *J, int n, int min, js_CFunction F) +{ + int save_top; + int i; + js_Value v; + + for (i = n; i < min; ++i) + js_pushundefined(J); + + save_top = TOP; + F(J); + if (TOP > save_top) { + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + } else { + TOP = --BOT; /* clear stack */ + js_pushundefined(J); + } +} + +static void jsR_pushtrace(js_State *J, const char *name, const char *file, int line) +{ + if (J->tracetop + 1 == JS_ENVLIMIT) + js_error(J, "call stack overflow"); + ++J->tracetop; + J->trace[J->tracetop].name = name; + J->trace[J->tracetop].file = file; + J->trace[J->tracetop].line = line; +} + +void js_call(js_State *J, int n) +{ + js_Object *obj; + int savebot; + + if (n < 0) + js_rangeerror(J, "number of arguments cannot be negative"); + + if (!js_iscallable(J, -n-2)) + js_typeerror(J, "%s is not callable", js_typeof(J, -n-2)); + + obj = js_toobject(J, -n-2); + + savebot = BOT; + BOT = TOP - n - 1; + + if (obj->type == JS_CFUNCTION) { + jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); + if (obj->u.f.function->lightweight) + jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope); + else + jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope); + --J->tracetop; + } else if (obj->type == JS_CSCRIPT) { + jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); + jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope); + --J->tracetop; + } else if (obj->type == JS_CCFUNCTION) { + jsR_pushtrace(J, obj->u.c.name, "native", 0); + jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function); + --J->tracetop; + } + + BOT = savebot; +} + +void js_construct(js_State *J, int n) +{ + js_Object *obj; + js_Object *prototype; + js_Object *newobj; + + if (!js_iscallable(J, -n-1)) + js_typeerror(J, "%s is not callable", js_typeof(J, -n-1)); + + obj = js_toobject(J, -n-1); + + /* built-in constructors create their own objects, give them a 'null' this */ + if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) { + int savebot = BOT; + js_pushnull(J); + if (n > 0) + js_rot(J, n + 1); + BOT = TOP - n - 1; + + jsR_pushtrace(J, obj->u.c.name, "native", 0); + jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor); + --J->tracetop; + + BOT = savebot; + return; + } + + /* extract the function object's prototype property */ + js_getproperty(J, -n - 1, "prototype"); + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + else + prototype = J->Object_prototype; + js_pop(J, 1); + + /* create a new object with above prototype, and shift it into the 'this' slot */ + newobj = jsV_newobject(J, JS_COBJECT, prototype); + js_pushobject(J, newobj); + if (n > 0) + js_rot(J, n + 1); + + /* and save a copy to return */ + js_pushobject(J, newobj); + js_rot(J, n + 3); + + /* call the function */ + js_call(J, n); + + /* if result is not an object, return the original object we created */ + if (!js_isobject(J, -1)) { + js_pop(J, 1); + } else { + js_rot2pop1(J); + } +} + +void js_eval(js_State *J) +{ + if (!js_isstring(J, -1)) + return; + js_loadeval(J, "(eval)", js_tostring(J, -1)); + js_rot2pop1(J); + js_copy(J, 0); /* copy 'this' */ + js_call(J, 0); +} + +int js_pconstruct(js_State *J, int n) +{ + int savetop = TOP - n - 2; + if (js_try(J)) { + /* clean up the stack to only hold the error object */ + STACK[savetop] = STACK[TOP-1]; + TOP = savetop + 1; + return 1; + } + js_construct(J, n); + js_endtry(J); + return 0; +} + +int js_pcall(js_State *J, int n) +{ + int savetop = TOP - n - 2; + if (js_try(J)) { + /* clean up the stack to only hold the error object */ + STACK[savetop] = STACK[TOP-1]; + TOP = savetop + 1; + return 1; + } + js_call(J, n); + js_endtry(J); + return 0; +} + +/* Exceptions */ + +void *js_savetrypc(js_State *J, js_Instruction *pc) +{ + if (J->trytop == JS_TRYLIMIT) + js_trystackoverflow(J); + J->trybuf[J->trytop].E = J->E; + J->trybuf[J->trytop].envtop = J->envtop; + J->trybuf[J->trytop].tracetop = J->tracetop; + J->trybuf[J->trytop].top = J->top; + J->trybuf[J->trytop].bot = J->bot; + J->trybuf[J->trytop].strict = J->strict; + J->trybuf[J->trytop].pc = pc; + return J->trybuf[J->trytop++].buf; +} + +void *js_savetry(js_State *J) +{ + if (J->trytop == JS_TRYLIMIT) + js_trystackoverflow(J); + J->trybuf[J->trytop].E = J->E; + J->trybuf[J->trytop].envtop = J->envtop; + J->trybuf[J->trytop].tracetop = J->tracetop; + J->trybuf[J->trytop].top = J->top; + J->trybuf[J->trytop].bot = J->bot; + J->trybuf[J->trytop].strict = J->strict; + J->trybuf[J->trytop].pc = NULL; + return J->trybuf[J->trytop++].buf; +} + +void js_endtry(js_State *J) +{ + if (J->trytop == 0) + js_error(J, "endtry: exception stack underflow"); + --J->trytop; +} + +void js_throw(js_State *J) +{ + if (J->trytop > 0) { + js_Value v = *stackidx(J, -1); + --J->trytop; + J->E = J->trybuf[J->trytop].E; + J->envtop = J->trybuf[J->trytop].envtop; + J->tracetop = J->trybuf[J->trytop].tracetop; + J->top = J->trybuf[J->trytop].top; + J->bot = J->trybuf[J->trytop].bot; + J->strict = J->trybuf[J->trytop].strict; + js_pushvalue(J, v); + longjmp(J->trybuf[J->trytop].buf, 1); + } + if (J->panic) + J->panic(J); + abort(); +} + +/* Main interpreter loop */ + +static void js_dumpvalue(js_State *J, js_Value v) +{ + switch (v.t.type) { + case JS_TUNDEFINED: printf("undefined"); break; + case JS_TNULL: printf("null"); break; + case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break; + case JS_TNUMBER: printf("%.9g", v.u.number); break; + case JS_TSHRSTR: printf("'%s'", v.u.shrstr); break; + case JS_TLITSTR: printf("'%s'", v.u.litstr); break; + case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break; + case JS_TOBJECT: + if (v.u.object == J->G) { + printf("[Global]"); + break; + } + switch (v.u.object->type) { + case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break; + case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break; + case JS_CFUNCTION: + printf("[Function %p, %s, %s:%d]", + (void*)v.u.object, + v.u.object->u.f.function->name, + v.u.object->u.f.function->filename, + v.u.object->u.f.function->line); + break; + case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break; + case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break; + case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break; + case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break; + case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break; + case JS_CERROR: printf("[Error]"); break; + case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break; + case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break; + case JS_CUSERDATA: + printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data); + break; + default: printf("[Object %p]", (void*)v.u.object); break; + } + break; + } +} + +static void js_stacktrace(js_State *J) +{ + int n; + printf("stack trace:\n"); + for (n = J->tracetop; n >= 0; --n) { + const char *name = J->trace[n].name; + const char *file = J->trace[n].file; + int line = J->trace[n].line; + if (line > 0) { + if (name[0]) + printf("\tat %s (%s:%d)\n", name, file, line); + else + printf("\tat %s:%d\n", file, line); + } else + printf("\tat %s (%s)\n", name, file); + } +} + +static void js_dumpstack(js_State *J) +{ + int i; + printf("stack {\n"); + for (i = 0; i < TOP; ++i) { + putchar(i == BOT ? '>' : ' '); + printf("%4d: ", i); + js_dumpvalue(J, STACK[i]); + putchar('\n'); + } + printf("}\n"); +} + +void js_trap(js_State *J, int pc) +{ + js_dumpstack(J); + js_stacktrace(J); +} + +static int jsR_isindex(js_State *J, int idx, int *k) +{ + js_Value *v = stackidx(J, idx); + if (v->t.type == JS_TNUMBER) { + *k = v->u.number; + return *k == v->u.number && *k >= 0; + } + return 0; +} + +static void jsR_run(js_State *J, js_Function *F) +{ + js_Function **FT = F->funtab; + const char **VT = F->vartab-1; + int lightweight = F->lightweight; + js_Instruction *pcstart = F->code; + js_Instruction *pc = F->code; + enum js_OpCode opcode; + int offset; + int savestrict; + + const char *str; + js_Object *obj; + double x, y; + unsigned int ux, uy; + int ix, iy, okay; + int b; + int transient; + + savestrict = J->strict; + J->strict = F->strict; + +#define READSTRING() \ + memcpy(&str, pc, sizeof(str)); \ + pc += sizeof(str) / sizeof(*pc) + + while (1) { + if (J->gccounter > J->gcthresh) + js_gc(J, 0); + + J->trace[J->tracetop].line = *pc++; + + opcode = *pc++; + + switch (opcode) { + case OP_POP: js_pop(J, 1); break; + case OP_DUP: js_dup(J); break; + case OP_DUP2: js_dup2(J); break; + case OP_ROT2: js_rot2(J); break; + case OP_ROT3: js_rot3(J); break; + case OP_ROT4: js_rot4(J); break; + + case OP_INTEGER: + js_pushnumber(J, *pc++ - 32768); + break; + + case OP_NUMBER: + memcpy(&x, pc, sizeof(x)); + pc += sizeof(x) / sizeof(*pc); + js_pushnumber(J, x); + break; + + case OP_STRING: + READSTRING(); + js_pushliteral(J, str); + break; + + case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break; + case OP_NEWOBJECT: js_newobject(J); break; + case OP_NEWARRAY: js_newarray(J); break; + case OP_NEWREGEXP: + READSTRING(); + js_newregexp(J, str, *pc++); + break; + + case OP_UNDEF: js_pushundefined(J); break; + case OP_NULL: js_pushnull(J); break; + case OP_TRUE: js_pushboolean(J, 1); break; + case OP_FALSE: js_pushboolean(J, 0); break; + + case OP_THIS: + if (J->strict) { + js_copy(J, 0); + } else { + if (js_iscoercible(J, 0)) + js_copy(J, 0); + else + js_pushglobal(J); + } + break; + + case OP_CURRENT: + js_currentfunction(J); + break; + + case OP_GETLOCAL: + if (lightweight) { + CHECKSTACK(1); + STACK[TOP++] = STACK[BOT + *pc++]; + } else { + str = VT[*pc++]; + if (!js_hasvar(J, str)) + js_referenceerror(J, "'%s' is not defined", str); + } + break; + + case OP_SETLOCAL: + if (lightweight) { + STACK[BOT + *pc++] = STACK[TOP-1]; + } else { + js_setvar(J, VT[*pc++]); + } + break; + + case OP_DELLOCAL: + if (lightweight) { + ++pc; + js_pushboolean(J, 0); + } else { + b = js_delvar(J, VT[*pc++]); + js_pushboolean(J, b); + } + break; + + case OP_GETVAR: + READSTRING(); + if (!js_hasvar(J, str)) + js_referenceerror(J, "'%s' is not defined", str); + break; + + case OP_HASVAR: + READSTRING(); + if (!js_hasvar(J, str)) + js_pushundefined(J); + break; + + case OP_SETVAR: + READSTRING(); + js_setvar(J, str); + break; + + case OP_DELVAR: + READSTRING(); + b = js_delvar(J, str); + js_pushboolean(J, b); + break; + + case OP_IN: + str = js_tostring(J, -2); + if (!js_isobject(J, -1)) + js_typeerror(J, "operand to 'in' is not an object"); + b = js_hasproperty(J, -1, str); + js_pop(J, 2 + b); + js_pushboolean(J, b); + break; + + case OP_SKIPARRAY: + js_setlength(J, -1, js_getlength(J, -1) + 1); + break; + case OP_INITARRAY: + js_setindex(J, -2, js_getlength(J, -2)); + break; + + case OP_INITPROP: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_setproperty(J, obj, str, 0); + js_pop(J, 2); + break; + + case OP_INITGETTER: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL, 0); + js_pop(J, 2); + break; + + case OP_INITSETTER: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1), 0); + js_pop(J, 2); + break; + + case OP_GETPROP: + if (jsR_isindex(J, -1, &ix)) { + obj = js_toobject(J, -2); + jsR_getindex(J, obj, ix); + } else { + str = js_tostring(J, -1); + obj = js_toobject(J, -2); + jsR_getproperty(J, obj, str); + } + js_rot3pop2(J); + break; + + case OP_GETPROP_S: + READSTRING(); + obj = js_toobject(J, -1); + jsR_getproperty(J, obj, str); + js_rot2pop1(J); + break; + + case OP_SETPROP: + if (jsR_isindex(J, -2, &ix)) { + obj = js_toobject(J, -3); + transient = !js_isobject(J, -3); + jsR_setindex(J, obj, ix, transient); + } else { + str = js_tostring(J, -2); + obj = js_toobject(J, -3); + transient = !js_isobject(J, -3); + jsR_setproperty(J, obj, str, transient); + } + js_rot3pop2(J); + break; + + case OP_SETPROP_S: + READSTRING(); + obj = js_toobject(J, -2); + transient = !js_isobject(J, -2); + jsR_setproperty(J, obj, str, transient); + js_rot2pop1(J); + break; + + case OP_DELPROP: + str = js_tostring(J, -1); + obj = js_toobject(J, -2); + b = jsR_delproperty(J, obj, str); + js_pop(J, 2); + js_pushboolean(J, b); + break; + + case OP_DELPROP_S: + READSTRING(); + obj = js_toobject(J, -1); + b = jsR_delproperty(J, obj, str); + js_pop(J, 1); + js_pushboolean(J, b); + break; + + case OP_ITERATOR: + if (js_iscoercible(J, -1)) { + obj = jsV_newiterator(J, js_toobject(J, -1), 0); + js_pop(J, 1); + js_pushobject(J, obj); + } + break; + + case OP_NEXTITER: + if (js_isobject(J, -1)) { + obj = js_toobject(J, -1); + str = jsV_nextiterator(J, obj); + if (str) { + js_pushstring(J, str); + js_pushboolean(J, 1); + } else { + js_pop(J, 1); + js_pushboolean(J, 0); + } + } else { + js_pop(J, 1); + js_pushboolean(J, 0); + } + break; + + /* Function calls */ + + case OP_EVAL: + js_eval(J); + break; + + case OP_CALL: + js_call(J, *pc++); + break; + + case OP_NEW: + js_construct(J, *pc++); + break; + + /* Unary operators */ + + case OP_TYPEOF: + str = js_typeof(J, -1); + js_pop(J, 1); + js_pushliteral(J, str); + break; + + case OP_POS: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x); + break; + + case OP_NEG: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, -x); + break; + + case OP_BITNOT: + ix = js_toint32(J, -1); + js_pop(J, 1); + js_pushnumber(J, ~ix); + break; + + case OP_LOGNOT: + b = js_toboolean(J, -1); + js_pop(J, 1); + js_pushboolean(J, !b); + break; + + case OP_INC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x + 1); + break; + + case OP_DEC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x - 1); + break; + + case OP_POSTINC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x + 1); + js_pushnumber(J, x); + break; + + case OP_POSTDEC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x - 1); + js_pushnumber(J, x); + break; + + /* Multiplicative operators */ + + case OP_MUL: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x * y); + break; + + case OP_DIV: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x / y); + break; + + case OP_MOD: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, fmod(x, y)); + break; + + /* Additive operators */ + + case OP_ADD: + js_concat(J); + break; + + case OP_SUB: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x - y); + break; + + /* Shift operators */ + + case OP_SHL: + ix = js_toint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix << (uy & 0x1F)); + break; + + case OP_SHR: + ix = js_toint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix >> (uy & 0x1F)); + break; + + case OP_USHR: + ux = js_touint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ux >> (uy & 0x1F)); + break; + + /* Relational operators */ + + case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break; + case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break; + case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break; + case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break; + + case OP_INSTANCEOF: + b = js_instanceof(J); + js_pop(J, 2); + js_pushboolean(J, b); + break; + + /* Equality */ + + case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break; + case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break; + case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break; + case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break; + + case OP_JCASE: + offset = *pc++; + b = js_strictequal(J); + if (b) { + js_pop(J, 2); + pc = pcstart + offset; + } else { + js_pop(J, 1); + } + break; + + /* Binary bitwise operators */ + + case OP_BITAND: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix & iy); + break; + + case OP_BITXOR: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix ^ iy); + break; + + case OP_BITOR: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix | iy); + break; + + /* Try and Catch */ + + case OP_THROW: + js_throw(J); + + case OP_TRY: + offset = *pc++; + if (js_trypc(J, pc)) { + pc = J->trybuf[J->trytop].pc; + } else { + pc = pcstart + offset; + } + break; + + case OP_ENDTRY: + js_endtry(J); + break; + + case OP_CATCH: + READSTRING(); + obj = jsV_newobject(J, JS_COBJECT, NULL); + js_pushobject(J, obj); + js_rot2(J); + js_setproperty(J, -2, str); + J->E = jsR_newenvironment(J, obj, J->E); + js_pop(J, 1); + break; + + case OP_ENDCATCH: + J->E = J->E->outer; + break; + + /* With */ + + case OP_WITH: + obj = js_toobject(J, -1); + J->E = jsR_newenvironment(J, obj, J->E); + js_pop(J, 1); + break; + + case OP_ENDWITH: + J->E = J->E->outer; + break; + + /* Branching */ + + case OP_DEBUGGER: + js_trap(J, (int)(pc - pcstart) - 1); + break; + + case OP_JUMP: + pc = pcstart + *pc; + break; + + case OP_JTRUE: + offset = *pc++; + b = js_toboolean(J, -1); + js_pop(J, 1); + if (b) + pc = pcstart + offset; + break; + + case OP_JFALSE: + offset = *pc++; + b = js_toboolean(J, -1); + js_pop(J, 1); + if (!b) + pc = pcstart + offset; + break; + + case OP_RETURN: + J->strict = savestrict; + return; + } + } +} diff --git a/src/mujs/jsstate.c b/src/mujs/jsstate.c new file mode 100644 index 0000000..715b793 --- /dev/null +++ b/src/mujs/jsstate.c @@ -0,0 +1,334 @@ +#include "jsi.h" + +#include +#include + +static int js_ptry(js_State *J) { + if (J->trytop == JS_TRYLIMIT) { + J->stack[J->top].t.type = JS_TLITSTR; + J->stack[J->top].u.litstr = "exception stack overflow"; + ++J->top; + return 1; + } + return 0; +} + +static void *js_defaultalloc(void *actx, void *ptr, int size) +{ + if (size == 0) { + free(ptr); + return NULL; + } + return realloc(ptr, (size_t)size); +} + +static void js_defaultreport(js_State *J, const char *message) +{ + fputs(message, stderr); + fputc('\n', stderr); +} + +static void js_defaultpanic(js_State *J) +{ + js_report(J, "uncaught exception"); + /* return to javascript to abort */ +} + +int js_ploadstring(js_State *J, const char *filename, const char *source) +{ + if (js_ptry(J)) + return 1; + if (js_try(J)) + return 1; + js_loadstring(J, filename, source); + js_endtry(J); + return 0; +} + +int js_ploadfile(js_State *J, const char *filename) +{ + if (js_ptry(J)) + return 1; + if (js_try(J)) + return 1; + js_loadfile(J, filename); + js_endtry(J); + return 0; +} + +const char *js_trystring(js_State *J, int idx, const char *error) +{ + const char *s; + if (js_ptry(J)) { + js_pop(J, 1); + return error; + } + if (js_try(J)) { + js_pop(J, 1); + return error; + } + s = js_tostring(J, idx); + js_endtry(J); + return s; +} + +double js_trynumber(js_State *J, int idx, double error) +{ + double v; + if (js_ptry(J)) { + js_pop(J, 1); + return error; + } + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_tonumber(J, idx); + js_endtry(J); + return v; +} + +int js_tryinteger(js_State *J, int idx, int error) +{ + int v; + if (js_ptry(J)) { + js_pop(J, 1); + return error; + } + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_tointeger(J, idx); + js_endtry(J); + return v; +} + +int js_tryboolean(js_State *J, int idx, int error) +{ + int v; + if (js_ptry(J)) { + js_pop(J, 1); + return error; + } + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_toboolean(J, idx); + js_endtry(J); + return v; +} + +static void js_loadstringx(js_State *J, const char *filename, const char *source, int iseval) +{ + js_Ast *P; + js_Function *F; + + if (js_try(J)) { + jsP_freeparse(J); + js_throw(J); + } + + P = jsP_parse(J, filename, source); + F = jsC_compilescript(J, P, iseval ? J->strict : J->default_strict); + jsP_freeparse(J); + js_newscript(J, F, iseval ? (J->strict ? J->E : NULL) : J->GE); + + js_endtry(J); +} + +void js_loadeval(js_State *J, const char *filename, const char *source) +{ + js_loadstringx(J, filename, source, 1); +} + +void js_loadstring(js_State *J, const char *filename, const char *source) +{ + js_loadstringx(J, filename, source, 0); +} + +void js_loadfile(js_State *J, const char *filename) +{ + FILE *f; + char *s, *p; + int n, t; + + f = fopen(filename, "rb"); + if (!f) { + js_error(J, "cannot open file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_END) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + n = ftell(f); + if (n < 0) { + fclose(f); + js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_SET) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + if (js_try(J)) { + fclose(f); + js_throw(J); + } + s = js_malloc(J, n + 1); /* add space for string terminator */ + js_endtry(J); + + t = fread(s, 1, (size_t)n, f); + if (t != n) { + js_free(J, s); + fclose(f); + js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno)); + } + + s[n] = 0; /* zero-terminate string containing file data */ + + if (js_try(J)) { + js_free(J, s); + fclose(f); + js_throw(J); + } + + /* skip first line if it starts with "#!" */ + p = s; + if (p[0] == '#' && p[1] == '!') { + p += 2; + while (*p && *p != '\n') + ++p; + } + + js_loadstring(J, filename, p); + + js_free(J, s); + fclose(f); + js_endtry(J); +} + +int js_dostring(js_State *J, const char *source) +{ + if (js_ptry(J)) { + js_report(J, "exception stack overflow"); + js_pop(J, 1); + return 1; + } + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_loadstring(J, "[string]", source); + js_pushundefined(J); + js_call(J, 0); + js_pop(J, 1); + js_endtry(J); + return 0; +} + +int js_dofile(js_State *J, const char *filename) +{ + if (js_ptry(J)) { + js_report(J, "exception stack overflow"); + js_pop(J, 1); + return 1; + } + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_loadfile(J, filename); + js_pushundefined(J); + js_call(J, 0); + js_pop(J, 1); + js_endtry(J); + return 0; +} + +js_Panic js_atpanic(js_State *J, js_Panic panic) +{ + js_Panic old = J->panic; + J->panic = panic; + return old; +} + +void js_report(js_State *J, const char *message) +{ + if (J->report) + J->report(J, message); +} + +void js_setreport(js_State *J, js_Report report) +{ + J->report = report; +} + +void js_setcontext(js_State *J, void *uctx) +{ + J->uctx = uctx; +} + +void *js_getcontext(js_State *J) +{ + return J->uctx; +} + +js_State *js_newstate(js_Alloc alloc, void *actx, int flags) +{ + js_State *J; + + assert(sizeof(js_Value) == 16); + assert(soffsetof(js_Value, t.type) == 15); + + if (!alloc) + alloc = js_defaultalloc; + + J = alloc(actx, NULL, sizeof *J); + if (!J) + return NULL; + memset(J, 0, sizeof(*J)); + J->actx = actx; + J->alloc = alloc; + + if (flags & JS_STRICT) + J->strict = J->default_strict = 1; + + J->trace[0].name = "-top-"; + J->trace[0].file = "native"; + J->trace[0].line = 0; + + J->report = js_defaultreport; + J->panic = js_defaultpanic; + + J->stack = alloc(actx, NULL, JS_STACKSIZE * sizeof *J->stack); + if (!J->stack) { + alloc(actx, J, 0); + return NULL; + } + + J->gcmark = 1; + J->nextref = 0; + J->gcthresh = 0; /* reaches stability within ~ 2-5 GC cycles */ + + if (js_try(J)) { + js_freestate(J); + return NULL; + } + + J->R = jsV_newobject(J, JS_COBJECT, NULL); + J->G = jsV_newobject(J, JS_COBJECT, NULL); + J->E = jsR_newenvironment(J, J->G, NULL); + J->GE = J->E; + + jsB_init(J); + + js_endtry(J); + return J; +} diff --git a/src/mujs/jsstring.c b/src/mujs/jsstring.c new file mode 100644 index 0000000..4954d75 --- /dev/null +++ b/src/mujs/jsstring.c @@ -0,0 +1,848 @@ +#include "jsi.h" +#include "utf.h" +#include "regexp.h" + +static int js_doregexec(js_State *J, Reprog *prog, const char *string, Resub *sub, int eflags) +{ + int result = js_regexec(prog, string, sub, eflags); + if (result < 0) + js_error(J, "regexec failed"); + return result; +} + +static const char *checkstring(js_State *J, int idx) +{ + if (!js_iscoercible(J, idx)) + js_typeerror(J, "string function called on null or undefined"); + return js_tostring(J, idx); +} + +int js_runeat(js_State *J, const char *s, int i) +{ + Rune rune = EOF; + while (i >= 0) { + rune = *(unsigned char*)s; + if (rune < Runeself) { + if (rune == 0) + return EOF; + ++s; + --i; + } else { + s += chartorune(&rune, s); + if (rune >= 0x10000) + i -= 2; + else + --i; + } + } + if (rune >= 0x10000) { + /* high surrogate */ + if (i == -2) + return 0xd800 + ((rune - 0x10000) >> 10); + /* low surrogate */ + else + return 0xdc00 + ((rune - 0x10000) & 0x3ff); + } + return rune; +} + +int js_utflen(const char *s) +{ + int c; + int n; + Rune rune; + + n = 0; + for(;;) { + c = *(unsigned char *)s; + if (c < Runeself) { + if (c == 0) + return n; + s++; + n++; + } else { + s += chartorune(&rune, s); + if (rune >= 0x10000) + n += 2; + else + n++; + } + } +} + +int js_utfptrtoidx(const char *s, const char *p) +{ + Rune rune; + int i = 0; + while (s < p) { + if (*(unsigned char *)s < Runeself) + ++s; + else + s += chartorune(&rune, s); + if (rune >= 0x10000) + i += 2; + else + i += 1; + } + return i; +} + +static void jsB_new_String(js_State *J) +{ + js_newstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); +} + +static void jsB_String(js_State *J) +{ + js_pushstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); +} + +static void Sp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); + js_pushstring(J, self->u.s.string); +} + +static void Sp_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); + js_pushstring(J, self->u.s.string); +} + +static void Sp_charAt(js_State *J) +{ + char buf[UTFmax + 1]; + const char *s = checkstring(J, 0); + int pos = js_tointeger(J, 1); + Rune rune = js_runeat(J, s, pos); + if (rune >= 0) { + buf[runetochar(buf, &rune)] = 0; + js_pushstring(J, buf); + } else { + js_pushliteral(J, ""); + } +} + +static void Sp_charCodeAt(js_State *J) +{ + const char *s = checkstring(J, 0); + int pos = js_tointeger(J, 1); + Rune rune = js_runeat(J, s, pos); + if (rune >= 0) + js_pushnumber(J, rune); + else + js_pushnumber(J, NAN); +} + +static void Sp_concat(js_State *J) +{ + int i, top = js_gettop(J); + int n; + char * volatile out = NULL; + const char *s; + + if (top == 1) + return; + + s = checkstring(J, 0); + n = 1 + strlen(s); + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + if (n > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + out = js_malloc(J, n); + strcpy(out, s); + + for (i = 1; i < top; ++i) { + s = js_tostring(J, i); + n += strlen(s); + if (n > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + out = js_realloc(J, out, n); + strcat(out, s); + } + + js_pushstring(J, out); + js_endtry(J); + js_free(J, out); +} + +static void Sp_indexOf(js_State *J) +{ + const char *haystack = checkstring(J, 0); + const char *needle = js_tostring(J, 1); + int pos = js_tointeger(J, 2); + int len = strlen(needle); + int k = 0; + Rune rune; + while (*haystack) { + if (k >= pos && !strncmp(haystack, needle, len)) { + js_pushnumber(J, k); + return; + } + haystack += chartorune(&rune, haystack); + ++k; + } + js_pushnumber(J, -1); +} + +static void Sp_lastIndexOf(js_State *J) +{ + const char *haystack = checkstring(J, 0); + const char *needle = js_tostring(J, 1); + int pos = js_isdefined(J, 2) ? js_tointeger(J, 2) : (int)strlen(haystack); + int len = strlen(needle); + int k = 0, last = -1; + Rune rune; + while (*haystack && k <= pos) { + if (!strncmp(haystack, needle, len)) + last = k; + haystack += chartorune(&rune, haystack); + ++k; + } + js_pushnumber(J, last); +} + +static void Sp_localeCompare(js_State *J) +{ + const char *a = checkstring(J, 0); + const char *b = js_tostring(J, 1); + js_pushnumber(J, strcmp(a, b)); +} + +static void Sp_substring_imp(js_State *J, const char *s, int a, int n) +{ + Rune head_rune = 0, tail_rune = 0; + const char *head, *tail; + char *p; + int i, k, head_len, tail_len; + + /* find start of substring */ + head = s; + for (i = 0; i < a; ++i) { + head += chartorune(&head_rune, head); + if (head_rune >= 0x10000) + ++i; + } + + /* find end of substring */ + tail = head; + for (k = i - a; k < n; ++k) { + tail += chartorune(&tail_rune, tail); + if (tail_rune >= 0x10000) + ++k; + } + + /* no surrogate pair splits! */ + if (i == a && k == n) { + js_pushlstring(J, head, tail - head); + return; + } + + if (js_try(J)) { + js_free(J, p); + js_throw(J); + } + + p = js_malloc(J, UTFmax + (tail - head)); + + /* substring starts with low surrogate (head is just after character) */ + if (i > a) { + head_rune = 0xdc00 + ((head_rune - 0x10000) & 0x3ff); + head_len = runetochar(p, &head_rune); + memcpy(p + head_len, head, tail - head); + js_pushlstring(J, p, head_len + (tail - head)); + } + + /* substring ends with high surrogate (tail is just after character) */ + if (k > n) { + tail -= runelen(tail_rune); + memcpy(p, head, tail - head); + tail_rune = 0xd800 + ((tail_rune - 0x10000) >> 10); + tail_len = runetochar(p + (tail - head), &tail_rune); + js_pushlstring(J, p, (tail - head) + tail_len); + } + + js_endtry(J); + js_free(J, p); +} + +static void Sp_slice(js_State *J) +{ + const char *str = checkstring(J, 0); + int len = js_utflen(str); + int s = js_tointeger(J, 1); + int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + s = s < 0 ? s + len : s; + e = e < 0 ? e + len : e; + + s = s < 0 ? 0 : s > len ? len : s; + e = e < 0 ? 0 : e > len ? len : e; + + if (s < e) + Sp_substring_imp(J, str, s, e - s); + else + Sp_substring_imp(J, str, e, s - e); +} + +static void Sp_substring(js_State *J) +{ + const char *str = checkstring(J, 0); + int len = js_utflen(str); + int s = js_tointeger(J, 1); + int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + s = s < 0 ? 0 : s > len ? len : s; + e = e < 0 ? 0 : e > len ? len : e; + + if (s < e) + Sp_substring_imp(J, str, s, e - s); + else + Sp_substring_imp(J, str, e, s - e); +} + +static void Sp_toLowerCase(js_State *J) +{ + const char *s, *s0 = checkstring(J, 0); + char * volatile dst = NULL; + char *d; + Rune rune; + const Rune *full; + int n; + + n = 1; + for (s = s0; *s;) { + s += chartorune(&rune, s); + full = tolowerrune_full(rune); + if (full) { + while (*full) { + n += runelen(*full); + ++full; + } + } else { + rune = tolowerrune(rune); + n += runelen(rune); + } + } + + if (js_try(J)) { + js_free(J, dst); + js_throw(J); + } + + d = dst = js_malloc(J, n); + for (s = s0; *s;) { + s += chartorune(&rune, s); + full = tolowerrune_full(rune); + if (full) { + while (*full) { + d += runetochar(d, full); + ++full; + } + } else { + rune = tolowerrune(rune); + d += runetochar(d, &rune); + } + } + *d = 0; + + js_pushstring(J, dst); + js_endtry(J); + js_free(J, dst); +} + +static void Sp_toUpperCase(js_State *J) +{ + const char *s, *s0 = checkstring(J, 0); + char * volatile dst = NULL; + char *d; + const Rune *full; + Rune rune; + int n; + + n = 1; + for (s = s0; *s;) { + s += chartorune(&rune, s); + full = toupperrune_full(rune); + if (full) { + while (*full) { + n += runelen(*full); + ++full; + } + } else { + rune = toupperrune(rune); + n += runelen(rune); + } + } + + if (js_try(J)) { + js_free(J, dst); + js_throw(J); + } + + d = dst = js_malloc(J, n); + for (s = s0; *s;) { + s += chartorune(&rune, s); + full = toupperrune_full(rune); + if (full) { + while (*full) { + d += runetochar(d, full); + ++full; + } + } else { + rune = toupperrune(rune); + d += runetochar(d, &rune); + } + } + *d = 0; + + js_pushstring(J, dst); + js_endtry(J); + js_free(J, dst); +} + +static int istrim(int c) +{ + return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF || + c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +static void Sp_trim(js_State *J) +{ + const char *s, *e; + s = checkstring(J, 0); + while (istrim(*s)) + ++s; + e = s + strlen(s); + while (e > s && istrim(e[-1])) + --e; + js_pushlstring(J, s, e - s); +} + +static void S_fromCharCode(js_State *J) +{ + int i, top = js_gettop(J); + char * volatile s = NULL; + char *p; + Rune c; + + if (js_try(J)) { + js_free(J, s); + js_throw(J); + } + + s = p = js_malloc(J, (top-1) * UTFmax + 1); + + for (i = 1; i < top; ++i) { + c = js_touint32(J, i); + p += runetochar(p, &c); + } + *p = 0; + + js_pushstring(J, s); + js_endtry(J); + js_free(J, s); +} + +static void Sp_match(js_State *J) +{ + js_Regexp *re; + const char *text; + int len; + const char *a, *b, *c, *e; + Resub m; + + text = checkstring(J, 0); + + if (js_isregexp(J, 1)) + js_copy(J, 1); + else if (js_isundefined(J, 1)) + js_newregexp(J, "", 0); + else + js_newregexp(J, js_tostring(J, 1), 0); + + re = js_toregexp(J, -1); + if (!(re->flags & JS_REGEXP_G)) { + js_RegExp_prototype_exec(J, re, text); + return; + } + + re->last = 0; + + js_newarray(J); + + len = 0; + a = text; + e = text + strlen(text); + while (a <= e) { + if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) + break; + + b = m.sub[0].sp; + c = m.sub[0].ep; + + js_pushlstring(J, b, c - b); + js_setindex(J, -2, len++); + + a = c; + if (c - b == 0) + ++a; + } + + if (len == 0) { + js_pop(J, 1); + js_pushnull(J); + } +} + +static void Sp_search(js_State *J) +{ + js_Regexp *re; + const char *text; + Resub m; + + text = checkstring(J, 0); + + if (js_isregexp(J, 1)) + js_copy(J, 1); + else if (js_isundefined(J, 1)) + js_newregexp(J, "", 0); + else + js_newregexp(J, js_tostring(J, 1), 0); + + re = js_toregexp(J, -1); + + if (!js_doregexec(J, re->prog, text, &m, 0)) + js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); + else + js_pushnumber(J, -1); +} + +static void Sp_replace_regexp(js_State *J) +{ + js_Regexp *re; + const char *source, *s, *r; + js_Buffer *sb = NULL; + int n, x; + Resub m; + + source = checkstring(J, 0); + re = js_toregexp(J, 1); + + if (js_doregexec(J, re->prog, source, &m, 0)) { + js_copy(J, 0); + return; + } + + re->last = 0; + +loop: + s = m.sub[0].sp; + n = m.sub[0].ep - m.sub[0].sp; + + if (js_iscallable(J, 2)) { + js_copy(J, 2); + js_pushundefined(J); + for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ + js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp); + js_pushnumber(J, s - source); /* arg x+2: offset within search string */ + js_copy(J, 0); /* arg x+3: search string */ + js_call(J, 2 + x); + r = js_tostring(J, -1); + js_putm(J, &sb, source, s); + js_puts(J, &sb, r); + js_pop(J, 1); + } else { + r = js_tostring(J, 2); + js_putm(J, &sb, source, s); + while (*r) { + if (*r == '$') { + switch (*(++r)) { + case 0: --r; /* end of string; back up */ + /* fallthrough */ + case '$': js_putc(J, &sb, '$'); break; + case '`': js_putm(J, &sb, source, s); break; + case '\'': js_puts(J, &sb, s + n); break; + case '&': + js_putm(J, &sb, s, s + n); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + x = *r - '0'; + if (r[1] >= '0' && r[1] <= '9') + x = x * 10 + *(++r) - '0'; + if (x > 0 && x < m.nsub) { + js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep); + } else { + js_putc(J, &sb, '$'); + if (x > 10) { + js_putc(J, &sb, '0' + x / 10); + js_putc(J, &sb, '0' + x % 10); + } else { + js_putc(J, &sb, '0' + x); + } + } + break; + default: + js_putc(J, &sb, '$'); + js_putc(J, &sb, *r); + break; + } + ++r; + } else { + js_putc(J, &sb, *r++); + } + } + } + + if (re->flags & JS_REGEXP_G) { + source = m.sub[0].ep; + if (n == 0) { + if (*source) + js_putc(J, &sb, *source++); + else + goto end; + } + if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL)) + goto loop; + } + +end: + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Sp_replace_string(js_State *J) +{ + const char *source, *needle, *s, *r; + js_Buffer *sb = NULL; + int n; + + source = checkstring(J, 0); + needle = js_tostring(J, 1); + + s = strstr(source, needle); + if (!s) { + js_copy(J, 0); + return; + } + n = strlen(needle); + + if (js_iscallable(J, 2)) { + js_copy(J, 2); + js_pushundefined(J); + js_pushlstring(J, s, n); /* arg 1: substring that matched */ + js_pushnumber(J, s - source); /* arg 2: offset within search string */ + js_copy(J, 0); /* arg 3: search string */ + js_call(J, 3); + r = js_tostring(J, -1); + js_putm(J, &sb, source, s); + js_puts(J, &sb, r); + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + js_pop(J, 1); + } else { + r = js_tostring(J, 2); + js_putm(J, &sb, source, s); + while (*r) { + if (*r == '$') { + switch (*(++r)) { + case 0: --r; /* end of string; back up */ + /* fallthrough */ + case '$': js_putc(J, &sb, '$'); break; + case '&': js_putm(J, &sb, s, s + n); break; + case '`': js_putm(J, &sb, source, s); break; + case '\'': js_puts(J, &sb, s + n); break; + default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break; + } + ++r; + } else { + js_putc(J, &sb, *r++); + } + } + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + } + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Sp_replace(js_State *J) +{ + if (js_isregexp(J, 1)) + Sp_replace_regexp(J); + else + Sp_replace_string(J); +} + +static void Sp_split_regexp(js_State *J) +{ + js_Regexp *re; + const char *text; + int limit, len, k; + const char *p, *a, *b, *c, *e; + Resub m; + + text = checkstring(J, 0); + re = js_toregexp(J, 1); + limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; + + js_newarray(J); + len = 0; + + if (limit == 0) + return; + + e = text + strlen(text); + + /* splitting the empty string */ + if (e == text) { + if (js_doregexec(J, re->prog, text, &m, 0)) { + js_pushliteral(J, ""); + js_setindex(J, -2, 0); + } + return; + } + + p = a = text; + while (a < e) { + if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) + break; /* no match */ + + b = m.sub[0].sp; + c = m.sub[0].ep; + + /* empty string at end of last match */ + if (b == c && b == p) { + ++a; + continue; + } + + if (len == limit) return; + js_pushlstring(J, p, b - p); + js_setindex(J, -2, len++); + + for (k = 1; k < m.nsub; ++k) { + if (len == limit) return; + js_pushlstring(J, m.sub[k].sp, m.sub[k].ep - m.sub[k].sp); + js_setindex(J, -2, len++); + } + + a = p = c; + } + + if (len == limit) return; + js_pushstring(J, p); + js_setindex(J, -2, len); +} + +static void Sp_split_string(js_State *J) +{ + const char *str = checkstring(J, 0); + const char *sep = js_tostring(J, 1); + int limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; + int i, n; + + js_newarray(J); + + if (limit == 0) + return; + + n = strlen(sep); + + /* empty string */ + if (n == 0) { + Rune rune; + for (i = 0; *str && i < limit; ++i) { + n = chartorune(&rune, str); + js_pushlstring(J, str, n); + js_setindex(J, -2, i); + str += n; + } + return; + } + + for (i = 0; str && i < limit; ++i) { + const char *s = strstr(str, sep); + if (s) { + js_pushlstring(J, str, s-str); + js_setindex(J, -2, i); + str = s + n; + } else { + js_pushstring(J, str); + js_setindex(J, -2, i); + str = NULL; + } + } +} + +static void Sp_split(js_State *J) +{ + if (js_isundefined(J, 1)) { + js_newarray(J); + js_pushstring(J, js_tostring(J, 0)); + js_setindex(J, -2, 0); + } else if (js_isregexp(J, 1)) { + Sp_split_regexp(J); + } else { + Sp_split_string(J); + } +} + +void jsB_initstring(js_State *J) +{ + J->String_prototype->u.s.shrstr[0] = 0; + J->String_prototype->u.s.string = J->String_prototype->u.s.shrstr; + J->String_prototype->u.s.length = 0; + + js_pushobject(J, J->String_prototype); + { + jsB_propf(J, "String.prototype.toString", Sp_toString, 0); + jsB_propf(J, "String.prototype.valueOf", Sp_valueOf, 0); + jsB_propf(J, "String.prototype.charAt", Sp_charAt, 1); + jsB_propf(J, "String.prototype.charCodeAt", Sp_charCodeAt, 1); + jsB_propf(J, "String.prototype.concat", Sp_concat, 0); /* 1 */ + jsB_propf(J, "String.prototype.indexOf", Sp_indexOf, 1); + jsB_propf(J, "String.prototype.lastIndexOf", Sp_lastIndexOf, 1); + jsB_propf(J, "String.prototype.localeCompare", Sp_localeCompare, 1); + jsB_propf(J, "String.prototype.match", Sp_match, 1); + jsB_propf(J, "String.prototype.replace", Sp_replace, 2); + jsB_propf(J, "String.prototype.search", Sp_search, 1); + jsB_propf(J, "String.prototype.slice", Sp_slice, 2); + jsB_propf(J, "String.prototype.split", Sp_split, 2); + jsB_propf(J, "String.prototype.substring", Sp_substring, 2); + jsB_propf(J, "String.prototype.toLowerCase", Sp_toLowerCase, 0); + jsB_propf(J, "String.prototype.toLocaleLowerCase", Sp_toLowerCase, 0); + jsB_propf(J, "String.prototype.toUpperCase", Sp_toUpperCase, 0); + jsB_propf(J, "String.prototype.toLocaleUpperCase", Sp_toUpperCase, 0); + + /* ES5 */ + jsB_propf(J, "String.prototype.trim", Sp_trim, 0); + } + js_newcconstructor(J, jsB_String, jsB_new_String, "String", 0); /* 1 */ + { + jsB_propf(J, "String.fromCharCode", S_fromCharCode, 0); /* 1 */ + } + js_defglobal(J, "String", JS_DONTENUM); +} diff --git a/src/mujs/jsvalue.c b/src/mujs/jsvalue.c new file mode 100644 index 0000000..4cbdd49 --- /dev/null +++ b/src/mujs/jsvalue.c @@ -0,0 +1,708 @@ +#include "jsi.h" +#include "utf.h" + +#define JSV_ISSTRING(v) (v->t.type==JS_TSHRSTR || v->t.type==JS_TMEMSTR || v->t.type==JS_TLITSTR) +#define JSV_TOSTRING(v) (v->t.type==JS_TSHRSTR ? v->u.shrstr : v->t.type==JS_TLITSTR ? v->u.litstr : v->t.type==JS_TMEMSTR ? v->u.memstr->p : "") + +double js_strtol(const char *s, char **p, int base) +{ + /* ascii -> digit value. max base is 36. */ + static const unsigned char table[256] = { + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 80, 80, 80, 80, 80, + 80, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 80, 80, 80, 80, 80, + 80, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + }; + double x; + unsigned char c; + if (base == 10) + for (x = 0, c = *s++; (0 <= c - '0') && (c - '0' < 10); c = *s++) + x = x * 10 + (c - '0'); + else + for (x = 0, c = *s++; table[c] < base; c = *s++) + x = x * base + table[c]; + if (p) + *p = (char*)s-1; + return x; +} + +int jsV_numbertointeger(double n) +{ + if (n == 0) return 0; + if (isnan(n)) return 0; + n = (n < 0) ? -floor(-n) : floor(n); + if (n < INT_MIN) return INT_MIN; + if (n > INT_MAX) return INT_MAX; + return (int)n; +} + +int jsV_numbertoint32(double n) +{ + double two32 = 4294967296.0; + double two31 = 2147483648.0; + + if (!isfinite(n) || n == 0) + return 0; + + n = fmod(n, two32); + n = n >= 0 ? floor(n) : ceil(n) + two32; + if (n >= two31) + return n - two32; + else + return n; +} + +unsigned int jsV_numbertouint32(double n) +{ + return (unsigned int)jsV_numbertoint32(n); +} + +short jsV_numbertoint16(double n) +{ + return jsV_numbertoint32(n); +} + +unsigned short jsV_numbertouint16(double n) +{ + return jsV_numbertoint32(n); +} + +/* obj.toString() */ +static int jsV_toString(js_State *J, js_Object *obj) +{ + js_pushobject(J, obj); + js_getproperty(J, -1, "toString"); + if (js_iscallable(J, -1)) { + js_rot2(J); + js_call(J, 0); + if (js_isprimitive(J, -1)) + return 1; + js_pop(J, 1); + return 0; + } + js_pop(J, 2); + return 0; +} + +/* obj.valueOf() */ +static int jsV_valueOf(js_State *J, js_Object *obj) +{ + js_pushobject(J, obj); + js_getproperty(J, -1, "valueOf"); + if (js_iscallable(J, -1)) { + js_rot2(J); + js_call(J, 0); + if (js_isprimitive(J, -1)) + return 1; + js_pop(J, 1); + return 0; + } + js_pop(J, 2); + return 0; +} + +/* ToPrimitive() on a value */ +void jsV_toprimitive(js_State *J, js_Value *v, int preferred) +{ + js_Object *obj; + + if (v->t.type != JS_TOBJECT) + return; + + obj = v->u.object; + + if (preferred == JS_HNONE) + preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER; + + if (preferred == JS_HSTRING) { + if (jsV_toString(J, obj) || jsV_valueOf(J, obj)) { + *v = *js_tovalue(J, -1); + js_pop(J, 1); + return; + } + } else { + if (jsV_valueOf(J, obj) || jsV_toString(J, obj)) { + *v = *js_tovalue(J, -1); + js_pop(J, 1); + return; + } + } + + if (J->strict) + js_typeerror(J, "cannot convert object to primitive"); + + v->t.type = JS_TLITSTR; + v->u.litstr = "[object]"; + return; +} + +/* ToBoolean() on a value */ +int jsV_toboolean(js_State *J, js_Value *v) +{ + switch (v->t.type) { + default: + case JS_TSHRSTR: return v->u.shrstr[0] != 0; + case JS_TUNDEFINED: return 0; + case JS_TNULL: return 0; + case JS_TBOOLEAN: return v->u.boolean; + case JS_TNUMBER: return v->u.number != 0 && !isnan(v->u.number); + case JS_TLITSTR: return v->u.litstr[0] != 0; + case JS_TMEMSTR: return v->u.memstr->p[0] != 0; + case JS_TOBJECT: return 1; + } +} + +const char *js_itoa(char *out, int v) +{ + char buf[32], *s = out; + unsigned int a; + int i = 0; + if (v < 0) { + a = -v; + *s++ = '-'; + } else { + a = v; + } + while (a) { + buf[i++] = (a % 10) + '0'; + a /= 10; + } + if (i == 0) + buf[i++] = '0'; + while (i > 0) + *s++ = buf[--i]; + *s = 0; + return out; +} + +double js_stringtofloat(const char *s, char **ep) +{ + char *end; + double n; + const char *e = s; + int isflt = 0; + if (*e == '+' || *e == '-') ++e; + while (*e >= '0' && *e <= '9') ++e; + if (*e == '.') { ++e; isflt = 1; } + while (*e >= '0' && *e <= '9') ++e; + if (*e == 'e' || *e == 'E') { + ++e; + if (*e == '+' || *e == '-') ++e; + while (*e >= '0' && *e <= '9') ++e; + isflt = 1; + } + if (isflt) + n = js_strtod(s, &end); + else { + /* js_strtol doesn't parse the sign */ + if (*s == '-') + n = -js_strtol(s+1, &end, 10); + else if (*s == '+') + n = js_strtol(s+1, &end, 10); + else + n = js_strtol(s, &end, 10); + } + if (end == e) { + *ep = (char*)e; + return n; + } + *ep = (char*)s; + return 0; +} + +/* ToNumber() on a string */ +double jsV_stringtonumber(js_State *J, const char *s) +{ + char *e; + double n; + while (jsY_iswhite(*s) || jsY_isnewline(*s)) ++s; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && s[2] != 0) + n = js_strtol(s + 2, &e, 16); + else if (!strncmp(s, "Infinity", 8)) + n = INFINITY, e = (char*)s + 8; + else if (!strncmp(s, "+Infinity", 9)) + n = INFINITY, e = (char*)s + 9; + else if (!strncmp(s, "-Infinity", 9)) + n = -INFINITY, e = (char*)s + 9; + else + n = js_stringtofloat(s, &e); + while (jsY_iswhite(*e) || jsY_isnewline(*e)) ++e; + if (*e) return NAN; + return n; +} + +/* ToNumber() on a value */ +double jsV_tonumber(js_State *J, js_Value *v) +{ + switch (v->t.type) { + default: + case JS_TSHRSTR: return jsV_stringtonumber(J, v->u.shrstr); + case JS_TUNDEFINED: return NAN; + case JS_TNULL: return 0; + case JS_TBOOLEAN: return v->u.boolean; + case JS_TNUMBER: return v->u.number; + case JS_TLITSTR: return jsV_stringtonumber(J, v->u.litstr); + case JS_TMEMSTR: return jsV_stringtonumber(J, v->u.memstr->p); + case JS_TOBJECT: + jsV_toprimitive(J, v, JS_HNUMBER); + return jsV_tonumber(J, v); + } +} + +double jsV_tointeger(js_State *J, js_Value *v) +{ + return jsV_numbertointeger(jsV_tonumber(J, v)); +} + +/* ToString() on a number */ +const char *jsV_numbertostring(js_State *J, char buf[32], double f) +{ + char digits[32], *p = buf, *s = digits; + int exp, ndigits, point; + + if (f == 0) return "0"; + if (isnan(f)) return "NaN"; + if (isinf(f)) return f < 0 ? "-Infinity" : "Infinity"; + + /* Fast case for integers. This only works assuming all integers can be + * exactly represented by a float. This is true for 32-bit integers and + * 64-bit floats. */ + if (f >= INT_MIN && f <= INT_MAX) { + int i = (int)f; + if ((double)i == f) + return js_itoa(buf, i); + } + + ndigits = js_grisu2(f, digits, &exp); + point = ndigits + exp; + + if (signbit(f)) + *p++ = '-'; + + if (point < -5 || point > 21) { + *p++ = *s++; + if (ndigits > 1) { + int n = ndigits - 1; + *p++ = '.'; + while (n--) + *p++ = *s++; + } + js_fmtexp(p, point - 1); + } + + else if (point <= 0) { + *p++ = '0'; + *p++ = '.'; + while (point++ < 0) + *p++ = '0'; + while (ndigits-- > 0) + *p++ = *s++; + *p = 0; + } + + else { + while (ndigits-- > 0) { + *p++ = *s++; + if (--point == 0 && ndigits > 0) + *p++ = '.'; + } + while (point-- > 0) + *p++ = '0'; + *p = 0; + } + + return buf; +} + +/* ToString() on a value */ +const char *jsV_tostring(js_State *J, js_Value *v) +{ + char buf[32]; + const char *p; + switch (v->t.type) { + default: + case JS_TSHRSTR: return v->u.shrstr; + case JS_TUNDEFINED: return "undefined"; + case JS_TNULL: return "null"; + case JS_TBOOLEAN: return v->u.boolean ? "true" : "false"; + case JS_TLITSTR: return v->u.litstr; + case JS_TMEMSTR: return v->u.memstr->p; + case JS_TNUMBER: + p = jsV_numbertostring(J, buf, v->u.number); + if (p == buf) { + int n = strlen(p); + if (n <= soffsetof(js_Value, t.type)) { + char *s = v->u.shrstr; + while (n--) *s++ = *p++; + *s = 0; + v->t.type = JS_TSHRSTR; + return v->u.shrstr; + } else { + v->u.memstr = jsV_newmemstring(J, p, n); + v->t.type = JS_TMEMSTR; + return v->u.memstr->p; + } + } + return p; + case JS_TOBJECT: + jsV_toprimitive(J, v, JS_HSTRING); + return jsV_tostring(J, v); + } +} + +/* Objects */ + +static js_Object *jsV_newboolean(js_State *J, int v) +{ + js_Object *obj = jsV_newobject(J, JS_CBOOLEAN, J->Boolean_prototype); + obj->u.boolean = v; + return obj; +} + +static js_Object *jsV_newnumber(js_State *J, double v) +{ + js_Object *obj = jsV_newobject(J, JS_CNUMBER, J->Number_prototype); + obj->u.number = v; + return obj; +} + +static js_Object *jsV_newstring(js_State *J, const char *v) +{ + js_Object *obj = jsV_newobject(J, JS_CSTRING, J->String_prototype); + size_t n = strlen(v); + if (n < sizeof(obj->u.s.shrstr)) { + obj->u.s.string = obj->u.s.shrstr; + memcpy(obj->u.s.shrstr, v, n + 1); + } else { + obj->u.s.string = js_strdup(J, v); + } + obj->u.s.length = js_utflen(v); + return obj; +} + +/* ToObject() on a value */ +js_Object *jsV_toobject(js_State *J, js_Value *v) +{ + js_Object *o; + switch (v->t.type) { + default: + case JS_TUNDEFINED: js_typeerror(J, "cannot convert undefined to object"); + case JS_TNULL: js_typeerror(J, "cannot convert null to object"); + case JS_TOBJECT: return v->u.object; + case JS_TSHRSTR: o = jsV_newstring(J, v->u.shrstr); break; + case JS_TLITSTR: o = jsV_newstring(J, v->u.litstr); break; + case JS_TMEMSTR: o = jsV_newstring(J, v->u.memstr->p); break; + case JS_TBOOLEAN: o = jsV_newboolean(J, v->u.boolean); break; + case JS_TNUMBER: o = jsV_newnumber(J, v->u.number); break; + } + v->t.type = JS_TOBJECT; + v->u.object = o; + return o; +} + +void js_newobjectx(js_State *J) +{ + js_Object *prototype = NULL; + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + js_pop(J, 1); + js_pushobject(J, jsV_newobject(J, JS_COBJECT, prototype)); +} + +void js_newobject(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_COBJECT, J->Object_prototype)); +} + +void js_newarguments(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_CARGUMENTS, J->Object_prototype)); +} + +void js_newarray(js_State *J) +{ + js_Object *obj = jsV_newobject(J, JS_CARRAY, J->Array_prototype); + obj->u.a.simple = 1; + js_pushobject(J, obj); +} + +void js_newboolean(js_State *J, int v) +{ + js_pushobject(J, jsV_newboolean(J, v)); +} + +void js_newnumber(js_State *J, double v) +{ + js_pushobject(J, jsV_newnumber(J, v)); +} + +void js_newstring(js_State *J, const char *v) +{ + js_pushobject(J, jsV_newstring(J, v)); +} + +void js_newfunction(js_State *J, js_Function *fun, js_Environment *scope) +{ + js_Object *obj = jsV_newobject(J, JS_CFUNCTION, J->Function_prototype); + obj->u.f.function = fun; + obj->u.f.scope = scope; + js_pushobject(J, obj); + { + js_pushnumber(J, fun->numparams); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_newobject(J); + { + js_copy(J, -2); + js_defproperty(J, -2, "constructor", JS_DONTENUM); + } + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +void js_newscript(js_State *J, js_Function *fun, js_Environment *scope) +{ + js_Object *obj = jsV_newobject(J, JS_CSCRIPT, NULL); + obj->u.f.function = fun; + obj->u.f.scope = scope; + js_pushobject(J, obj); +} + +void js_newcfunctionx(js_State *J, js_CFunction cfun, const char *name, int length, void *data, js_Finalize finalize) +{ + js_Object *obj; + + if (js_try(J)) { + if (finalize) + finalize(J, data); + js_throw(J); + } + + obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype); + obj->u.c.name = name; + obj->u.c.function = cfun; + obj->u.c.constructor = NULL; + obj->u.c.length = length; + obj->u.c.data = data; + obj->u.c.finalize = finalize; + + js_endtry(J); + + js_pushobject(J, obj); + { + js_pushnumber(J, length); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_newobject(J); + { + js_copy(J, -2); + js_defproperty(J, -2, "constructor", JS_DONTENUM); + } + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +void js_newcfunction(js_State *J, js_CFunction cfun, const char *name, int length) +{ + js_newcfunctionx(J, cfun, name, length, NULL, NULL); +} + +/* prototype -- constructor */ +void js_newcconstructor(js_State *J, js_CFunction cfun, js_CFunction ccon, const char *name, int length) +{ + js_Object *obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype); + obj->u.c.name = name; + obj->u.c.function = cfun; + obj->u.c.constructor = ccon; + obj->u.c.length = length; + js_pushobject(J, obj); /* proto obj */ + { + js_pushnumber(J, length); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_rot2(J); /* obj proto */ + js_copy(J, -2); /* obj proto obj */ + js_defproperty(J, -2, "constructor", JS_DONTENUM); + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Delete delete, js_Finalize finalize) +{ + js_Object *prototype = NULL; + js_Object *obj; + + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + js_pop(J, 1); + + if (js_try(J)) { + if (finalize) + finalize(J, data); + js_throw(J); + } + + obj = jsV_newobject(J, JS_CUSERDATA, prototype); + obj->u.user.tag = tag; + obj->u.user.data = data; + obj->u.user.has = has; + obj->u.user.put = put; + obj->u.user.delete = delete; + obj->u.user.finalize = finalize; + + js_endtry(J); + + js_pushobject(J, obj); +} + +void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize) +{ + js_newuserdatax(J, tag, data, NULL, NULL, NULL, finalize); +} + +/* Non-trivial operations on values. These are implemented using the stack. */ + +int js_instanceof(js_State *J) +{ + js_Object *O, *V; + + if (!js_iscallable(J, -1)) + js_typeerror(J, "instanceof: invalid operand"); + + if (!js_isobject(J, -2)) + return 0; + + js_getproperty(J, -1, "prototype"); + if (!js_isobject(J, -1)) + js_typeerror(J, "instanceof: 'prototype' property is not an object"); + O = js_toobject(J, -1); + js_pop(J, 1); + + V = js_toobject(J, -2); + while (V) { + V = V->prototype; + if (O == V) + return 1; + } + + return 0; +} + +void js_concat(js_State *J) +{ + js_toprimitive(J, -2, JS_HNONE); + js_toprimitive(J, -1, JS_HNONE); + + if (js_isstring(J, -2) || js_isstring(J, -1)) { + const char *sa = js_tostring(J, -2); + const char *sb = js_tostring(J, -1); + char * volatile sab = NULL; + /* TODO: create js_String directly */ + if (js_try(J)) { + js_free(J, sab); + js_throw(J); + } + sab = js_malloc(J, strlen(sa) + strlen(sb) + 1); + strcpy(sab, sa); + strcat(sab, sb); + js_pop(J, 2); + js_pushstring(J, sab); + js_endtry(J); + js_free(J, sab); + } else { + double x = js_tonumber(J, -2); + double y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x + y); + } +} + +int js_compare(js_State *J, int *okay) +{ + js_toprimitive(J, -2, JS_HNUMBER); + js_toprimitive(J, -1, JS_HNUMBER); + + *okay = 1; + if (js_isstring(J, -2) && js_isstring(J, -1)) { + return strcmp(js_tostring(J, -2), js_tostring(J, -1)); + } else { + double x = js_tonumber(J, -2); + double y = js_tonumber(J, -1); + if (isnan(x) || isnan(y)) + *okay = 0; + return x < y ? -1 : x > y ? 1 : 0; + } +} + +int js_equal(js_State *J) +{ + js_Value *x = js_tovalue(J, -2); + js_Value *y = js_tovalue(J, -1); + +retry: + if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) + return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); + if (x->t.type == y->t.type) { + if (x->t.type == JS_TUNDEFINED) return 1; + if (x->t.type == JS_TNULL) return 1; + if (x->t.type == JS_TNUMBER) return x->u.number == y->u.number; + if (x->t.type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; + if (x->t.type == JS_TOBJECT) return x->u.object == y->u.object; + return 0; + } + + if (x->t.type == JS_TNULL && y->t.type == JS_TUNDEFINED) return 1; + if (x->t.type == JS_TUNDEFINED && y->t.type == JS_TNULL) return 1; + + if (x->t.type == JS_TNUMBER && JSV_ISSTRING(y)) + return x->u.number == jsV_tonumber(J, y); + if (JSV_ISSTRING(x) && y->t.type == JS_TNUMBER) + return jsV_tonumber(J, x) == y->u.number; + + if (x->t.type == JS_TBOOLEAN) { + x->t.type = JS_TNUMBER; + x->u.number = x->u.boolean ? 1 : 0; + goto retry; + } + if (y->t.type == JS_TBOOLEAN) { + y->t.type = JS_TNUMBER; + y->u.number = y->u.boolean ? 1 : 0; + goto retry; + } + if ((JSV_ISSTRING(x) || x->t.type == JS_TNUMBER) && y->t.type == JS_TOBJECT) { + jsV_toprimitive(J, y, JS_HNONE); + goto retry; + } + if (x->t.type == JS_TOBJECT && (JSV_ISSTRING(y) || y->t.type == JS_TNUMBER)) { + jsV_toprimitive(J, x, JS_HNONE); + goto retry; + } + + return 0; +} + +int js_strictequal(js_State *J) +{ + js_Value *x = js_tovalue(J, -2); + js_Value *y = js_tovalue(J, -1); + + if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) + return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); + + if (x->t.type != y->t.type) return 0; + if (x->t.type == JS_TUNDEFINED) return 1; + if (x->t.type == JS_TNULL) return 1; + if (x->t.type == JS_TNUMBER) return x->u.number == y->u.number; + if (x->t.type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; + if (x->t.type == JS_TOBJECT) return x->u.object == y->u.object; + return 0; +} diff --git a/src/mujs/main.c b/src/mujs/main.c new file mode 100644 index 0000000..a86e9c2 --- /dev/null +++ b/src/mujs/main.c @@ -0,0 +1,400 @@ +#include +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif +#include + +#include "mujs.h" + +#include +#include + +#include "../libtemple/os.h" + +static char *xoptarg; /* Global argument pointer. */ +static int xoptind = 0; /* Global argv index. */ +static int xgetopt(int argc, char *argv[], char *optstring) +{ + static char *scan = NULL; /* Private scan pointer. */ + + char c; + char *place; + + xoptarg = NULL; + + if (!scan || *scan == '\0') { + if (xoptind == 0) + xoptind++; + + if (xoptind >= argc || argv[xoptind][0] != '-' || argv[xoptind][1] == '\0') + return EOF; + if (argv[xoptind][1] == '-' && argv[xoptind][2] == '\0') { + xoptind++; + return EOF; + } + + scan = argv[xoptind]+1; + xoptind++; + } + + c = *scan++; + place = strchr(optstring, c); + + if (!place || c == ':') { + fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); + return '?'; + } + + place++; + if (*place == ':') { + if (*scan != '\0') { + xoptarg = scan; + scan = NULL; + } else if (xoptind < argc) { + xoptarg = argv[xoptind]; + xoptind++; + } else { + fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c); + return ':'; + } + } + + return c; +} + +#ifdef HAVE_READLINE +#include +#include +#else +void using_history(void) { } +void add_history(const char *string) { } +void rl_bind_key(int key, void (*fun)(void)) { } +void rl_insert(void) { } +char *readline(const char *prompt) +{ + static char line[500], *p; + int n; + fputs(prompt, stdout); + p = fgets(line, sizeof line, stdin); + if (p) { + n = strlen(line); + if (n > 0 && line[n-1] == '\n') + line[--n] = 0; + p = malloc(n+1); + memcpy(p, line, n+1); + return p; + } + return NULL; +} +#endif + +#define PS1 "> " + +static void jsB_gc(js_State *J) +{ + int report = js_toboolean(J, 1); + js_gc(J, report); + js_pushundefined(J); +} + +static void jsB_load(js_State *J) +{ + int i, n = js_gettop(J); + for (i = 1; i < n; ++i) { + js_loadfile(J, js_tostring(J, i)); + js_pushundefined(J); + js_call(J, 0); + js_pop(J, 1); + } + js_pushundefined(J); +} + +static void jsB_compile(js_State *J) +{ + const char *source = js_tostring(J, 1); + const char *filename = js_isdefined(J, 2) ? js_tostring(J, 2) : "[string]"; + js_loadstring(J, filename, source); +} + +static void jsB_alert(js_State *J) +{ + long message = (long)(js_isundefined(J, 1) ? "" : js_tostring(J, 1)); + os_call_ext_str_2("PopUpOk", message, 0); + js_pushundefined(J); +} + +static void jsB_confirm(js_State *J) +{ + long message = (long)(js_isundefined(J, 1) ? "" : js_tostring(J, 1)); + js_pushboolean(J, os_call_ext_str_2("PopUpCancelOk", message, 0)); +} + +static void jsB_prompt(js_State *J) +{ + long message = (long)(js_isundefined(J, 1) ? "" : js_tostring(J, 1)); + js_pushstring(J, (char*)os_call_ext_str_1("PopUpGetStr", message)); +} + +static void jsB_print(js_State *J) +{ + int i, top = js_gettop(J); + for (i = 1; i < top; ++i) { + const char *s = js_tostring(J, i); + if (i > 1) putchar(' '); + fputs(s, stdout); + } + putchar('\n'); + js_pushundefined(J); +} + +static void jsB_write(js_State *J) +{ + int i, top = js_gettop(J); + for (i = 1; i < top; ++i) { + const char *s = js_tostring(J, i); + if (i > 1) putchar(' '); + fputs(s, stdout); + } + js_pushundefined(J); +} + +static void jsB_read(js_State *J) +{ + const char *filename = js_tostring(J, 1); + FILE *f; + char *s; + int n, t; + + f = fopen(filename, "rb"); + if (!f) { + js_error(J, "cannot open file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_END) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + n = ftell(f); + if (n < 0) { + fclose(f); + js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_SET) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + s = malloc(n + 1); + if (!s) { + fclose(f); + js_error(J, "out of memory"); + } + + t = fread(s, 1, n, f); + if (t != n) { + free(s); + fclose(f); + js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno)); + } + s[n] = 0; + + js_pushstring(J, s); + free(s); + fclose(f); +} + +static void jsB_readline(js_State *J) +{ + char *line = readline(""); + if (!line) { + js_pushnull(J); + return; + } + js_pushstring(J, line); + if (*line) + add_history(line); + free(line); +} + +static void jsB_quit(js_State *J) +{ + exit(js_tonumber(J, 1)); +} + +static void jsB_repr(js_State *J) +{ + js_repr(J, 1); +} + +static const char *require_js = + "function require(name) {\n" + "var cache = require.cache;\n" + "if (name in cache) return cache[name];\n" + "var exports = {};\n" + "cache[name] = exports;\n" + "Function('exports', read(name+'.js'))(exports);\n" + "return exports;\n" + "}\n" + "require.cache = Object.create(null);\n" +; + + +static const char *stacktrace_js = + "Error.prototype.toString = function() {\n" + "var s = this.name;\n" + "if ('message' in this) s += ': ' + this.message;\n" + "if ('stackTrace' in this) s += this.stackTrace;\n" + "return s;\n" + "};\n" +; + +static const char *console_js = + "var console = { log: print, debug: print, warn: print, error: print };" +; + +static int eval_file(js_State *J, const char* filename) +{ + char* source = (char*)os_call_ext_str_3("FileRead", (uint64_t)filename, 0, 0); + int res = js_ploadstring(J, filename, source); + free(source); + if (res) { + fprintf(stderr, "%s\n", js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_pushundefined(J); + if (js_pcall(J, 0)) { + fprintf(stderr, "%s\n", js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + if (js_isdefined(J, -1)) { + printf("%s\n", js_tryrepr(J, -1, "can't convert to string")); + } + js_pop(J, 1); + return 0; +} + +static int eval_print(js_State *J, const char *source) +{ + if (js_ploadstring(J, "[stdin]", source)) { + fprintf(stderr, "%s\n", js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_pushundefined(J); + if (js_pcall(J, 0)) { + fprintf(stderr, "%s\n", js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + if (js_isdefined(J, -1)) { + printf("%s\n", js_tryrepr(J, -1, "can't convert to string")); + } + js_pop(J, 1); + return 0; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: mujs [options] [script [scriptArgs*]]\n"); + fprintf(stderr, "\t-i: Enter interactive prompt after running code.\n"); + fprintf(stderr, "\t-s: Check strictness.\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + char *input; + js_State *J; + int status = 0; + int strict = 0; + int interactive = 0; + int c; + + while ((c = xgetopt(argc, argv, "is")) != -1) { + switch (c) { + default: usage(); break; + case 'i': interactive = 1; break; + case 's': strict = 1; break; + } + } + + J = js_newstate(NULL, NULL, strict ? JS_STRICT : 0); + if (!J) { + fprintf(stderr, "Could not initialize MuJS.\n"); + exit(1); + } + + js_newcfunction(J, jsB_gc, "gc", 0); + js_setglobal(J, "gc"); + + js_newcfunction(J, jsB_load, "load", 1); + js_setglobal(J, "load"); + + js_newcfunction(J, jsB_compile, "compile", 2); + js_setglobal(J, "compile"); + + js_newcfunction(J, jsB_alert, "alert", 0); + js_setglobal(J, "alert"); + + js_newcfunction(J, jsB_confirm, "confirm", 0); + js_setglobal(J, "confirm"); + + js_newcfunction(J, jsB_print, "print", 0); + js_setglobal(J, "print"); + + js_newcfunction(J, jsB_prompt, "prompt", 0); + js_setglobal(J, "prompt"); + + js_newcfunction(J, jsB_write, "write", 0); + js_setglobal(J, "write"); + + js_newcfunction(J, jsB_read, "read", 1); + js_setglobal(J, "read"); + + js_newcfunction(J, jsB_readline, "readline", 0); + js_setglobal(J, "readline"); + + js_newcfunction(J, jsB_repr, "repr", 0); + js_setglobal(J, "repr"); + + js_newcfunction(J, jsB_quit, "quit", 1); + js_setglobal(J, "quit"); + + js_dostring(J, require_js); + js_dostring(J, stacktrace_js); + js_dostring(J, console_js); + + js_initlibtemple(J); + + if (xoptind == argc) { + interactive = 1; + } else { + status = eval_file(J, argv[1]); + } + + if (interactive) { + printf("Welcome to MuJS %d.%d.%d.\n", + JS_VERSION_MAJOR, JS_VERSION_MINOR, JS_VERSION_PATCH); + input = readline(PS1); + for (;;) { + eval_print(J, input); + free(input); + input = readline(PS1); + } + putchar('\n'); + } + + js_gc(J, 0); + js_freestate(J); + + exit(status); +} diff --git a/src/mujs/mujs.h b/src/mujs/mujs.h new file mode 100644 index 0000000..8107d9f --- /dev/null +++ b/src/mujs/mujs.h @@ -0,0 +1,254 @@ +#ifndef mujs_h +#define mujs_h + +#include /* required for setjmp in fz_try macro */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define JS_VERSION_MAJOR 1 +#define JS_VERSION_MINOR 3 +#define JS_VERSION_PATCH 5 + +#define JS_VERSION (JS_VERSION_MAJOR * 10000 + JS_VERSION_MINOR * 100 + JS_VERSION_PATCH) +#define JS_CHECKVERSION(x,y,z) (JS_VERSION >= ((x) * 10000 + (y) * 100 + (z))) + +/* noreturn is a GCC extension */ +#ifdef __GNUC__ +#define JS_NORETURN __attribute__((noreturn)) +#else +#ifdef _MSC_VER +#define JS_NORETURN __declspec(noreturn) +#else +#define JS_NORETURN +#endif +#endif + +/* GCC can do type checking of printf strings */ +#ifdef __printflike +#define JS_PRINTFLIKE __printflike +#else +#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +#define JS_PRINTFLIKE(fmtarg, firstvararg) \ + __attribute__((__format__ (__printf__, fmtarg, firstvararg))) +#else +#define JS_PRINTFLIKE(fmtarg, firstvararg) +#endif +#endif + +typedef struct js_State js_State; + +typedef void *(*js_Alloc)(void *memctx, void *ptr, int size); +typedef void (*js_Panic)(js_State *J); +typedef void (*js_CFunction)(js_State *J); +typedef void (*js_Finalize)(js_State *J, void *p); +typedef int (*js_HasProperty)(js_State *J, void *p, const char *name); +typedef int (*js_Put)(js_State *J, void *p, const char *name); +typedef int (*js_Delete)(js_State *J, void *p, const char *name); +typedef void (*js_Report)(js_State *J, const char *message); + +/* Basic functions */ +js_State *js_newstate(js_Alloc alloc, void *actx, int flags); +void js_setcontext(js_State *J, void *uctx); +void *js_getcontext(js_State *J); +void js_setreport(js_State *J, js_Report report); +js_Panic js_atpanic(js_State *J, js_Panic panic); +void js_freestate(js_State *J); +void js_gc(js_State *J, int report); + +int js_dostring(js_State *J, const char *source); +int js_dofile(js_State *J, const char *filename); +int js_ploadstring(js_State *J, const char *filename, const char *source); +int js_ploadfile(js_State *J, const char *filename); +int js_pcall(js_State *J, int n); +int js_pconstruct(js_State *J, int n); + +/* Exception handling */ + +void *js_savetry(js_State *J); /* returns a jmp_buf */ + +#define js_try(J) \ + setjmp(js_savetry(J)) + +void js_endtry(js_State *J); + +/* State constructor flags */ +enum { + JS_STRICT = 1, +}; + +/* RegExp flags */ +enum { + JS_REGEXP_G = 1, + JS_REGEXP_I = 2, + JS_REGEXP_M = 4, +}; + +/* Property attribute flags */ +enum { + JS_READONLY = 1, + JS_DONTENUM = 2, + JS_DONTCONF = 4, +}; + +/* enum for js_type() */ +enum { + JS_ISUNDEFINED, + JS_ISNULL, + JS_ISBOOLEAN, + JS_ISNUMBER, + JS_ISSTRING, + JS_ISFUNCTION, + JS_ISOBJECT +}; + +void js_report(js_State *J, const char *message); + +void js_newerror(js_State *J, const char *message); +void js_newevalerror(js_State *J, const char *message); +void js_newrangeerror(js_State *J, const char *message); +void js_newreferenceerror(js_State *J, const char *message); +void js_newsyntaxerror(js_State *J, const char *message); +void js_newtypeerror(js_State *J, const char *message); +void js_newurierror(js_State *J, const char *message); + +JS_NORETURN void js_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_evalerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_rangeerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_referenceerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_syntaxerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_typeerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_urierror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); +JS_NORETURN void js_throw(js_State *J); + +void js_loadstring(js_State *J, const char *filename, const char *source); +void js_loadfile(js_State *J, const char *filename); + +void js_eval(js_State *J); +void js_call(js_State *J, int n); +void js_construct(js_State *J, int n); + +const char *js_ref(js_State *J); +void js_unref(js_State *J, const char *ref); + +void js_getregistry(js_State *J, const char *name); +void js_setregistry(js_State *J, const char *name); +void js_delregistry(js_State *J, const char *name); + +void js_getglobal(js_State *J, const char *name); +void js_setglobal(js_State *J, const char *name); +void js_defglobal(js_State *J, const char *name, int atts); +void js_delglobal(js_State *J, const char *name); + +int js_hasproperty(js_State *J, int idx, const char *name); +void js_getproperty(js_State *J, int idx, const char *name); +void js_setproperty(js_State *J, int idx, const char *name); +void js_defproperty(js_State *J, int idx, const char *name, int atts); +void js_delproperty(js_State *J, int idx, const char *name); +void js_defaccessor(js_State *J, int idx, const char *name, int atts); + +int js_getlength(js_State *J, int idx); +void js_setlength(js_State *J, int idx, int len); +int js_hasindex(js_State *J, int idx, int i); +void js_getindex(js_State *J, int idx, int i); +void js_setindex(js_State *J, int idx, int i); +void js_delindex(js_State *J, int idx, int i); + +void js_currentfunction(js_State *J); +void *js_currentfunctiondata(js_State *J); +void js_pushglobal(js_State *J); +void js_pushundefined(js_State *J); +void js_pushnull(js_State *J); +void js_pushboolean(js_State *J, int v); +void js_pushnumber(js_State *J, double v); +void js_pushstring(js_State *J, const char *v); +void js_pushlstring(js_State *J, const char *v, int n); +void js_pushliteral(js_State *J, const char *v); + +void js_newobjectx(js_State *J); +void js_newobject(js_State *J); +void js_newarray(js_State *J); +void js_newboolean(js_State *J, int v); +void js_newnumber(js_State *J, double v); +void js_newstring(js_State *J, const char *v); +void js_newcfunction(js_State *J, js_CFunction fun, const char *name, int length); +void js_newcfunctionx(js_State *J, js_CFunction fun, const char *name, int length, void *data, js_Finalize finalize); +void js_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con, const char *name, int length); +void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize); +void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Delete del, js_Finalize finalize); +void js_newregexp(js_State *J, const char *pattern, int flags); + +void js_pushiterator(js_State *J, int idx, int own); +const char *js_nextiterator(js_State *J, int idx); + +int js_isdefined(js_State *J, int idx); +int js_isundefined(js_State *J, int idx); +int js_isnull(js_State *J, int idx); +int js_isboolean(js_State *J, int idx); +int js_isnumber(js_State *J, int idx); +int js_isstring(js_State *J, int idx); +int js_isprimitive(js_State *J, int idx); +int js_isobject(js_State *J, int idx); +int js_isarray(js_State *J, int idx); +int js_isregexp(js_State *J, int idx); +int js_iscoercible(js_State *J, int idx); +int js_iscallable(js_State *J, int idx); +int js_isuserdata(js_State *J, int idx, const char *tag); +int js_iserror(js_State *J, int idx); +int js_isnumberobject(js_State *J, int idx); +int js_isstringobject(js_State *J, int idx); +int js_isbooleanobject(js_State *J, int idx); +int js_isdateobject(js_State *J, int idx); + +int js_toboolean(js_State *J, int idx); +double js_tonumber(js_State *J, int idx); +const char *js_tostring(js_State *J, int idx); +void *js_touserdata(js_State *J, int idx, const char *tag); + +const char *js_trystring(js_State *J, int idx, const char *error); +double js_trynumber(js_State *J, int idx, double error); +int js_tryinteger(js_State *J, int idx, int error); +int js_tryboolean(js_State *J, int idx, int error); + +int js_tointeger(js_State *J, int idx); +int js_toint32(js_State *J, int idx); +unsigned int js_touint32(js_State *J, int idx); +short js_toint16(js_State *J, int idx); +unsigned short js_touint16(js_State *J, int idx); + +int js_gettop(js_State *J); +void js_pop(js_State *J, int n); +void js_rot(js_State *J, int n); +void js_copy(js_State *J, int idx); +void js_remove(js_State *J, int idx); +void js_insert(js_State *J, int idx); +void js_replace(js_State* J, int idx); + +void js_dup(js_State *J); +void js_dup2(js_State *J); +void js_rot2(js_State *J); +void js_rot3(js_State *J); +void js_rot4(js_State *J); +void js_rot2pop1(js_State *J); +void js_rot3pop2(js_State *J); + +void js_concat(js_State *J); +int js_compare(js_State *J, int *okay); +int js_equal(js_State *J); +int js_strictequal(js_State *J); +int js_instanceof(js_State *J); +const char *js_typeof(js_State *J, int idx); +int js_type(js_State *J, int idx); + +void js_repr(js_State *J, int idx); +const char *js_torepr(js_State *J, int idx); +const char *js_tryrepr(js_State *J, int idx, const char *error); + +#ifdef __cplusplus +} +#endif + +#endif + +void js_initlibtemple(js_State *J); diff --git a/src/mujs/nanoprintf.h b/src/mujs/nanoprintf.h new file mode 100644 index 0000000..a415ad9 --- /dev/null +++ b/src/mujs/nanoprintf.h @@ -0,0 +1,1203 @@ +/* nanoprintf v0.5.5: a tiny embeddable printf replacement written in C. + https://github.com/charlesnicholson/nanoprintf + charles.nicholson+nanoprintf@gmail.com + dual-licensed under 0bsd and unlicense, take your pick. see eof for details. */ + +#ifndef NPF_H_INCLUDED +#define NPF_H_INCLUDED + +#include +#include + +// Define this to fully sandbox nanoprintf inside of a translation unit. +#ifdef NANOPRINTF_VISIBILITY_STATIC + #define NPF_VISIBILITY static +#else + #define NPF_VISIBILITY extern +#endif + +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX) \ + __attribute__((format(printf, FORMAT_INDEX, VARGS_INDEX))) +#else + #define NPF_PRINTF_ATTR(FORMAT_INDEX, VARGS_INDEX) +#endif + +// Public API + +#ifdef __cplusplus +#define NPF_RESTRICT +extern "C" { +#else +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define NPF_RESTRICT restrict +#else +#define NPF_RESTRICT +#endif +#endif + +// The npf_ functions all return the number of bytes required to express the +// fully-formatted string, not including the null terminator character. +// The npf_ functions do not return negative values, since the lack of 'l' length +// modifier support makes encoding errors impossible. + +NPF_VISIBILITY int npf_snprintf(char * NPF_RESTRICT buffer, + size_t bufsz, + const char * NPF_RESTRICT format, + ...) NPF_PRINTF_ATTR(3, 4); + +NPF_VISIBILITY int npf_vsnprintf(char * NPF_RESTRICT buffer, + size_t bufsz, + char const * NPF_RESTRICT format, + va_list vlist) NPF_PRINTF_ATTR(3, 0); + +typedef void (*npf_putc)(int c, void *ctx); +NPF_VISIBILITY int npf_pprintf(npf_putc pc, + void * NPF_RESTRICT pc_ctx, + char const * NPF_RESTRICT format, + ...) NPF_PRINTF_ATTR(3, 4); + +NPF_VISIBILITY int npf_vpprintf(npf_putc pc, + void * NPF_RESTRICT pc_ctx, + char const * NPF_RESTRICT format, + va_list vlist) NPF_PRINTF_ATTR(3, 0); + +#ifdef __cplusplus +} +#endif + +#endif // NPF_H_INCLUDED + +/* The implementation of nanoprintf begins here, to be compiled only if + NANOPRINTF_IMPLEMENTATION is defined. In a multi-file library what follows would + be nanoprintf.c. */ + +#ifdef NANOPRINTF_IMPLEMENTATION + +#ifndef NPF_IMPLEMENTATION_INCLUDED +#define NPF_IMPLEMENTATION_INCLUDED + +#include +#include + +// The conversion buffer must fit at least UINT64_MAX in octal format with the leading '0'. +#ifndef NANOPRINTF_CONVERSION_BUFFER_SIZE + #define NANOPRINTF_CONVERSION_BUFFER_SIZE 23 +#endif +#if NANOPRINTF_CONVERSION_BUFFER_SIZE < 23 + #error The size of the conversion buffer must be at least 23 bytes. +#endif + +// Pick reasonable defaults if nothing's been configured. +#if !defined(NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS) && \ + !defined(NANOPRINTF_USE_ALT_FORM_FLAG) + #define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1 + #define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1 + #define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 1 + #define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 0 + #define NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS 1 + #define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 0 + #define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0 + #define NANOPRINTF_USE_ALT_FORM_FLAG 1 +#endif + +// If anything's been configured, everything must be configured. +#ifndef NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif +#ifndef NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS + #error NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS must be #defined to 0 or 1 +#endif + +// Ensure flags are compatible. +#if (NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1) && \ + (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 0) + #error Precision format specifiers must be enabled if float support is enabled. +#endif + +// intmax_t / uintmax_t require stdint from c99 / c++11 +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + #ifndef _MSC_VER + #ifdef __cplusplus + #if __cplusplus < 201103L + #error large format specifier support requires C++11 or later. + #endif + #else + #if __STDC_VERSION__ < 199409L + #error nanoprintf requires C99 or later. + #endif + #endif + #endif +#endif + +// Figure out if we can disable warnings with pragmas. +#ifdef __clang__ + #define NPF_CLANG 1 + #define NPF_GCC_PAST_4_6 0 +#else + #define NPF_CLANG 0 + #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6))) + #define NPF_GCC_PAST_4_6 1 + #else + #define NPF_GCC_PAST_4_6 0 + #endif +#endif + +#if NPF_CLANG || NPF_GCC_PAST_4_6 + #define NPF_HAVE_GCC_WARNING_PRAGMAS 1 +#else + #define NPF_HAVE_GCC_WARNING_PRAGMAS 0 +#endif + +#if NPF_HAVE_GCC_WARNING_PRAGMAS + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-function" + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + #ifdef __cplusplus + #pragma GCC diagnostic ignored "-Wold-style-cast" + #endif + #pragma GCC diagnostic ignored "-Wpadded" + #pragma GCC diagnostic ignored "-Wfloat-equal" + #if NPF_CLANG + #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" + #pragma GCC diagnostic ignored "-Wcovered-switch-default" + #pragma GCC diagnostic ignored "-Wdeclaration-after-statement" + #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" + #ifndef __APPLE__ + #pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" + #endif + #elif NPF_GCC_PAST_4_6 + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + #endif +#endif + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4619) // there is no warning number 'number' + // C4619 has to be disabled first! + #pragma warning(disable:4127) // conditional expression is constant + #pragma warning(disable:4505) // unreferenced local function has been removed + #pragma warning(disable:4514) // unreferenced inline function has been removed + #pragma warning(disable:4701) // potentially uninitialized local variable used + #pragma warning(disable:4706) // assignment within conditional expression + #pragma warning(disable:4710) // function not inlined + #pragma warning(disable:4711) // function selected for inline expansion + #pragma warning(disable:4820) // padding added after struct member + #pragma warning(disable:5039) // potentially throwing function passed to extern C function + #pragma warning(disable:5045) // compiler will insert Spectre mitigation for memory load + #pragma warning(disable:5262) // implicit switch fall-through + #pragma warning(disable:26812) // enum type is unscoped +#endif + +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define NPF_NOINLINE __attribute__((noinline)) + #define NPF_FORCE_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define NPF_NOINLINE __declspec(noinline) + #define NPF_FORCE_INLINE inline __forceinline +#else + #define NPF_NOINLINE + #define NPF_FORCE_INLINE +#endif + +#if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) || \ + (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1) +enum { + NPF_FMT_SPEC_OPT_NONE, + NPF_FMT_SPEC_OPT_LITERAL, + NPF_FMT_SPEC_OPT_STAR, +}; +#endif + +enum { + NPF_FMT_SPEC_LEN_MOD_NONE, +#if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1 + NPF_FMT_SPEC_LEN_MOD_SHORT, // 'h' + NPF_FMT_SPEC_LEN_MOD_CHAR, // 'hh' +#endif + NPF_FMT_SPEC_LEN_MOD_LONG, // 'l' + NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE, // 'L' +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG, // 'll' + NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX, // 'j' + NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET, // 'z' + NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT, // 't' +#endif +}; + +enum { + NPF_FMT_SPEC_CONV_NONE, + NPF_FMT_SPEC_CONV_PERCENT, // '%' + NPF_FMT_SPEC_CONV_CHAR, // 'c' + NPF_FMT_SPEC_CONV_STRING, // 's' + NPF_FMT_SPEC_CONV_SIGNED_INT, // 'i', 'd' +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + NPF_FMT_SPEC_CONV_BINARY, // 'b' +#endif + NPF_FMT_SPEC_CONV_OCTAL, // 'o' + NPF_FMT_SPEC_CONV_HEX_INT, // 'x', 'X' + NPF_FMT_SPEC_CONV_UNSIGNED_INT, // 'u' + NPF_FMT_SPEC_CONV_POINTER, // 'p' +#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1 + NPF_FMT_SPEC_CONV_WRITEBACK, // 'n' +#endif +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + NPF_FMT_SPEC_CONV_FLOAT_DEC, // 'f', 'F' + NPF_FMT_SPEC_CONV_FLOAT_SCI, // 'e', 'E' + NPF_FMT_SPEC_CONV_FLOAT_SHORTEST, // 'g', 'G' + NPF_FMT_SPEC_CONV_FLOAT_HEX, // 'a', 'A' +#endif +}; + +typedef struct npf_format_spec { +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + int field_width; +#endif +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + int prec; + uint8_t prec_opt; +#endif +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + uint8_t field_width_opt; + char left_justified; // '-' + char leading_zero_pad; // '0' +#endif + char prepend; // ' ' or '+' +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + char alt_form; // '#' +#endif + char case_adjust; // 'a' - 'A' , or 0 (must be non-negative to work) + uint8_t length_modifier; + uint8_t conv_spec; +} npf_format_spec_t; + +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0 + typedef long npf_int_t; + typedef unsigned long npf_uint_t; +#else + typedef intmax_t npf_int_t; + typedef uintmax_t npf_uint_t; +#endif + +typedef struct npf_bufputc_ctx { + char *dst; + size_t len; + size_t cur; +} npf_bufputc_ctx_t; + +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + typedef char npf_size_is_ptrdiff[(sizeof(size_t) == sizeof(ptrdiff_t)) ? 1 : -1]; + typedef ptrdiff_t npf_ssize_t; + typedef size_t npf_uptrdiff_t; +#endif + +#ifdef _MSC_VER + #include +#endif + +#define NPF_MIN(x, y) ((x) <= (y) ? (x) : (y)) +#define NPF_MAX(x, y) ((x) >= (y) ? (x) : (y)) + +static int npf_parse_format_spec(char const *format, npf_format_spec_t *out_spec) { + char const *cur = format; + +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + out_spec->left_justified = 0; + out_spec->leading_zero_pad = 0; +#endif + out_spec->case_adjust = 'a' - 'A'; // lowercase + out_spec->prepend = 0; +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + out_spec->alt_form = 0; +#endif + + while (*++cur) { // cur points at the leading '%' character + switch (*cur) { // Optional flags +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + case '-': out_spec->left_justified = '-'; out_spec->leading_zero_pad = 0; continue; + case '0': out_spec->leading_zero_pad = !out_spec->left_justified; continue; +#endif + case '+': out_spec->prepend = '+'; continue; + case ' ': if (out_spec->prepend == 0) { out_spec->prepend = ' '; } continue; +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + case '#': out_spec->alt_form = '#'; continue; +#endif + default: break; + } + break; + } + +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + out_spec->field_width = 0; + out_spec->field_width_opt = NPF_FMT_SPEC_OPT_NONE; + if (*cur == '*') { + out_spec->field_width_opt = NPF_FMT_SPEC_OPT_STAR; + ++cur; + } else { + while ((*cur >= '0') && (*cur <= '9')) { + out_spec->field_width_opt = NPF_FMT_SPEC_OPT_LITERAL; + out_spec->field_width = (out_spec->field_width * 10) + (*cur++ - '0'); + } + } +#endif + +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + out_spec->prec = 0; + out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE; + if (*cur == '.') { + ++cur; + if (*cur == '*') { + out_spec->prec_opt = NPF_FMT_SPEC_OPT_STAR; + ++cur; + } else { + if (*cur == '-') { + ++cur; + } else { + out_spec->prec_opt = NPF_FMT_SPEC_OPT_LITERAL; + } + while ((*cur >= '0') && (*cur <= '9')) { + out_spec->prec = (out_spec->prec * 10) + (*cur++ - '0'); + } + } + } +#endif + + uint_fast8_t tmp_conv = NPF_FMT_SPEC_CONV_NONE; + out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_NONE; + switch (*cur++) { // Length modifier +#if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1 + case 'h': + out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_SHORT; + if (*cur == 'h') { + out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_CHAR; + ++cur; + } + break; +#endif + case 'l': + out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG; +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + if (*cur == 'l') { + out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_LONG_LONG; + ++cur; + } +#endif + break; +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + case 'L': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE; break; +#endif +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + case 'j': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_INTMAX; break; + case 'z': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_SIZET; break; + case 't': out_spec->length_modifier = NPF_FMT_SPEC_LEN_MOD_LARGE_PTRDIFFT; break; +#endif + default: --cur; break; + } + + switch (*cur++) { // Conversion specifier + case '%': out_spec->conv_spec = NPF_FMT_SPEC_CONV_PERCENT; +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE; + out_spec->prec = 0; +#endif + break; + + case 'c': out_spec->conv_spec = NPF_FMT_SPEC_CONV_CHAR; +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE; + out_spec->prec = 0; +#endif + break; + + case 's': out_spec->conv_spec = NPF_FMT_SPEC_CONV_STRING; + break; + + case 'i': + case 'd': tmp_conv = NPF_FMT_SPEC_CONV_SIGNED_INT; goto finish; + case 'o': tmp_conv = NPF_FMT_SPEC_CONV_OCTAL; goto finish; + case 'u': tmp_conv = NPF_FMT_SPEC_CONV_UNSIGNED_INT; goto finish; + case 'X': out_spec->case_adjust = 0; + case 'x': tmp_conv = NPF_FMT_SPEC_CONV_HEX_INT; goto finish; + finish: + out_spec->conv_spec = (uint8_t)tmp_conv; +#if (NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1) && \ + (NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1) + if (out_spec->prec_opt != NPF_FMT_SPEC_OPT_NONE) { out_spec->leading_zero_pad = 0; } +#endif + break; + +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + case 'F': out_spec->case_adjust = 0; + case 'f': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_DEC; + if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; } + break; + + case 'E': out_spec->case_adjust = 0; + case 'e': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SCI; + if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; } + break; + + case 'G': out_spec->case_adjust = 0; + case 'g': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_SHORTEST; + if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; } + break; + + case 'A': out_spec->case_adjust = 0; + case 'a': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_FLOAT_HEX; + if (out_spec->prec_opt == NPF_FMT_SPEC_OPT_NONE) { out_spec->prec = 6; } + break; +#endif + +#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1 + case 'n': + // todo: reject string if flags or width or precision exist + out_spec->conv_spec = NPF_FMT_SPEC_CONV_WRITEBACK; +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE; +#endif + break; +#endif + + case 'p': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_POINTER; +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + out_spec->prec_opt = NPF_FMT_SPEC_OPT_NONE; +#endif + break; + +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + case 'B': + out_spec->case_adjust = 0; + case 'b': + out_spec->conv_spec = NPF_FMT_SPEC_CONV_BINARY; + break; +#endif + + default: return 0; + } + + return (int)(cur - format); +} + +static NPF_NOINLINE int npf_utoa_rev( + npf_uint_t val, char *buf, uint_fast8_t base, char case_adj) { + uint_fast8_t n = 0; + do { + int_fast8_t const d = (int_fast8_t)(val % base); + *buf++ = (char)(((d < 10) ? '0' : ('A' - 10 + case_adj)) + d); + ++n; + val /= base; + } while (val); + return (int)n; +} + +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + +#include + +#if (DBL_MANT_DIG <= 11) && (DBL_MAX_EXP <= 16) + typedef uint_fast16_t npf_double_bin_t; + typedef int_fast8_t npf_ftoa_exp_t; +#elif (DBL_MANT_DIG <= 24) && (DBL_MAX_EXP <= 128) + typedef uint_fast32_t npf_double_bin_t; + typedef int_fast8_t npf_ftoa_exp_t; +#elif (DBL_MANT_DIG <= 53) && (DBL_MAX_EXP <= 1024) + typedef uint_fast64_t npf_double_bin_t; + typedef int_fast16_t npf_ftoa_exp_t; +#else + #error Unsupported width of the double type. +#endif + +// The floating point conversion code works with an unsigned integer type of any size. +#ifndef NANOPRINTF_CONVERSION_FLOAT_TYPE + #define NANOPRINTF_CONVERSION_FLOAT_TYPE unsigned int +#endif +typedef NANOPRINTF_CONVERSION_FLOAT_TYPE npf_ftoa_man_t; + +#if (NANOPRINTF_CONVERSION_BUFFER_SIZE <= UINT_FAST8_MAX) && (UINT_FAST8_MAX <= INT_MAX) + typedef uint_fast8_t npf_ftoa_dec_t; +#else + typedef int npf_ftoa_dec_t; +#endif + +enum { + NPF_DOUBLE_EXP_MASK = DBL_MAX_EXP * 2 - 1, + NPF_DOUBLE_EXP_BIAS = DBL_MAX_EXP - 1, + NPF_DOUBLE_MAN_BITS = DBL_MANT_DIG - 1, + NPF_DOUBLE_BIN_BITS = sizeof(npf_double_bin_t) * CHAR_BIT, + NPF_DOUBLE_SIGN_POS = sizeof(double) * CHAR_BIT - 1, + NPF_FTOA_MAN_BITS = sizeof(npf_ftoa_man_t) * CHAR_BIT, + NPF_FTOA_SHIFT_BITS = + ((NPF_FTOA_MAN_BITS < DBL_MANT_DIG) ? NPF_FTOA_MAN_BITS : DBL_MANT_DIG) - 1 +}; + +/* Generally, floating-point conversion implementations use + grisu2 (https://bit.ly/2JgMggX) and ryu (https://bit.ly/2RLXSg0) algorithms, + which are mathematically exact and fast, but require large lookup tables. + + This implementation was inspired by Wojciech Muła's (zdjęcia@garnek.pl) + algorithm (http://0x80.pl/notesen/2015-12-29-float-to-string.html) and + extended further by adding dynamic scaling and configurable integer width by + Oskars Rubenis (https://github.com/Okarss). */ + +static NPF_FORCE_INLINE npf_double_bin_t npf_double_to_int_rep(double f) { + // Union-cast is UB pre-C11 and in all C++; the compiler optimizes the code below. + npf_double_bin_t bin; + char const *src = (char const *)&f; + char *dst = (char *)&bin; + for (uint_fast8_t i = 0; i < sizeof(f); ++i) { dst[i] = src[i]; } + return bin; +} + +static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) { + char const *ret = NULL; + npf_double_bin_t bin = npf_double_to_int_rep(f); + + // Unsigned -> signed int casting is IB and can raise a signal but generally doesn't. + npf_ftoa_exp_t exp = + (npf_ftoa_exp_t)((npf_ftoa_exp_t)(bin >> NPF_DOUBLE_MAN_BITS) & NPF_DOUBLE_EXP_MASK); + + bin &= ((npf_double_bin_t)0x1 << NPF_DOUBLE_MAN_BITS) - 1; + if (exp == (npf_ftoa_exp_t)NPF_DOUBLE_EXP_MASK) { // special value + ret = (bin) ? "NAN" : "FNI"; + goto exit; + } + if (spec->prec > (NANOPRINTF_CONVERSION_BUFFER_SIZE - 2)) { goto exit; } + if (exp) { // normal number + bin |= (npf_double_bin_t)0x1 << NPF_DOUBLE_MAN_BITS; + } else { // subnormal number + ++exp; + } + exp = (npf_ftoa_exp_t)(exp - NPF_DOUBLE_EXP_BIAS); + + uint_fast8_t carry; carry = 0; + npf_ftoa_dec_t end, dec; dec = (npf_ftoa_dec_t)spec->prec; + if (dec +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + || spec->alt_form +#endif + ) { + buf[dec++] = '.'; + } + + { // Integer part + npf_ftoa_man_t man_i; + + if (exp >= 0) { + int_fast8_t shift_i = + (int_fast8_t)((exp > NPF_FTOA_SHIFT_BITS) ? (int)NPF_FTOA_SHIFT_BITS : exp); + npf_ftoa_exp_t exp_i = (npf_ftoa_exp_t)(exp - shift_i); + shift_i = (int_fast8_t)(NPF_DOUBLE_MAN_BITS - shift_i); + man_i = (npf_ftoa_man_t)(bin >> shift_i); + + if (exp_i) { + if (shift_i) { + carry = (bin >> (shift_i - 1)) & 0x1; + } + exp = NPF_DOUBLE_MAN_BITS; // invalidate the fraction part + } + + // Scale the exponent from base-2 to base-10. + for (; exp_i; --exp_i) { + if (!(man_i & ((npf_ftoa_man_t)0x1 << (NPF_FTOA_MAN_BITS - 1)))) { + man_i = (npf_ftoa_man_t)(man_i << 1); + man_i = (npf_ftoa_man_t)(man_i | carry); carry = 0; + } else { + if (dec >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; } + buf[dec++] = '0'; + carry = (((uint_fast8_t)(man_i % 5) + carry) > 2); + man_i /= 5; + } + } + } else { + man_i = 0; + } + end = dec; + + do { // Print the integer + if (end >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; } + buf[end++] = (char)('0' + (char)(man_i % 10)); + man_i /= 10; + } while (man_i); + } + + { // Fraction part + npf_ftoa_man_t man_f; + npf_ftoa_dec_t dec_f = (npf_ftoa_dec_t)spec->prec; + + if (exp < NPF_DOUBLE_MAN_BITS) { + int_fast8_t shift_f = (int_fast8_t)((exp < 0) ? -1 : exp); + npf_ftoa_exp_t exp_f = (npf_ftoa_exp_t)(exp - shift_f); + npf_double_bin_t bin_f = + bin << ((NPF_DOUBLE_BIN_BITS - NPF_DOUBLE_MAN_BITS) + shift_f); + + // This if-else statement can be completely optimized at compile time. + if (NPF_DOUBLE_BIN_BITS > NPF_FTOA_MAN_BITS) { + man_f = (npf_ftoa_man_t)(bin_f >> ((unsigned)(NPF_DOUBLE_BIN_BITS - + NPF_FTOA_MAN_BITS) % + NPF_DOUBLE_BIN_BITS)); + carry = (uint_fast8_t)((bin_f >> ((unsigned)(NPF_DOUBLE_BIN_BITS - + NPF_FTOA_MAN_BITS - 1) % + NPF_DOUBLE_BIN_BITS)) & 0x1); + } else { + man_f = (npf_ftoa_man_t)((npf_ftoa_man_t)bin_f + << ((unsigned)(NPF_FTOA_MAN_BITS - + NPF_DOUBLE_BIN_BITS) % NPF_FTOA_MAN_BITS)); + carry = 0; + } + + // Scale the exponent from base-2 to base-10 and prepare the first digit. + for (uint_fast8_t digit = 0; dec_f && (exp_f < 4); ++exp_f) { + if ((man_f > ((npf_ftoa_man_t)-4 / 5)) || digit) { + carry = (uint_fast8_t)(man_f & 0x1); + man_f = (npf_ftoa_man_t)(man_f >> 1); + } else { + man_f = (npf_ftoa_man_t)(man_f * 5); + if (carry) { man_f = (npf_ftoa_man_t)(man_f + 3); carry = 0; } + if (exp_f < 0) { + buf[--dec_f] = '0'; + } else { + ++digit; + } + } + } + man_f = (npf_ftoa_man_t)(man_f + carry); + carry = (exp_f >= 0); + dec = 0; + } else { + man_f = 0; + } + + if (dec_f) { + // Print the fraction + for (;;) { + buf[--dec_f] = (char)('0' + (char)(man_f >> (NPF_FTOA_MAN_BITS - 4))); + man_f = (npf_ftoa_man_t)(man_f & ~((npf_ftoa_man_t)0xF << (NPF_FTOA_MAN_BITS - 4))); + if (!dec_f) { break; } + man_f = (npf_ftoa_man_t)(man_f * 10); + } + man_f = (npf_ftoa_man_t)(man_f << 4); + } + if (exp < NPF_DOUBLE_MAN_BITS) { + carry &= (uint_fast8_t)(man_f >> (NPF_FTOA_MAN_BITS - 1)); + } + } + + // Round the number + for (; carry; ++dec) { + if (dec >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; } + if (dec >= end) { buf[end++] = '0'; } + if (buf[dec] == '.') { continue; } + carry = (buf[dec] == '9'); + buf[dec] = (char)(carry ? '0' : (buf[dec] + 1)); + } + + return (int)end; +exit: + if (!ret) { ret = "RRE"; } + uint_fast8_t i; + for (i = 0; ret[i]; ++i) { buf[i] = (char)(ret[i] + spec->case_adjust); } + return -(int)i; +} + +#endif // NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS + +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 +static int npf_bin_len(npf_uint_t u) { + // Return the length of the binary string format of 'u', preferring intrinsics. + if (!u) { return 1; } + +#ifdef _MSC_VER // Win64, use _BSR64 for everything. If x86, use _BSR when non-large. + #ifdef _M_X64 + #define NPF_HAVE_BUILTIN_CLZ + #define NPF_CLZ _BitScanReverse64 + #elif NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 0 + #define NPF_HAVE_BUILTIN_CLZ + #define NPF_CLZ _BitScanReverse + #endif + #ifdef NPF_HAVE_BUILTIN_CLZ + unsigned long idx; + NPF_CLZ(&idx, u); + return (int)(idx + 1); + #endif +#elif NPF_CLANG || NPF_GCC_PAST_4_6 + #define NPF_HAVE_BUILTIN_CLZ + #if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + #define NPF_CLZ(X) ((sizeof(long long) * CHAR_BIT) - (size_t)__builtin_clzll(X)) + #else + #define NPF_CLZ(X) ((sizeof(long) * CHAR_BIT) - (size_t)__builtin_clzl(X)) + #endif + return (int)NPF_CLZ(u); +#endif + +#ifndef NPF_HAVE_BUILTIN_CLZ + int n; + for (n = 0; u; ++n, u >>= 1); // slow but small software fallback + return n; +#else + #undef NPF_HAVE_BUILTIN_CLZ + #undef NPF_CLZ +#endif +} +#endif + +static void npf_bufputc(int c, void *ctx) { + npf_bufputc_ctx_t *bpc = (npf_bufputc_ctx_t *)ctx; + if (bpc->cur < bpc->len) { bpc->dst[bpc->cur++] = (char)c; } +} + +static void npf_bufputc_nop(int c, void *ctx) { (void)c; (void)ctx; } + +typedef struct npf_cnt_putc_ctx { + npf_putc pc; + void *ctx; + int n; +} npf_cnt_putc_ctx_t; + +static void npf_putc_cnt(int c, void *ctx) { + npf_cnt_putc_ctx_t *pc_cnt = (npf_cnt_putc_ctx_t *)ctx; + ++pc_cnt->n; + pc_cnt->pc(c, pc_cnt->ctx); // sibling-call optimization +} + +#define NPF_PUTC(VAL) do { npf_putc_cnt((int)(VAL), &pc_cnt); } while (0) + +#define NPF_EXTRACT(MOD, CAST_TO, EXTRACT_AS) \ + case NPF_FMT_SPEC_LEN_MOD_##MOD: val = (CAST_TO)va_arg(args, EXTRACT_AS); break + +#define NPF_WRITEBACK(MOD, TYPE) \ + case NPF_FMT_SPEC_LEN_MOD_##MOD: *(va_arg(args, TYPE *)) = (TYPE)pc_cnt.n; break + +int npf_vpprintf(npf_putc pc, void *pc_ctx, char const *format, va_list args) { + npf_format_spec_t fs; + char const *cur = format; + npf_cnt_putc_ctx_t pc_cnt; + pc_cnt.pc = pc; + pc_cnt.ctx = pc_ctx; + pc_cnt.n = 0; + + while (*cur) { + int const fs_len = (*cur != '%') ? 0 : npf_parse_format_spec(cur, &fs); + if (!fs_len) { NPF_PUTC(*cur++); continue; } + cur += fs_len; + + // Extract star-args immediately +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + if (fs.field_width_opt == NPF_FMT_SPEC_OPT_STAR) { + fs.field_width = va_arg(args, int); + if (fs.field_width < 0) { + fs.field_width = -fs.field_width; + fs.left_justified = 1; + } + } +#endif +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + if (fs.prec_opt == NPF_FMT_SPEC_OPT_STAR) { + fs.prec = va_arg(args, int); + if (fs.prec < 0) { fs.prec_opt = NPF_FMT_SPEC_OPT_NONE; } + } +#endif + + union { char cbuf_mem[NANOPRINTF_CONVERSION_BUFFER_SIZE]; npf_uint_t binval; } u; + char *cbuf = u.cbuf_mem, sign_c = 0; + int cbuf_len = 0; + char need_0x = 0; +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + int field_pad = 0; + char pad_c = 0; +#endif +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + int prec_pad = 0; +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + uint_fast8_t zero = 0; +#endif +#endif + + // Extract and convert the argument to string, point cbuf at the text. + switch (fs.conv_spec) { + case NPF_FMT_SPEC_CONV_PERCENT: + *cbuf = '%'; + cbuf_len = 1; + break; + + case NPF_FMT_SPEC_CONV_CHAR: + *cbuf = (char)va_arg(args, int); + cbuf_len = (*cbuf) ? 1 : 0; + break; + + case NPF_FMT_SPEC_CONV_STRING: { + cbuf = va_arg(args, char *); +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + for (char const *s = cbuf; + ((fs.prec_opt == NPF_FMT_SPEC_OPT_NONE) || (cbuf_len < fs.prec)) && cbuf && *s; + ++s, ++cbuf_len); +#else + for (char const *s = cbuf; cbuf && *s; ++s, ++cbuf_len); // strlen +#endif + } break; + + case NPF_FMT_SPEC_CONV_SIGNED_INT: { + npf_int_t val = 0; + switch (fs.length_modifier) { + NPF_EXTRACT(NONE, int, int); +#if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1 + NPF_EXTRACT(SHORT, short, int); + NPF_EXTRACT(CHAR, signed char, int); +#endif + NPF_EXTRACT(LONG, long, long); +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + NPF_EXTRACT(LARGE_LONG_LONG, long long, long long); + NPF_EXTRACT(LARGE_INTMAX, intmax_t, intmax_t); + NPF_EXTRACT(LARGE_SIZET, npf_ssize_t, npf_ssize_t); + NPF_EXTRACT(LARGE_PTRDIFFT, ptrdiff_t, ptrdiff_t); +#endif + default: break; + } + + sign_c = (val < 0) ? '-' : fs.prepend; + +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + zero = !val; +#endif + // special case, if prec and value are 0, skip + if (!val && (fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec) { + cbuf_len = 0; + } else +#endif + { + npf_uint_t uval = (npf_uint_t)val; + if (val < 0) { uval = 0 - uval; } + cbuf_len = npf_utoa_rev(uval, cbuf, 10, fs.case_adjust); + } + } break; + +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + case NPF_FMT_SPEC_CONV_BINARY: +#endif + case NPF_FMT_SPEC_CONV_OCTAL: + case NPF_FMT_SPEC_CONV_HEX_INT: + case NPF_FMT_SPEC_CONV_UNSIGNED_INT: + case NPF_FMT_SPEC_CONV_POINTER: { + npf_uint_t val = 0; + + if (fs.conv_spec == NPF_FMT_SPEC_CONV_POINTER) { + val = (npf_uint_t)(uintptr_t)va_arg(args, void *); + } else { + switch (fs.length_modifier) { + NPF_EXTRACT(NONE, unsigned, unsigned); +#if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1 + NPF_EXTRACT(SHORT, unsigned short, unsigned); + NPF_EXTRACT(CHAR, unsigned char, unsigned); +#endif + NPF_EXTRACT(LONG, unsigned long, unsigned long); +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + NPF_EXTRACT(LARGE_LONG_LONG, unsigned long long, unsigned long long); + NPF_EXTRACT(LARGE_INTMAX, uintmax_t, uintmax_t); + NPF_EXTRACT(LARGE_SIZET, size_t, size_t); + NPF_EXTRACT(LARGE_PTRDIFFT, npf_uptrdiff_t, npf_uptrdiff_t); +#endif + default: break; + } + } + +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + zero = !val; +#endif + if (!val && (fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec) { + // Zero value and explicitly-requested zero precision means "print nothing". +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + if ((fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) && fs.alt_form) { + fs.prec = 1; // octal special case, print a single '0' + } +#endif + } else +#endif +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) { + cbuf_len = npf_bin_len(val); u.binval = val; + } else +#endif + { + uint_fast8_t const base = (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL) ? + 8u : ((fs.conv_spec == NPF_FMT_SPEC_CONV_UNSIGNED_INT) ? 10u : 16u); + cbuf_len = npf_utoa_rev(val, cbuf, base, fs.case_adjust); + } + +#if NANOPRINTF_USE_ALT_FORM_FLAG == 1 + if (val && fs.alt_form && (fs.conv_spec == NPF_FMT_SPEC_CONV_OCTAL)) { + cbuf[cbuf_len++] = '0'; // OK to add leading octal '0' immediately. + } + + if (val && fs.alt_form) { // 0x or 0b but can't write it yet. + if ((fs.conv_spec == NPF_FMT_SPEC_CONV_HEX_INT) || + (fs.conv_spec == NPF_FMT_SPEC_CONV_POINTER)) { need_0x = 'X'; } +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + else if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) { need_0x = 'B'; } +#endif + if (need_0x) { need_0x = (char)(need_0x + fs.case_adjust); } + } +#endif + } break; + +#if NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS == 1 + case NPF_FMT_SPEC_CONV_WRITEBACK: + switch (fs.length_modifier) { + NPF_WRITEBACK(NONE, int); +#if NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS == 1 + NPF_WRITEBACK(SHORT, short); + NPF_WRITEBACK(CHAR, signed char); +#endif + NPF_WRITEBACK(LONG, long); +#if NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS == 1 + NPF_WRITEBACK(LARGE_LONG_LONG, long long); + NPF_WRITEBACK(LARGE_INTMAX, intmax_t); + NPF_WRITEBACK(LARGE_SIZET, npf_ssize_t); + NPF_WRITEBACK(LARGE_PTRDIFFT, ptrdiff_t); +#endif + default: break; + } break; +#endif + +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + case NPF_FMT_SPEC_CONV_FLOAT_DEC: + case NPF_FMT_SPEC_CONV_FLOAT_SCI: + case NPF_FMT_SPEC_CONV_FLOAT_SHORTEST: + case NPF_FMT_SPEC_CONV_FLOAT_HEX: { + double val; + if (fs.length_modifier == NPF_FMT_SPEC_LEN_MOD_LONG_DOUBLE) { + val = (double)va_arg(args, long double); + } else { + val = va_arg(args, double); + } + + sign_c = (npf_double_to_int_rep(val) >> NPF_DOUBLE_SIGN_POS) ? '-' : fs.prepend; +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + zero = (val == 0.); +#endif + cbuf_len = npf_ftoa_rev(cbuf, &fs, val); + if (cbuf_len < 0) { // negative means text (not number), so ignore the '0' flag + cbuf_len = -cbuf_len; +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + fs.leading_zero_pad = 0; +#endif + } + } break; +#endif + default: break; + } + +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + // Compute the field width pad character + if (fs.field_width_opt != NPF_FMT_SPEC_OPT_NONE) { + if (fs.leading_zero_pad) { +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + if ((fs.prec_opt != NPF_FMT_SPEC_OPT_NONE) && !fs.prec && zero) { + pad_c = ' '; + } else +#endif + { pad_c = '0'; } + } else { pad_c = ' '; } + } +#endif + + // Compute the number of bytes to truncate or '0'-pad. +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + if (fs.conv_spec != NPF_FMT_SPEC_CONV_STRING) { +#if NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS == 1 + // float precision is after the decimal point + if ((fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_DEC) && + (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_SCI) && + (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_SHORTEST) && + (fs.conv_spec != NPF_FMT_SPEC_CONV_FLOAT_HEX)) +#endif + { prec_pad = NPF_MAX(0, fs.prec - cbuf_len); } + } +#endif + +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + // Given the full converted length, how many pad bytes? + field_pad = fs.field_width - cbuf_len - !!sign_c; + if (need_0x) { field_pad -= 2; } +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + field_pad -= prec_pad; +#endif + field_pad = NPF_MAX(0, field_pad); + + // Apply right-justified field width if requested + if (!fs.left_justified && pad_c) { // If leading zeros pad, sign goes first. + if (pad_c == '0') { + if (sign_c) { NPF_PUTC(sign_c); sign_c = 0; } + // Pad byte is '0', write '0x' before '0' pad chars. + if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); } + } + while (field_pad-- > 0) { NPF_PUTC(pad_c); } + // Pad byte is ' ', write '0x' after ' ' pad chars but before number. + if ((pad_c != '0') && need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); } + } else +#endif + { if (need_0x) { NPF_PUTC('0'); NPF_PUTC(need_0x); } } // no pad, '0x' requested. + + // Write the converted payload + if (fs.conv_spec == NPF_FMT_SPEC_CONV_STRING) { + for (int i = 0; cbuf && (i < cbuf_len); ++i) { NPF_PUTC(cbuf[i]); } + } else { + if (sign_c) { NPF_PUTC(sign_c); } +#if NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS == 1 + while (prec_pad-- > 0) { NPF_PUTC('0'); } // int precision leads. +#endif +#if NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS == 1 + if (fs.conv_spec == NPF_FMT_SPEC_CONV_BINARY) { + while (cbuf_len) { NPF_PUTC('0' + ((u.binval >> --cbuf_len) & 1)); } + } else +#endif + { while (cbuf_len-- > 0) { NPF_PUTC(cbuf[cbuf_len]); } } // payload is reversed + } + +#if NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS == 1 + if (fs.left_justified && pad_c) { // Apply left-justified field width + while (field_pad-- > 0) { NPF_PUTC(pad_c); } + } +#endif + } + + return pc_cnt.n; +} + +#undef NPF_PUTC +#undef NPF_EXTRACT +#undef NPF_WRITEBACK + +int npf_pprintf(npf_putc pc, + void * NPF_RESTRICT pc_ctx, + char const * NPF_RESTRICT format, + ...) { + va_list val; + va_start(val, format); + int const rv = npf_vpprintf(pc, pc_ctx, format, val); + va_end(val); + return rv; +} + +int npf_snprintf(char * NPF_RESTRICT buffer, + size_t bufsz, + const char * NPF_RESTRICT format, + ...) { + va_list val; + va_start(val, format); + int const rv = npf_vsnprintf(buffer, bufsz, format, val); + va_end(val); + return rv; +} + +int npf_vsnprintf(char * NPF_RESTRICT buffer, + size_t bufsz, + char const * NPF_RESTRICT format, + va_list vlist) { + npf_bufputc_ctx_t bufputc_ctx; + bufputc_ctx.dst = buffer; + bufputc_ctx.len = bufsz; + bufputc_ctx.cur = 0; + + npf_putc const pc = buffer ? npf_bufputc : npf_bufputc_nop; + int const n = npf_vpprintf(pc, &bufputc_ctx, format, vlist); + + if (buffer && bufsz) { +#ifdef NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW + buffer[(n < 0 || (unsigned)n >= bufsz) ? 0 : n] = '\0'; +#else + buffer[n < 0 ? 0 : NPF_MIN((unsigned)n, bufsz - 1)] = '\0'; +#endif + } + + return n; +} + +#if NPF_HAVE_GCC_WARNING_PRAGMAS + #pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif // NPF_IMPLEMENTATION_INCLUDED +#endif // NANOPRINTF_IMPLEMENTATION + +/* + nanoprintf is dual-licensed under both the "Unlicense" and the + "Zero-Clause BSD" (0BSD) licenses. The intent of this dual-licensing + structure is to make nanoprintf as consumable as possible in as many + environments / countries / companies as possible without any + encumberances. + + The text of the two licenses follows below: + + ============================== UNLICENSE ============================== + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + 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 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. + + For more information, please refer to + + ================================ 0BSD ================================= + + Copyright (C) 2019- by Charles Nicholson + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted. + + 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. +*/ diff --git a/src/mujs/opnames.h b/src/mujs/opnames.h new file mode 100644 index 0000000..509ca1c --- /dev/null +++ b/src/mujs/opnames.h @@ -0,0 +1,85 @@ +"pop", +"dup", +"dup2", +"rot2", +"rot3", +"rot4", +"integer", +"number", +"string", +"closure", +"newarray", +"newobject", +"newregexp", +"undef", +"null", +"true", +"false", +"this", +"current", +"getlocal", +"setlocal", +"dellocal", +"hasvar", +"getvar", +"setvar", +"delvar", +"in", +"skiparray", +"initarray", +"initprop", +"initgetter", +"initsetter", +"getprop", +"getprop_s", +"setprop", +"setprop_s", +"delprop", +"delprop_s", +"iterator", +"nextiter", +"eval", +"call", +"new", +"typeof", +"pos", +"neg", +"bitnot", +"lognot", +"inc", +"dec", +"postinc", +"postdec", +"mul", +"div", +"mod", +"add", +"sub", +"shl", +"shr", +"ushr", +"lt", +"gt", +"le", +"ge", +"eq", +"ne", +"stricteq", +"strictne", +"jcase", +"bitand", +"bitxor", +"bitor", +"instanceof", +"throw", +"try", +"endtry", +"catch", +"endcatch", +"with", +"endwith", +"debugger", +"jump", +"jtrue", +"jfalse", +"return", diff --git a/src/mujs/pp.c b/src/mujs/pp.c new file mode 100644 index 0000000..c186399 --- /dev/null +++ b/src/mujs/pp.c @@ -0,0 +1,980 @@ +/* Pretty-print input source by emitting parse tree back as syntax. + * with no flags: pretty-printed source + * with -m: minified source with line breaks + * with -mm: minified source without line breaks + * with -s: s-expression syntax tree + */ + +#include +#include + +#include "jsi.h" +#include "utf.h" + +static const char *astname[] = { +#include "astnames.h" +NULL +}; + +static const char *opname[] = { +#include "opnames.h" +NULL +}; + +static int format = 0; +static int minify = 0; + +static void pc(int c) +{ + putchar(c); +} + +static void ps(const char *s) +{ + fputs(s, stdout); +} + +static void in(int d) +{ + if (minify < 1) + while (d-- > 0) + putchar('\t'); +} + +static void nl(void) +{ + if (minify < 2) + putchar('\n'); +} + +static void sp(void) +{ + if (minify < 1) + putchar(' '); +} + +static void comma(void) +{ + putchar(','); + sp(); +} + +static void pstr(const char *s) +{ + static const char *HEX = "0123456789ABCDEF"; + Rune c; + pc(minify ? '\'' : '"'); + while (*s) { + s += chartorune(&c, s); + switch (c) { + case '\'': ps("\\'"); break; + case '"': ps("\\\""); break; + case '\\': ps("\\\\"); break; + case '\b': ps("\\b"); break; + case '\f': ps("\\f"); break; + case '\n': ps("\\n"); break; + case '\r': ps("\\r"); break; + case '\t': ps("\\t"); break; + default: + if (c < ' ' || c > 127) { + ps("\\u"); + pc(HEX[(c>>12)&15]); + pc(HEX[(c>>8)&15]); + pc(HEX[(c>>4)&15]); + pc(HEX[c&15]); + } else { + pc(c); break; + } + } + } + pc(minify ? '\'' : '"'); +} + +static void pregexp(const char *prog, int flags) +{ + pc('/'); + while (*prog) { + if (*prog == '/') + pc('\\'); + pc(*prog); + ++prog; + } + pc('/'); + if (flags & JS_REGEXP_G) pc('g'); + if (flags & JS_REGEXP_I) pc('i'); + if (flags & JS_REGEXP_M) pc('m'); +} + +/* Bytecode */ + +static void jsC_dumpfunction(js_State *J, js_Function *F) +{ + js_Instruction *p = F->code; + js_Instruction *end = F->code + F->codelen; + char *s; + double n; + int i; + + printf("%s(%d)\n", F->name, F->numparams); + if (F->strict) printf("\tstrict\n"); + if (F->lightweight) printf("\tlightweight\n"); + if (F->arguments) printf("\targuments\n"); + printf("\tsource %s:%d\n", F->filename, F->line); + for (i = 0; i < F->funlen; ++i) + printf("\tfunction %d %s\n", i, F->funtab[i]->name); + for (i = 0; i < F->varlen; ++i) + printf("\tlocal %d %s\n", i + 1, F->vartab[i]); + + printf("{\n"); + while (p < end) { + int ln = *p++; + int c = *p++; + + printf("%5d(%3d): ", (int)(p - F->code) - 2, ln); + ps(opname[c]); + + switch (c) { + case OP_INTEGER: + printf(" %ld", (long)((*p++) - 32768)); + break; + case OP_NUMBER: + memcpy(&n, p, sizeof(n)); + p += sizeof(n) / sizeof(*p); + printf(" %.9g", n); + break; + case OP_STRING: + memcpy(&s, p, sizeof(s)); + p += sizeof(s) / sizeof(*p); + pc(' '); + pstr(s); + break; + case OP_NEWREGEXP: + pc(' '); + memcpy(&s, p, sizeof(s)); + p += sizeof(s) / sizeof(*p); + pregexp(s, *p++); + break; + + case OP_GETVAR: + case OP_HASVAR: + case OP_SETVAR: + case OP_DELVAR: + case OP_GETPROP_S: + case OP_SETPROP_S: + case OP_DELPROP_S: + case OP_CATCH: + memcpy(&s, p, sizeof(s)); + p += sizeof(s) / sizeof(*p); + pc(' '); + ps(s); + break; + + case OP_GETLOCAL: + case OP_SETLOCAL: + case OP_DELLOCAL: + printf(" %s", F->vartab[*p++ - 1]); + break; + + case OP_CLOSURE: + case OP_CALL: + case OP_NEW: + case OP_JUMP: + case OP_JTRUE: + case OP_JFALSE: + case OP_JCASE: + case OP_TRY: + printf(" %ld", (long)*p++); + break; + } + + putchar('\n'); + } + printf("}\n"); + + for (i = 0; i < F->funlen; ++i) { + if (F->funtab[i] != F) { + printf("function %d ", i); + jsC_dumpfunction(J, F->funtab[i]); + } + } +} + +/* Pretty-printed Javascript syntax */ + +static int prec(enum js_AstType type) +{ + switch (type) { + case AST_IDENTIFIER: + case EXP_IDENTIFIER: + case EXP_NUMBER: + case EXP_STRING: + case EXP_REGEXP: + case EXP_ELISION: + case EXP_NULL: + case EXP_TRUE: + case EXP_FALSE: + case EXP_THIS: + case EXP_ARRAY: + case EXP_OBJECT: + return 170; + + case EXP_FUN: + case EXP_INDEX: + case EXP_MEMBER: + case EXP_CALL: + case EXP_NEW: + return 160; + + case EXP_POSTINC: + case EXP_POSTDEC: + return 150; + + case EXP_DELETE: + case EXP_VOID: + case EXP_TYPEOF: + case EXP_PREINC: + case EXP_PREDEC: + case EXP_POS: + case EXP_NEG: + case EXP_BITNOT: + case EXP_LOGNOT: + return 140; + + case EXP_MOD: + case EXP_DIV: + case EXP_MUL: + return 130; + + case EXP_SUB: + case EXP_ADD: + return 120; + + case EXP_USHR: + case EXP_SHR: + case EXP_SHL: + return 110; + + case EXP_IN: + case EXP_INSTANCEOF: + case EXP_GE: + case EXP_LE: + case EXP_GT: + case EXP_LT: + return 100; + + case EXP_STRICTNE: + case EXP_STRICTEQ: + case EXP_NE: + case EXP_EQ: + return 90; + + case EXP_BITAND: return 80; + case EXP_BITXOR: return 70; + case EXP_BITOR: return 60; + case EXP_LOGAND: return 50; + case EXP_LOGOR: return 40; + + case EXP_COND: + return 30; + + case EXP_ASS: + case EXP_ASS_MUL: + case EXP_ASS_DIV: + case EXP_ASS_MOD: + case EXP_ASS_ADD: + case EXP_ASS_SUB: + case EXP_ASS_SHL: + case EXP_ASS_SHR: + case EXP_ASS_USHR: + case EXP_ASS_BITAND: + case EXP_ASS_BITXOR: + case EXP_ASS_BITOR: + return 20; + +#define COMMA 15 + + case EXP_COMMA: + return 10; + + default: + return 0; + } +} + +static void pstmlist(int d, js_Ast *list); +static void pexpi(int d, int i, js_Ast *exp); +static void pstm(int d, js_Ast *stm); +static void slist(int d, js_Ast *list); +static void sblock(int d, js_Ast *list); + +static void pargs(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pexpi(d, COMMA, list->a); + list = list->b; + if (list) + comma(); + } +} + +static void parray(int d, js_Ast *list) +{ + pc('['); + while (list) { + assert(list->type == AST_LIST); + pexpi(d, COMMA, list->a); + list = list->b; + if (list) + comma(); + } + pc(']'); +} + +static void pobject(int d, js_Ast *list) +{ + pc('{'); + if (list) { + nl(); + in(d+1); + } + while (list) { + js_Ast *kv = list->a; + assert(list->type == AST_LIST); + switch (kv->type) { + default: break; + case EXP_PROP_VAL: + pexpi(d+1, COMMA, kv->a); + pc(':'); sp(); + pexpi(d+1, COMMA, kv->b); + break; + case EXP_PROP_GET: + ps("get "); + pexpi(d+1, COMMA, kv->a); + ps("()"); sp(); pc('{'); nl(); + pstmlist(d+1, kv->c); + in(d+1); pc('}'); + break; + case EXP_PROP_SET: + ps("set "); + pexpi(d+1, COMMA, kv->a); + pc('('); + pargs(d+1, kv->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d+1, kv->c); + in(d+1); pc('}'); + break; + } + list = list->b; + if (list) { + pc(','); + nl(); + in(d+1); + } else { + nl(); + in(d); + } + } + pc('}'); +} + +static void pbin(int d, int p, js_Ast *exp, const char *op) +{ + pexpi(d, p, exp->a); + sp(); + ps(op); + sp(); + pexpi(d, p, exp->b); +} + +static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf) +{ + ps(pre); + pexpi(d, p, exp->a); + ps(suf); +} + +static void pexpi(int d, int p, js_Ast *exp) +{ + int tp, paren; + + if (!exp) return; + + tp = prec(exp->type); + paren = 0; + if (tp < p) { + pc('('); + paren = 1; + } + p = tp; + + switch (exp->type) { + case AST_IDENTIFIER: ps(exp->string); break; + case EXP_IDENTIFIER: ps(exp->string); break; + case EXP_NUMBER: printf("%.9g", exp->number); break; + case EXP_STRING: pstr(exp->string); break; + case EXP_REGEXP: pregexp(exp->string, exp->number); break; + + case EXP_ELISION: ps("elision"); break; + case EXP_NULL: ps("null"); break; + case EXP_TRUE: ps("true"); break; + case EXP_FALSE: ps("false"); break; + case EXP_THIS: ps("this"); break; + + case EXP_OBJECT: pobject(d, exp->a); break; + case EXP_ARRAY: parray(d, exp->a); break; + + case EXP_DELETE: puna(d, p, exp, "delete ", ""); break; + case EXP_VOID: puna(d, p, exp, "void ", ""); break; + case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break; + case EXP_PREINC: puna(d, p, exp, "++", ""); break; + case EXP_PREDEC: puna(d, p, exp, "--", ""); break; + case EXP_POSTINC: puna(d, p, exp, "", "++"); break; + case EXP_POSTDEC: puna(d, p, exp, "", "--"); break; + case EXP_POS: puna(d, p, exp, "+", ""); break; + case EXP_NEG: puna(d, p, exp, "-", ""); break; + case EXP_BITNOT: puna(d, p, exp, "~", ""); break; + case EXP_LOGNOT: puna(d, p, exp, "!", ""); break; + + case EXP_LOGOR: pbin(d, p, exp, "||"); break; + case EXP_LOGAND: pbin(d, p, exp, "&&"); break; + case EXP_BITOR: pbin(d, p, exp, "|"); break; + case EXP_BITXOR: pbin(d, p, exp, "^"); break; + case EXP_BITAND: pbin(d, p, exp, "&"); break; + case EXP_EQ: pbin(d, p, exp, "=="); break; + case EXP_NE: pbin(d, p, exp, "!="); break; + case EXP_STRICTEQ: pbin(d, p, exp, "==="); break; + case EXP_STRICTNE: pbin(d, p, exp, "!=="); break; + case EXP_LT: pbin(d, p, exp, "<"); break; + case EXP_GT: pbin(d, p, exp, ">"); break; + case EXP_LE: pbin(d, p, exp, "<="); break; + case EXP_GE: pbin(d, p, exp, ">="); break; + case EXP_IN: pbin(d, p, exp, "in"); break; + case EXP_SHL: pbin(d, p, exp, "<<"); break; + case EXP_SHR: pbin(d, p, exp, ">>"); break; + case EXP_USHR: pbin(d, p, exp, ">>>"); break; + case EXP_ADD: pbin(d, p, exp, "+"); break; + case EXP_SUB: pbin(d, p, exp, "-"); break; + case EXP_MUL: pbin(d, p, exp, "*"); break; + case EXP_DIV: pbin(d, p, exp, "/"); break; + case EXP_MOD: pbin(d, p, exp, "%"); break; + case EXP_ASS: pbin(d, p, exp, "="); break; + case EXP_ASS_MUL: pbin(d, p, exp, "*="); break; + case EXP_ASS_DIV: pbin(d, p, exp, "/="); break; + case EXP_ASS_MOD: pbin(d, p, exp, "%="); break; + case EXP_ASS_ADD: pbin(d, p, exp, "+="); break; + case EXP_ASS_SUB: pbin(d, p, exp, "-="); break; + case EXP_ASS_SHL: pbin(d, p, exp, "<<="); break; + case EXP_ASS_SHR: pbin(d, p, exp, ">>="); break; + case EXP_ASS_USHR: pbin(d, p, exp, ">>>="); break; + case EXP_ASS_BITAND: pbin(d, p, exp, "&="); break; + case EXP_ASS_BITXOR: pbin(d, p, exp, "^="); break; + case EXP_ASS_BITOR: pbin(d, p, exp, "|="); break; + + case EXP_INSTANCEOF: + pexpi(d, p, exp->a); + ps(" instanceof "); + pexpi(d, p, exp->b); + break; + + case EXP_COMMA: + pexpi(d, p, exp->a); + pc(','); sp(); + pexpi(d, p, exp->b); + break; + + case EXP_COND: + pexpi(d, p, exp->a); + sp(); pc('?'); sp(); + pexpi(d, p, exp->b); + sp(); pc(':'); sp(); + pexpi(d, p, exp->c); + break; + + case EXP_INDEX: + pexpi(d, p, exp->a); + pc('['); + pexpi(d, 0, exp->b); + pc(']'); + break; + + case EXP_MEMBER: + pexpi(d, p, exp->a); + pc('.'); + pexpi(d, 0, exp->b); + break; + + case EXP_CALL: + pexpi(d, p, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); + break; + + case EXP_NEW: + ps("new "); + pexpi(d, p, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); + break; + + case EXP_FUN: + if (p == 0) pc('('); + ps("function "); + pexpi(d, 0, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d, exp->c); + in(d); pc('}'); + if (p == 0) pc(')'); + break; + + default: + ps(""); + break; + } + + if (paren) pc(')'); +} + +static void pexp(int d, js_Ast *exp) +{ + pexpi(d, 0, exp); +} + +static void pvar(int d, js_Ast *var) +{ + assert(var->type == EXP_VAR); + pexp(d, var->a); + if (var->b) { + sp(); pc('='); sp(); + pexp(d, var->b); + } +} + +static void pvarlist(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pvar(d, list->a); + list = list->b; + if (list) + comma(); + } +} + +static void pblock(int d, js_Ast *block) +{ + assert(block->type == STM_BLOCK); + pc('{'); nl(); + pstmlist(d, block->a); + in(d); pc('}'); +} + +static void pstmh(int d, js_Ast *stm) +{ + if (stm->type == STM_BLOCK) { + sp(); + pblock(d, stm); + } else { + nl(); + pstm(d+1, stm); + } +} + +static void pcaselist(int d, js_Ast *list) +{ + while (list) { + js_Ast *stm = list->a; + if (stm->type == STM_CASE) { + in(d); ps("case "); pexp(d, stm->a); pc(':'); nl(); + pstmlist(d, stm->b); + } + if (stm->type == STM_DEFAULT) { + in(d); ps("default:"); nl(); + pstmlist(d, stm->a); + } + list = list->b; + } +} + +static void pstm(int d, js_Ast *stm) +{ + if (stm->type == STM_BLOCK) { + pblock(d, stm); + return; + } + + in(d); + + switch (stm->type) { + case AST_FUNDEC: + ps("function "); + pexp(d, stm->a); + pc('('); + pargs(d, stm->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d, stm->c); + in(d); pc('}'); + break; + + case STM_EMPTY: + pc(';'); + break; + + case STM_VAR: + ps("var "); + pvarlist(d, stm->a); + pc(';'); + break; + + case STM_IF: + ps("if"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + if (stm->c) { + nl(); in(d); ps("else"); + pstmh(d, stm->c); + } + break; + + case STM_DO: + ps("do"); + pstmh(d, stm->a); + nl(); + in(d); ps("while"); sp(); pc('('); pexp(d, stm->b); pc(')'); pc(';'); + break; + + case STM_WHILE: + ps("while"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + break; + + case STM_FOR: + ps("for"); sp(); pc('('); + pexp(d, stm->a); pc(';'); sp(); + pexp(d, stm->b); pc(';'); sp(); + pexp(d, stm->c); pc(')'); + pstmh(d, stm->d); + break; + case STM_FOR_VAR: + ps("for"); sp(); ps("(var "); + pvarlist(d, stm->a); pc(';'); sp(); + pexp(d, stm->b); pc(';'); sp(); + pexp(d, stm->c); pc(')'); + pstmh(d, stm->d); + break; + case STM_FOR_IN: + ps("for"); sp(); pc('('); + pexp(d, stm->a); ps(" in "); + pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + break; + case STM_FOR_IN_VAR: + ps("for"); sp(); ps("(var "); + pvarlist(d, stm->a); ps(" in "); + pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + break; + + case STM_CONTINUE: + ps("continue"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_BREAK: + ps("break"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_RETURN: + ps("return"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_WITH: + ps("with"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + break; + + case STM_SWITCH: + ps("switch"); sp(); pc('('); + pexp(d, stm->a); + pc(')'); sp(); pc('{'); nl(); + pcaselist(d, stm->b); + in(d); pc('}'); + break; + + case STM_THROW: + ps("throw "); pexp(d, stm->a); pc(';'); + break; + + case STM_TRY: + ps("try"); + if (minify && stm->a->type != STM_BLOCK) + pc(' '); + pstmh(d, stm->a); + if (stm->b && stm->c) { + nl(); in(d); ps("catch"); sp(); pc('('); pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + } + if (stm->d) { + nl(); in(d); ps("finally"); + pstmh(d, stm->d); + } + break; + + case STM_LABEL: + pexp(d, stm->a); pc(':'); sp(); pstm(d, stm->b); + break; + + case STM_DEBUGGER: + ps("debugger"); + pc(';'); + break; + + default: + pexp(d, stm); + pc(';'); + } +} + +static void pstmlist(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pstm(d+1, list->a); + nl(); + list = list->b; + } +} + +static void jsP_dumpsyntax(js_State *J, js_Ast *prog) +{ + if (prog) { + if (prog->type == AST_LIST) + pstmlist(-1, prog); + else { + pstm(0, prog); + nl(); + } + } + if (minify > 1) + putchar('\n'); +} + +/* S-expression list representation */ + +static void snode(int d, js_Ast *node) +{ + void (*afun)(int,js_Ast*) = snode; + void (*bfun)(int,js_Ast*) = snode; + void (*cfun)(int,js_Ast*) = snode; + void (*dfun)(int,js_Ast*) = snode; + + if (!node) { + return; + } + + if (node->type == AST_LIST) { + slist(d, node); + return; + } + + pc('('); + ps(astname[node->type]); + switch (node->type) { + default: break; + case AST_IDENTIFIER: pc(' '); ps(node->string); break; + case EXP_IDENTIFIER: pc(' '); ps(node->string); break; + case EXP_STRING: pc(' '); pstr(node->string); break; + case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break; + case EXP_NUMBER: printf(" %.9g", node->number); break; + case STM_BLOCK: afun = sblock; break; + case AST_FUNDEC: case EXP_FUN: cfun = sblock; break; + case EXP_PROP_GET: cfun = sblock; break; + case EXP_PROP_SET: cfun = sblock; break; + case STM_SWITCH: bfun = sblock; break; + case STM_CASE: bfun = sblock; break; + case STM_DEFAULT: afun = sblock; break; + } + if (node->a) { pc(' '); afun(d, node->a); } + if (node->b) { pc(' '); bfun(d, node->b); } + if (node->c) { pc(' '); cfun(d, node->c); } + if (node->d) { pc(' '); dfun(d, node->d); } + pc(')'); +} + +static void slist(int d, js_Ast *list) +{ + pc('['); + while (list) { + assert(list->type == AST_LIST); + snode(d, list->a); + list = list->b; + if (list) + pc(' '); + } + pc(']'); +} + +static void sblock(int d, js_Ast *list) +{ + ps("[\n"); + in(d+1); + while (list) { + assert(list->type == AST_LIST); + snode(d+1, list->a); + list = list->b; + if (list) { + nl(); + in(d+1); + } + } + nl(); in(d); pc(']'); +} + +static void jsP_dumplist(js_State *J, js_Ast *prog) +{ + if (prog) { + if (prog->type == AST_LIST) + sblock(0, prog); + else + snode(0, prog); + nl(); + } +} + +static void js_ppstring(js_State *J, const char *filename, const char *source) +{ + js_Ast *P; + js_Function *F; + + if (js_try(J)) { + jsP_freeparse(J); + js_throw(J); + } + + P = jsP_parse(J, filename, source); + F = jsC_compilescript(J, P, J->default_strict); + + switch (format) { + case 0: + jsP_dumpsyntax(J, P); + break; + case 1: + jsP_dumplist(J, P); + break; + case 2: + jsC_dumpfunction(J, F); + break; + } + + jsP_freeparse(J); + js_endtry(J); +} + +static void js_ppfile(js_State *J, const char *filename) +{ + FILE * volatile f = NULL; + char * volatile s = NULL; + int n, t; + + if (js_try(J)) { + js_free(J, s); + if (f) fclose(f); + js_throw(J); + } + + f = fopen(filename, "rb"); + if (!f) { + js_error(J, "cannot open file: '%s'", filename); + } + + if (fseek(f, 0, SEEK_END) < 0) { + js_error(J, "cannot seek in file: '%s'", filename); + } + + n = ftell(f); + if (n < 0) { + js_error(J, "cannot tell in file: '%s'", filename); + } + + if (fseek(f, 0, SEEK_SET) < 0) { + js_error(J, "cannot seek in file: '%s'", filename); + } + + s = js_malloc(J, n + 1); /* add space for string terminator */ + if (!s) { + js_error(J, "cannot allocate storage for file contents: '%s'", filename); + } + + t = fread(s, 1, (size_t)n, f); + if (t != n) { + js_error(J, "cannot read data from file: '%s'", filename); + } + + s[n] = 0; /* zero-terminate string containing file data */ + + js_ppstring(J, filename, s); + + js_endtry(J); + js_free(J, s); + fclose(f); +} + +static void js_tryppfile(js_State *J, const char *file) +{ + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + return; + } + js_ppfile(J, file); + js_endtry(J); +} + +int +main(int argc, char **argv) +{ + js_State *J; + int i; + + if (argc < 2) { + fprintf(stderr, "usage: mujs-pp [-m | -mm | -s | -c] input.js\n"); + fprintf(stderr, " -m\tminify output\n"); + fprintf(stderr, " -mm\tminify output more\n"); + fprintf(stderr, " -s\tprint syntax tree\n"); + fprintf(stderr, " -c\tprint bytecode\n"); + } + + J = js_newstate(NULL, NULL, 0); + + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-m")) + format = 0, minify = 1; + else if (!strcmp(argv[i], "-mm")) + format = 0, minify = 2; + else if (!strcmp(argv[i], "-s")) + format = 1, minify = 0; + else if (!strcmp(argv[i], "-c")) + format = 2, minify = 0; + else + js_tryppfile(J, argv[i]); + } + + js_gc(J, 0); + js_freestate(J); + + return 0; +} diff --git a/src/mujs/regexp.c b/src/mujs/regexp.c new file mode 100644 index 0000000..952a1d2 --- /dev/null +++ b/src/mujs/regexp.c @@ -0,0 +1,1277 @@ +#include +#include +#include +#include +#include + +#include "regexp.h" +#include "utf.h" + +#define emit regemit +#define next regnext +#define accept regaccept + +#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) + +#define REPINF 255 +#ifndef REG_MAXPROG +#define REG_MAXPROG (32 << 10) +#endif +#ifndef REG_MAXREC +#define REG_MAXREC 1024 +#endif +#ifndef REG_MAXSPAN +#define REG_MAXSPAN 64 +#endif +#ifndef REG_MAXCLASS +#define REG_MAXCLASS 128 +#endif + +typedef struct Reclass Reclass; +typedef struct Renode Renode; +typedef struct Reinst Reinst; +typedef struct Rethread Rethread; + +struct Reclass { + Rune *end; + Rune spans[REG_MAXSPAN]; +}; + +struct Reprog { + Reinst *start, *end; + Reclass *cclass; + int flags; + int nsub; +}; + +struct cstate { + Reprog *prog; + Renode *pstart, *pend; + + const char *source; + int ncclass; + int nsub; + Renode *sub[REG_MAXSUB]; + + int lookahead; + Rune yychar; + Reclass *yycc; + int yymin, yymax; + + const char *error; + jmp_buf kaboom; + + Reclass cclass[REG_MAXCLASS]; +}; + +static void die(struct cstate *g, const char *message) +{ + g->error = message; + longjmp(g->kaboom, 1); +} + +static int canon(Rune c) +{ + Rune u = toupperrune(c); + if (c >= 128 && u < 128) + return c; + return u; +} + +/* Scan */ + +enum { + L_CHAR = 256, + L_CCLASS, /* character class */ + L_NCCLASS, /* negative character class */ + L_NC, /* "(?:" no capture */ + L_PLA, /* "(?=" positive lookahead */ + L_NLA, /* "(?!" negative lookahead */ + L_WORD, /* "\b" word boundary */ + L_NWORD, /* "\B" non-word boundary */ + L_REF, /* "\1" back-reference */ + L_COUNT, /* {M,N} */ +}; + +static int hex(struct cstate *g, int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + die(g, "invalid escape sequence"); + return 0; +} + +static int dec(struct cstate *g, int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + die(g, "invalid quantifier"); + return 0; +} + +#define ESCAPES "BbDdSsWw^$\\.*+?()[]{}|-0123456789" + +static int isunicodeletter(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || isalpharune(c); +} + +static int nextrune(struct cstate *g) +{ + if (!*g->source) { + g->yychar = EOF; + return 0; + } + g->source += chartorune(&g->yychar, g->source); + if (g->yychar == '\\') { + if (!*g->source) + die(g, "unterminated escape sequence"); + g->source += chartorune(&g->yychar, g->source); + switch (g->yychar) { + case 'f': g->yychar = '\f'; return 0; + case 'n': g->yychar = '\n'; return 0; + case 'r': g->yychar = '\r'; return 0; + case 't': g->yychar = '\t'; return 0; + case 'v': g->yychar = '\v'; return 0; + case 'c': + if (!g->source[0]) + die(g, "unterminated escape sequence"); + g->yychar = (*g->source++) & 31; + return 0; + case 'x': + if (!g->source[0] || !g->source[1]) + die(g, "unterminated escape sequence"); + g->yychar = hex(g, *g->source++) << 4; + g->yychar += hex(g, *g->source++); + if (g->yychar == 0) { + g->yychar = '0'; + return 1; + } + return 0; + case 'u': + if (!g->source[0] || !g->source[1] || !g->source[2] || !g->source[3]) + die(g, "unterminated escape sequence"); + g->yychar = hex(g, *g->source++) << 12; + g->yychar += hex(g, *g->source++) << 8; + g->yychar += hex(g, *g->source++) << 4; + g->yychar += hex(g, *g->source++); + if (g->yychar == 0) { + g->yychar = '0'; + return 1; + } + return 0; + case 0: + g->yychar = '0'; + return 1; + } + if (strchr(ESCAPES, g->yychar)) + return 1; + if (isunicodeletter(g->yychar) || g->yychar == '_') /* check identity escape */ + die(g, "invalid escape character"); + return 0; + } + return 0; +} + +static int lexcount(struct cstate *g) +{ + g->yychar = *g->source++; + + g->yymin = dec(g, g->yychar); + g->yychar = *g->source++; + while (g->yychar != ',' && g->yychar != '}') { + g->yymin = g->yymin * 10 + dec(g, g->yychar); + g->yychar = *g->source++; + if (g->yymin >= REPINF) + die(g, "numeric overflow"); + } + + if (g->yychar == ',') { + g->yychar = *g->source++; + if (g->yychar == '}') { + g->yymax = REPINF; + } else { + g->yymax = dec(g, g->yychar); + g->yychar = *g->source++; + while (g->yychar != '}') { + g->yymax = g->yymax * 10 + dec(g, g->yychar); + g->yychar = *g->source++; + if (g->yymax >= REPINF) + die(g, "numeric overflow"); + } + } + } else { + g->yymax = g->yymin; + } + + return L_COUNT; +} + +static void newcclass(struct cstate *g) +{ + if (g->ncclass >= REG_MAXCLASS) + die(g, "too many character classes"); + g->yycc = g->cclass + g->ncclass++; + g->yycc->end = g->yycc->spans; +} + +static void addrange(struct cstate *g, Rune a, Rune b) +{ + Reclass *cc = g->yycc; + Rune *p; + + if (a > b) + die(g, "invalid character class range"); + + /* extend existing ranges if they overlap */ + for (p = cc->spans; p < cc->end; p += 2) { + /* completely inside old range */ + if (a >= p[0] && b <= p[1]) + return; + + /* completely swallows old range */ + if (a < p[0] && b >= p[1]) { + p[0] = a; + p[1] = b; + return; + } + + /* extend at start */ + if (b >= p[0] - 1 && b <= p[1] && a < p[0]) { + p[0] = a; + return; + } + + /* extend at end */ + if (a >= p[0] && a <= p[1] + 1 && b > p[1]) { + p[1] = b; + return; + } + } + + if (cc->end + 2 >= cc->spans + nelem(cc->spans)) + die(g, "too many character class ranges"); + *cc->end++ = a; + *cc->end++ = b; +} + +static void addranges_d(struct cstate *g) +{ + addrange(g, '0', '9'); +} + +static void addranges_D(struct cstate *g) +{ + addrange(g, 0, '0'-1); + addrange(g, '9'+1, 0xFFFF); +} + +static void addranges_s(struct cstate *g) +{ + addrange(g, 0x9, 0xD); + addrange(g, 0x20, 0x20); + addrange(g, 0xA0, 0xA0); + addrange(g, 0x2028, 0x2029); + addrange(g, 0xFEFF, 0xFEFF); +} + +static void addranges_S(struct cstate *g) +{ + addrange(g, 0, 0x9-1); + addrange(g, 0xD+1, 0x20-1); + addrange(g, 0x20+1, 0xA0-1); + addrange(g, 0xA0+1, 0x2028-1); + addrange(g, 0x2029+1, 0xFEFF-1); + addrange(g, 0xFEFF+1, 0xFFFF); +} + +static void addranges_w(struct cstate *g) +{ + addrange(g, '0', '9'); + addrange(g, 'A', 'Z'); + addrange(g, '_', '_'); + addrange(g, 'a', 'z'); +} + +static void addranges_W(struct cstate *g) +{ + addrange(g, 0, '0'-1); + addrange(g, '9'+1, 'A'-1); + addrange(g, 'Z'+1, '_'-1); + addrange(g, '_'+1, 'a'-1); + addrange(g, 'z'+1, 0xFFFF); +} + +static int lexclass(struct cstate *g) +{ + int type = L_CCLASS; + int quoted, havesave, havedash; + Rune save = 0; + + newcclass(g); + + quoted = nextrune(g); + if (!quoted && g->yychar == '^') { + type = L_NCCLASS; + quoted = nextrune(g); + } + + havesave = havedash = 0; + for (;;) { + if (g->yychar == EOF) + die(g, "unterminated character class"); + if (!quoted && g->yychar == ']') + break; + + if (!quoted && g->yychar == '-') { + if (havesave) { + if (havedash) { + addrange(g, save, '-'); + havesave = havedash = 0; + } else { + havedash = 1; + } + } else { + save = '-'; + havesave = 1; + } + } else if (quoted && strchr("DSWdsw", g->yychar)) { + if (havesave) { + addrange(g, save, save); + if (havedash) + addrange(g, '-', '-'); + } + switch (g->yychar) { + case 'd': addranges_d(g); break; + case 's': addranges_s(g); break; + case 'w': addranges_w(g); break; + case 'D': addranges_D(g); break; + case 'S': addranges_S(g); break; + case 'W': addranges_W(g); break; + } + havesave = havedash = 0; + } else { + if (quoted) { + if (g->yychar == 'b') + g->yychar = '\b'; + else if (g->yychar == '0') + g->yychar = 0; + /* else identity escape */ + } + if (havesave) { + if (havedash) { + addrange(g, save, g->yychar); + havesave = havedash = 0; + } else { + addrange(g, save, save); + save = g->yychar; + } + } else { + save = g->yychar; + havesave = 1; + } + } + + quoted = nextrune(g); + } + + if (havesave) { + addrange(g, save, save); + if (havedash) + addrange(g, '-', '-'); + } + + return type; +} + +static int lex(struct cstate *g) +{ + int quoted = nextrune(g); + if (quoted) { + switch (g->yychar) { + case 'b': return L_WORD; + case 'B': return L_NWORD; + case 'd': newcclass(g); addranges_d(g); return L_CCLASS; + case 's': newcclass(g); addranges_s(g); return L_CCLASS; + case 'w': newcclass(g); addranges_w(g); return L_CCLASS; + case 'D': newcclass(g); addranges_d(g); return L_NCCLASS; + case 'S': newcclass(g); addranges_s(g); return L_NCCLASS; + case 'W': newcclass(g); addranges_w(g); return L_NCCLASS; + case '0': g->yychar = 0; return L_CHAR; + } + if (g->yychar >= '0' && g->yychar <= '9') { + g->yychar -= '0'; + if (*g->source >= '0' && *g->source <= '9') + g->yychar = g->yychar * 10 + *g->source++ - '0'; + return L_REF; + } + return L_CHAR; + } + + switch (g->yychar) { + case EOF: + case '$': case ')': case '*': case '+': + case '.': case '?': case '^': case '|': + return g->yychar; + } + + if (g->yychar == '{') + return lexcount(g); + if (g->yychar == '[') + return lexclass(g); + if (g->yychar == '(') { + if (g->source[0] == '?') { + if (g->source[1] == ':') { + g->source += 2; + return L_NC; + } + if (g->source[1] == '=') { + g->source += 2; + return L_PLA; + } + if (g->source[1] == '!') { + g->source += 2; + return L_NLA; + } + } + return '('; + } + + return L_CHAR; +} + +/* Parse */ + +enum { + P_CAT, P_ALT, P_REP, + P_BOL, P_EOL, P_WORD, P_NWORD, + P_PAR, P_PLA, P_NLA, + P_ANY, P_CHAR, P_CCLASS, P_NCCLASS, + P_REF, +}; + +struct Renode { + unsigned char type; + unsigned char ng, m, n; + Rune c; + int cc; + Renode *x; + Renode *y; +}; + +static Renode *newnode(struct cstate *g, int type) +{ + Renode *node = g->pend++; + node->type = type; + node->cc = -1; + node->c = 0; + node->ng = 0; + node->m = 0; + node->n = 0; + node->x = node->y = NULL; + return node; +} + +static int empty(Renode *node) +{ + if (!node) return 1; + switch (node->type) { + default: return 1; + case P_CAT: return empty(node->x) && empty(node->y); + case P_ALT: return empty(node->x) || empty(node->y); + case P_REP: return empty(node->x) || node->m == 0; + case P_PAR: return empty(node->x); + case P_REF: return empty(node->x); + case P_ANY: case P_CHAR: case P_CCLASS: case P_NCCLASS: return 0; + } +} + +static Renode *newrep(struct cstate *g, Renode *atom, int ng, int min, int max) +{ + Renode *rep = newnode(g, P_REP); + if (max == REPINF && empty(atom)) + die(g, "infinite loop matching the empty string"); + rep->ng = ng; + rep->m = min; + rep->n = max; + rep->x = atom; + return rep; +} + +static void next(struct cstate *g) +{ + g->lookahead = lex(g); +} + +static int accept(struct cstate *g, int t) +{ + if (g->lookahead == t) { + next(g); + return 1; + } + return 0; +} + +static Renode *parsealt(struct cstate *g); + +static Renode *parseatom(struct cstate *g) +{ + Renode *atom; + if (g->lookahead == L_CHAR) { + atom = newnode(g, P_CHAR); + atom->c = g->yychar; + next(g); + return atom; + } + if (g->lookahead == L_CCLASS) { + atom = newnode(g, P_CCLASS); + atom->cc = g->yycc - g->cclass; + next(g); + return atom; + } + if (g->lookahead == L_NCCLASS) { + atom = newnode(g, P_NCCLASS); + atom->cc = g->yycc - g->cclass; + next(g); + return atom; + } + if (g->lookahead == L_REF) { + atom = newnode(g, P_REF); + if (g->yychar == 0 || g->yychar >= g->nsub || !g->sub[g->yychar]) + die(g, "invalid back-reference"); + atom->n = g->yychar; + atom->x = g->sub[g->yychar]; + next(g); + return atom; + } + if (accept(g, '.')) + return newnode(g, P_ANY); + if (accept(g, '(')) { + atom = newnode(g, P_PAR); + if (g->nsub == REG_MAXSUB) + die(g, "too many captures"); + atom->n = g->nsub++; + atom->x = parsealt(g); + g->sub[atom->n] = atom; + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_NC)) { + atom = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_PLA)) { + atom = newnode(g, P_PLA); + atom->x = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_NLA)) { + atom = newnode(g, P_NLA); + atom->x = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + die(g, "syntax error"); + return NULL; +} + +static Renode *parserep(struct cstate *g) +{ + Renode *atom; + + if (accept(g, '^')) return newnode(g, P_BOL); + if (accept(g, '$')) return newnode(g, P_EOL); + if (accept(g, L_WORD)) return newnode(g, P_WORD); + if (accept(g, L_NWORD)) return newnode(g, P_NWORD); + + atom = parseatom(g); + if (g->lookahead == L_COUNT) { + int min = g->yymin, max = g->yymax; + next(g); + if (max < min) + die(g, "invalid quantifier"); + return newrep(g, atom, accept(g, '?'), min, max); + } + if (accept(g, '*')) return newrep(g, atom, accept(g, '?'), 0, REPINF); + if (accept(g, '+')) return newrep(g, atom, accept(g, '?'), 1, REPINF); + if (accept(g, '?')) return newrep(g, atom, accept(g, '?'), 0, 1); + return atom; +} + +static Renode *parsecat(struct cstate *g) +{ + Renode *cat, *head, **tail; + if (g->lookahead != EOF && g->lookahead != '|' && g->lookahead != ')') { + /* Build a right-leaning tree by splicing in new 'cat' at the tail. */ + head = parserep(g); + tail = &head; + while (g->lookahead != EOF && g->lookahead != '|' && g->lookahead != ')') { + cat = newnode(g, P_CAT); + cat->x = *tail; + cat->y = parserep(g); + *tail = cat; + tail = &cat->y; + } + return head; + } + return NULL; +} + +static Renode *parsealt(struct cstate *g) +{ + Renode *alt, *x; + alt = parsecat(g); + while (accept(g, '|')) { + x = alt; + alt = newnode(g, P_ALT); + alt->x = x; + alt->y = parsecat(g); + } + return alt; +} + +/* Compile */ + +enum { + I_END, I_JUMP, I_SPLIT, I_PLA, I_NLA, + I_ANYNL, I_ANY, I_CHAR, I_CCLASS, I_NCCLASS, I_REF, + I_BOL, I_EOL, I_WORD, I_NWORD, + I_LPAR, I_RPAR +}; + +struct Reinst { + unsigned char opcode; + unsigned char n; + Rune c; + Reclass *cc; + Reinst *x; + Reinst *y; +}; + +static int count(struct cstate *g, Renode *node, int depth) +{ + int min, max, n; + if (!node) return 0; + if (++depth > REG_MAXREC) die(g, "stack overflow"); + switch (node->type) { + default: return 1; + case P_CAT: return count(g, node->x, depth) + count(g, node->y, depth); + case P_ALT: return count(g, node->x, depth) + count(g, node->y, depth) + 2; + case P_REP: + min = node->m; + max = node->n; + if (min == max) n = count(g, node->x, depth) * min; + else if (max < REPINF) n = count(g, node->x, depth) * max + (max - min); + else n = count(g, node->x, depth) * (min + 1) + 2; + if (n < 0 || n > REG_MAXPROG) die(g, "program too large"); + return n; + case P_PAR: return count(g, node->x, depth) + 2; + case P_PLA: return count(g, node->x, depth) + 2; + case P_NLA: return count(g, node->x, depth) + 2; + } +} + +static Reinst *emit(Reprog *prog, int opcode) +{ + Reinst *inst = prog->end++; + inst->opcode = opcode; + inst->n = 0; + inst->c = 0; + inst->cc = NULL; + inst->x = inst->y = NULL; + return inst; +} + +static void compile(Reprog *prog, Renode *node) +{ + Reinst *inst, *split, *jump; + int i; + +loop: + if (!node) + return; + + switch (node->type) { + case P_CAT: + compile(prog, node->x); + node = node->y; + goto loop; + + case P_ALT: + split = emit(prog, I_SPLIT); + compile(prog, node->x); + jump = emit(prog, I_JUMP); + compile(prog, node->y); + split->x = split + 1; + split->y = jump + 1; + jump->x = prog->end; + break; + + case P_REP: + inst = NULL; /* silence compiler warning. assert(node->m > 0). */ + for (i = 0; i < node->m; ++i) { + inst = prog->end; + compile(prog, node->x); + } + if (node->m == node->n) + break; + if (node->n < REPINF) { + for (i = node->m; i < node->n; ++i) { + split = emit(prog, I_SPLIT); + compile(prog, node->x); + if (node->ng) { + split->y = split + 1; + split->x = prog->end; + } else { + split->x = split + 1; + split->y = prog->end; + } + } + } else if (node->m == 0) { + split = emit(prog, I_SPLIT); + compile(prog, node->x); + jump = emit(prog, I_JUMP); + if (node->ng) { + split->y = split + 1; + split->x = prog->end; + } else { + split->x = split + 1; + split->y = prog->end; + } + jump->x = split; + } else { + split = emit(prog, I_SPLIT); + if (node->ng) { + split->y = inst; + split->x = prog->end; + } else { + split->x = inst; + split->y = prog->end; + } + } + break; + + case P_BOL: emit(prog, I_BOL); break; + case P_EOL: emit(prog, I_EOL); break; + case P_WORD: emit(prog, I_WORD); break; + case P_NWORD: emit(prog, I_NWORD); break; + + case P_PAR: + inst = emit(prog, I_LPAR); + inst->n = node->n; + compile(prog, node->x); + inst = emit(prog, I_RPAR); + inst->n = node->n; + break; + case P_PLA: + split = emit(prog, I_PLA); + compile(prog, node->x); + emit(prog, I_END); + split->x = split + 1; + split->y = prog->end; + break; + case P_NLA: + split = emit(prog, I_NLA); + compile(prog, node->x); + emit(prog, I_END); + split->x = split + 1; + split->y = prog->end; + break; + + case P_ANY: + emit(prog, I_ANY); + break; + case P_CHAR: + inst = emit(prog, I_CHAR); + inst->c = (prog->flags & REG_ICASE) ? canon(node->c) : node->c; + break; + case P_CCLASS: + inst = emit(prog, I_CCLASS); + inst->cc = prog->cclass + node->cc; + break; + case P_NCCLASS: + inst = emit(prog, I_NCCLASS); + inst->cc = prog->cclass + node->cc; + break; + case P_REF: + inst = emit(prog, I_REF); + inst->n = node->n; + break; + } +} + +#ifdef TEST +static void dumpnode(struct cstate *g, Renode *node) +{ + Rune *p; + Reclass *cc; + if (!node) { printf("Empty"); return; } + switch (node->type) { + case P_CAT: printf("Cat("); dumpnode(g, node->x); printf(", "); dumpnode(g, node->y); printf(")"); break; + case P_ALT: printf("Alt("); dumpnode(g, node->x); printf(", "); dumpnode(g, node->y); printf(")"); break; + case P_REP: + printf(node->ng ? "NgRep(%d,%d," : "Rep(%d,%d,", node->m, node->n); + dumpnode(g, node->x); + printf(")"); + break; + case P_BOL: printf("Bol"); break; + case P_EOL: printf("Eol"); break; + case P_WORD: printf("Word"); break; + case P_NWORD: printf("NotWord"); break; + case P_PAR: printf("Par(%d,", node->n); dumpnode(g, node->x); printf(")"); break; + case P_PLA: printf("PLA("); dumpnode(g, node->x); printf(")"); break; + case P_NLA: printf("NLA("); dumpnode(g, node->x); printf(")"); break; + case P_ANY: printf("Any"); break; + case P_CHAR: printf("Char(%c)", node->c); break; + case P_CCLASS: + printf("Class("); + cc = g->cclass + node->cc; + for (p = cc->spans; p < cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); + printf(")"); + break; + case P_NCCLASS: + printf("NotClass("); + cc = g->cclass + node->cc; + for (p = cc->spans; p < cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); + printf(")"); + break; + case P_REF: printf("Ref(%d)", node->n); break; + } +} + +static void dumpcclass(Reclass *cc) { + Rune *p; + for (p = cc->spans; p < cc->end; p += 2) { + if (p[0] > 32 && p[0] < 127) + printf(" %c", p[0]); + else + printf(" \\x%02x", p[0]); + if (p[1] > 32 && p[1] < 127) + printf("-%c", p[1]); + else + printf("-\\x%02x", p[1]); + } + putchar('\n'); +} + +static void dumpprog(Reprog *prog) +{ + Reinst *inst; + int i; + for (i = 0, inst = prog->start; inst < prog->end; ++i, ++inst) { + printf("% 5d: ", i); + switch (inst->opcode) { + case I_END: puts("end"); break; + case I_JUMP: printf("jump %d\n", (int)(inst->x - prog->start)); break; + case I_SPLIT: printf("split %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_PLA: printf("pla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_NLA: printf("nla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_ANY: puts("any"); break; + case I_ANYNL: puts("anynl"); break; + case I_CHAR: printf(inst->c >= 32 && inst->c < 127 ? "char '%c'\n" : "char U+%04X\n", inst->c); break; + case I_CCLASS: printf("cclass"); dumpcclass(inst->cc); break; + case I_NCCLASS: printf("ncclass"); dumpcclass(inst->cc); break; + case I_REF: printf("ref %d\n", inst->n); break; + case I_BOL: puts("bol"); break; + case I_EOL: puts("eol"); break; + case I_WORD: puts("word"); break; + case I_NWORD: puts("nword"); break; + case I_LPAR: printf("lpar %d\n", inst->n); break; + case I_RPAR: printf("rpar %d\n", inst->n); break; + } + } +} +#endif + +Reprog *regcompx(void *(*alloc)(void *ctx, void *p, int n), void *ctx, + const char *pattern, int cflags, const char **errorp) +{ + struct cstate g; + Renode *node; + Reinst *split, *jump; + int i, n; + + g.pstart = NULL; + g.prog = NULL; + + if (setjmp(g.kaboom)) { + if (errorp) *errorp = g.error; + alloc(ctx, g.pstart, 0); + if (g.prog) { + alloc(ctx, g.prog->cclass, 0); + alloc(ctx, g.prog->start, 0); + alloc(ctx, g.prog, 0); + } + return NULL; + } + + g.prog = alloc(ctx, NULL, sizeof (Reprog)); + if (!g.prog) + die(&g, "cannot allocate regular expression"); + g.prog->start = NULL; + g.prog->cclass = NULL; + + n = strlen(pattern) * 2; + if (n > REG_MAXPROG) + die(&g, "program too large"); + if (n > 0) { + g.pstart = g.pend = alloc(ctx, NULL, sizeof (Renode) * n); + if (!g.pstart) + die(&g, "cannot allocate regular expression parse list"); + } + + g.source = pattern; + g.ncclass = 0; + g.nsub = 1; + for (i = 0; i < REG_MAXSUB; ++i) + g.sub[i] = 0; + + g.prog->flags = cflags; + + next(&g); + node = parsealt(&g); + if (g.lookahead == ')') + die(&g, "unmatched ')'"); + if (g.lookahead != EOF) + die(&g, "syntax error"); + +#ifdef TEST + dumpnode(&g, node); + putchar('\n'); +#endif + + n = 6 + count(&g, node, 0); + if (n < 0 || n > REG_MAXPROG) + die(&g, "program too large"); + + g.prog->nsub = g.nsub; + g.prog->start = g.prog->end = alloc(ctx, NULL, n * sizeof (Reinst)); + if (!g.prog->start) + die(&g, "cannot allocate regular expression instruction list"); + + if (g.ncclass > 0) { + g.prog->cclass = alloc(ctx, NULL, g.ncclass * sizeof (Reclass)); + if (!g.prog->cclass) + die(&g, "cannot allocate regular expression character class list"); + memcpy(g.prog->cclass, g.cclass, g.ncclass * sizeof (Reclass)); + for (i = 0; i < g.ncclass; ++i) + g.prog->cclass[i].end = g.prog->cclass[i].spans + (g.cclass[i].end - g.cclass[i].spans); + } + + split = emit(g.prog, I_SPLIT); + split->x = split + 3; + split->y = split + 1; + emit(g.prog, I_ANYNL); + jump = emit(g.prog, I_JUMP); + jump->x = split; + emit(g.prog, I_LPAR); + compile(g.prog, node); + emit(g.prog, I_RPAR); + emit(g.prog, I_END); + +#ifdef TEST + dumpprog(g.prog); +#endif + + alloc(ctx, g.pstart, 0); + + if (errorp) *errorp = NULL; + return g.prog; +} + +void regfreex(void *(*alloc)(void *ctx, void *p, int n), void *ctx, Reprog *prog) +{ + if (prog) { + if (prog->cclass) + alloc(ctx, prog->cclass, 0); + alloc(ctx, prog->start, 0); + alloc(ctx, prog, 0); + } +} + +static void *default_alloc(void *ctx, void *p, int n) +{ + if (n == 0) { + free(p); + return NULL; + } + return realloc(p, (size_t)n); +} + +Reprog *regcomp(const char *pattern, int cflags, const char **errorp) +{ + return regcompx(default_alloc, NULL, pattern, cflags, errorp); +} + +void regfree(Reprog *prog) +{ + regfreex(default_alloc, NULL, prog); +} + +/* Match */ + +static int isnewline(int c) +{ + return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +static int iswordchar(int c) +{ + return c == '_' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9'); +} + +static int incclass(Reclass *cc, Rune c) +{ + Rune *p; + for (p = cc->spans; p < cc->end; p += 2) + if (p[0] <= c && c <= p[1]) + return 1; + return 0; +} + +static int incclasscanon(Reclass *cc, Rune c) +{ + Rune *p, r; + for (p = cc->spans; p < cc->end; p += 2) + for (r = p[0]; r <= p[1]; ++r) + if (c == canon(r)) + return 1; + return 0; +} + +static int strncmpcanon(const char *a, const char *b, int n) +{ + Rune ra, rb; + int c; + while (n--) { + if (!*a) return -1; + if (!*b) return 1; + a += chartorune(&ra, a); + b += chartorune(&rb, b); + c = canon(ra) - canon(rb); + if (c) + return c; + } + return 0; +} + +static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth) +{ + Resub scratch; + int result; + int i; + Rune c; + + /* stack overflow */ + if (depth > REG_MAXREC) + return -1; + + for (;;) { + switch (pc->opcode) { + case I_END: + return 0; + case I_JUMP: + pc = pc->x; + break; + case I_SPLIT: + scratch = *out; + result = match(pc->x, sp, bol, flags, &scratch, depth+1); + if (result == -1) + return -1; + if (result == 0) { + *out = scratch; + return 0; + } + pc = pc->y; + break; + + case I_PLA: + result = match(pc->x, sp, bol, flags, out, depth+1); + if (result == -1) + return -1; + if (result == 1) + return 1; + pc = pc->y; + break; + case I_NLA: + scratch = *out; + result = match(pc->x, sp, bol, flags, &scratch, depth+1); + if (result == -1) + return -1; + if (result == 0) + return 1; + pc = pc->y; + break; + + case I_ANYNL: + if (!*sp) return 1; + sp += chartorune(&c, sp); + pc = pc + 1; + break; + case I_ANY: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (isnewline(c)) + return 1; + pc = pc + 1; + break; + case I_CHAR: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) + c = canon(c); + if (c != pc->c) + return 1; + pc = pc + 1; + break; + case I_CCLASS: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) { + if (!incclasscanon(pc->cc, canon(c))) + return 1; + } else { + if (!incclass(pc->cc, c)) + return 1; + } + pc = pc + 1; + break; + case I_NCCLASS: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) { + if (incclasscanon(pc->cc, canon(c))) + return 1; + } else { + if (incclass(pc->cc, c)) + return 1; + } + pc = pc + 1; + break; + case I_REF: + i = out->sub[pc->n].ep - out->sub[pc->n].sp; + if (flags & REG_ICASE) { + if (strncmpcanon(sp, out->sub[pc->n].sp, i)) + return 1; + } else { + if (strncmp(sp, out->sub[pc->n].sp, i)) + return 1; + } + if (i > 0) + sp += i; + pc = pc + 1; + break; + + case I_BOL: + if (sp == bol && !(flags & REG_NOTBOL)) { + pc = pc + 1; + break; + } + if (flags & REG_NEWLINE) { + if (sp > bol && isnewline(sp[-1])) { + pc = pc + 1; + break; + } + } + return 1; + case I_EOL: + if (*sp == 0) { + pc = pc + 1; + break; + } + if (flags & REG_NEWLINE) { + if (isnewline(*sp)) { + pc = pc + 1; + break; + } + } + return 1; + case I_WORD: + i = sp > bol && iswordchar(sp[-1]); + i ^= iswordchar(sp[0]); + if (!i) + return 1; + pc = pc + 1; + break; + case I_NWORD: + i = sp > bol && iswordchar(sp[-1]); + i ^= iswordchar(sp[0]); + if (i) + return 1; + pc = pc + 1; + break; + + case I_LPAR: + out->sub[pc->n].sp = sp; + pc = pc + 1; + break; + case I_RPAR: + out->sub[pc->n].ep = sp; + pc = pc + 1; + break; + default: + return 1; + } + } +} + +int regexec(Reprog *prog, const char *sp, Resub *sub, int eflags) +{ + Resub scratch; + int i; + + if (!sub) + sub = &scratch; + + sub->nsub = prog->nsub; + for (i = 0; i < REG_MAXSUB; ++i) + sub->sub[i].sp = sub->sub[i].ep = NULL; + + return match(prog->start, sp, sp, prog->flags | eflags, sub, 0); +} + +#ifdef TEST +int main(int argc, char **argv) +{ + const char *error; + const char *s; + Reprog *p; + Resub m; + int i; + + if (argc > 1) { + p = regcomp(argv[1], 0, &error); + if (!p) { + fprintf(stderr, "regcomp: %s\n", error); + return 1; + } + + if (argc > 2) { + s = argv[2]; + printf("nsub = %d\n", p->nsub); + if (!regexec(p, s, &m, 0)) { + for (i = 0; i < m.nsub; ++i) { + int n = m.sub[i].ep - m.sub[i].sp; + if (n > 0) + printf("match %d: s=%d e=%d n=%d '%.*s'\n", i, (int)(m.sub[i].sp - s), (int)(m.sub[i].ep - s), n, n, m.sub[i].sp); + else + printf("match %d: n=0 ''\n", i); + } + } else { + printf("no match\n"); + } + } + } + + return 0; +} +#endif diff --git a/src/mujs/regexp.h b/src/mujs/regexp.h new file mode 100644 index 0000000..d627e66 --- /dev/null +++ b/src/mujs/regexp.h @@ -0,0 +1,46 @@ +#ifndef regexp_h +#define regexp_h + +#define regcompx js_regcompx +#define regfreex js_regfreex +#define regcomp js_regcomp +#define regexec js_regexec +#define regfree js_regfree + +typedef struct Reprog Reprog; +typedef struct Resub Resub; + +Reprog *regcompx(void *(*alloc)(void *ctx, void *p, int n), void *ctx, + const char *pattern, int cflags, const char **errorp); +void regfreex(void *(*alloc)(void *ctx, void *p, int n), void *ctx, + Reprog *prog); + +Reprog *regcomp(const char *pattern, int cflags, const char **errorp); +int regexec(Reprog *prog, const char *string, Resub *sub, int eflags); +void regfree(Reprog *prog); + +enum { + /* regcomp flags */ + REG_ICASE = 1, + REG_NEWLINE = 2, + + /* regexec flags */ + REG_NOTBOL = 4, +}; + +/* If you redefine REG_MAXSUB, you must make sure both the calling + * code and the regexp.c compilation unit use the same value! + */ +#ifndef REG_MAXSUB +#define REG_MAXSUB 16 +#endif + +struct Resub { + int nsub; + struct { + const char *sp; + const char *ep; + } sub[REG_MAXSUB]; +}; + +#endif diff --git a/src/mujs/tools/test262 b/src/mujs/tools/test262 new file mode 100755 index 0000000..204184e --- /dev/null +++ b/src/mujs/tools/test262 @@ -0,0 +1,139 @@ +#!/bin/sh + +usage() { + [ "${1-}" ] && { to=2; >&$to printf "Error: %s\n" "$1"; } || to=1 + >&$to echo "Usage: ${0##*/} [OPTIONS] test-file | test-dir" + >&$to echo "Run test-262 ES5 test file or directory (at the test262 dir)." + >&$to echo " -s Print source code of failed tests." + >&$to echo " -p Print every test name before running it" + >&$to echo " -f Display full paths and full stack trace when possible" + >&$to echo " -l file.js Load file.js after the harness and before the test (up to one)" + >&$to echo " -m MUJS MUJS is [path/to/]mujs binary to test" + >&$to echo " Default is $(dirname "$0")/../build/release/mujs or mujs at \$PATH" + >&$to echo " -b Don't skip known bad (crashing/hanging) tests" + >&$to echo " -B Run only known bad tests" + exit $((to-1)) +} + +KNOWN_BAD=" + --hang-with-sta.js: + S15.1.3.2_A2.5_T1.js + S15.1.3.1_A2.5_T1.js + + --Hang-(or-taking-more-than-few-seconds): + 15.4.4.18-3-14.js + 15.4.4.20-3-14.js + S15.4.4.10_A3_T2.js + S15.4.4.10_A3_T1.js + 15.4.4.19-3-29.js + 15.4.4.19-3-28.js + 15.4.4.19-3-8.js + 15.4.4.19-3-14.js + S15.4.4.8_A3_T3.js + 15.4.4.22-3-9.js + 15.4.4.22-3-7.js + 15.4.4.22-3-25.js + 15.4.4.22-3-14.js + 15.4.4.21-3-14.js + 15.4.4.15-3-28.js + 15.4.4.15-3-14.js + 15.4.4.15-3-7.js + 15.4.4.15-3-25.js + 15.4.4.15-3-9.js +" + +SKIP_KNOWN=yes # "yes": skip bad "no": don't skip "neg": run only bad +PRINT_ALL= +EXTRA_ARGS= +mujs= lopt= + +while getopts bBfhl:ps o; do + case $o in + h) usage ;; + b) SKIP_KNOWN=no ;; + B) SKIP_KNOWN=neg ;; + p) PRINT_ALL=yes ;; + s) EXTRA_ARGS="$EXTRA_ARGS -s" ;; + f) EXTRA_ARGS="$EXTRA_ARGS -f" ;; + l) [ "$OPTARG" ] && lopt=$OPTARG || usage "empty file for -l" ;; + m) mujs=$OPTARG;; + *) usage "unknown option -$o" ;; + esac +done +shift $((OPTIND-1)) +[ $# = 1 ] || usage "expecting one file/dir" + +BAD= +if [ "$SKIP_KNOWN" != no ]; then + for b in $KNOWN_BAD; do + BAD="$BAD $b " + done +fi + +find_root() { + ROOT=$1 + n=0 + while ! [ -e "$ROOT"/test/harness/sta.js ]; do + ROOT=$ROOT/.. + n=$((n+1)) + [ $n -lt 10 ] || usage "can't find test-suite root" + done +} + +if [ -d "$1" ]; then + find_root "$1" + + if [ "$ROOT" = "$1" ]; then + FILES_CMD='find "$1/test/suite" -name "*.js" | sort -V' + else + FILES_CMD='find "$1" -name "*.js" | sort -V' + fi +else + find_root "$(dirname "$1")" + FILES_CMD='printf "%s\n" "$1"' +fi + +if ! [ "$mujs" ]; then + # try to use a recently built mujs rather than a global one + mujs=$(dirname "$0")/../build/release/mujs + [ -e "$mujs" ] || mujs=mujs +fi +jsharness=$(dirname "$0")/test262-harness.js + +total=0 +skipped=0 +failed=0 + +eval "$FILES_CMD" | ( + while IFS= read -r f && [ "$f" ]; do + total=$((total+1)) + base=${f##*/} + + case $BAD in *" $base "*) bad=yes;; *) bad=no;; esac + + case $bad-$SKIP_KNOWN in + yes-yes) + skipped=$((skipped+1)) + printf "[Skipping: $base]\n\n" + ;; + no-neg) # not known bad and running only bad - don't print anything + skipped=$((skipped+1)) + ;; + *) + [ "$PRINT_ALL" ] && echo "Testing: $f" + if ! "$mujs" -- "$jsharness" $EXTRA_ARGS ${lopt:+-l "$lopt"} "$ROOT" "$f" 2>&1; then + failed=$((failed+1)) + echo + fi + esac + done + + if [ $total -gt 1 ]; then + printf "Total: $total\n" + printf "Pass: %${#total}s\n" $((total - skipped - failed)) + printf "Skip: %${#total}s\n" $skipped + printf "Fail: %${#total}s\n" $failed + fi + + [ "$failed" = 0 ] +) diff --git a/src/mujs/tools/test262-harness.js b/src/mujs/tools/test262-harness.js new file mode 100644 index 0000000..1b7eab1 --- /dev/null +++ b/src/mujs/tools/test262-harness.js @@ -0,0 +1,152 @@ +/* + * Runs one test file from the ES5 test suite test-262 + * Usage: mujs [-s ] [-f] [-l file1.js -l ...] suit-root test-file + * -s: print test source on failure + * -f: print full paths/stacktraces if possible + * -l: load a js file after the harness and before the test (to override things) + * + * If there are errors, print them and exits with code 1, else exit code is 0. + * + * The test suite is at: https://github.com/tc39/test262.git + * The ES5 suite is at branch "es5-tests" + * + * - The test suite throws on any error, possibly with info at ex.message . + * - Some tests make irreversible changes to global attrubutes, therefore it's + * required to run each test file in a new mujs instance. + */ + +(function(global) { + "use strict"; + + // clean the global environment + var mujs = {}; + + ["gc", "load", "compile", "print", "write", "read", "readline", "quit", "scriptArgs"] + .forEach(function(a) { + mujs[a] = global[a]; + delete global[a]; + }); + + // restore the original Error.toString behavior - it's being tested too + Error.prototype.toString = function() { + return this.name + ': ' + this.message; + } + + function die_usage(str) { + if (str) + mujs.print(str); + mujs.print("Usage: mujs [-f] [-l file1.js -l ...] suit-root test-file"); + mujs.quit(1); + } + + // our file loader + function load(str, as_filename) { + try { + var runtime_err = false; + var compiled = mujs.compile(str, as_filename); + runtime_err = true; + compiled(); + return false; + } catch (e) { + return {err: e, runtime: runtime_err}; + } + } + + var args = mujs.scriptArgs; + var full_mode = false; + var print_src = false; + var overrides = []; + while ((""+args[0])[0] == "-") { + switch (args[0]) { + case "-f": full_mode = true; + break; + case "-s": print_src = true; + break; + case "-l": args.shift(); + overrides.push(args[0]); + break; + default: die_usage("Unknown option " + args[0]); + } + args.shift(); + } + if (args.length != 2) + die_usage("Exactly 2 paths are expected"); + var root_path = args[0]; + var test_path = args[1]; + + // load suite utils + ["sta.js", "testBuiltInObject.js", "testIntl.js"] + .forEach(function(u) { + var path = root_path + "/test/harness/" + u; + var as_file = full_mode ? path : "test/harness/" + u; + var err = load(mujs.read(path), as_file); + if (err) throw (err.err); + }); + + // load user overrides (e.g. reduced getPrecision), with a global mujs + if (overrides.length) { + global.mujs = mujs + overrides.forEach(function(f) { + var err = load(mujs.read(f), f); + if (err) throw (err.err); + }); + delete global.mujs; + } + + // the actual test + var source = mujs.read(test_path); + var negative = !!source.match(/@negative/); + if (negative) + var neg_str = (source.match(/@negative (.*)/) || [])[1]; + var as_file = test_path; + if (!full_mode) { + as_file = test_path.replace(/\\/g, "/"); + var sub = as_file.indexOf("/suite/"); + if (sub >= 0) + as_file = "test" + as_file.substring(sub); + } + + var result = load(mujs.read(test_path), as_file); + if (!!result == negative) { + // The docs don't really help about matching str, but this covers all cases + if (neg_str) + var err_for_match = /NotEarlyError/.test(neg_str) ? result.err.message : result.err.name; + if (!negative || !neg_str || RegExp(neg_str).exec(err_for_match)) + mujs.quit(0); + } + + // failed + // FIXME: @description can span lines. E.g. test/suite/bestPractice/Sbp_A3_T2.js + var desc = source.match(/@description (.*)/); + var info = "[File] " + as_file + + (desc ? "\n[Desc] " + desc[1] : "") + + "\n"; + + if (result) { + var err = result.err; + var msg = !neg_str ? err : "[Mismatch @negative " + neg_str + "]" + "\n " + err; + + info += (result.runtime ? "[run] " : "[load] ") + msg; + if (err && err.stackTrace && (result.runtime || full_mode)) { + if (full_mode) { + info += err.stackTrace; + } else { + // trim the internal loader from the trace + var internal = err.stackTrace.indexOf("\n" + load("mujs_blahblah()").err.stackTrace.trim().split("\n")[1]); + if (internal >= 0) + info += err.stackTrace.substring(0, internal); + else + info += err.stackTrace; + } + } + } else { + info += "[run] [Error expected but none thrown]"; + } + + if (print_src) + info += "\n[Source]\n" + source; + + mujs.print(info); + mujs.quit(1); + +})(this) diff --git a/src/mujs/utf.c b/src/mujs/utf.c new file mode 100644 index 0000000..d492055 --- /dev/null +++ b/src/mujs/utf.c @@ -0,0 +1,305 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE + * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ +#include +#include + +#include "utf.h" +#include "utfdata.h" + +#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) + +typedef unsigned char uchar; + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + Bit5 = 2, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */ + Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ + + Maskx = (1< T1 + */ + c = *(uchar*)str; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(uchar*)(str+1) ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * four character sequence + * 10000-10FFFF => T4 Tx Tx Tx + */ + if(UTFmax >= 4) { + c3 = *(uchar*)(str+3) ^ Tx; + if(c3 & Testx) + goto bad; + if(c < T5) { + l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; + if(l <= Rune3) + goto bad; + if(l > Runemax) + goto bad; + *rune = l; + return 4; + } + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, const Rune *rune) +{ + int c = *rune; + + /* overlong null character */ + if (c == 0) { + str[0] = (char)0xc0; + str[1] = (char)0x80; + return 2; + } + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * two character sequence + * 00080-007FF => T2 Tx + */ + if(c <= Rune2) { + str[0] = T2 | (c >> 1*Bitx); + str[1] = Tx | (c & Maskx); + return 2; + } + + /* + * three character sequence + * 00800-0FFFF => T3 Tx Tx + */ + if(c > Runemax) + c = Runeerror; + if(c <= Rune3) { + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; + } + + /* + * four character sequence + * 010000-1FFFFF => T4 Tx Tx Tx + */ + str[0] = T4 | (c >> 3*Bitx); + str[1] = Tx | ((c >> 2*Bitx) & Maskx); + str[2] = Tx | ((c >> 1*Bitx) & Maskx); + str[3] = Tx | (c & Maskx); + return 4; +} + +int +runelen(int c) +{ + Rune rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +static const Rune * +ucd_bsearch(Rune c, const Rune *t, int n, int ne) +{ + const Rune *p; + int m; + + while(n > 1) { + m = n/2; + p = t + m*ne; + if(c >= p[0]) { + t = p; + n = n-m; + } else + n = m; + } + if(n && c >= t[0]) + return t; + return 0; +} + +Rune +tolowerrune(Rune c) +{ + const Rune *p; + + p = ucd_bsearch(c, ucd_tolower2, nelem(ucd_tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2]; + p = ucd_bsearch(c, ucd_tolower1, nelem(ucd_tolower1)/2, 2); + if(p && c == p[0]) + return c + p[1]; + return c; +} + +Rune +toupperrune(Rune c) +{ + const Rune *p; + + p = ucd_bsearch(c, ucd_toupper2, nelem(ucd_toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2]; + p = ucd_bsearch(c, ucd_toupper1, nelem(ucd_toupper1)/2, 2); + if(p && c == p[0]) + return c + p[1]; + return c; +} + +int +islowerrune(Rune c) +{ + const Rune *p; + + p = ucd_bsearch(c, ucd_toupper2, nelem(ucd_toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = ucd_bsearch(c, ucd_toupper1, nelem(ucd_toupper1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isupperrune(Rune c) +{ + const Rune *p; + + p = ucd_bsearch(c, ucd_tolower2, nelem(ucd_tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = ucd_bsearch(c, ucd_tolower1, nelem(ucd_tolower1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isalpharune(Rune c) +{ + const Rune *p; + + p = ucd_bsearch(c, ucd_alpha2, nelem(ucd_alpha2)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = ucd_bsearch(c, ucd_alpha1, nelem(ucd_alpha1), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +const Rune * +tolowerrune_full(Rune c) +{ + const Rune *p; + p = ucd_bsearch(c, ucd_tolower_full, nelem(ucd_tolower_full)/4, 4); + if(p && c == p[0]) + return p + 1; + return NULL; +} + +const Rune * +toupperrune_full(Rune c) +{ + const Rune *p; + p = ucd_bsearch(c, ucd_toupper_full, nelem(ucd_toupper_full)/5, 5); + if(p && c == p[0]) + return p + 1; + return NULL; +} diff --git a/src/mujs/utf.h b/src/mujs/utf.h new file mode 100644 index 0000000..77ee029 --- /dev/null +++ b/src/mujs/utf.h @@ -0,0 +1,52 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE + * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ +#ifndef js_utf_h +#define js_utf_h + +typedef int Rune; /* 32 bits */ + +#define chartorune jsU_chartorune +#define runetochar jsU_runetochar +#define runelen jsU_runelen + +#define isalpharune jsU_isalpharune +#define islowerrune jsU_islowerrune +#define isupperrune jsU_isupperrune +#define tolowerrune jsU_tolowerrune +#define toupperrune jsU_toupperrune +#define tolowerrune_full jsU_tolowerrune_full +#define toupperrune_full jsU_toupperrune_full + +enum +{ + UTFmax = 4, /* maximum bytes per rune */ + Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ + Runeerror = 0xFFFD, /* decoding error in UTF */ + Runemax = 0x10FFFF, /* maximum rune value */ +}; + +int chartorune(Rune *rune, const char *str); +int runetochar(char *str, const Rune *rune); +int runelen(int c); + +int isalpharune(Rune c); +int islowerrune(Rune c); +int isupperrune(Rune c); +Rune tolowerrune(Rune c); +Rune toupperrune(Rune c); +const Rune* tolowerrune_full(Rune c); +const Rune* toupperrune_full(Rune c); + +#endif diff --git a/src/mujs/utfdata.h b/src/mujs/utfdata.h new file mode 100644 index 0000000..f74ea89 --- /dev/null +++ b/src/mujs/utfdata.h @@ -0,0 +1,2209 @@ +/* This file was automatically created from UnicodeData.txt */ + +static const Rune ucd_alpha2[] = { +0x41,0x5a, +0x61,0x7a, +0xc0,0xd6, +0xd8,0xf6, +0xf8,0x2c1, +0x2c6,0x2d1, +0x2e0,0x2e4, +0x370,0x374, +0x376,0x377, +0x37a,0x37d, +0x388,0x38a, +0x38e,0x3a1, +0x3a3,0x3f5, +0x3f7,0x481, +0x48a,0x52f, +0x531,0x556, +0x560,0x588, +0x5d0,0x5ea, +0x5ef,0x5f2, +0x620,0x64a, +0x66e,0x66f, +0x671,0x6d3, +0x6e5,0x6e6, +0x6ee,0x6ef, +0x6fa,0x6fc, +0x712,0x72f, +0x74d,0x7a5, +0x7ca,0x7ea, +0x7f4,0x7f5, +0x800,0x815, +0x840,0x858, +0x860,0x86a, +0x870,0x887, +0x889,0x88e, +0x8a0,0x8c9, +0x904,0x939, +0x958,0x961, +0x971,0x980, +0x985,0x98c, +0x98f,0x990, +0x993,0x9a8, +0x9aa,0x9b0, +0x9b6,0x9b9, +0x9dc,0x9dd, +0x9df,0x9e1, +0x9f0,0x9f1, +0xa05,0xa0a, +0xa0f,0xa10, +0xa13,0xa28, +0xa2a,0xa30, +0xa32,0xa33, +0xa35,0xa36, +0xa38,0xa39, +0xa59,0xa5c, +0xa72,0xa74, +0xa85,0xa8d, +0xa8f,0xa91, +0xa93,0xaa8, +0xaaa,0xab0, +0xab2,0xab3, +0xab5,0xab9, +0xae0,0xae1, +0xb05,0xb0c, +0xb0f,0xb10, +0xb13,0xb28, +0xb2a,0xb30, +0xb32,0xb33, +0xb35,0xb39, +0xb5c,0xb5d, +0xb5f,0xb61, +0xb85,0xb8a, +0xb8e,0xb90, +0xb92,0xb95, +0xb99,0xb9a, +0xb9e,0xb9f, +0xba3,0xba4, +0xba8,0xbaa, +0xbae,0xbb9, +0xc05,0xc0c, +0xc0e,0xc10, +0xc12,0xc28, +0xc2a,0xc39, +0xc58,0xc5a, +0xc60,0xc61, +0xc85,0xc8c, +0xc8e,0xc90, +0xc92,0xca8, +0xcaa,0xcb3, +0xcb5,0xcb9, +0xcdd,0xcde, +0xce0,0xce1, +0xcf1,0xcf2, +0xd04,0xd0c, +0xd0e,0xd10, +0xd12,0xd3a, +0xd54,0xd56, +0xd5f,0xd61, +0xd7a,0xd7f, +0xd85,0xd96, +0xd9a,0xdb1, +0xdb3,0xdbb, +0xdc0,0xdc6, +0xe01,0xe30, +0xe32,0xe33, +0xe40,0xe46, +0xe81,0xe82, +0xe86,0xe8a, +0xe8c,0xea3, +0xea7,0xeb0, +0xeb2,0xeb3, +0xec0,0xec4, +0xedc,0xedf, +0xf40,0xf47, +0xf49,0xf6c, +0xf88,0xf8c, +0x1000,0x102a, +0x1050,0x1055, +0x105a,0x105d, +0x1065,0x1066, +0x106e,0x1070, +0x1075,0x1081, +0x10a0,0x10c5, +0x10d0,0x10fa, +0x10fc,0x1248, +0x124a,0x124d, +0x1250,0x1256, +0x125a,0x125d, +0x1260,0x1288, +0x128a,0x128d, +0x1290,0x12b0, +0x12b2,0x12b5, +0x12b8,0x12be, +0x12c2,0x12c5, +0x12c8,0x12d6, +0x12d8,0x1310, +0x1312,0x1315, +0x1318,0x135a, +0x1380,0x138f, +0x13a0,0x13f5, +0x13f8,0x13fd, +0x1401,0x166c, +0x166f,0x167f, +0x1681,0x169a, +0x16a0,0x16ea, +0x16f1,0x16f8, +0x1700,0x1711, +0x171f,0x1731, +0x1740,0x1751, +0x1760,0x176c, +0x176e,0x1770, +0x1780,0x17b3, +0x1820,0x1878, +0x1880,0x1884, +0x1887,0x18a8, +0x18b0,0x18f5, +0x1900,0x191e, +0x1950,0x196d, +0x1970,0x1974, +0x1980,0x19ab, +0x19b0,0x19c9, +0x1a00,0x1a16, +0x1a20,0x1a54, +0x1b05,0x1b33, +0x1b45,0x1b4c, +0x1b83,0x1ba0, +0x1bae,0x1baf, +0x1bba,0x1be5, +0x1c00,0x1c23, +0x1c4d,0x1c4f, +0x1c5a,0x1c7d, +0x1c80,0x1c8a, +0x1c90,0x1cba, +0x1cbd,0x1cbf, +0x1ce9,0x1cec, +0x1cee,0x1cf3, +0x1cf5,0x1cf6, +0x1d00,0x1dbf, +0x1e00,0x1f15, +0x1f18,0x1f1d, +0x1f20,0x1f45, +0x1f48,0x1f4d, +0x1f50,0x1f57, +0x1f5f,0x1f7d, +0x1f80,0x1fb4, +0x1fb6,0x1fbc, +0x1fc2,0x1fc4, +0x1fc6,0x1fcc, +0x1fd0,0x1fd3, +0x1fd6,0x1fdb, +0x1fe0,0x1fec, +0x1ff2,0x1ff4, +0x1ff6,0x1ffc, +0x2090,0x209c, +0x210a,0x2113, +0x2119,0x211d, +0x212a,0x212d, +0x212f,0x2139, +0x213c,0x213f, +0x2145,0x2149, +0x2183,0x2184, +0x2c00,0x2ce4, +0x2ceb,0x2cee, +0x2cf2,0x2cf3, +0x2d00,0x2d25, +0x2d30,0x2d67, +0x2d80,0x2d96, +0x2da0,0x2da6, +0x2da8,0x2dae, +0x2db0,0x2db6, +0x2db8,0x2dbe, +0x2dc0,0x2dc6, +0x2dc8,0x2dce, +0x2dd0,0x2dd6, +0x2dd8,0x2dde, +0x3005,0x3006, +0x3031,0x3035, +0x303b,0x303c, +0x3041,0x3096, +0x309d,0x309f, +0x30a1,0x30fa, +0x30fc,0x30ff, +0x3105,0x312f, +0x3131,0x318e, +0x31a0,0x31bf, +0x31f0,0x31ff, +0x9fff,0xa48c, +0xa4d0,0xa4fd, +0xa500,0xa60c, +0xa610,0xa61f, +0xa62a,0xa62b, +0xa640,0xa66e, +0xa67f,0xa69d, +0xa6a0,0xa6e5, +0xa717,0xa71f, +0xa722,0xa788, +0xa78b,0xa7cd, +0xa7d0,0xa7d1, +0xa7d5,0xa7dc, +0xa7f2,0xa801, +0xa803,0xa805, +0xa807,0xa80a, +0xa80c,0xa822, +0xa840,0xa873, +0xa882,0xa8b3, +0xa8f2,0xa8f7, +0xa8fd,0xa8fe, +0xa90a,0xa925, +0xa930,0xa946, +0xa960,0xa97c, +0xa984,0xa9b2, +0xa9e0,0xa9e4, +0xa9e6,0xa9ef, +0xa9fa,0xa9fe, +0xaa00,0xaa28, +0xaa40,0xaa42, +0xaa44,0xaa4b, +0xaa60,0xaa76, +0xaa7e,0xaaaf, +0xaab5,0xaab6, +0xaab9,0xaabd, +0xaadb,0xaadd, +0xaae0,0xaaea, +0xaaf2,0xaaf4, +0xab01,0xab06, +0xab09,0xab0e, +0xab11,0xab16, +0xab20,0xab26, +0xab28,0xab2e, +0xab30,0xab5a, +0xab5c,0xab69, +0xab70,0xabe2, +0xd7b0,0xd7c6, +0xd7cb,0xd7fb, +0xf900,0xfa6d, +0xfa70,0xfad9, +0xfb00,0xfb06, +0xfb13,0xfb17, +0xfb1f,0xfb28, +0xfb2a,0xfb36, +0xfb38,0xfb3c, +0xfb40,0xfb41, +0xfb43,0xfb44, +0xfb46,0xfbb1, +0xfbd3,0xfd3d, +0xfd50,0xfd8f, +0xfd92,0xfdc7, +0xfdf0,0xfdfb, +0xfe70,0xfe74, +0xfe76,0xfefc, +0xff21,0xff3a, +0xff41,0xff5a, +0xff66,0xffbe, +0xffc2,0xffc7, +0xffca,0xffcf, +0xffd2,0xffd7, +0xffda,0xffdc, +0x10000,0x1000b, +0x1000d,0x10026, +0x10028,0x1003a, +0x1003c,0x1003d, +0x1003f,0x1004d, +0x10050,0x1005d, +0x10080,0x100fa, +0x10280,0x1029c, +0x102a0,0x102d0, +0x10300,0x1031f, +0x1032d,0x10340, +0x10342,0x10349, +0x10350,0x10375, +0x10380,0x1039d, +0x103a0,0x103c3, +0x103c8,0x103cf, +0x10400,0x1049d, +0x104b0,0x104d3, +0x104d8,0x104fb, +0x10500,0x10527, +0x10530,0x10563, +0x10570,0x1057a, +0x1057c,0x1058a, +0x1058c,0x10592, +0x10594,0x10595, +0x10597,0x105a1, +0x105a3,0x105b1, +0x105b3,0x105b9, +0x105bb,0x105bc, +0x105c0,0x105f3, +0x10600,0x10736, +0x10740,0x10755, +0x10760,0x10767, +0x10780,0x10785, +0x10787,0x107b0, +0x107b2,0x107ba, +0x10800,0x10805, +0x1080a,0x10835, +0x10837,0x10838, +0x1083f,0x10855, +0x10860,0x10876, +0x10880,0x1089e, +0x108e0,0x108f2, +0x108f4,0x108f5, +0x10900,0x10915, +0x10920,0x10939, +0x10980,0x109b7, +0x109be,0x109bf, +0x10a10,0x10a13, +0x10a15,0x10a17, +0x10a19,0x10a35, +0x10a60,0x10a7c, +0x10a80,0x10a9c, +0x10ac0,0x10ac7, +0x10ac9,0x10ae4, +0x10b00,0x10b35, +0x10b40,0x10b55, +0x10b60,0x10b72, +0x10b80,0x10b91, +0x10c00,0x10c48, +0x10c80,0x10cb2, +0x10cc0,0x10cf2, +0x10d00,0x10d23, +0x10d4a,0x10d65, +0x10d6f,0x10d85, +0x10e80,0x10ea9, +0x10eb0,0x10eb1, +0x10ec2,0x10ec4, +0x10f00,0x10f1c, +0x10f30,0x10f45, +0x10f70,0x10f81, +0x10fb0,0x10fc4, +0x10fe0,0x10ff6, +0x11003,0x11037, +0x11071,0x11072, +0x11083,0x110af, +0x110d0,0x110e8, +0x11103,0x11126, +0x11150,0x11172, +0x11183,0x111b2, +0x111c1,0x111c4, +0x11200,0x11211, +0x11213,0x1122b, +0x1123f,0x11240, +0x11280,0x11286, +0x1128a,0x1128d, +0x1128f,0x1129d, +0x1129f,0x112a8, +0x112b0,0x112de, +0x11305,0x1130c, +0x1130f,0x11310, +0x11313,0x11328, +0x1132a,0x11330, +0x11332,0x11333, +0x11335,0x11339, +0x1135d,0x11361, +0x11380,0x11389, +0x11390,0x113b5, +0x11400,0x11434, +0x11447,0x1144a, +0x1145f,0x11461, +0x11480,0x114af, +0x114c4,0x114c5, +0x11580,0x115ae, +0x115d8,0x115db, +0x11600,0x1162f, +0x11680,0x116aa, +0x11700,0x1171a, +0x11740,0x11746, +0x11800,0x1182b, +0x118a0,0x118df, +0x118ff,0x11906, +0x1190c,0x11913, +0x11915,0x11916, +0x11918,0x1192f, +0x119a0,0x119a7, +0x119aa,0x119d0, +0x11a0b,0x11a32, +0x11a5c,0x11a89, +0x11ab0,0x11af8, +0x11bc0,0x11be0, +0x11c00,0x11c08, +0x11c0a,0x11c2e, +0x11c72,0x11c8f, +0x11d00,0x11d06, +0x11d08,0x11d09, +0x11d0b,0x11d30, +0x11d60,0x11d65, +0x11d67,0x11d68, +0x11d6a,0x11d89, +0x11ee0,0x11ef2, +0x11f04,0x11f10, +0x11f12,0x11f33, +0x12000,0x12399, +0x12480,0x12543, +0x12f90,0x12ff0, +0x13000,0x1342f, +0x13441,0x13446, +0x13460,0x143fa, +0x14400,0x14646, +0x16100,0x1611d, +0x16800,0x16a38, +0x16a40,0x16a5e, +0x16a70,0x16abe, +0x16ad0,0x16aed, +0x16b00,0x16b2f, +0x16b40,0x16b43, +0x16b63,0x16b77, +0x16b7d,0x16b8f, +0x16d40,0x16d6c, +0x16e40,0x16e7f, +0x16f00,0x16f4a, +0x16f93,0x16f9f, +0x16fe0,0x16fe1, +0x18800,0x18cd5, +0x18cff,0x18d00, +0x1aff0,0x1aff3, +0x1aff5,0x1affb, +0x1affd,0x1affe, +0x1b000,0x1b122, +0x1b150,0x1b152, +0x1b164,0x1b167, +0x1b170,0x1b2fb, +0x1bc00,0x1bc6a, +0x1bc70,0x1bc7c, +0x1bc80,0x1bc88, +0x1bc90,0x1bc99, +0x1d400,0x1d454, +0x1d456,0x1d49c, +0x1d49e,0x1d49f, +0x1d4a5,0x1d4a6, +0x1d4a9,0x1d4ac, +0x1d4ae,0x1d4b9, +0x1d4bd,0x1d4c3, +0x1d4c5,0x1d505, +0x1d507,0x1d50a, +0x1d50d,0x1d514, +0x1d516,0x1d51c, +0x1d51e,0x1d539, +0x1d53b,0x1d53e, +0x1d540,0x1d544, +0x1d54a,0x1d550, +0x1d552,0x1d6a5, +0x1d6a8,0x1d6c0, +0x1d6c2,0x1d6da, +0x1d6dc,0x1d6fa, +0x1d6fc,0x1d714, +0x1d716,0x1d734, +0x1d736,0x1d74e, +0x1d750,0x1d76e, +0x1d770,0x1d788, +0x1d78a,0x1d7a8, +0x1d7aa,0x1d7c2, +0x1d7c4,0x1d7cb, +0x1df00,0x1df1e, +0x1df25,0x1df2a, +0x1e030,0x1e06d, +0x1e100,0x1e12c, +0x1e137,0x1e13d, +0x1e290,0x1e2ad, +0x1e2c0,0x1e2eb, +0x1e4d0,0x1e4eb, +0x1e5d0,0x1e5ed, +0x1e7e0,0x1e7e6, +0x1e7e8,0x1e7eb, +0x1e7ed,0x1e7ee, +0x1e7f0,0x1e7fe, +0x1e800,0x1e8c4, +0x1e900,0x1e943, +0x1ee00,0x1ee03, +0x1ee05,0x1ee1f, +0x1ee21,0x1ee22, +0x1ee29,0x1ee32, +0x1ee34,0x1ee37, +0x1ee4d,0x1ee4f, +0x1ee51,0x1ee52, +0x1ee61,0x1ee62, +0x1ee67,0x1ee6a, +0x1ee6c,0x1ee72, +0x1ee74,0x1ee77, +0x1ee79,0x1ee7c, +0x1ee80,0x1ee89, +0x1ee8b,0x1ee9b, +0x1eea1,0x1eea3, +0x1eea5,0x1eea9, +0x1eeab,0x1eebb, +0x2f800,0x2fa1d, +}; + +static const Rune ucd_alpha1[] = { +0xaa, +0xb5, +0xba, +0x2ec, +0x2ee, +0x37f, +0x386, +0x38c, +0x559, +0x6d5, +0x6ff, +0x710, +0x7b1, +0x7fa, +0x81a, +0x824, +0x828, +0x93d, +0x950, +0x9b2, +0x9bd, +0x9ce, +0x9fc, +0xa5e, +0xabd, +0xad0, +0xaf9, +0xb3d, +0xb71, +0xb83, +0xb9c, +0xbd0, +0xc3d, +0xc5d, +0xc80, +0xcbd, +0xd3d, +0xd4e, +0xdbd, +0xe84, +0xea5, +0xebd, +0xec6, +0xf00, +0x103f, +0x1061, +0x108e, +0x10c7, +0x10cd, +0x1258, +0x12c0, +0x17d7, +0x17dc, +0x18aa, +0x1aa7, +0x1cfa, +0x1f59, +0x1f5b, +0x1f5d, +0x1fbe, +0x2071, +0x207f, +0x2102, +0x2107, +0x2115, +0x2124, +0x2126, +0x2128, +0x214e, +0x2d27, +0x2d2d, +0x2d6f, +0x2e2f, +0x3400, +0x4dbf, +0x4e00, +0xa7d3, +0xa8fb, +0xa9cf, +0xaa7a, +0xaab1, +0xaac0, +0xaac2, +0xac00, +0xd7a3, +0xfb1d, +0xfb3e, +0x10808, +0x1083c, +0x10a00, +0x10f27, +0x11075, +0x11144, +0x11147, +0x11176, +0x111da, +0x111dc, +0x11288, +0x1133d, +0x11350, +0x1138b, +0x1138e, +0x113b7, +0x113d1, +0x113d3, +0x114c7, +0x11644, +0x116b8, +0x11909, +0x1193f, +0x11941, +0x119e1, +0x119e3, +0x11a00, +0x11a3a, +0x11a50, +0x11a9d, +0x11c40, +0x11d46, +0x11d98, +0x11f02, +0x11fb0, +0x16f50, +0x16fe3, +0x17000, +0x187f7, +0x18d08, +0x1b132, +0x1b155, +0x1d4a2, +0x1d4bb, +0x1d546, +0x1e14e, +0x1e5f0, +0x1e94b, +0x1ee24, +0x1ee27, +0x1ee39, +0x1ee3b, +0x1ee42, +0x1ee47, +0x1ee49, +0x1ee4b, +0x1ee54, +0x1ee57, +0x1ee59, +0x1ee5b, +0x1ee5d, +0x1ee5f, +0x1ee64, +0x1ee7e, +0x20000, +0x2a6df, +0x2a700, +0x2b739, +0x2b740, +0x2b81d, +0x2b820, +0x2cea1, +0x2ceb0, +0x2ebe0, +0x2ebf0, +0x2ee5d, +0x30000, +0x3134a, +0x31350, +0x323af, +}; + +static const Rune ucd_tolower2[] = { +0x41,0x5a,32, +0xc0,0xd6,32, +0xd8,0xde,32, +0x189,0x18a,205, +0x1b1,0x1b2,217, +0x388,0x38a,37, +0x38e,0x38f,63, +0x391,0x3a1,32, +0x3a3,0x3ab,32, +0x3fd,0x3ff,-130, +0x400,0x40f,80, +0x410,0x42f,32, +0x531,0x556,48, +0x10a0,0x10c5,7264, +0x13a0,0x13ef,38864, +0x13f0,0x13f5,8, +0x1c90,0x1cba,-3008, +0x1cbd,0x1cbf,-3008, +0x1f08,0x1f0f,-8, +0x1f18,0x1f1d,-8, +0x1f28,0x1f2f,-8, +0x1f38,0x1f3f,-8, +0x1f48,0x1f4d,-8, +0x1f68,0x1f6f,-8, +0x1f88,0x1f8f,-8, +0x1f98,0x1f9f,-8, +0x1fa8,0x1faf,-8, +0x1fb8,0x1fb9,-8, +0x1fba,0x1fbb,-74, +0x1fc8,0x1fcb,-86, +0x1fd8,0x1fd9,-8, +0x1fda,0x1fdb,-100, +0x1fe8,0x1fe9,-8, +0x1fea,0x1feb,-112, +0x1ff8,0x1ff9,-128, +0x1ffa,0x1ffb,-126, +0x2160,0x216f,16, +0x24b6,0x24cf,26, +0x2c00,0x2c2f,48, +0x2c7e,0x2c7f,-10815, +0xff21,0xff3a,32, +0x10400,0x10427,40, +0x104b0,0x104d3,40, +0x10570,0x1057a,39, +0x1057c,0x1058a,39, +0x1058c,0x10592,39, +0x10594,0x10595,39, +0x10c80,0x10cb2,64, +0x10d50,0x10d65,32, +0x118a0,0x118bf,32, +0x16e40,0x16e5f,32, +0x1e900,0x1e921,34, +}; + +static const Rune ucd_tolower1[] = { +0x100,1, +0x102,1, +0x104,1, +0x106,1, +0x108,1, +0x10a,1, +0x10c,1, +0x10e,1, +0x110,1, +0x112,1, +0x114,1, +0x116,1, +0x118,1, +0x11a,1, +0x11c,1, +0x11e,1, +0x120,1, +0x122,1, +0x124,1, +0x126,1, +0x128,1, +0x12a,1, +0x12c,1, +0x12e,1, +0x130,-199, +0x132,1, +0x134,1, +0x136,1, +0x139,1, +0x13b,1, +0x13d,1, +0x13f,1, +0x141,1, +0x143,1, +0x145,1, +0x147,1, +0x14a,1, +0x14c,1, +0x14e,1, +0x150,1, +0x152,1, +0x154,1, +0x156,1, +0x158,1, +0x15a,1, +0x15c,1, +0x15e,1, +0x160,1, +0x162,1, +0x164,1, +0x166,1, +0x168,1, +0x16a,1, +0x16c,1, +0x16e,1, +0x170,1, +0x172,1, +0x174,1, +0x176,1, +0x178,-121, +0x179,1, +0x17b,1, +0x17d,1, +0x181,210, +0x182,1, +0x184,1, +0x186,206, +0x187,1, +0x18b,1, +0x18e,79, +0x18f,202, +0x190,203, +0x191,1, +0x193,205, +0x194,207, +0x196,211, +0x197,209, +0x198,1, +0x19c,211, +0x19d,213, +0x19f,214, +0x1a0,1, +0x1a2,1, +0x1a4,1, +0x1a6,218, +0x1a7,1, +0x1a9,218, +0x1ac,1, +0x1ae,218, +0x1af,1, +0x1b3,1, +0x1b5,1, +0x1b7,219, +0x1b8,1, +0x1bc,1, +0x1c4,2, +0x1c5,1, +0x1c7,2, +0x1c8,1, +0x1ca,2, +0x1cb,1, +0x1cd,1, +0x1cf,1, +0x1d1,1, +0x1d3,1, +0x1d5,1, +0x1d7,1, +0x1d9,1, +0x1db,1, +0x1de,1, +0x1e0,1, +0x1e2,1, +0x1e4,1, +0x1e6,1, +0x1e8,1, +0x1ea,1, +0x1ec,1, +0x1ee,1, +0x1f1,2, +0x1f2,1, +0x1f4,1, +0x1f6,-97, +0x1f7,-56, +0x1f8,1, +0x1fa,1, +0x1fc,1, +0x1fe,1, +0x200,1, +0x202,1, +0x204,1, +0x206,1, +0x208,1, +0x20a,1, +0x20c,1, +0x20e,1, +0x210,1, +0x212,1, +0x214,1, +0x216,1, +0x218,1, +0x21a,1, +0x21c,1, +0x21e,1, +0x220,-130, +0x222,1, +0x224,1, +0x226,1, +0x228,1, +0x22a,1, +0x22c,1, +0x22e,1, +0x230,1, +0x232,1, +0x23a,10795, +0x23b,1, +0x23d,-163, +0x23e,10792, +0x241,1, +0x243,-195, +0x244,69, +0x245,71, +0x246,1, +0x248,1, +0x24a,1, +0x24c,1, +0x24e,1, +0x370,1, +0x372,1, +0x376,1, +0x37f,116, +0x386,38, +0x38c,64, +0x3cf,8, +0x3d8,1, +0x3da,1, +0x3dc,1, +0x3de,1, +0x3e0,1, +0x3e2,1, +0x3e4,1, +0x3e6,1, +0x3e8,1, +0x3ea,1, +0x3ec,1, +0x3ee,1, +0x3f4,-60, +0x3f7,1, +0x3f9,-7, +0x3fa,1, +0x460,1, +0x462,1, +0x464,1, +0x466,1, +0x468,1, +0x46a,1, +0x46c,1, +0x46e,1, +0x470,1, +0x472,1, +0x474,1, +0x476,1, +0x478,1, +0x47a,1, +0x47c,1, +0x47e,1, +0x480,1, +0x48a,1, +0x48c,1, +0x48e,1, +0x490,1, +0x492,1, +0x494,1, +0x496,1, +0x498,1, +0x49a,1, +0x49c,1, +0x49e,1, +0x4a0,1, +0x4a2,1, +0x4a4,1, +0x4a6,1, +0x4a8,1, +0x4aa,1, +0x4ac,1, +0x4ae,1, +0x4b0,1, +0x4b2,1, +0x4b4,1, +0x4b6,1, +0x4b8,1, +0x4ba,1, +0x4bc,1, +0x4be,1, +0x4c0,15, +0x4c1,1, +0x4c3,1, +0x4c5,1, +0x4c7,1, +0x4c9,1, +0x4cb,1, +0x4cd,1, +0x4d0,1, +0x4d2,1, +0x4d4,1, +0x4d6,1, +0x4d8,1, +0x4da,1, +0x4dc,1, +0x4de,1, +0x4e0,1, +0x4e2,1, +0x4e4,1, +0x4e6,1, +0x4e8,1, +0x4ea,1, +0x4ec,1, +0x4ee,1, +0x4f0,1, +0x4f2,1, +0x4f4,1, +0x4f6,1, +0x4f8,1, +0x4fa,1, +0x4fc,1, +0x4fe,1, +0x500,1, +0x502,1, +0x504,1, +0x506,1, +0x508,1, +0x50a,1, +0x50c,1, +0x50e,1, +0x510,1, +0x512,1, +0x514,1, +0x516,1, +0x518,1, +0x51a,1, +0x51c,1, +0x51e,1, +0x520,1, +0x522,1, +0x524,1, +0x526,1, +0x528,1, +0x52a,1, +0x52c,1, +0x52e,1, +0x10c7,7264, +0x10cd,7264, +0x1c89,1, +0x1e00,1, +0x1e02,1, +0x1e04,1, +0x1e06,1, +0x1e08,1, +0x1e0a,1, +0x1e0c,1, +0x1e0e,1, +0x1e10,1, +0x1e12,1, +0x1e14,1, +0x1e16,1, +0x1e18,1, +0x1e1a,1, +0x1e1c,1, +0x1e1e,1, +0x1e20,1, +0x1e22,1, +0x1e24,1, +0x1e26,1, +0x1e28,1, +0x1e2a,1, +0x1e2c,1, +0x1e2e,1, +0x1e30,1, +0x1e32,1, +0x1e34,1, +0x1e36,1, +0x1e38,1, +0x1e3a,1, +0x1e3c,1, +0x1e3e,1, +0x1e40,1, +0x1e42,1, +0x1e44,1, +0x1e46,1, +0x1e48,1, +0x1e4a,1, +0x1e4c,1, +0x1e4e,1, +0x1e50,1, +0x1e52,1, +0x1e54,1, +0x1e56,1, +0x1e58,1, +0x1e5a,1, +0x1e5c,1, +0x1e5e,1, +0x1e60,1, +0x1e62,1, +0x1e64,1, +0x1e66,1, +0x1e68,1, +0x1e6a,1, +0x1e6c,1, +0x1e6e,1, +0x1e70,1, +0x1e72,1, +0x1e74,1, +0x1e76,1, +0x1e78,1, +0x1e7a,1, +0x1e7c,1, +0x1e7e,1, +0x1e80,1, +0x1e82,1, +0x1e84,1, +0x1e86,1, +0x1e88,1, +0x1e8a,1, +0x1e8c,1, +0x1e8e,1, +0x1e90,1, +0x1e92,1, +0x1e94,1, +0x1e9e,-7615, +0x1ea0,1, +0x1ea2,1, +0x1ea4,1, +0x1ea6,1, +0x1ea8,1, +0x1eaa,1, +0x1eac,1, +0x1eae,1, +0x1eb0,1, +0x1eb2,1, +0x1eb4,1, +0x1eb6,1, +0x1eb8,1, +0x1eba,1, +0x1ebc,1, +0x1ebe,1, +0x1ec0,1, +0x1ec2,1, +0x1ec4,1, +0x1ec6,1, +0x1ec8,1, +0x1eca,1, +0x1ecc,1, +0x1ece,1, +0x1ed0,1, +0x1ed2,1, +0x1ed4,1, +0x1ed6,1, +0x1ed8,1, +0x1eda,1, +0x1edc,1, +0x1ede,1, +0x1ee0,1, +0x1ee2,1, +0x1ee4,1, +0x1ee6,1, +0x1ee8,1, +0x1eea,1, +0x1eec,1, +0x1eee,1, +0x1ef0,1, +0x1ef2,1, +0x1ef4,1, +0x1ef6,1, +0x1ef8,1, +0x1efa,1, +0x1efc,1, +0x1efe,1, +0x1f59,-8, +0x1f5b,-8, +0x1f5d,-8, +0x1f5f,-8, +0x1fbc,-9, +0x1fcc,-9, +0x1fec,-7, +0x1ffc,-9, +0x2126,-7517, +0x212a,-8383, +0x212b,-8262, +0x2132,28, +0x2183,1, +0x2c60,1, +0x2c62,-10743, +0x2c63,-3814, +0x2c64,-10727, +0x2c67,1, +0x2c69,1, +0x2c6b,1, +0x2c6d,-10780, +0x2c6e,-10749, +0x2c6f,-10783, +0x2c70,-10782, +0x2c72,1, +0x2c75,1, +0x2c80,1, +0x2c82,1, +0x2c84,1, +0x2c86,1, +0x2c88,1, +0x2c8a,1, +0x2c8c,1, +0x2c8e,1, +0x2c90,1, +0x2c92,1, +0x2c94,1, +0x2c96,1, +0x2c98,1, +0x2c9a,1, +0x2c9c,1, +0x2c9e,1, +0x2ca0,1, +0x2ca2,1, +0x2ca4,1, +0x2ca6,1, +0x2ca8,1, +0x2caa,1, +0x2cac,1, +0x2cae,1, +0x2cb0,1, +0x2cb2,1, +0x2cb4,1, +0x2cb6,1, +0x2cb8,1, +0x2cba,1, +0x2cbc,1, +0x2cbe,1, +0x2cc0,1, +0x2cc2,1, +0x2cc4,1, +0x2cc6,1, +0x2cc8,1, +0x2cca,1, +0x2ccc,1, +0x2cce,1, +0x2cd0,1, +0x2cd2,1, +0x2cd4,1, +0x2cd6,1, +0x2cd8,1, +0x2cda,1, +0x2cdc,1, +0x2cde,1, +0x2ce0,1, +0x2ce2,1, +0x2ceb,1, +0x2ced,1, +0x2cf2,1, +0xa640,1, +0xa642,1, +0xa644,1, +0xa646,1, +0xa648,1, +0xa64a,1, +0xa64c,1, +0xa64e,1, +0xa650,1, +0xa652,1, +0xa654,1, +0xa656,1, +0xa658,1, +0xa65a,1, +0xa65c,1, +0xa65e,1, +0xa660,1, +0xa662,1, +0xa664,1, +0xa666,1, +0xa668,1, +0xa66a,1, +0xa66c,1, +0xa680,1, +0xa682,1, +0xa684,1, +0xa686,1, +0xa688,1, +0xa68a,1, +0xa68c,1, +0xa68e,1, +0xa690,1, +0xa692,1, +0xa694,1, +0xa696,1, +0xa698,1, +0xa69a,1, +0xa722,1, +0xa724,1, +0xa726,1, +0xa728,1, +0xa72a,1, +0xa72c,1, +0xa72e,1, +0xa732,1, +0xa734,1, +0xa736,1, +0xa738,1, +0xa73a,1, +0xa73c,1, +0xa73e,1, +0xa740,1, +0xa742,1, +0xa744,1, +0xa746,1, +0xa748,1, +0xa74a,1, +0xa74c,1, +0xa74e,1, +0xa750,1, +0xa752,1, +0xa754,1, +0xa756,1, +0xa758,1, +0xa75a,1, +0xa75c,1, +0xa75e,1, +0xa760,1, +0xa762,1, +0xa764,1, +0xa766,1, +0xa768,1, +0xa76a,1, +0xa76c,1, +0xa76e,1, +0xa779,1, +0xa77b,1, +0xa77d,-35332, +0xa77e,1, +0xa780,1, +0xa782,1, +0xa784,1, +0xa786,1, +0xa78b,1, +0xa78d,-42280, +0xa790,1, +0xa792,1, +0xa796,1, +0xa798,1, +0xa79a,1, +0xa79c,1, +0xa79e,1, +0xa7a0,1, +0xa7a2,1, +0xa7a4,1, +0xa7a6,1, +0xa7a8,1, +0xa7aa,-42308, +0xa7ab,-42319, +0xa7ac,-42315, +0xa7ad,-42305, +0xa7ae,-42308, +0xa7b0,-42258, +0xa7b1,-42282, +0xa7b2,-42261, +0xa7b3,928, +0xa7b4,1, +0xa7b6,1, +0xa7b8,1, +0xa7ba,1, +0xa7bc,1, +0xa7be,1, +0xa7c0,1, +0xa7c2,1, +0xa7c4,-48, +0xa7c5,-42307, +0xa7c6,-35384, +0xa7c7,1, +0xa7c9,1, +0xa7cb,-42343, +0xa7cc,1, +0xa7d0,1, +0xa7d6,1, +0xa7d8,1, +0xa7da,1, +0xa7dc,-42561, +0xa7f5,1, +}; + +static const Rune ucd_toupper2[] = { +0x61,0x7a,-32, +0xe0,0xf6,-32, +0xf8,0xfe,-32, +0x23f,0x240,10815, +0x256,0x257,-205, +0x28a,0x28b,-217, +0x37b,0x37d,130, +0x3ad,0x3af,-37, +0x3b1,0x3c1,-32, +0x3c3,0x3cb,-32, +0x3cd,0x3ce,-63, +0x430,0x44f,-32, +0x450,0x45f,-80, +0x561,0x586,-48, +0x10d0,0x10fa,3008, +0x10fd,0x10ff,3008, +0x13f8,0x13fd,-8, +0x1c83,0x1c84,-6242, +0x1f00,0x1f07,8, +0x1f10,0x1f15,8, +0x1f20,0x1f27,8, +0x1f30,0x1f37,8, +0x1f40,0x1f45,8, +0x1f60,0x1f67,8, +0x1f70,0x1f71,74, +0x1f72,0x1f75,86, +0x1f76,0x1f77,100, +0x1f78,0x1f79,128, +0x1f7a,0x1f7b,112, +0x1f7c,0x1f7d,126, +0x1f80,0x1f87,8, +0x1f90,0x1f97,8, +0x1fa0,0x1fa7,8, +0x1fb0,0x1fb1,8, +0x1fd0,0x1fd1,8, +0x1fe0,0x1fe1,8, +0x2170,0x217f,-16, +0x24d0,0x24e9,-26, +0x2c30,0x2c5f,-48, +0x2d00,0x2d25,-7264, +0xab70,0xabbf,-38864, +0xff41,0xff5a,-32, +0x10428,0x1044f,-40, +0x104d8,0x104fb,-40, +0x10597,0x105a1,-39, +0x105a3,0x105b1,-39, +0x105b3,0x105b9,-39, +0x105bb,0x105bc,-39, +0x10cc0,0x10cf2,-64, +0x10d70,0x10d85,-32, +0x118c0,0x118df,-32, +0x16e60,0x16e7f,-32, +0x1e922,0x1e943,-34, +}; + +static const Rune ucd_toupper1[] = { +0xb5,743, +0xff,121, +0x101,-1, +0x103,-1, +0x105,-1, +0x107,-1, +0x109,-1, +0x10b,-1, +0x10d,-1, +0x10f,-1, +0x111,-1, +0x113,-1, +0x115,-1, +0x117,-1, +0x119,-1, +0x11b,-1, +0x11d,-1, +0x11f,-1, +0x121,-1, +0x123,-1, +0x125,-1, +0x127,-1, +0x129,-1, +0x12b,-1, +0x12d,-1, +0x12f,-1, +0x131,-232, +0x133,-1, +0x135,-1, +0x137,-1, +0x13a,-1, +0x13c,-1, +0x13e,-1, +0x140,-1, +0x142,-1, +0x144,-1, +0x146,-1, +0x148,-1, +0x14b,-1, +0x14d,-1, +0x14f,-1, +0x151,-1, +0x153,-1, +0x155,-1, +0x157,-1, +0x159,-1, +0x15b,-1, +0x15d,-1, +0x15f,-1, +0x161,-1, +0x163,-1, +0x165,-1, +0x167,-1, +0x169,-1, +0x16b,-1, +0x16d,-1, +0x16f,-1, +0x171,-1, +0x173,-1, +0x175,-1, +0x177,-1, +0x17a,-1, +0x17c,-1, +0x17e,-1, +0x17f,-300, +0x180,195, +0x183,-1, +0x185,-1, +0x188,-1, +0x18c,-1, +0x192,-1, +0x195,97, +0x199,-1, +0x19a,163, +0x19b,42561, +0x19e,130, +0x1a1,-1, +0x1a3,-1, +0x1a5,-1, +0x1a8,-1, +0x1ad,-1, +0x1b0,-1, +0x1b4,-1, +0x1b6,-1, +0x1b9,-1, +0x1bd,-1, +0x1bf,56, +0x1c5,-1, +0x1c6,-2, +0x1c8,-1, +0x1c9,-2, +0x1cb,-1, +0x1cc,-2, +0x1ce,-1, +0x1d0,-1, +0x1d2,-1, +0x1d4,-1, +0x1d6,-1, +0x1d8,-1, +0x1da,-1, +0x1dc,-1, +0x1dd,-79, +0x1df,-1, +0x1e1,-1, +0x1e3,-1, +0x1e5,-1, +0x1e7,-1, +0x1e9,-1, +0x1eb,-1, +0x1ed,-1, +0x1ef,-1, +0x1f2,-1, +0x1f3,-2, +0x1f5,-1, +0x1f9,-1, +0x1fb,-1, +0x1fd,-1, +0x1ff,-1, +0x201,-1, +0x203,-1, +0x205,-1, +0x207,-1, +0x209,-1, +0x20b,-1, +0x20d,-1, +0x20f,-1, +0x211,-1, +0x213,-1, +0x215,-1, +0x217,-1, +0x219,-1, +0x21b,-1, +0x21d,-1, +0x21f,-1, +0x223,-1, +0x225,-1, +0x227,-1, +0x229,-1, +0x22b,-1, +0x22d,-1, +0x22f,-1, +0x231,-1, +0x233,-1, +0x23c,-1, +0x242,-1, +0x247,-1, +0x249,-1, +0x24b,-1, +0x24d,-1, +0x24f,-1, +0x250,10783, +0x251,10780, +0x252,10782, +0x253,-210, +0x254,-206, +0x259,-202, +0x25b,-203, +0x25c,42319, +0x260,-205, +0x261,42315, +0x263,-207, +0x264,42343, +0x265,42280, +0x266,42308, +0x268,-209, +0x269,-211, +0x26a,42308, +0x26b,10743, +0x26c,42305, +0x26f,-211, +0x271,10749, +0x272,-213, +0x275,-214, +0x27d,10727, +0x280,-218, +0x282,42307, +0x283,-218, +0x287,42282, +0x288,-218, +0x289,-69, +0x28c,-71, +0x292,-219, +0x29d,42261, +0x29e,42258, +0x345,84, +0x371,-1, +0x373,-1, +0x377,-1, +0x3ac,-38, +0x3c2,-31, +0x3cc,-64, +0x3d0,-62, +0x3d1,-57, +0x3d5,-47, +0x3d6,-54, +0x3d7,-8, +0x3d9,-1, +0x3db,-1, +0x3dd,-1, +0x3df,-1, +0x3e1,-1, +0x3e3,-1, +0x3e5,-1, +0x3e7,-1, +0x3e9,-1, +0x3eb,-1, +0x3ed,-1, +0x3ef,-1, +0x3f0,-86, +0x3f1,-80, +0x3f2,7, +0x3f3,-116, +0x3f5,-96, +0x3f8,-1, +0x3fb,-1, +0x461,-1, +0x463,-1, +0x465,-1, +0x467,-1, +0x469,-1, +0x46b,-1, +0x46d,-1, +0x46f,-1, +0x471,-1, +0x473,-1, +0x475,-1, +0x477,-1, +0x479,-1, +0x47b,-1, +0x47d,-1, +0x47f,-1, +0x481,-1, +0x48b,-1, +0x48d,-1, +0x48f,-1, +0x491,-1, +0x493,-1, +0x495,-1, +0x497,-1, +0x499,-1, +0x49b,-1, +0x49d,-1, +0x49f,-1, +0x4a1,-1, +0x4a3,-1, +0x4a5,-1, +0x4a7,-1, +0x4a9,-1, +0x4ab,-1, +0x4ad,-1, +0x4af,-1, +0x4b1,-1, +0x4b3,-1, +0x4b5,-1, +0x4b7,-1, +0x4b9,-1, +0x4bb,-1, +0x4bd,-1, +0x4bf,-1, +0x4c2,-1, +0x4c4,-1, +0x4c6,-1, +0x4c8,-1, +0x4ca,-1, +0x4cc,-1, +0x4ce,-1, +0x4cf,-15, +0x4d1,-1, +0x4d3,-1, +0x4d5,-1, +0x4d7,-1, +0x4d9,-1, +0x4db,-1, +0x4dd,-1, +0x4df,-1, +0x4e1,-1, +0x4e3,-1, +0x4e5,-1, +0x4e7,-1, +0x4e9,-1, +0x4eb,-1, +0x4ed,-1, +0x4ef,-1, +0x4f1,-1, +0x4f3,-1, +0x4f5,-1, +0x4f7,-1, +0x4f9,-1, +0x4fb,-1, +0x4fd,-1, +0x4ff,-1, +0x501,-1, +0x503,-1, +0x505,-1, +0x507,-1, +0x509,-1, +0x50b,-1, +0x50d,-1, +0x50f,-1, +0x511,-1, +0x513,-1, +0x515,-1, +0x517,-1, +0x519,-1, +0x51b,-1, +0x51d,-1, +0x51f,-1, +0x521,-1, +0x523,-1, +0x525,-1, +0x527,-1, +0x529,-1, +0x52b,-1, +0x52d,-1, +0x52f,-1, +0x1c80,-6254, +0x1c81,-6253, +0x1c82,-6244, +0x1c85,-6243, +0x1c86,-6236, +0x1c87,-6181, +0x1c88,35266, +0x1c8a,-1, +0x1d79,35332, +0x1d7d,3814, +0x1d8e,35384, +0x1e01,-1, +0x1e03,-1, +0x1e05,-1, +0x1e07,-1, +0x1e09,-1, +0x1e0b,-1, +0x1e0d,-1, +0x1e0f,-1, +0x1e11,-1, +0x1e13,-1, +0x1e15,-1, +0x1e17,-1, +0x1e19,-1, +0x1e1b,-1, +0x1e1d,-1, +0x1e1f,-1, +0x1e21,-1, +0x1e23,-1, +0x1e25,-1, +0x1e27,-1, +0x1e29,-1, +0x1e2b,-1, +0x1e2d,-1, +0x1e2f,-1, +0x1e31,-1, +0x1e33,-1, +0x1e35,-1, +0x1e37,-1, +0x1e39,-1, +0x1e3b,-1, +0x1e3d,-1, +0x1e3f,-1, +0x1e41,-1, +0x1e43,-1, +0x1e45,-1, +0x1e47,-1, +0x1e49,-1, +0x1e4b,-1, +0x1e4d,-1, +0x1e4f,-1, +0x1e51,-1, +0x1e53,-1, +0x1e55,-1, +0x1e57,-1, +0x1e59,-1, +0x1e5b,-1, +0x1e5d,-1, +0x1e5f,-1, +0x1e61,-1, +0x1e63,-1, +0x1e65,-1, +0x1e67,-1, +0x1e69,-1, +0x1e6b,-1, +0x1e6d,-1, +0x1e6f,-1, +0x1e71,-1, +0x1e73,-1, +0x1e75,-1, +0x1e77,-1, +0x1e79,-1, +0x1e7b,-1, +0x1e7d,-1, +0x1e7f,-1, +0x1e81,-1, +0x1e83,-1, +0x1e85,-1, +0x1e87,-1, +0x1e89,-1, +0x1e8b,-1, +0x1e8d,-1, +0x1e8f,-1, +0x1e91,-1, +0x1e93,-1, +0x1e95,-1, +0x1e9b,-59, +0x1ea1,-1, +0x1ea3,-1, +0x1ea5,-1, +0x1ea7,-1, +0x1ea9,-1, +0x1eab,-1, +0x1ead,-1, +0x1eaf,-1, +0x1eb1,-1, +0x1eb3,-1, +0x1eb5,-1, +0x1eb7,-1, +0x1eb9,-1, +0x1ebb,-1, +0x1ebd,-1, +0x1ebf,-1, +0x1ec1,-1, +0x1ec3,-1, +0x1ec5,-1, +0x1ec7,-1, +0x1ec9,-1, +0x1ecb,-1, +0x1ecd,-1, +0x1ecf,-1, +0x1ed1,-1, +0x1ed3,-1, +0x1ed5,-1, +0x1ed7,-1, +0x1ed9,-1, +0x1edb,-1, +0x1edd,-1, +0x1edf,-1, +0x1ee1,-1, +0x1ee3,-1, +0x1ee5,-1, +0x1ee7,-1, +0x1ee9,-1, +0x1eeb,-1, +0x1eed,-1, +0x1eef,-1, +0x1ef1,-1, +0x1ef3,-1, +0x1ef5,-1, +0x1ef7,-1, +0x1ef9,-1, +0x1efb,-1, +0x1efd,-1, +0x1eff,-1, +0x1f51,8, +0x1f53,8, +0x1f55,8, +0x1f57,8, +0x1fb3,9, +0x1fbe,-7205, +0x1fc3,9, +0x1fe5,7, +0x1ff3,9, +0x214e,-28, +0x2184,-1, +0x2c61,-1, +0x2c65,-10795, +0x2c66,-10792, +0x2c68,-1, +0x2c6a,-1, +0x2c6c,-1, +0x2c73,-1, +0x2c76,-1, +0x2c81,-1, +0x2c83,-1, +0x2c85,-1, +0x2c87,-1, +0x2c89,-1, +0x2c8b,-1, +0x2c8d,-1, +0x2c8f,-1, +0x2c91,-1, +0x2c93,-1, +0x2c95,-1, +0x2c97,-1, +0x2c99,-1, +0x2c9b,-1, +0x2c9d,-1, +0x2c9f,-1, +0x2ca1,-1, +0x2ca3,-1, +0x2ca5,-1, +0x2ca7,-1, +0x2ca9,-1, +0x2cab,-1, +0x2cad,-1, +0x2caf,-1, +0x2cb1,-1, +0x2cb3,-1, +0x2cb5,-1, +0x2cb7,-1, +0x2cb9,-1, +0x2cbb,-1, +0x2cbd,-1, +0x2cbf,-1, +0x2cc1,-1, +0x2cc3,-1, +0x2cc5,-1, +0x2cc7,-1, +0x2cc9,-1, +0x2ccb,-1, +0x2ccd,-1, +0x2ccf,-1, +0x2cd1,-1, +0x2cd3,-1, +0x2cd5,-1, +0x2cd7,-1, +0x2cd9,-1, +0x2cdb,-1, +0x2cdd,-1, +0x2cdf,-1, +0x2ce1,-1, +0x2ce3,-1, +0x2cec,-1, +0x2cee,-1, +0x2cf3,-1, +0x2d27,-7264, +0x2d2d,-7264, +0xa641,-1, +0xa643,-1, +0xa645,-1, +0xa647,-1, +0xa649,-1, +0xa64b,-1, +0xa64d,-1, +0xa64f,-1, +0xa651,-1, +0xa653,-1, +0xa655,-1, +0xa657,-1, +0xa659,-1, +0xa65b,-1, +0xa65d,-1, +0xa65f,-1, +0xa661,-1, +0xa663,-1, +0xa665,-1, +0xa667,-1, +0xa669,-1, +0xa66b,-1, +0xa66d,-1, +0xa681,-1, +0xa683,-1, +0xa685,-1, +0xa687,-1, +0xa689,-1, +0xa68b,-1, +0xa68d,-1, +0xa68f,-1, +0xa691,-1, +0xa693,-1, +0xa695,-1, +0xa697,-1, +0xa699,-1, +0xa69b,-1, +0xa723,-1, +0xa725,-1, +0xa727,-1, +0xa729,-1, +0xa72b,-1, +0xa72d,-1, +0xa72f,-1, +0xa733,-1, +0xa735,-1, +0xa737,-1, +0xa739,-1, +0xa73b,-1, +0xa73d,-1, +0xa73f,-1, +0xa741,-1, +0xa743,-1, +0xa745,-1, +0xa747,-1, +0xa749,-1, +0xa74b,-1, +0xa74d,-1, +0xa74f,-1, +0xa751,-1, +0xa753,-1, +0xa755,-1, +0xa757,-1, +0xa759,-1, +0xa75b,-1, +0xa75d,-1, +0xa75f,-1, +0xa761,-1, +0xa763,-1, +0xa765,-1, +0xa767,-1, +0xa769,-1, +0xa76b,-1, +0xa76d,-1, +0xa76f,-1, +0xa77a,-1, +0xa77c,-1, +0xa77f,-1, +0xa781,-1, +0xa783,-1, +0xa785,-1, +0xa787,-1, +0xa78c,-1, +0xa791,-1, +0xa793,-1, +0xa794,48, +0xa797,-1, +0xa799,-1, +0xa79b,-1, +0xa79d,-1, +0xa79f,-1, +0xa7a1,-1, +0xa7a3,-1, +0xa7a5,-1, +0xa7a7,-1, +0xa7a9,-1, +0xa7b5,-1, +0xa7b7,-1, +0xa7b9,-1, +0xa7bb,-1, +0xa7bd,-1, +0xa7bf,-1, +0xa7c1,-1, +0xa7c3,-1, +0xa7c8,-1, +0xa7ca,-1, +0xa7cd,-1, +0xa7d1,-1, +0xa7d7,-1, +0xa7d9,-1, +0xa7db,-1, +0xa7f6,-1, +0xab53,-928, +}; + +static const Rune ucd_tolower_full[] = { +0x130,0x69,0x307,0x0, +0x1f88,0x1f80,0x0,0x0, +0x1f89,0x1f81,0x0,0x0, +0x1f8a,0x1f82,0x0,0x0, +0x1f8b,0x1f83,0x0,0x0, +0x1f8c,0x1f84,0x0,0x0, +0x1f8d,0x1f85,0x0,0x0, +0x1f8e,0x1f86,0x0,0x0, +0x1f8f,0x1f87,0x0,0x0, +0x1f98,0x1f90,0x0,0x0, +0x1f99,0x1f91,0x0,0x0, +0x1f9a,0x1f92,0x0,0x0, +0x1f9b,0x1f93,0x0,0x0, +0x1f9c,0x1f94,0x0,0x0, +0x1f9d,0x1f95,0x0,0x0, +0x1f9e,0x1f96,0x0,0x0, +0x1f9f,0x1f97,0x0,0x0, +0x1fa8,0x1fa0,0x0,0x0, +0x1fa9,0x1fa1,0x0,0x0, +0x1faa,0x1fa2,0x0,0x0, +0x1fab,0x1fa3,0x0,0x0, +0x1fac,0x1fa4,0x0,0x0, +0x1fad,0x1fa5,0x0,0x0, +0x1fae,0x1fa6,0x0,0x0, +0x1faf,0x1fa7,0x0,0x0, +0x1fbc,0x1fb3,0x0,0x0, +0x1fcc,0x1fc3,0x0,0x0, +0x1ffc,0x1ff3,0x0,0x0, +}; + +static const Rune ucd_toupper_full[] = { +0xdf,0x53,0x53,0x0,0x0, +0x149,0x2bc,0x4e,0x0,0x0, +0x1f0,0x4a,0x30c,0x0,0x0, +0x390,0x399,0x308,0x301,0x0, +0x3b0,0x3a5,0x308,0x301,0x0, +0x587,0x535,0x552,0x0,0x0, +0x1e96,0x48,0x331,0x0,0x0, +0x1e97,0x54,0x308,0x0,0x0, +0x1e98,0x57,0x30a,0x0,0x0, +0x1e99,0x59,0x30a,0x0,0x0, +0x1e9a,0x41,0x2be,0x0,0x0, +0x1f50,0x3a5,0x313,0x0,0x0, +0x1f52,0x3a5,0x313,0x300,0x0, +0x1f54,0x3a5,0x313,0x301,0x0, +0x1f56,0x3a5,0x313,0x342,0x0, +0x1f80,0x1f08,0x399,0x0,0x0, +0x1f81,0x1f09,0x399,0x0,0x0, +0x1f82,0x1f0a,0x399,0x0,0x0, +0x1f83,0x1f0b,0x399,0x0,0x0, +0x1f84,0x1f0c,0x399,0x0,0x0, +0x1f85,0x1f0d,0x399,0x0,0x0, +0x1f86,0x1f0e,0x399,0x0,0x0, +0x1f87,0x1f0f,0x399,0x0,0x0, +0x1f88,0x1f08,0x399,0x0,0x0, +0x1f89,0x1f09,0x399,0x0,0x0, +0x1f8a,0x1f0a,0x399,0x0,0x0, +0x1f8b,0x1f0b,0x399,0x0,0x0, +0x1f8c,0x1f0c,0x399,0x0,0x0, +0x1f8d,0x1f0d,0x399,0x0,0x0, +0x1f8e,0x1f0e,0x399,0x0,0x0, +0x1f8f,0x1f0f,0x399,0x0,0x0, +0x1f90,0x1f28,0x399,0x0,0x0, +0x1f91,0x1f29,0x399,0x0,0x0, +0x1f92,0x1f2a,0x399,0x0,0x0, +0x1f93,0x1f2b,0x399,0x0,0x0, +0x1f94,0x1f2c,0x399,0x0,0x0, +0x1f95,0x1f2d,0x399,0x0,0x0, +0x1f96,0x1f2e,0x399,0x0,0x0, +0x1f97,0x1f2f,0x399,0x0,0x0, +0x1f98,0x1f28,0x399,0x0,0x0, +0x1f99,0x1f29,0x399,0x0,0x0, +0x1f9a,0x1f2a,0x399,0x0,0x0, +0x1f9b,0x1f2b,0x399,0x0,0x0, +0x1f9c,0x1f2c,0x399,0x0,0x0, +0x1f9d,0x1f2d,0x399,0x0,0x0, +0x1f9e,0x1f2e,0x399,0x0,0x0, +0x1f9f,0x1f2f,0x399,0x0,0x0, +0x1fa0,0x1f68,0x399,0x0,0x0, +0x1fa1,0x1f69,0x399,0x0,0x0, +0x1fa2,0x1f6a,0x399,0x0,0x0, +0x1fa3,0x1f6b,0x399,0x0,0x0, +0x1fa4,0x1f6c,0x399,0x0,0x0, +0x1fa5,0x1f6d,0x399,0x0,0x0, +0x1fa6,0x1f6e,0x399,0x0,0x0, +0x1fa7,0x1f6f,0x399,0x0,0x0, +0x1fa8,0x1f68,0x399,0x0,0x0, +0x1fa9,0x1f69,0x399,0x0,0x0, +0x1faa,0x1f6a,0x399,0x0,0x0, +0x1fab,0x1f6b,0x399,0x0,0x0, +0x1fac,0x1f6c,0x399,0x0,0x0, +0x1fad,0x1f6d,0x399,0x0,0x0, +0x1fae,0x1f6e,0x399,0x0,0x0, +0x1faf,0x1f6f,0x399,0x0,0x0, +0x1fb2,0x1fba,0x399,0x0,0x0, +0x1fb3,0x391,0x399,0x0,0x0, +0x1fb4,0x386,0x399,0x0,0x0, +0x1fb6,0x391,0x342,0x0,0x0, +0x1fb7,0x391,0x342,0x399,0x0, +0x1fbc,0x391,0x399,0x0,0x0, +0x1fc2,0x1fca,0x399,0x0,0x0, +0x1fc3,0x397,0x399,0x0,0x0, +0x1fc4,0x389,0x399,0x0,0x0, +0x1fc6,0x397,0x342,0x0,0x0, +0x1fc7,0x397,0x342,0x399,0x0, +0x1fcc,0x397,0x399,0x0,0x0, +0x1fd2,0x399,0x308,0x300,0x0, +0x1fd3,0x399,0x308,0x301,0x0, +0x1fd6,0x399,0x342,0x0,0x0, +0x1fd7,0x399,0x308,0x342,0x0, +0x1fe2,0x3a5,0x308,0x300,0x0, +0x1fe3,0x3a5,0x308,0x301,0x0, +0x1fe4,0x3a1,0x313,0x0,0x0, +0x1fe6,0x3a5,0x342,0x0,0x0, +0x1fe7,0x3a5,0x308,0x342,0x0, +0x1ff2,0x1ffa,0x399,0x0,0x0, +0x1ff3,0x3a9,0x399,0x0,0x0, +0x1ff4,0x38f,0x399,0x0,0x0, +0x1ff6,0x3a9,0x342,0x0,0x0, +0x1ff7,0x3a9,0x342,0x399,0x0, +0x1ffc,0x3a9,0x399,0x0,0x0, +0xfb00,0x46,0x46,0x0,0x0, +0xfb01,0x46,0x49,0x0,0x0, +0xfb02,0x46,0x4c,0x0,0x0, +0xfb03,0x46,0x46,0x49,0x0, +0xfb04,0x46,0x46,0x4c,0x0, +0xfb05,0x53,0x54,0x0,0x0, +0xfb06,0x53,0x54,0x0,0x0, +0xfb13,0x544,0x546,0x0,0x0, +0xfb14,0x544,0x535,0x0,0x0, +0xfb15,0x544,0x53b,0x0,0x0, +0xfb16,0x54e,0x546,0x0,0x0, +0xfb17,0x544,0x53d,0x0,0x0, +}; diff --git a/src/openlibm/.github/dependabot.yml b/src/openlibm/.github/dependabot.yml new file mode 100644 index 0000000..d60f070 --- /dev/null +++ b/src/openlibm/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/src/openlibm/.github/workflows/ci.yml b/src/openlibm/.github/workflows/ci.yml new file mode 100644 index 0000000..cdb9358 --- /dev/null +++ b/src/openlibm/.github/workflows/ci.yml @@ -0,0 +1,93 @@ +name: CI +on: + pull_request: + branches: + - master + push: + branches: + - master + tags: '*' +jobs: + test-unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + steps: + - uses: actions/checkout@v4 + - run: make + - run: make test + windows: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - { sys: mingw64, env: x86_64 } + - { sys: mingw32, env: i686 } + - { sys: ucrt64, env: ucrt-x86_64 } # Experimental! + - { sys: clang64, env: clang-x86_64 } # Experimental! + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v4 + - name: Set up the desired MSYS2 environment + uses: msys2/setup-msys2@v2 + with: + msystem: ${{matrix.sys}} + install: base-devel mingw-w64-${{matrix.env}}-toolchain + - run: make + - run: make test + code-coverage-old: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup LCOV + uses: hrishikesh-kadam/setup-lcov@v1 + - name: Build and Run tests + run: make coverage -j + # - name: Upload coverage to Codecov + # uses: codecov/codecov-action@v5 + # with: + # files: ./cov-html/libopenlibm.info + # token: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/upload-artifact@v4 + with: + name: code-coverage-report-old + path: ./cov-html/ + code-coverage: + runs-on: ubuntu-latest + steps: + - name: Checkout Openlibm + uses: actions/checkout@v4 + - name: Checkout Openlibm-test + uses: actions/checkout@v4 + with: + repository: 'JuliaMath/openlibm-test' + path: 'openlibm-test' + - name: Setup LCOV + uses: hrishikesh-kadam/setup-lcov@v1 + - name: Build Openlibm + run: make -j`nproc` CODE_COVERAGE=1 + - name: Run Test + run: | + make -j`nproc` -C openlibm-test \ + USE_OPENLIBM=1 OPENLIBM_HOME="$(pwd)" \ + SKIP_FP_EXCEPT_TEST=1 \ + - name: Show Test Result + run: cat openlibm-test/src/REPORT + - name: Gen Coverage Report + run: make gen-cov-report + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: ./cov-html/libopenlibm.info + token: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/upload-artifact@v4 + with: + name: code-coverage-report + path: ./cov-html/ diff --git a/src/openlibm/.github/workflows/cross-loongarch64.yml b/src/openlibm/.github/workflows/cross-loongarch64.yml new file mode 100644 index 0000000..1c8e769 --- /dev/null +++ b/src/openlibm/.github/workflows/cross-loongarch64.yml @@ -0,0 +1,54 @@ +# merge this file into cross.yml +# when we can `sudo apt install gcc-loongarch64-linux-gnu` on ubuntu +name: Cross + +on: + pull_request: + branches: + - master + push: + branches: + - master + tags: '*' + +jobs: + build-cross-qemu: + # TODO: We need Ubuntu 24.04 to use newer version of qemu, + # switch to ubuntu-latest when `ubuntu-latest >= 24.04` + runs-on: ubuntu-24.04 + name: build-cross-qemu-${{ matrix.config.arch }} + strategy: + fail-fast: false + matrix: + config: + - { arch: loongarch64, triple: loongarch64-linux-gnu } + env: + ARCH: ${{ matrix.config.arch }} + TRIPLE: ${{ matrix.config.triple }} + steps: + - uses: actions/checkout@v4 + - name: Install qemu + run: | + sudo apt update + sudo apt install -y qemu-user qemu-user-binfmt + - name: Install gcc-${{ matrix.config.triple }} + # package gcc-loongarch64-linux-gnu seems not exist + # https://packages.debian.org/sid/amd64/gcc-loongarch64-linux-gnu + run: sudo apt install -y gcc-14-loongarch64-linux-gnu + - name: Build with ${{ matrix.config.triple }}-gcc + run: | + make ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ + CC='loongarch64-linux-gnu-gcc-14' \ + AR='loongarch64-linux-gnu-gcc-ar-14' \ + - name: Build tests + run: | + make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- \ + CC='loongarch64-linux-gnu-gcc-14' \ + AR='loongarch64-linux-gnu-gcc-ar-14' \ + - name: Run Tests + env: + QEMU_EXEC: qemu-${{ matrix.config.arch }} + CROSS_LIB: /usr/${{ matrix.config.triple }} + run: | + $QEMU_EXEC -L . -L $CROSS_LIB/ test/test-float + $QEMU_EXEC -L . -L $CROSS_LIB/ test/test-double diff --git a/src/openlibm/.github/workflows/cross.yml b/src/openlibm/.github/workflows/cross.yml new file mode 100644 index 0000000..267341a --- /dev/null +++ b/src/openlibm/.github/workflows/cross.yml @@ -0,0 +1,53 @@ +name: Cross + +on: + pull_request: + branches: + - master + push: + branches: + - master + tags: '*' + +jobs: + build-cross-qemu: + # TODO: We need Ubuntu 24.04 to use newer version of qemu, + # switch to ubuntu-latest when `ubuntu-latest >= 24.04` + runs-on: ubuntu-24.04 + name: build-cross-qemu-${{ matrix.config.arch }} + strategy: + fail-fast: false + matrix: + config: + - { arch: arm, triple: arm-linux-gnueabihf } + - { arch: aarch64, triple: aarch64-linux-gnu } + - { arch: ppc, triple: powerpc-linux-gnu } + - { arch: ppc64, triple: powerpc64-linux-gnu } + - { arch: ppc64le, triple: powerpc64le-linux-gnu } + - { arch: mips, triple: mips-linux-gnu } + - { arch: mipsel, triple: mipsel-linux-gnu } + # Builds successfully, but tests fail. + # - { arch: mips64, triple: mips64-linux-gnuabi64 } + # - { arch: mips64el, triple: mips64el-linux-gnuabi64 } + - { arch: riscv64, triple: riscv64-linux-gnu } + - { arch: s390x, triple: s390x-linux-gnu } + env: + ARCH: ${{ matrix.config.arch }} + TRIPLE: ${{ matrix.config.triple }} + steps: + - uses: actions/checkout@v4 + - name: Install qemu and toolchain gcc-${{ matrix.config.triple }} + run: | + sudo apt update + sudo apt install qemu-user qemu-user-binfmt gcc-$TRIPLE -y + - name: Build with ${{ matrix.config.triple }}-gcc + run: make ARCH=$ARCH TOOLPREFIX=$TRIPLE- + - name: Build tests + run: make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- + - name: Run Tests + env: + QEMU_EXEC: qemu-${{ matrix.config.arch }} + CROSS_LIB: /usr/${{ matrix.config.triple }} + run: | + $QEMU_EXEC -L . -L $CROSS_LIB/ test/test-float + $QEMU_EXEC -L . -L $CROSS_LIB/ test/test-double diff --git a/src/openlibm/.mailmap b/src/openlibm/.mailmap new file mode 100644 index 0000000..637106f --- /dev/null +++ b/src/openlibm/.mailmap @@ -0,0 +1,61 @@ +JuliaLang +JuliaLang + +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson +Jeff Bezanson + +Stefan Karpinski +Stefan Karpinski +Stefan Karpinski + +Viral B. Shah +Viral B. Shah +Viral B. Shah +Viral B. Shah + +George Xing +George Xing + +Stephan Boyer +Stephan Boyer +Stephan Boyer +Stephan Boyer + +Giuseppe Zingales +Giuseppe Zingales + +Jameson Nash +Jameson Nash +Jameson Nash + +Alan Edelman + +PlayMyCode +PlayMyCode + +Corey M. Hoffstein +Corey M. Hoffstein + +Stefan Kroboth + +Tim Holy +Tim Holy + +Patrick O'Leary + +Ivan Mantova + +Keno Fischer +Keno Fischer +Keno Fischer diff --git a/src/openlibm/CMakeLists.txt b/src/openlibm/CMakeLists.txt new file mode 100755 index 0000000..81045e2 --- /dev/null +++ b/src/openlibm/CMakeLists.txt @@ -0,0 +1,576 @@ +cmake_minimum_required(VERSION 3.25) + +# Get version string from Make.inc +file(READ "${CMAKE_CURRENT_LIST_DIR}/Make.inc" MAKE_FILE) +string(REGEX MATCH "VERSION = ([0-9\.]+)" _ ${MAKE_FILE}) + +project(openlibm + VERSION ${CMAKE_MATCH_1} + LANGUAGES C ASM) + +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + +add_library("${PROJECT_NAME}") + +# Find the relevant folder depending on the architecture +set(OPENLIBM_ARCH_FOLDER ${CMAKE_SYSTEM_PROCESSOR}) +string(TOLOWER "${OPENLIBM_ARCH_FOLDER}" OPENLIBM_ARCH_FOLDER) + +if(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "x86_64") + set(OPENLIBM_ARCH_FOLDER "amd64") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") + set(OPENLIBM_ARCH_FOLDER "aarch64") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "armv7-a") + set(OPENLIBM_ARCH_FOLDER "arm") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "x86" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "i686") + set(OPENLIBM_ARCH_FOLDER "i387") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") + set(OPENLIBM_ARCH_FOLDER "powerpc") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") + set(OPENLIBM_ARCH_FOLDER "riscv64") +else() + message(FATAL_ERROR "${PROJECT_NAME} not set up for detected architecture: ${OPENLIBM_ARCH_FOLDER}") +endif() + + +# Compile flags +list(APPEND C_ASM_COMPILE_FLAGS "-ffp-contract=off" "-fno-fast-math" "-fno-rounding-math" "-fno-math-errno") +list(APPEND C_ASM_COMPILE_FLAGS "-fPIC" "-std=c99" "-fno-builtin") +list(APPEND C_ASM_COMPILE_FLAGS "-Wall" "-Wno-implicit-function-declaration") +list(APPEND C_ASM_COMPILE_FLAGS "-DASSEMBLER" "-D__BSD_VISIBLE" "-O3") + +# Compiler-specific compile flags +if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") + list(APPEND C_ASM_COMPILE_FLAGS "-fno-strict-aliasing" "-ffp-exception-behavior=strict") +elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + list(APPEND C_ASM_COMPILE_FLAGS "-fno-gnu89-inline") +else() + message(FATAL_ERROR "${PROJECT_NAME} not set up to be compiled with ${CMAKE_C_COMPILER_ID}") +endif() + +# Architecture-specific compile flags - take advantage of sse on x86 +if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") + list(APPEND C_ASM_COMPILE_FLAGS "-march=i686" "-m32" "-msse2" "-mfpmath=sse") +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") + list(APPEND C_ASM_COMPILE_FLAGS "-m64" "-msse2" "-mfpmath=sse") +endif() + +# Suppress warnings if requested +if(OPENLIBM_SUPPRESS_WARNINGS) + list(APPEND C_ASM_COMPILE_FLAGS "-w") +endif() + +# Add compile flags +target_compile_options("${PROJECT_NAME}" PUBLIC ${C_ASM_COMPILE_FLAGS}) + +# Project Source +set(PROJECT_SRC "${CMAKE_CURRENT_SOURCE_DIR}") + +# Common +list(APPEND OPENLIBM_C_SOURCE + # src + "${PROJECT_SRC}/src/common.c" + "${PROJECT_SRC}/src/e_acos.c" + "${PROJECT_SRC}/src/e_acosf.c" + "${PROJECT_SRC}/src/e_acosh.c" + "${PROJECT_SRC}/src/e_acoshf.c" + "${PROJECT_SRC}/src/e_asin.c" + "${PROJECT_SRC}/src/e_asinf.c" + "${PROJECT_SRC}/src/e_atan2.c" + "${PROJECT_SRC}/src/e_atan2f.c" + "${PROJECT_SRC}/src/e_atanh.c" + "${PROJECT_SRC}/src/e_atanhf.c" + "${PROJECT_SRC}/src/e_cosh.c" + "${PROJECT_SRC}/src/e_coshf.c" + "${PROJECT_SRC}/src/e_exp.c" + "${PROJECT_SRC}/src/e_expf.c" + "${PROJECT_SRC}/src/e_fmod.c" + "${PROJECT_SRC}/src/e_fmodf.c" + "${PROJECT_SRC}/src/e_hypot.c" + "${PROJECT_SRC}/src/e_hypotf.c" + "${PROJECT_SRC}/src/e_j0.c" + "${PROJECT_SRC}/src/e_j0f.c" + "${PROJECT_SRC}/src/e_j1.c" + "${PROJECT_SRC}/src/e_j1f.c" + "${PROJECT_SRC}/src/e_jn.c" + "${PROJECT_SRC}/src/e_jnf.c" + "${PROJECT_SRC}/src/e_lgamma.c" + "${PROJECT_SRC}/src/e_lgamma_r.c" + "${PROJECT_SRC}/src/e_lgammaf.c" + "${PROJECT_SRC}/src/e_lgammaf_r.c" + "${PROJECT_SRC}/src/e_log.c" + "${PROJECT_SRC}/src/e_log10.c" + "${PROJECT_SRC}/src/e_log10f.c" + "${PROJECT_SRC}/src/e_log2.c" + "${PROJECT_SRC}/src/e_log2f.c" + "${PROJECT_SRC}/src/e_logf.c" + "${PROJECT_SRC}/src/e_pow.c" + "${PROJECT_SRC}/src/e_powf.c" + "${PROJECT_SRC}/src/e_remainder.c" + "${PROJECT_SRC}/src/e_remainderf.c" + "${PROJECT_SRC}/src/e_rem_pio2.c" + "${PROJECT_SRC}/src/e_rem_pio2f.c" + "${PROJECT_SRC}/src/e_sinh.c" + "${PROJECT_SRC}/src/e_sinhf.c" + "${PROJECT_SRC}/src/e_sqrt.c" + "${PROJECT_SRC}/src/e_sqrtf.c" + "${PROJECT_SRC}/src/k_cos.c" + "${PROJECT_SRC}/src/k_exp.c" + "${PROJECT_SRC}/src/k_expf.c" + "${PROJECT_SRC}/src/k_rem_pio2.c" + "${PROJECT_SRC}/src/k_sin.c" + "${PROJECT_SRC}/src/k_tan.c" + "${PROJECT_SRC}/src/k_cosf.c" + "${PROJECT_SRC}/src/k_sinf.c" + "${PROJECT_SRC}/src/k_tanf.c" + "${PROJECT_SRC}/src/s_asinh.c" + "${PROJECT_SRC}/src/s_asinhf.c" + "${PROJECT_SRC}/src/s_atan.c" + "${PROJECT_SRC}/src/s_atanf.c" + "${PROJECT_SRC}/src/s_carg.c" + "${PROJECT_SRC}/src/s_cargf.c" + "${PROJECT_SRC}/src/s_cbrt.c" + "${PROJECT_SRC}/src/s_cbrtf.c" + "${PROJECT_SRC}/src/s_ceil.c" + "${PROJECT_SRC}/src/s_ceilf.c" + "${PROJECT_SRC}/src/s_copysign.c" + "${PROJECT_SRC}/src/s_copysignf.c" + "${PROJECT_SRC}/src/s_cos.c" + "${PROJECT_SRC}/src/s_cosf.c" + "${PROJECT_SRC}/src/s_csqrt.c" + "${PROJECT_SRC}/src/s_csqrtf.c" + "${PROJECT_SRC}/src/s_erf.c" + "${PROJECT_SRC}/src/s_erff.c" + "${PROJECT_SRC}/src/s_exp2.c" + "${PROJECT_SRC}/src/s_exp2f.c" + "${PROJECT_SRC}/src/s_expm1.c" + "${PROJECT_SRC}/src/s_expm1f.c" + "${PROJECT_SRC}/src/s_fabs.c" + "${PROJECT_SRC}/src/s_fabsf.c" + "${PROJECT_SRC}/src/s_fdim.c" + "${PROJECT_SRC}/src/s_floor.c" + "${PROJECT_SRC}/src/s_floorf.c" + "${PROJECT_SRC}/src/s_fmax.c" + "${PROJECT_SRC}/src/s_fmaxf.c" + "${PROJECT_SRC}/src/s_fmin.c" + "${PROJECT_SRC}/src/s_fminf.c" + "${PROJECT_SRC}/src/s_fpclassify.c" + "${PROJECT_SRC}/src/s_frexp.c" + "${PROJECT_SRC}/src/s_frexpf.c" + "${PROJECT_SRC}/src/s_ilogb.c" + "${PROJECT_SRC}/src/s_ilogbf.c" + "${PROJECT_SRC}/src/s_isinf.c" + "${PROJECT_SRC}/src/s_isfinite.c" + "${PROJECT_SRC}/src/s_isnormal.c" + "${PROJECT_SRC}/src/s_isnan.c" + "${PROJECT_SRC}/src/s_log1p.c" + "${PROJECT_SRC}/src/s_log1pf.c" + "${PROJECT_SRC}/src/s_logb.c" + "${PROJECT_SRC}/src/s_logbf.c" + "${PROJECT_SRC}/src/s_modf.c" + "${PROJECT_SRC}/src/s_modff.c" + "${PROJECT_SRC}/src/s_nextafter.c" + "${PROJECT_SRC}/src/s_nextafterf.c" + "${PROJECT_SRC}/src/s_nexttowardf.c" + "${PROJECT_SRC}/src/s_remquo.c" + "${PROJECT_SRC}/src/s_remquof.c" + "${PROJECT_SRC}/src/s_rint.c" + "${PROJECT_SRC}/src/s_rintf.c" + "${PROJECT_SRC}/src/s_round.c" + "${PROJECT_SRC}/src/s_roundf.c" + "${PROJECT_SRC}/src/s_scalbln.c" + "${PROJECT_SRC}/src/s_scalbn.c" + "${PROJECT_SRC}/src/s_scalbnf.c" + "${PROJECT_SRC}/src/s_signbit.c" + "${PROJECT_SRC}/src/s_signgam.c" + "${PROJECT_SRC}/src/s_sin.c" + "${PROJECT_SRC}/src/s_sincos.c" + "${PROJECT_SRC}/src/s_sinf.c" + "${PROJECT_SRC}/src/s_sincosf.c" + "${PROJECT_SRC}/src/s_tan.c" + "${PROJECT_SRC}/src/s_tanf.c" + "${PROJECT_SRC}/src/s_tanh.c" + "${PROJECT_SRC}/src/s_tanhf.c" + "${PROJECT_SRC}/src/s_tgammaf.c" + "${PROJECT_SRC}/src/s_trunc.c" + "${PROJECT_SRC}/src/s_truncf.c" + "${PROJECT_SRC}/src/s_cpow.c" + "${PROJECT_SRC}/src/s_cpowf.c" + "${PROJECT_SRC}/src/w_cabs.c" + "${PROJECT_SRC}/src/w_cabsf.c" + + "${PROJECT_SRC}/src/s_fma.c" + "${PROJECT_SRC}/src/s_fmaf.c" + "${PROJECT_SRC}/src/s_lrint.c" + "${PROJECT_SRC}/src/s_lrintf.c" + "${PROJECT_SRC}/src/s_lround.c" + "${PROJECT_SRC}/src/s_lroundf.c" + "${PROJECT_SRC}/src/s_llrint.c" + "${PROJECT_SRC}/src/s_llrintf.c" + "${PROJECT_SRC}/src/s_llround.c" + "${PROJECT_SRC}/src/s_llroundf.c" + "${PROJECT_SRC}/src/s_nearbyint.c" + + # C99 complex functions + "${PROJECT_SRC}/src/s_ccosh.c" + "${PROJECT_SRC}/src/s_ccoshf.c" + "${PROJECT_SRC}/src/s_cexp.c" + "${PROJECT_SRC}/src/s_cexpf.c" + "${PROJECT_SRC}/src/s_cimag.c" + "${PROJECT_SRC}/src/s_cimagf.c" + "${PROJECT_SRC}/src/s_conj.c" + "${PROJECT_SRC}/src/s_conjf.c" + "${PROJECT_SRC}/src/s_cproj.c" + "${PROJECT_SRC}/src/s_cprojf.c" + "${PROJECT_SRC}/src/s_creal.c" + "${PROJECT_SRC}/src/s_crealf.c" + "${PROJECT_SRC}/src/s_csinh.c" + "${PROJECT_SRC}/src/s_csinhf.c" + "${PROJECT_SRC}/src/s_ctanh.c" + "${PROJECT_SRC}/src/s_ctanhf.c" + "${PROJECT_SRC}/src/s_cacos.c" + "${PROJECT_SRC}/src/s_cacosf.c" + "${PROJECT_SRC}/src/s_cacosh.c" + "${PROJECT_SRC}/src/s_cacoshf.c" + "${PROJECT_SRC}/src/s_casin.c" + "${PROJECT_SRC}/src/s_casinf.c" + "${PROJECT_SRC}/src/s_casinh.c" + "${PROJECT_SRC}/src/s_casinhf.c" + "${PROJECT_SRC}/src/s_catan.c" + "${PROJECT_SRC}/src/s_catanf.c" + "${PROJECT_SRC}/src/s_catanh.c" + "${PROJECT_SRC}/src/s_catanhf.c" + "${PROJECT_SRC}/src/s_clog.c" + "${PROJECT_SRC}/src/s_clogf.c" + + # bsdsrc + "${PROJECT_SRC}/bsdsrc/b_exp.c" + "${PROJECT_SRC}/bsdsrc/b_log.c" + "${PROJECT_SRC}/bsdsrc/b_tgamma.c" +) + +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/src/s_nan.c" + ) +endif() + +# Determine if long double and double are the same size +include(CheckCSourceCompiles) +check_c_source_compiles(" +#include +#if (LDBL_MANT_DIG == DBL_MANT_DIG) +#error \"long double and double are the same size\" +#endif +int main(void ) { return 0; } +" LONG_DOUBLE_NOT_DOUBLE) + +# Add in long double functions for x86, x64 and aarch64 +if(LONG_DOUBLE_NOT_DOUBLE) + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/src/s_copysignl.c" + "${PROJECT_SRC}/src/s_fabsl.c" + "${PROJECT_SRC}/src/s_llrintl.c" + "${PROJECT_SRC}/src/s_lrintl.c" + "${PROJECT_SRC}/src/s_modfl.c" + + "${PROJECT_SRC}/src/e_acosl.c" + "${PROJECT_SRC}/src/e_asinl.c" + "${PROJECT_SRC}/src/e_atan2l.c" + "${PROJECT_SRC}/src/e_fmodl.c" + "${PROJECT_SRC}/src/s_fmaxl.c" + "${PROJECT_SRC}/src/s_fminl.c" + "${PROJECT_SRC}/src/s_ilogbl.c" + "${PROJECT_SRC}/src/e_hypotl.c" + "${PROJECT_SRC}/src/e_lgammal.c" + "${PROJECT_SRC}/src/e_remainderl.c" + "${PROJECT_SRC}/src/e_sqrtl.c" + "${PROJECT_SRC}/src/s_atanl.c" + "${PROJECT_SRC}/src/s_ceill.c" + "${PROJECT_SRC}/src/s_cosl.c" + "${PROJECT_SRC}/src/s_cprojl.c" + "${PROJECT_SRC}/src/s_csqrtl.c" + "${PROJECT_SRC}/src/s_floorl.c" + "${PROJECT_SRC}/src/s_fmal.c" + "${PROJECT_SRC}/src/s_frexpl.c" + "${PROJECT_SRC}/src/s_logbl.c" + "${PROJECT_SRC}/src/s_nexttoward.c" + "${PROJECT_SRC}/src/s_remquol.c" + "${PROJECT_SRC}/src/s_roundl.c" + "${PROJECT_SRC}/src/s_lroundl.c" + "${PROJECT_SRC}/src/s_llroundl.c" + "${PROJECT_SRC}/src/s_cpowl.c" + "${PROJECT_SRC}/src/s_cargl.c" + "${PROJECT_SRC}/src/s_sinl.c" + "${PROJECT_SRC}/src/s_sincosl.c" + "${PROJECT_SRC}/src/s_tanl.c" + "${PROJECT_SRC}/src/s_truncl.c" + "${PROJECT_SRC}/src/w_cabsl.c" + "${PROJECT_SRC}/src/s_nextafterl.c" + "${PROJECT_SRC}/src/s_rintl.c" + "${PROJECT_SRC}/src/s_scalbnl.c" + "${PROJECT_SRC}/src/polevll.c" + "${PROJECT_SRC}/src/s_casinl.c" + "${PROJECT_SRC}/src/s_ctanl.c" + "${PROJECT_SRC}/src/s_cimagl.c" + "${PROJECT_SRC}/src/s_conjl.c" + "${PROJECT_SRC}/src/s_creall.c" + "${PROJECT_SRC}/src/s_cacoshl.c" + "${PROJECT_SRC}/src/s_catanhl.c" + "${PROJECT_SRC}/src/s_casinhl.c" + "${PROJECT_SRC}/src/s_catanl.c" + "${PROJECT_SRC}/src/s_csinl.c" + "${PROJECT_SRC}/src/s_cacosl.c" + "${PROJECT_SRC}/src/s_cexpl.c" + "${PROJECT_SRC}/src/s_csinhl.c" + "${PROJECT_SRC}/src/s_ccoshl.c" + "${PROJECT_SRC}/src/s_clogl.c" + "${PROJECT_SRC}/src/s_ctanhl.c" + "${PROJECT_SRC}/src/s_ccosl.c" + "${PROJECT_SRC}/src/s_cbrtl.c" + ) +endif() + +if (LONG_DOUBLE_NOT_DOUBLE) + if (${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") + list(APPEND OPENLIBM_C_SOURCE + # ld80 + "${PROJECT_SRC}/ld80/invtrig.c" + "${PROJECT_SRC}/ld80/e_acoshl.c" + "${PROJECT_SRC}/ld80/e_powl.c" + "${PROJECT_SRC}/ld80/k_tanl.c" + "${PROJECT_SRC}/ld80/s_exp2l.c" + "${PROJECT_SRC}/ld80/e_atanhl.c" + "${PROJECT_SRC}/ld80/e_lgammal_r.c" + "${PROJECT_SRC}/ld80/e_sinhl.c" + "${PROJECT_SRC}/ld80/s_asinhl.c" + "${PROJECT_SRC}/ld80/s_expm1l.c" + "${PROJECT_SRC}/ld80/e_coshl.c" + "${PROJECT_SRC}/ld80/e_log10l.c" + "${PROJECT_SRC}/ld80/e_tgammal.c" + "${PROJECT_SRC}/ld80/e_expl.c" + "${PROJECT_SRC}/ld80/e_log2l.c" + "${PROJECT_SRC}/ld80/k_cosl.c" + "${PROJECT_SRC}/ld80/s_log1pl.c" + "${PROJECT_SRC}/ld80/s_tanhl.c" + "${PROJECT_SRC}/ld80/e_logl.c" + "${PROJECT_SRC}/ld80/k_sinl.c" + "${PROJECT_SRC}/ld80/s_erfl.c" + ) + + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/ld80/s_nanl.c" + ) + endif() + else() + if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") + list(APPEND OPENLIBM_C_SOURCE + # ld128 + "${PROJECT_SRC}/ld128/invtrig.c" + "${PROJECT_SRC}/ld128/e_acoshl.c" + "${PROJECT_SRC}/ld128/e_powl.c" + "${PROJECT_SRC}/ld128/k_tanl.c" + "${PROJECT_SRC}/ld128/s_exp2l.c" + "${PROJECT_SRC}/ld128/e_atanhl.c" + "${PROJECT_SRC}/ld128/e_lgammal_r.c" + "${PROJECT_SRC}/ld128/e_sinhl.c" + "${PROJECT_SRC}/ld128/s_asinhl.c" + "${PROJECT_SRC}/ld128/s_expm1l.c" + "${PROJECT_SRC}/ld128/e_coshl.c" + "${PROJECT_SRC}/ld128/e_log10l.c" + "${PROJECT_SRC}/ld128/e_tgammal.c" + "${PROJECT_SRC}/ld128/e_expl.c" + "${PROJECT_SRC}/ld128/e_log2l.c" + "${PROJECT_SRC}/ld128/k_cosl.c" + "${PROJECT_SRC}/ld128/s_log1pl.c" + "${PROJECT_SRC}/ld128/s_tanhl.c" + "${PROJECT_SRC}/ld128/e_logl.c" + "${PROJECT_SRC}/ld128/k_sinl.c" + "${PROJECT_SRC}/ld128/s_erfl.c" + ) + + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/ld128/s_nanl.c" + ) + endif() + endif() + endif() +endif() + +# Architecture-specific sources +if (${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/amd64/fenv.c" + ) + + list(APPEND OPENLIBM_ASM_SOURCE + "${PROJECT_SRC}/amd64/e_remainder.S" + "${PROJECT_SRC}/amd64/e_remainderf.S" + "${PROJECT_SRC}/amd64/e_remainderl.S" + "${PROJECT_SRC}/amd64/e_sqrt.S" + "${PROJECT_SRC}/amd64/e_sqrtf.S" + "${PROJECT_SRC}/amd64/e_sqrtl.S" + "${PROJECT_SRC}/amd64/s_llrint.S" + "${PROJECT_SRC}/amd64/s_llrintf.S" + "${PROJECT_SRC}/amd64/s_llrintl.S" + "${PROJECT_SRC}/amd64/s_logbl.S" + "${PROJECT_SRC}/amd64/s_lrint.S" + "${PROJECT_SRC}/amd64/s_lrintf.S" + "${PROJECT_SRC}/amd64/s_lrintl.S" + "${PROJECT_SRC}/amd64/s_remquo.S" + "${PROJECT_SRC}/amd64/s_remquof.S" + "${PROJECT_SRC}/amd64/s_remquol.S" + "${PROJECT_SRC}/amd64/s_rintl.S" + "${PROJECT_SRC}/amd64/s_scalbn.S" + "${PROJECT_SRC}/amd64/s_scalbnf.S" + "${PROJECT_SRC}/amd64/s_scalbnl.S" + "${PROJECT_SRC}/amd64/e_fmod.S" + "${PROJECT_SRC}/amd64/e_fmodf.S" + "${PROJECT_SRC}/amd64/e_fmodl.S" + ) + +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/aarch64/fenv.c" + ) + +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "arm") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/${OPENLIBM_ARCH_FOLDER}/fenv.c" + ) + +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/i387/fenv.c" + ) + + list(APPEND OPENLIBM_ASM_SOURCE + "${PROJECT_SRC}/i387/e_exp.S" + "${PROJECT_SRC}/i387/e_fmod.S" + "${PROJECT_SRC}/i387/e_log.S" + "${PROJECT_SRC}/i387/e_log10.S" + "${PROJECT_SRC}/i387/e_remainder.S" + "${PROJECT_SRC}/i387/e_sqrt.S" + "${PROJECT_SRC}/i387/s_ceil.S" + "${PROJECT_SRC}/i387/s_copysign.S" + "${PROJECT_SRC}/i387/s_floor.S" + "${PROJECT_SRC}/i387/s_llrint.S" + "${PROJECT_SRC}/i387/s_logb.S" + "${PROJECT_SRC}/i387/s_lrint.S" + "${PROJECT_SRC}/i387/s_remquo.S" + "${PROJECT_SRC}/i387/s_rint.S" + "${PROJECT_SRC}/i387/s_tan.S" + "${PROJECT_SRC}/i387/s_trunc.S" + + # float counterparts + "${PROJECT_SRC}/i387/e_log10f.S" + "${PROJECT_SRC}/i387/e_logf.S" + "${PROJECT_SRC}/i387/e_remainderf.S" + "${PROJECT_SRC}/i387/e_sqrtf.S" + "${PROJECT_SRC}/i387/s_ceilf.S" + "${PROJECT_SRC}/i387/s_copysignf.S" + "${PROJECT_SRC}/i387/s_floorf.S" + "${PROJECT_SRC}/i387/s_llrintf.S" + "${PROJECT_SRC}/i387/s_logbf.S" + "${PROJECT_SRC}/i387/s_lrintf.S" + "${PROJECT_SRC}/i387/s_remquof.S" + "${PROJECT_SRC}/i387/s_rintf.S" + "${PROJECT_SRC}/i387/s_truncf.S" + + # long double counterparts + "${PROJECT_SRC}/i387/e_remainderl.S" + "${PROJECT_SRC}/i387/e_sqrtl.S" + "${PROJECT_SRC}/i387/s_ceill.S" + "${PROJECT_SRC}/i387/s_copysignl.S" + "${PROJECT_SRC}/i387/s_floorl.S" + "${PROJECT_SRC}/i387/s_llrintl.S" + "${PROJECT_SRC}/i387/s_logbl.S" + "${PROJECT_SRC}/i387/s_lrintl.S" + "${PROJECT_SRC}/i387/s_remquol.S" + "${PROJECT_SRC}/i387/s_rintl.S" + "${PROJECT_SRC}/i387/s_truncl.S" + ) + + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(APPEND OPENLIBM_ASM_SOURCE + "${PROJECT_SRC}/i387/s_scalbn.S" + "${PROJECT_SRC}/i387/s_scalbnf.S" + "${PROJECT_SRC}/i387/s_scalbnl.S" + ) + endif() + +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/powerpc/fenv.c" + ) +elseif(${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") + list(APPEND OPENLIBM_C_SOURCE + "${PROJECT_SRC}/riscv64/fenv.c") +else() + message(FATAL_ERROR "${PROJECT_NAME} CMake build is not set up for ${OPENLIBM_ARCH_FOLDER}") +endif() + + +# Filter out C implementation from compilation list if a native implementation exists +foreach(FILE_TO_REMOVE ${OPENLIBM_ASM_SOURCE}) + # Get filename and strip out extension + cmake_path(GET FILE_TO_REMOVE FILENAME FILENAME_TO_REMOVE) + cmake_path(REMOVE_EXTENSION FILENAME_TO_REMOVE OUTPUT_VARIABLE FILENAME_TO_REMOVE) + message(DEBUG "Filename to remove: ${FILENAME_TO_REMOVE}") + + # Go through files and remove one with the same name + foreach(CUR_FILE ${OPENLIBM_C_SOURCE}) + cmake_path(GET CUR_FILE FILENAME CUR_FILENAME) + cmake_path(REMOVE_EXTENSION CUR_FILENAME OUTPUT_VARIABLE CUR_FILENAME) + + if(${CUR_FILENAME} STREQUAL ${FILENAME_TO_REMOVE}) + list(REMOVE_ITEM OPENLIBM_C_SOURCE ${CUR_FILE}) + message(DEBUG "Removed source file from compilation list: ${CUR_FILE}") + break() + endif() + endforeach() +endforeach() + + +# Add sources +target_sources("${PROJECT_NAME}" PRIVATE ${OPENLIBM_C_SOURCE} + ${OPENLIBM_ASM_SOURCE} +) + + +# Include directories +list(APPEND OPENLIBM_INCLUDE_DIRS + "${PROJECT_SRC}" + "${PROJECT_SRC}/include" + "${PROJECT_SRC}/${OPENLIBM_ARCH_FOLDER}" + "${PROJECT_SRC}/src" +) + +if(${OPENLIBM_ARCH_FOLDER} STREQUAL "i387" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "amd64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "powerpc") + list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld80") +else() + if(${OPENLIBM_ARCH_FOLDER} STREQUAL "aarch64" OR ${OPENLIBM_ARCH_FOLDER} STREQUAL "riscv64") + list(APPEND OPENLIBM_INCLUDE_DIRS "${PROJECT_SRC}/ld128") + endif() +endif() + +target_include_directories("${PROJECT_NAME}" PUBLIC ${OPENLIBM_INCLUDE_DIRS}) + +file(GLOB PUBLIC_HEADERS "*.h" "include/*.h" "${OPENLIBM_ARCH_FOLDER}/*.h" "src/*.h") +set_target_properties("${PROJECT_NAME}" PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") +install (TARGETS "${PROJECT_NAME}") + +# Can't use configure_file because openlibm.pc.in uses $var instead of CMake configure @var's +# Would rather string replace variables here instead of editing .pc.in, because editing .pc.in +# might build break autotools build. +file(READ "${PROJECT_SRC}/openlibm.pc.in" PC_FILE) +string(REPLACE "\${version}" ${CMAKE_PROJECT_VERSION} PC_FILE ${PC_FILE}) +string(PREPEND PC_FILE "prefix=${CMAKE_INSTALL_PREFIX} +includedir=\${prefix}/${CMAKE_INSTALL_INCLUDEDIR} +libdir=\${prefix}/${CMAKE_INSTALL_LIBDIR}\n +") +file(WRITE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" ${PC_FILE}) +install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") diff --git a/src/openlibm/LICENSE.md b/src/openlibm/LICENSE.md new file mode 100644 index 0000000..d76019e --- /dev/null +++ b/src/openlibm/LICENSE.md @@ -0,0 +1,115 @@ +## OpenLibm + +OpenLibm contains code that is covered by various licenses. + +The OpenLibm code derives from the FreeBSD msun and OpenBSD libm +implementations, which in turn derives from FDLIBM 5.3. As a result, it +has a number of fixes and updates that have accumulated over the years +in msun, and also optimized assembly versions of many functions. These +improvements are provided under the BSD and ISC licenses. The msun +library also includes work placed under the public domain, which is +noted in the individual files. Further work on making a standalone +OpenLibm library from msun, as part of the Julia project is covered +under the MIT license. The test files, test-double.c and test-float.c +are under the LGPL. + +## Parts copyrighted by the Julia project (MIT License) + +> Copyright (c) 2011-14 The Julia Project. +> https://github.com/JuliaMath/openlibm/graphs/contributors +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Parts copyrighted by Stephen L. Moshier (ISC License) + +> Copyright (c) 2008 Stephen L. Moshier +> +> Permission to use, copy, modify, and distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## FREEBSD MSUN (FreeBSD/2-clause BSD/Simplified BSD License) + +> Copyright 1992-2011 The FreeBSD Project. All rights reserved. +> +> Redistribution and use in source and binary forms, with or without +> modification, are permitted provided that the following conditions are +> met: +> +> 1. Redistributions of source code must retain the above copyright +> notice, this list of conditions and the following disclaimer. +> +> 2. Redistributions in binary form must reproduce the above copyright +> notice, this list of conditions and the following disclaimer in the +> documentation and/or other materials provided with the distribution. +> THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY +> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +> PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR +> CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +> EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +> PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +> PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +> LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +> NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +> SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +> +> The views and conclusions contained in the software and documentation +> are those of the authors and should not be interpreted as representing +> official policies, either expressed or implied, of the FreeBSD +> Project. + +## FDLIBM + +> Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +> +> Developed at SunPro, a Sun Microsystems, Inc. business. +> Permission to use, copy, modify, and distribute this +> software is freely granted, provided that this notice +> is preserved. + +## Tests + +> Copyright (C) 1997, 1999 Free Software Foundation, Inc. +> This file is part of the GNU C Library. +> Contributed by Andreas Jaeger , 1997. +> +> The GNU C Library is free software; you can redistribute it and/or +> modify it under the terms of the GNU Lesser General Public +> License as published by the Free Software Foundation; either +> version 2.1 of the License, or (at your option) any later version. +> +> The GNU C Library is distributed in the hope that it will be useful, +> but WITHOUT ANY WARRANTY; without even the implied warranty of +> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +> Lesser General Public License for more details. +> +> You should have received a copy of the GNU Lesser General Public +> License along with the GNU C Library; if not, write to the Free +> Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +> 02111-1307 USA. diff --git a/src/openlibm/Make.inc b/src/openlibm/Make.inc new file mode 100644 index 0000000..7914e82 --- /dev/null +++ b/src/openlibm/Make.inc @@ -0,0 +1,197 @@ +# -*- mode: makefile-gmake -*- +# vi:ft=make + +# Default build rule for any Makefile in this project: all +default: all + +OS := $(shell uname) +# Do not forget to bump SOMINOR when changing VERSION, +# and SOMAJOR when breaking ABI in a backward-incompatible way +VERSION = 0.8.0 +SOMAJOR = 4 +SOMINOR = 0 +DESTDIR = +prefix ?= /usr/local +bindir ?= $(prefix)/bin +libdir ?= $(prefix)/lib +includedir ?= $(prefix)/include + +ifeq ($(OS), FreeBSD) +pkgconfigdir ?= $(prefix)/libdata/pkgconfig +else +pkgconfigdir ?= $(libdir)/pkgconfig +endif + +# Build with Code Coverage +# Only test with Ubuntu + gcc + lcov, may not work for other platform. +# deps: https://github.com/linux-test-project/lcov +# You don't need to set this flag manually, `make coverage` will do it for you. +# Just Run: make clean && make coverage -j +CODE_COVERAGE ?= 0 + +ifneq (,$(findstring $(OS),Darwin FreeBSD OpenBSD)) +USEGCC ?= 0 +USECLANG ?= 1 +endif + +ifneq (,$(findstring CLANG,$(MSYSTEM))) +# In MSYS2 +USEGCC = 0 +USECLANG = 1 +endif + +ifeq ($(ARCH),wasm32) +USECLANG = 1 +USEGCC = 0 +TOOLPREFIX = llvm- +endif + +USEGCC ?= 1 +USECLANG ?= 0 +TOOLPREFIX ?= + +AR := $(TOOLPREFIX)ar + +ifeq ($(USECLANG),1) +USEGCC = 0 +CC = clang +CFLAGS_add += -fno-builtin -fno-strict-aliasing +endif + +ifeq ($(USEGCC),1) +CC := $(TOOLPREFIX)gcc +CFLAGS_add += -fno-gnu89-inline -fno-builtin +endif + +ARCH ?= $(shell $(CC) -dumpmachine | sed "s/\([^-]*\).*$$/\1/") + +ifeq ($(ARCH),mingw32) +$(error "the mingw32 compiler you are using fails the openblas testsuite. please see the Julia README.windows.md document for a replacement") +endif + +# OS-specific stuff +ifeq ($(ARCH),arm64) +override ARCH := aarch64 +endif +ifeq ($(findstring arm,$(ARCH)),arm) +override ARCH := arm +MARCH ?= armv7-a+fp +CFLAGS_add += -mhard-float +endif +ifeq ($(findstring powerpc,$(ARCH)),powerpc) +override ARCH := powerpc +endif +ifeq ($(findstring ppc,$(ARCH)),ppc) +override ARCH := powerpc +endif +ifeq ($(findstring s390,$(ARCH)),s390) +override ARCH := s390 +endif +ifneq ($(filter $(ARCH),i386 i486 i586 i686 i387 i487 i587 i687),) +override ARCH := i387 +MARCH ?= i686 +endif +ifeq ($(ARCH),x86_64) +override ARCH := amd64 +endif +ifeq ($(findstring mips,$(ARCH)),mips) +override ARCH := mips +endif +ifeq ($(findstring riscv64,$(ARCH)),riscv64) +override ARCH := riscv64 +endif +ifeq ($(findstring loongarch64,$(ARCH)),loongarch64) +override ARCH := loongarch64 +endif + +# If CFLAGS does not contain a -O optimization flag, default to -O3 +ifeq ($(findstring -O,$(CFLAGS)),) +CFLAGS_add += -O3 +endif + +ifneq (,$(findstring MINGW,$(OS))) +override OS=WINNT +endif + +#keep these if statements separate +ifeq ($(OS), WINNT) +SHLIB_EXT = dll +SONAME_FLAG = +shlibdir = $(bindir) +else +ifeq ($(OS), Darwin) +SHLIB_EXT = dylib +SONAME_FLAG = -install_name +else +SHLIB_EXT = so +SONAME_FLAG = -soname +endif +CFLAGS_add += -fPIC +shlibdir = $(libdir) +endif + +# Add `-march` to our CFLAGS if it's defined +ifneq ($(MARCH),) +CFLAGS_arch += -march=$(MARCH) +endif + +ifeq ($(ARCH),i387) +CFLAGS_arch += -m32 +SFLAGS_arch += -m32 +LDFLAGS_arch += -m32 +endif + +ifeq ($(ARCH),amd64) +CFLAGS_arch += -m64 +SFLAGS_arch += -m64 +LDFLAGS_arch += -m64 +endif + +ifeq ($(ARCH),wasm32) +CFLAGS_arch += -ffreestanding -nostdlib -nostdinc --target=wasm32-unknown-unknown +endif + +# Add our "arch"-related FLAGS in. We separate arch-related flags out so that +# we can conveniently get at them for targets that don't want the rest of +# *FLAGS_add, such as the testing Makefile targets +CFLAGS_add += $(CFLAGS_arch) +SFLAGS_add += $(SFLAGS_arch) +LDFLAGS_add += $(LDFLAGS_arch) + +CFLAGS_add += -std=c99 -Wall -I$(OPENLIBM_HOME) -I$(OPENLIBM_HOME)/include -I$(OPENLIBM_HOME)/$(ARCH) -I$(OPENLIBM_HOME)/src -DASSEMBLER -D__BSD_VISIBLE -Wno-implicit-function-declaration +ifneq ($(filter $(ARCH),i387 amd64 powerpc),) +CFLAGS_add += -I$(OPENLIBM_HOME)/ld80 +else +ifneq ($(filter $(ARCH),aarch64 riscv64),) +CFLAGS_add += -I$(OPENLIBM_HOME)/ld128 +endif +endif + +ifneq ($(filter $(ARCH),i387 amd64),) +# Determines whether `long double` is the same as `double` on this arch. +# linux x86_64, for instance, `long double` is 80 bits wide, whereas on macOS aarch64, +# `long double` is the same as `double`. +LONG_DOUBLE_NOT_DOUBLE := 1 +else ifeq ($(ARCH), aarch64) +ifeq ($(filter $(OS),Darwin WINNT),) +LONG_DOUBLE_NOT_DOUBLE := 1 +endif +endif + +ifeq ($(CODE_COVERAGE),1) +CFLAGS_add += -g -O0 --coverage +LDFLAGS_add += --coverage +endif # CODE_COVERAGE==1 + + +%.c.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) -c $< -o $@ + +%.S.o: %.S + $(CC) $(CPPFLAGS) $(SFLAGS) $(SFLAGS_add) $(filter -m% -B% -I% -D%,$(CFLAGS_add)) -c $< -o $@ + + +# Makefile debugging trick: +# call print-VARIABLE to see the runtime value of any variable +print-%: + @echo '$*=$($*)' diff --git a/src/openlibm/Makefile b/src/openlibm/Makefile new file mode 100644 index 0000000..0d7d918 --- /dev/null +++ b/src/openlibm/Makefile @@ -0,0 +1,140 @@ +OPENLIBM_HOME=$(abspath .) +include ./Make.inc + +SUBDIRS = src $(ARCH) bsdsrc +ifeq ($(LONG_DOUBLE_NOT_DOUBLE),1) +# Add ld80 directory on x86 and x64 +ifneq ($(filter $(ARCH),i387 amd64),) +SUBDIRS += ld80 +else +ifneq ($(filter $(ARCH),aarch64),) +SUBDIRS += ld128 +else +endif +endif +endif + +define INC_template +TEST=test +override CUR_SRCS = $(1)_SRCS +include $(1)/Make.files +SRCS += $$(addprefix $(1)/,$$($(1)_SRCS)) +endef + +DIR=test + +$(foreach dir,$(SUBDIRS),$(eval $(call INC_template,$(dir)))) + +DUPLICATE_NAMES = $(filter $(patsubst %.S,%,$($(ARCH)_SRCS)),$(patsubst %.c,%,$(src_SRCS))) +DUPLICATE_SRCS = $(addsuffix .c,$(DUPLICATE_NAMES)) + +OBJS = $(patsubst %.f,%.f.o,\ + $(patsubst %.S,%.S.o,\ + $(patsubst %.c,%.c.o,$(filter-out $(addprefix src/,$(DUPLICATE_SRCS)),$(SRCS))))) + +# If we're on windows, don't do versioned shared libraries. Also, generate an import library +# for the DLL. If we're on OSX, put the version number before the .dylib. Otherwise, +# put it after. +ifeq ($(OS), WINNT) +OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT) +LDFLAGS_add += -Wl,--out-implib,libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT).a +else +ifeq ($(OS), Darwin) +OLM_MAJOR_MINOR_SHLIB_EXT := $(SOMAJOR).$(SOMINOR).$(SHLIB_EXT) +OLM_MAJOR_SHLIB_EXT := $(SOMAJOR).$(SHLIB_EXT) +else +OLM_MAJOR_MINOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR).$(SOMINOR) +OLM_MAJOR_SHLIB_EXT := $(SHLIB_EXT).$(SOMAJOR) +endif +LDFLAGS_add += -Wl,$(SONAME_FLAG),libopenlibm.$(OLM_MAJOR_SHLIB_EXT) +endif + +.PHONY: all check test clean distclean \ + install install-static install-shared install-pkgconfig install-headers + + +OLM_LIBS := libopenlibm.a +ifneq ($(ARCH), wasm32) +OLM_LIBS += libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT) +endif + +all : $(OLM_LIBS) + +check test: test/test-double test/test-float + test/test-double + test/test-float + +libopenlibm.a: $(OBJS) + $(AR) -rcs libopenlibm.a $(OBJS) + +libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT): $(OBJS) + $(CC) -shared $(OBJS) $(LDFLAGS) $(LDFLAGS_add) -o $@ +ifneq ($(OS),WINNT) + ln -sf $@ libopenlibm.$(OLM_MAJOR_SHLIB_EXT) + ln -sf $@ libopenlibm.$(SHLIB_EXT) +endif + +test/test-double: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT) + $(MAKE) -C test test-double + +test/test-float: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT) + $(MAKE) -C test test-float + +COVERAGE_DIR:=cov-html +COVERAGE_FILE:=$(COVERAGE_DIR)/libopenlibm.info +# Gen cov report with: make clean && make coverage -j +coverage: clean-coverage + $(MAKE) test CODE_COVERAGE=1 + $(MAKE) gen-cov-report + +gen-cov-report: + -mkdir $(COVERAGE_DIR) + lcov -d amd64 -d bsdsrc -d ld80 -d src \ + --rc lcov_branch_coverage=1 --capture --output-file $(COVERAGE_FILE) + genhtml --legend --branch-coverage \ + --title "Openlibm commit `git rev-parse HEAD`" \ + --output-directory $(COVERAGE_DIR)/ \ + $(COVERAGE_FILE) + +# Zero coverage statistics and Delete report +clean-coverage: + -lcov -d amd64 -d bsdsrc -d ld80 -d src --zerocounters + rm -f ./*/*.gcda + rm -rf $(COVERAGE_DIR)/ + +clean: clean-coverage + rm -f aarch64/*.o amd64/*.o arm/*.o bsdsrc/*.o i387/*.o loongarch64/*.o ld80/*.o ld128/*.o src/*.o powerpc/*.o mips/*.o s390/*.o riscv64/*.o + rm -f libopenlibm.a libopenlibm.*$(SHLIB_EXT)* + rm -f ./*/*.gcno + $(MAKE) -C test clean + +openlibm.pc: openlibm.pc.in Make.inc Makefile + echo "version=${VERSION}" > openlibm.pc + echo "libdir=$(DESTDIR)$(libdir)" >> openlibm.pc + echo "includedir=$(DESTDIR)$(includedir)/openlibm" >> openlibm.pc + cat openlibm.pc.in >> openlibm.pc + +install-static: libopenlibm.a + mkdir -p $(DESTDIR)$(libdir) + cp -RpP -f libopenlibm.a $(DESTDIR)$(libdir)/ + +install-shared: libopenlibm.$(OLM_MAJOR_MINOR_SHLIB_EXT) + mkdir -p $(DESTDIR)$(shlibdir) +ifeq ($(OS), WINNT) + mkdir -p $(DESTDIR)$(libdir) + cp -RpP -f libopenlibm.*$(SHLIB_EXT) $(DESTDIR)$(shlibdir)/ + cp -RpP -f libopenlibm.*$(SHLIB_EXT).a $(DESTDIR)$(libdir)/ +else + cp -RpP -f libopenlibm.*$(SHLIB_EXT)* $(DESTDIR)$(shlibdir)/ +endif + +install-pkgconfig: openlibm.pc + mkdir -p $(DESTDIR)$(pkgconfigdir) + cp -RpP -f openlibm.pc $(DESTDIR)$(pkgconfigdir)/ + +install-headers: + mkdir -p $(DESTDIR)$(includedir)/openlibm + cp -RpP -f include/*.h $(DESTDIR)$(includedir)/openlibm + cp -RpP -f src/*.h $(DESTDIR)$(includedir)/openlibm + +install: install-static install-shared install-pkgconfig install-headers diff --git a/src/openlibm/README.md b/src/openlibm/README.md new file mode 100644 index 0000000..d543a3b --- /dev/null +++ b/src/openlibm/README.md @@ -0,0 +1,71 @@ +# OpenLibm + +[![codecov](https://codecov.io/gh/JuliaMath/openlibm/graph/badge.svg?token=eTAdN7d9cg)](https://codecov.io/gh/JuliaMath/openlibm) + +[OpenLibm](https://openlibm.org/) is an effort to have a high quality, portable, standalone +C mathematical library ([`libm`](http://en.wikipedia.org/wiki/libm)). +It can be used standalone in applications and programming language +implementations. + +The project was born out of a need to have a good `libm` for the +[Julia programming language](http://www.julialang.org) that worked +consistently across compilers and operating systems, and in 32-bit and +64-bit environments. + +## Platform support + +OpenLibm builds on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, and +DragonFly BSD. It builds with both GCC and clang. Although largely +tested and widely used on the x86 and x86-64 architectures, OpenLibm +also supports arm, aarch64, ppc64le, mips, wasm32, riscv, s390(x) and +loongarch64. + +## Build instructions + +### GNU Make + +1. Use GNU Make to build OpenLibm. This is `make` on most systems, but `gmake` on BSDs. +2. Use `make USEGCC=1` to build with GCC. This is the default on + Linux and Windows. +3. Use `make USECLANG=1` to build with clang. This is the default on OS X, FreeBSD, + and OpenBSD. +4. Use `make ARCH=wasm32` to build the wasm32 library with clang. +5. Architectures are auto-detected. Use `make ARCH=i386` to force a + build for i386. Other supported architectures are i486, i586, and + i686. GCC 4.8 is the minimum requirement for correct codegen on + older 32-bit architectures. + + +**Cross Build** +Take `riscv64` as example: +1. install `qemu-riscv64-static`, `gcc-riscv64-linux-gnu` +2. Cross build: +```sh +ARCH=riscv64 +TRIPLE=$ARCH-linux-gnu +make ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j +make -C test ARCH=$ARCH TOOLPREFIX=$TRIPLE- -j +``` + +3. Run test with qemu: +```sh +qemu-$ARCH-static -L . -L /usr/$TRIPLE/ test/test-float +qemu-$ARCH-static -L . -L /usr/$TRIPLE/ test/test-double +``` + + +### CMake + +1. Create build directory with `mkdir build` and navigate into it with `cd build`. +2. Run CMake to configure project and generate native build system with `cmake /path/to/openlibm/` +or generate project with build system of choice e.g. `cmake /path/to/openlib/ -G "MinGW Makefiles"`. +3. Build with the build system with `cmake --build .`. + +Default CMake configuration builds a shared library, this can easily be configured using +[BUILD_SHARED_LIBS](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) +configuration option. + + +## Acknowledgements + +PowerPC support for openlibm was graciously sponsored by IBM. diff --git a/src/openlibm/aarch64/Make.files b/src/openlibm/aarch64/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/aarch64/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/aarch64/fenv.c b/src/openlibm/aarch64/fenv.c new file mode 100644 index 0000000..8ed8557 --- /dev/null +++ b/src/openlibm/aarch64/fenv.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.3 2011/10/16 05:37:56 das Exp $ + */ + +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +/* + * Hopefully the system ID byte is immutable, so it's valid to use + * this as a default environment. + */ +const fenv_t __fe_dfl_env = {0}; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); diff --git a/src/openlibm/amd64/Make.files b/src/openlibm/amd64/Make.files new file mode 100644 index 0000000..662071c --- /dev/null +++ b/src/openlibm/amd64/Make.files @@ -0,0 +1,7 @@ +$(CUR_SRCS) = fenv.c e_remainder.S e_remainderf.S e_remainderl.S \ + e_sqrt.S e_sqrtf.S e_sqrtl.S \ + s_llrint.S s_llrintf.S s_llrintl.S \ + s_logbl.S s_lrint.S s_lrintf.S s_lrintl.S \ + s_remquo.S s_remquof.S s_remquol.S \ + s_rintl.S s_scalbn.S s_scalbnf.S s_scalbnl.S \ + e_fmod.S e_fmodf.S e_fmodl.S diff --git a/src/openlibm/amd64/bsd_asm.h b/src/openlibm/amd64/bsd_asm.h new file mode 100644 index 0000000..b9c815b --- /dev/null +++ b/src/openlibm/amd64/bsd_asm.h @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)DEFS.h 5.1 (Berkeley) 4/23/90 + * $FreeBSD: src/sys/amd64/include/asm.h,v 1.18 2007/08/22 04:26:07 jkoshy Exp $ + */ + +#ifndef _BSD_ASM_H_ +#define _BSD_ASM_H_ + +#ifdef __APPLE__ +#include "../i387/osx_asm.h" +#define CNAME(x) EXT(x) +#else +#include "bsd_cdefs.h" + +#ifdef PIC +#define PIC_PLT(x) x@PLT +#define PIC_GOT(x) x@GOTPCREL(%rip) +#else +#define PIC_PLT(x) x +#define PIC_GOT(x) x +#endif + +/* + * CNAME and HIDENAME manage the relationship between symbol names in C + * and the equivalent assembly language names. CNAME is given a name as + * it would be used in a C program. It expands to the equivalent assembly + * language name. HIDENAME is given an assembly-language name, and expands + * to a possibly-modified form that will be invisible to C programs. + */ +#define CNAME(csym) csym +#define HIDENAME(asmsym) .asmsym + +#define _START_ENTRY .p2align 4,0x90 + +#if defined(__ELF__) +#define _ENTRY(x) .text; _START_ENTRY; \ + .globl CNAME(x); .type CNAME(x),@function; CNAME(x): +#define END(x) .size x, . - x + +#elif defined(_WIN32) +#ifndef _MSC_VER +#define END(x) .end +#define _START_ENTRY_WIN .text; _START_ENTRY +#else +#define END(x) end +#define _START_ENTRY_WIN .code; _START_ENTRY +#endif +#define _ENTRY(x) _START_ENTRY_WIN; \ + .globl CNAME(x); .section .drectve; .ascii " -export:", #x; \ + .section .text; .def CNAME(x); .scl 2; .type 32; .endef; CNAME(x): +#endif + +#ifdef PROF +#define ALTENTRY(x) _ENTRY(x); \ + pushq %rbp; movq %rsp,%rbp; \ + call PIC_PLT(HIDENAME(mcount)); \ + popq %rbp; \ + jmp 9f +#define ENTRY(x) _ENTRY(x); \ + pushq %rbp; movq %rsp,%rbp; \ + call PIC_PLT(HIDENAME(mcount)); \ + popq %rbp; \ + 9: +#else +#define ALTENTRY(x) _ENTRY(x) +#define ENTRY(x) _ENTRY(x) +#endif + + +#define RCSID(x) .text; .asciz x + +#undef __FBSDID +#if !defined(lint) && !defined(STRIP_FBSDID) +#define __FBSDID(s) .ident s +#else +#define __FBSDID(s) /* nothing */ +#endif /* not lint and not STRIP_FBSDID */ + +#endif +#endif /* !_BSD_ASM_H_ */ diff --git a/src/openlibm/amd64/bsd_fpu.h b/src/openlibm/amd64/bsd_fpu.h new file mode 100644 index 0000000..513b345 --- /dev/null +++ b/src/openlibm/amd64/bsd_fpu.h @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)npx.h 5.3 (Berkeley) 1/18/91 + * $FreeBSD: src/sys/x86/include/fpu.h,v 1.1 2012/03/16 20:24:30 tijl Exp $ + */ + +/* + * Floating Point Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef _BSD_FPU_H_ +#define _BSD_FPU_H_ + +#include "types-compat.h" + +/* Environment information of floating point unit. */ +struct env87 { + int32_t en_cw; /* control word (16bits) */ + int32_t en_sw; /* status word (16bits) */ + int32_t en_tw; /* tag word (16bits) */ + int32_t en_fip; /* fp instruction pointer */ + uint16_t en_fcs; /* fp code segment selector */ + uint16_t en_opcode; /* opcode last executed (11 bits) */ + int32_t en_foo; /* fp operand offset */ + int32_t en_fos; /* fp operand segment selector */ +}; + +/* Contents of each x87 floating point accumulator. */ +struct fpacc87 { + uint8_t fp_bytes[10]; +}; + +/* Floating point context. (i386 fnsave/frstor) */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ + uint8_t sv_pad0[4]; /* saved status word (now unused) */ + /* + * Bogus padding for emulators. Emulators should use their own + * struct and arrange to store into this struct (ending here) + * before it is inspected for ptracing or for core dumps. Some + * emulators overwrite the whole struct. We have no good way of + * knowing how much padding to leave. Leave just enough for the + * GPL emulator's i387_union (176 bytes total). + */ + uint8_t sv_pad[64]; /* padding; used by emulators */ +}; + +/* Contents of each SSE extended accumulator. */ +struct xmmacc { + uint8_t xmm_bytes[16]; +}; + +/* Contents of the upper 16 bytes of each AVX extended accumulator. */ +struct ymmacc { + uint8_t ymm_bytes[16]; +}; + +/* Rename structs below depending on machine architecture. */ +#ifdef __i386__ +#define __envxmm32 envxmm +#else +#define __envxmm32 envxmm32 +#define __envxmm64 envxmm +#endif + +struct __envxmm32 { + uint16_t en_cw; /* control word (16bits) */ + uint16_t en_sw; /* status word (16bits) */ + uint16_t en_tw; /* tag word (16bits) */ + uint16_t en_opcode; /* opcode last executed (11 bits) */ + uint32_t en_fip; /* fp instruction pointer */ + uint16_t en_fcs; /* fp code segment selector */ + uint16_t en_pad0; /* padding */ + uint32_t en_foo; /* fp operand offset */ + uint16_t en_fos; /* fp operand segment selector */ + uint16_t en_pad1; /* padding */ + uint32_t en_mxcsr; /* SSE control/status register */ + uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +struct __envxmm64 { + uint16_t en_cw; /* control word (16bits) */ + uint16_t en_sw; /* status word (16bits) */ + uint8_t en_tw; /* tag word (8bits) */ + uint8_t en_zero; + uint16_t en_opcode; /* opcode last executed (11 bits ) */ + uint64_t en_rip; /* fp instruction pointer */ + uint64_t en_rdp; /* fp operand pointer */ + uint32_t en_mxcsr; /* SSE control/status register */ + uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +/* Floating point context. (i386 fxsave/fxrstor) */ +struct savexmm { + struct __envxmm32 sv_env; + struct { + struct fpacc87 fp_acc; + uint8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[8]; + uint8_t sv_pad[224]; +} __attribute__ ((aligned(16))); + +#ifdef __i386__ +union savefpu { + struct save87 sv_87; + struct savexmm sv_xmm; +}; +#else +/* Floating point context. (amd64 fxsave/fxrstor) */ +struct savefpu { + struct __envxmm64 sv_env; + struct { + struct fpacc87 fp_acc; + uint8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; +} __attribute__ ((aligned(16))); +#endif + +struct xstate_hdr { + uint64_t xstate_bv; + uint8_t xstate_rsrv0[16]; + uint8_t xstate_rsrv[40]; +}; + +struct savexmm_xstate { + struct xstate_hdr sx_hd; + struct ymmacc sx_ymm[16]; +}; + +struct savexmm_ymm { + struct __envxmm32 sv_env; + struct { + struct fpacc87 fp_acc; + int8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; + struct savexmm_xstate sv_xstate; +} __attribute__ ((aligned(16))); + +struct savefpu_xstate { + struct xstate_hdr sx_hd; + struct ymmacc sx_ymm[16]; +}; + +struct savefpu_ymm { + struct __envxmm64 sv_env; + struct { + struct fpacc87 fp_acc; + int8_t fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + uint8_t sv_pad[96]; + struct savefpu_xstate sv_xstate; +} __attribute__ ((aligned(64))); + +#undef __envxmm32 +#undef __envxmm64 + +/* + * The hardware default control word for i387's and later coprocessors is + * 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc + * because of the difference between memory and fpu register stack arguments. + * If its using an intermediate fpu register, it has 80/64 bits to work + * with. If it uses memory, it has 64/53 bits to work with. However, + * gcc is aware of this and goes to a fair bit of trouble to make the + * best use of it. + * + * This is mostly academic for AMD64, because the ABI prefers the use + * SSE2 based math. For FreeBSD/amd64, we go with the default settings. + */ +#define __INITIAL_FPUCW__ 0x037F +#define __INITIAL_FPUCW_I386__ 0x127F +#define __INITIAL_NPXCW__ __INITIAL_FPUCW_I386__ +#define __INITIAL_MXCSR__ 0x1F80 +#define __INITIAL_MXCSR_MASK__ 0xFFBF + +#endif /* !_BSD_FPU_H_ */ diff --git a/src/openlibm/amd64/bsd_ieeefp.h b/src/openlibm/amd64/bsd_ieeefp.h new file mode 100644 index 0000000..6103d50 --- /dev/null +++ b/src/openlibm/amd64/bsd_ieeefp.h @@ -0,0 +1,272 @@ +/*- + * Copyright (c) 2003 Peter Wemm. + * Copyright (c) 1990 Andrew Moore, Talke Studio + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#) ieeefp.h 1.0 (Berkeley) 9/23/93 + * $FreeBSD: src/sys/amd64/include/ieeefp.h,v 1.14 2005/04/12 23:12:00 jhb Exp $ + */ + +/* + * IEEE floating point type and constant definitions. + */ + +#ifndef _BSD_IEEEFP_H_ +#define _BSD_IEEEFP_H_ + +/* + * FP rounding modes + */ +typedef enum { + FP_RN=0, /* round to nearest */ + FP_RM, /* round down to minus infinity */ + FP_RP, /* round up to plus infinity */ + FP_RZ /* truncate */ +} fp_rnd_t; + +/* + * FP precision modes + */ +typedef enum { + FP_PS=0, /* 24 bit (single-precision) */ + FP_PRS, /* reserved */ + FP_PD, /* 53 bit (double-precision) */ + FP_PE /* 64 bit (extended-precision) */ +} fp_prec_t; + +#define fp_except_t int + +/* + * FP exception masks + */ +#define FP_X_INV 0x01 /* invalid operation */ +#define FP_X_DNML 0x02 /* denormal */ +#define FP_X_DZ 0x04 /* zero divide */ +#define FP_X_OFL 0x08 /* overflow */ +#define FP_X_UFL 0x10 /* underflow */ +#define FP_X_IMP 0x20 /* (im)precision */ +#define FP_X_STK 0x40 /* stack fault */ + +/* + * FP registers + */ +#define FP_MSKS_REG 0 /* exception masks */ +#define FP_PRC_REG 0 /* precision */ +#define FP_RND_REG 0 /* direction */ +#define FP_STKY_REG 1 /* sticky flags */ + +/* + * FP register bit field masks + */ +#define FP_MSKS_FLD 0x3f /* exception masks field */ +#define FP_PRC_FLD 0x300 /* precision control field */ +#define FP_RND_FLD 0xc00 /* round control field */ +#define FP_STKY_FLD 0x3f /* sticky flags field */ + +/* + * SSE mxcsr register bit field masks + */ +#define SSE_STKY_FLD 0x3f /* exception flags */ +#define SSE_DAZ_FLD 0x40 /* Denormals are zero */ +#define SSE_MSKS_FLD 0x1f80 /* exception masks field */ +#define SSE_RND_FLD 0x6000 /* rounding control */ +#define SSE_FZ_FLD 0x8000 /* flush to zero on underflow */ + +/* + * FP register bit field offsets + */ +#define FP_MSKS_OFF 0 /* exception masks offset */ +#define FP_PRC_OFF 8 /* precision control offset */ +#define FP_RND_OFF 10 /* round control offset */ +#define FP_STKY_OFF 0 /* sticky flags offset */ + +/* + * SSE mxcsr register bit field offsets + */ +#define SSE_STKY_OFF 0 /* exception flags offset */ +#define SSE_DAZ_OFF 6 /* DAZ exception mask offset */ +#define SSE_MSKS_OFF 7 /* other exception masks offset */ +#define SSE_RND_OFF 13 /* rounding control offset */ +#define SSE_FZ_OFF 15 /* flush to zero offset */ + +#if (defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE__)) || defined(_WIN32) \ + && !defined(__cplusplus) + +#define __fldenv(addr) __asm __volatile("fldenv %0" : : "m" (*(addr))) +#define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr))) +#define __fldcw(addr) __asm __volatile("fldcw %0" : : "m" (*(addr))) +#define __fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) +#define __fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) +#define __ldmxcsr(addr) __asm __volatile("ldmxcsr %0" : : "m" (*(addr))) +#define __stmxcsr(addr) __asm __volatile("stmxcsr %0" : "=m" (*(addr))) + +/* + * General notes about conflicting SSE vs FP status bits. + * This code assumes that software will not fiddle with the control + * bits of the SSE and x87 in such a way to get them out of sync and + * still expect this to work. Break this at your peril. + * Because I based this on the i386 port, the x87 state is used for + * the fpget*() functions, and is shadowed into the SSE state for + * the fpset*() functions. For dual source fpget*() functions, I + * merge the two together. I think. + */ + +/* Set rounding control */ +static __inline__ fp_rnd_t +__fpgetround(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((_cw & FP_RND_FLD) >> FP_RND_OFF); +} + +static __inline__ fp_rnd_t +__fpsetround(fp_rnd_t _m) +{ + unsigned short _cw; + unsigned int _mxcsr; + fp_rnd_t _p; + + __fnstcw(&_cw); + _p = (_cw & FP_RND_FLD) >> FP_RND_OFF; + _cw &= ~FP_RND_FLD; + _cw |= (_m << FP_RND_OFF) & FP_RND_FLD; + __fldcw(&_cw); + __stmxcsr(&_mxcsr); + _mxcsr &= ~SSE_RND_FLD; + _mxcsr |= (_m << SSE_RND_OFF) & SSE_RND_FLD; + __ldmxcsr(&_mxcsr); + return (_p); +} + +/* + * Set precision for fadd/fsub/fsqrt etc x87 instructions + * There is no equivalent SSE mode or control. + */ +static __inline__ fp_prec_t +__fpgetprec(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((_cw & FP_PRC_FLD) >> FP_PRC_OFF); +} + +static __inline__ fp_prec_t +__fpsetprec(fp_rnd_t _m) +{ + unsigned short _cw; + fp_prec_t _p; + + __fnstcw(&_cw); + _p = (_cw & FP_PRC_FLD) >> FP_PRC_OFF; + _cw &= ~FP_PRC_FLD; + _cw |= (_m << FP_PRC_OFF) & FP_PRC_FLD; + __fldcw(&_cw); + return (_p); +} + +/* + * Look at the exception masks + * Note that x87 masks are inverse of the fp*() functions + * API. ie: mask = 1 means disable for x87 and SSE, but + * for the fp*() api, mask = 1 means enabled. + */ +static __inline__ fp_except_t +__fpgetmask(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((~_cw) & FP_MSKS_FLD); +} + +static __inline__ fp_except_t +__fpsetmask(fp_except_t _m) +{ + unsigned short _cw; + unsigned int _mxcsr; + fp_except_t _p; + + __fnstcw(&_cw); + _p = (~_cw) & FP_MSKS_FLD; + _cw &= ~FP_MSKS_FLD; + _cw |= (~_m) & FP_MSKS_FLD; + __fldcw(&_cw); + __stmxcsr(&_mxcsr); + /* XXX should we clear non-ieee SSE_DAZ_FLD and SSE_FZ_FLD ? */ + _mxcsr &= ~SSE_MSKS_FLD; + _mxcsr |= ((~_m) << SSE_MSKS_OFF) & SSE_MSKS_FLD; + __ldmxcsr(&_mxcsr); + return (_p); +} + +/* See which sticky exceptions are pending, and reset them */ +static __inline__ fp_except_t +__fpgetsticky(void) +{ + unsigned short _sw; + unsigned int _mxcsr; + fp_except_t _ex; + + __fnstsw(&_sw); + _ex = _sw & FP_STKY_FLD; + __stmxcsr(&_mxcsr); + _ex |= _mxcsr & SSE_STKY_FLD; + return (_ex); +} + +#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE__ && !__cplusplus */ + +#if !defined(__IEEEFP_NOINLINES__) && !defined(__cplusplus) \ + && defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE__) + +#define fpgetround() __fpgetround() +#define fpsetround(_m) __fpsetround(_m) +#define fpgetprec() __fpgetprec() +#define fpsetprec(_m) __fpsetprec(_m) +#define fpgetmask() __fpgetmask() +#define fpsetmask(_m) __fpsetmask(_m) +#define fpgetsticky() __fpgetsticky() + +/* Suppress prototypes in the MI header. */ +#define _IEEEFP_INLINED_ 1 + +#else /* !__IEEEFP_NOINLINES__ && !__cplusplus && __GNUCLIKE_ASM + && __CC_SUPPORTS___INLINE__ */ + +/* Augment the userland declarations */ +__BEGIN_DECLS +extern fp_prec_t fpgetprec(void); +extern fp_prec_t fpsetprec(fp_prec_t); +__END_DECLS + +#endif /* !__IEEEFP_NOINLINES__ && !__cplusplus && __GNUCLIKE_ASM + && __CC_SUPPORTS___INLINE__ */ + +#endif /* !_BSD_IEEEFP_H_ */ diff --git a/src/openlibm/amd64/e_fmod.S b/src/openlibm/amd64/e_fmod.S new file mode 100644 index 0000000..d2c8ecd --- /dev/null +++ b/src/openlibm/amd64/e_fmod.S @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1993,94 Winning Strategies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Winning Strategies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on the i387 version written by: + * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. + */ + +#include + +ENTRY(fmod) + movsd %xmm0,-8(%rsp) + movsd %xmm1,-16(%rsp) + fldl -16(%rsp) + fldl -8(%rsp) +1: fprem + fstsw %ax + testw $0x400,%ax + jne 1b + fstpl -8(%rsp) + movsd -8(%rsp),%xmm0 + fstp %st + ret +END(fmod) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_fmodf.S b/src/openlibm/amd64/e_fmodf.S new file mode 100644 index 0000000..b045e73 --- /dev/null +++ b/src/openlibm/amd64/e_fmodf.S @@ -0,0 +1,26 @@ +/* + * Based on the i387 version written by J.T. Conklin . + * Public domain. + */ + +#include + +ENTRY(fmodf) + movss %xmm0,-4(%rsp) + movss %xmm1,-8(%rsp) + flds -8(%rsp) + flds -4(%rsp) +1: fprem + fstsw %ax + testw $0x400,%ax + jne 1b + fstps -4(%rsp) + movss -4(%rsp),%xmm0 + fstp %st + ret +END(fmodf) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_fmodl.S b/src/openlibm/amd64/e_fmodl.S new file mode 100644 index 0000000..cab539d --- /dev/null +++ b/src/openlibm/amd64/e_fmodl.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1993,94 Winning Strategies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Winning Strategies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based on the i387 version written by: + * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. + */ + +#include + +ENTRY(fmodl) + fldt 24(%rsp) + fldt 8(%rsp) +1: fprem + fstsw %ax + testw $0x400,%ax + jne 1b + fstp %st(1) + ret +END(fmodl) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_remainder.S b/src/openlibm/amd64/e_remainder.S new file mode 100644 index 0000000..a0b4900 --- /dev/null +++ b/src/openlibm/amd64/e_remainder.S @@ -0,0 +1,30 @@ +/* + * Based on the i387 version written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +//RCSID("from: FreeBSD: src/lib/msun/i387/e_remainder.S,v 1.8 2005/02/04 14:08:32 das Exp") +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainder.S,v 1.2 2011/01/07 16:13:12 kib Exp $") + +ENTRY(remainder) + movsd %xmm0,-8(%rsp) + movsd %xmm1,-16(%rsp) + fldl -16(%rsp) + fldl -8(%rsp) +1: fprem1 + fstsw %ax + testw $0x400,%ax + jne 1b + fstpl -8(%rsp) + movsd -8(%rsp),%xmm0 + fstp %st + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_remainderf.S b/src/openlibm/amd64/e_remainderf.S new file mode 100644 index 0000000..c63e97e --- /dev/null +++ b/src/openlibm/amd64/e_remainderf.S @@ -0,0 +1,29 @@ +/* + * Based on the i387 version written by J.T. Conklin . + * Public domain. + */ + +#include + +//RCSID("from: $NetBSD: e_remainderf.S,v 1.2 1995/05/08 23:49:47 jtc Exp $") +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainderf.S,v 1.2 2011/01/07 16:13:12 kib Exp $") + +ENTRY(remainderf) + movss %xmm0,-4(%rsp) + movss %xmm1,-8(%rsp) + flds -8(%rsp) + flds -4(%rsp) +1: fprem1 + fstsw %ax + testw $0x400,%ax + jne 1b + fstps -4(%rsp) + movss -4(%rsp),%xmm0 + fstp %st + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_remainderl.S b/src/openlibm/amd64/e_remainderl.S new file mode 100644 index 0000000..5f21b93 --- /dev/null +++ b/src/openlibm/amd64/e_remainderl.S @@ -0,0 +1,35 @@ +/* + * Based on the i387 version written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_remainderl.S,v 1.2 2011/01/07 16:13:12 kib Exp $") + +ENTRY(remainderl) +#ifndef _WIN64 + fldt 24(%rsp) + fldt 8(%rsp) +#else + fldt (%r8) + fldt (%rdx) +#endif +1: fprem1 + fstsw %ax + testw $0x400,%ax + jne 1b + fstp %st(1) +#ifdef _WIN64 + mov %rcx,%rax + movq $0x0,0x8(%rcx) + fstpt (%rcx) +#endif + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_sqrt.S b/src/openlibm/amd64/e_sqrt.S new file mode 100644 index 0000000..a44e41f --- /dev/null +++ b/src/openlibm/amd64/e_sqrt.S @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrt.S,v 1.4 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sqrt) + sqrtsd %xmm0, %xmm0 + ret +END(sqrt) + + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_sqrtf.S b/src/openlibm/amd64/e_sqrtf.S new file mode 100644 index 0000000..f74175b --- /dev/null +++ b/src/openlibm/amd64/e_sqrtf.S @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrtf.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sqrtf) + sqrtss %xmm0, %xmm0 + ret +END(sqrtf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/e_sqrtl.S b/src/openlibm/amd64/e_sqrtl.S new file mode 100644 index 0000000..6e7eac0 --- /dev/null +++ b/src/openlibm/amd64/e_sqrtl.S @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/e_sqrtl.S,v 1.2 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sqrtl) +#ifndef _WIN64 + fldt 8(%rsp) + fsqrt +#else + fldt (%rdx) + fsqrt + mov %rcx,%rax + movq $0x0,0x8(%rcx) + fstpt (%rcx) +#endif + ret + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/fenv.c b/src/openlibm/amd64/fenv.c new file mode 100644 index 0000000..ddf7dba --- /dev/null +++ b/src/openlibm/amd64/fenv.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/amd64/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $ + */ + +#include "bsd_fpu.h" +#include "math_private.h" + +#ifdef _WIN32 +#define __fenv_static OLM_DLLEXPORT +#endif +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +const fenv_t __fe_dfl_env = { + { 0xffff0000 | __INITIAL_FPUCW__, + 0xffff0000, + 0xffffffff, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } + }, + __INITIAL_MXCSR__ +}; + +extern inline OLM_DLLEXPORT int feclearexcept(int __excepts); +extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts); + +OLM_DLLEXPORT int +fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + fenv_t env; + + __fnstenv(&env.__x87); + env.__x87.__status &= ~excepts; + env.__x87.__status |= *flagp & excepts; + __fldenv(env.__x87); + + __stmxcsr(&env.__mxcsr); + env.__mxcsr &= ~excepts; + env.__mxcsr |= *flagp & excepts; + __ldmxcsr(env.__mxcsr); + + return (0); +} + +OLM_DLLEXPORT int +feraiseexcept(int excepts) +{ + fexcept_t ex = excepts; + + fesetexceptflag(&ex, excepts); + __fwait(); + return (0); +} + +extern inline OLM_DLLEXPORT int fetestexcept(int __excepts); +extern inline OLM_DLLEXPORT int fegetround(void); +extern inline OLM_DLLEXPORT int fesetround(int __round); + +OLM_DLLEXPORT int +fegetenv(fenv_t *envp) +{ + + __fnstenv(&envp->__x87); + __stmxcsr(&envp->__mxcsr); + /* + * fnstenv masks all exceptions, so we need to restore the + * control word to avoid this side effect. + */ + __fldcw(envp->__x87.__control); + return (0); +} + +OLM_DLLEXPORT int +feholdexcept(fenv_t *envp) +{ + uint32_t mxcsr; + + __stmxcsr(&mxcsr); + __fnstenv(&envp->__x87); + __fnclex(); + envp->__mxcsr = mxcsr; + mxcsr &= ~FE_ALL_EXCEPT; + mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + return (0); +} + +extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp); + +OLM_DLLEXPORT int +feupdateenv(const fenv_t *envp) +{ + uint32_t mxcsr; + uint16_t status; + + __fnstsw(&status); + __stmxcsr(&mxcsr); + fesetenv(envp); + feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); + return (0); +} + +int +feenableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + __stmxcsr(&mxcsr); + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control &= ~mask; + __fldcw(control); + mxcsr &= ~(mask << _SSE_EMASK_SHIFT); + __ldmxcsr(mxcsr); + return (omask); +} + +int +fedisableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + __stmxcsr(&mxcsr); + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control |= mask; + __fldcw(control); + mxcsr |= mask << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + return (omask); +} diff --git a/src/openlibm/amd64/s_llrint.S b/src/openlibm/amd64/s_llrint.S new file mode 100644 index 0000000..d7a0f74 --- /dev/null +++ b/src/openlibm/amd64/s_llrint.S @@ -0,0 +1,12 @@ +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrint.S,v 1.3 2011/02/04 21:54:06 kib Exp $") + +ENTRY(llrint) + cvtsd2si %xmm0, %rax + ret +END(llrint) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_llrintf.S b/src/openlibm/amd64/s_llrintf.S new file mode 100644 index 0000000..f5d39b3 --- /dev/null +++ b/src/openlibm/amd64/s_llrintf.S @@ -0,0 +1,12 @@ +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrintf.S,v 1.3 2011/02/04 21:54:06 kib Exp $") + +ENTRY(llrintf) + cvtss2si %xmm0, %rax + ret +END(llrintf) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_llrintl.S b/src/openlibm/amd64/s_llrintl.S new file mode 100644 index 0000000..12f2d33 --- /dev/null +++ b/src/openlibm/amd64/s_llrintl.S @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_llrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(llrintl) +#ifndef _WIN64 + fldt 8(%rsp) +#else + fldt (%rcx) +#endif + subq $8,%rsp + fistpll (%rsp) + popq %rax + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_logbl.S b/src/openlibm/amd64/s_logbl.S new file mode 100644 index 0000000..d22afeb --- /dev/null +++ b/src/openlibm/amd64/s_logbl.S @@ -0,0 +1,29 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_logbl.S,v 1.4 2011/01/07 16:13:12 kib Exp $") + +ENTRY(logbl) +#ifndef _WIN64 + fldt 8(%rsp) +#else + fldt (%rdx) +#endif + fxtract + fstp %st +#ifdef _WIN64 + mov %rcx,%rax + movq $0x0,0x8(%rcx) + fstpt (%rcx) +#endif + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_lrint.S b/src/openlibm/amd64/s_lrint.S new file mode 100644 index 0000000..9e1b917 --- /dev/null +++ b/src/openlibm/amd64/s_lrint.S @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(lrint) +#ifndef _WIN64 + cvtsd2si %xmm0, %rax +#else + cvtsd2si %xmm0, %eax +#endif + ret +END(lrint) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_lrintf.S b/src/openlibm/amd64/s_lrintf.S new file mode 100644 index 0000000..8e0b0c2 --- /dev/null +++ b/src/openlibm/amd64/s_lrintf.S @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(lrintf) +#ifndef _WIN64 + cvtss2si %xmm0, %rax +#else + cvtss2si %xmm0, %eax +#endif + ret +END(lrintf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_lrintl.S b/src/openlibm/amd64/s_lrintl.S new file mode 100644 index 0000000..288c0bb --- /dev/null +++ b/src/openlibm/amd64/s_lrintl.S @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_lrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(lrintl) +#ifndef _WIN64 + fldt 8(%rsp) +#else + fldt (%rcx) +#endif + subq $8,%rsp + fistpll (%rsp) + popq %rax + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_remquo.S b/src/openlibm/amd64/s_remquo.S new file mode 100644 index 0000000..8ef8425 --- /dev/null +++ b/src/openlibm/amd64/s_remquo.S @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquo.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquo) + movsd %xmm0,-8(%rsp) + movsd %xmm1,-16(%rsp) + fldl -16(%rsp) + fldl -8(%rsp) +1: fprem1 + fstsw %ax + btw $10,%ax + jc 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl -12(%rsp),%ecx + xorl -4(%rsp),%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ +#ifndef _WIN64 + movl %eax,(%rdi) +#else + movl %eax,(%r8) +#endif + fstpl -8(%rsp) + movsd -8(%rsp),%xmm0 + ret +END(remquo) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_remquof.S b/src/openlibm/amd64/s_remquof.S new file mode 100644 index 0000000..129a807 --- /dev/null +++ b/src/openlibm/amd64/s_remquof.S @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquof.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquof) + movss %xmm0,-4(%rsp) + movss %xmm1,-8(%rsp) + flds -8(%rsp) + flds -4(%rsp) +1: fprem1 + fstsw %ax + btw $10,%ax + jc 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl -8(%rsp),%ecx + xorl -4(%rsp),%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ +#ifndef _WIN64 + movl %eax,(%rdi) +#else + movl %eax,(%r8) +#endif + fstps -4(%rsp) + movss -4(%rsp),%xmm0 + ret +END(remquof) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_remquol.S b/src/openlibm/amd64/s_remquol.S new file mode 100644 index 0000000..344e1fb --- /dev/null +++ b/src/openlibm/amd64/s_remquol.S @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_remquol.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquol) +#ifndef _WIN64 + fldt 24(%rsp) + fldt 8(%rsp) +#else + fldt (%r8) + fldt (%rdx) + mov %rcx,%r8 +#endif +1: fprem1 + fstsw %ax + btw $10,%ax + jc 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl 32(%rsp),%ecx + xorl 16(%rsp),%ecx + movsx %cx,%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ +#ifndef _WIN64 + movl %eax,(%rdi) +#else + movl %eax,(%r9) + mov %r8,%rax + movq $0x0,0x8(%r8) + fstpt (%r8) +#endif + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_rintl.S b/src/openlibm/amd64/s_rintl.S new file mode 100644 index 0000000..479e836 --- /dev/null +++ b/src/openlibm/amd64/s_rintl.S @@ -0,0 +1,26 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +ENTRY(rintl) +#ifndef _WIN64 + fldt 8(%rsp) + frndint +#else + fldt (%rdx) + frndint + mov %rcx,%rax + movq $0x0,0x8(%rcx) + fstpt (%rcx) +#endif + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_scalbn.S b/src/openlibm/amd64/s_scalbn.S new file mode 100644 index 0000000..9d4152b --- /dev/null +++ b/src/openlibm/amd64/s_scalbn.S @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbn.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(scalbn) + movsd %xmm0,-8(%rsp) +#ifndef _WIN64 + movl %edi,-12(%rsp) +#else + movl %edx,-12(%rsp) +#endif + fildl -12(%rsp) + fldl -8(%rsp) + fscale + fstp %st(1) + fstpl -8(%rsp) + movsd -8(%rsp),%xmm0 + ret +#ifndef _WIN64 +END(scalbn) +.globl CNAME(ldexp) +#else +.globl CNAME(ldexp); .section .drectve; .ascii " -export:ldexp" +#endif +.set CNAME(ldexp),CNAME(scalbn) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_scalbnf.S b/src/openlibm/amd64/s_scalbnf.S new file mode 100644 index 0000000..75b4bb2 --- /dev/null +++ b/src/openlibm/amd64/s_scalbnf.S @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbnf.S,v 1.4 2011/01/07 16:13:12 kib Exp $") + +ENTRY(scalbnf) + movss %xmm0,-8(%rsp) +#ifndef _WIN64 + movl %edi,-4(%rsp) +#else + movl %edx,-4(%rsp) +#endif + fildl -4(%rsp) + flds -8(%rsp) + fscale + fstp %st(1) + fstps -8(%rsp) + movss -8(%rsp),%xmm0 + ret +#ifndef _WIN64 +END(scalbnf) +.globl CNAME(ldexpf) +#else +.globl CNAME(ldexpf); .section .drectve; .ascii " -export:ldexpf" +#endif +.set CNAME(ldexpf),CNAME(scalbnf) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/amd64/s_scalbnl.S b/src/openlibm/amd64/s_scalbnl.S new file mode 100644 index 0000000..fa0d2bf --- /dev/null +++ b/src/openlibm/amd64/s_scalbnl.S @@ -0,0 +1,40 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/amd64/s_scalbnl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") +/* //RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */ + +ENTRY(scalbnl) +#ifndef _WIN64 + movl %edi,-4(%rsp) + fildl -4(%rsp) + fldt 8(%rsp) +#else + mov %r8,%rax + movl %eax,-4(%rsp) + fildl -4(%rsp) + fldt (%rdx) +#endif + fscale + fstp %st(1) +#ifdef _WIN64 + mov %rcx,%rax + movq $0x0,0x8(%rcx) + fstpt (%rcx) +#endif + ret +#ifndef _WIN64 +END(scalbnl) +.globl CNAME(ldexpl) +#else +.globl CNAME(ldexpl); .section .drectve; .ascii " -export:ldexpl" +#endif +.set CNAME(ldexpl),CNAME(scalbnl) + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/arm/Make.files b/src/openlibm/arm/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/arm/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/arm/fenv.c b/src/openlibm/arm/fenv.c new file mode 100644 index 0000000..c9abf14 --- /dev/null +++ b/src/openlibm/arm/fenv.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/arm/fenv.c,v 1.3 2011/10/16 05:37:56 das Exp $ + */ + +#define __fenv_static +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +/* + * Hopefully the system ID byte is immutable, so it's valid to use + * this as a default environment. + */ +const fenv_t __fe_dfl_env = 0; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); diff --git a/src/openlibm/bsdsrc/Make.files b/src/openlibm/bsdsrc/Make.files new file mode 100644 index 0000000..6777fe2 --- /dev/null +++ b/src/openlibm/bsdsrc/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) += b_exp.c b_log.c b_tgamma.c diff --git a/src/openlibm/bsdsrc/b_exp.c b/src/openlibm/bsdsrc/b_exp.c new file mode 100644 index 0000000..6af8dd7 --- /dev/null +++ b/src/openlibm/bsdsrc/b_exp.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* @(#)exp.c 8.1 (Berkeley) 6/4/93 */ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_exp.c,v 1.9 2011/10/16 05:37:20 das Exp $"); + +#include + +/* EXP(X) + * RETURN THE EXPONENTIAL OF X + * DOUBLE PRECISION (IEEE 53 bits, VAX D FORMAT 56 BITS) + * CODED IN C BY K.C. NG, 1/19/85; + * REVISED BY K.C. NG on 2/6/85, 2/15/85, 3/7/85, 3/24/85, 4/16/85, 6/14/86. + * + * Required system supported functions: + * scalb(x,n) + * copysign(x,y) + * finite(x) + * + * Method: + * 1. Argument Reduction: given the input x, find r and integer k such + * that + * x = k*ln2 + r, |r| <= 0.5*ln2 . + * r will be represented as r := z+c for better accuracy. + * + * 2. Compute exp(r) by + * + * exp(r) = 1 + r + r*R1/(2-R1), + * where + * R1 = x - x^2*(p1+x^2*(p2+x^2*(p3+x^2*(p4+p5*x^2)))). + * + * 3. exp(x) = 2^k * exp(r) . + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF)= 0; + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * exp(x) returns the exponential of x nearly rounded. In a test run + * with 1,156,000 random arguments on a VAX, the maximum observed + * error was 0.869 ulps (units in the last place). + */ + +#include "mathimpl.h" + +static const double p1 = 0x1.555555555553ep-3; +static const double p2 = -0x1.6c16c16bebd93p-9; +static const double p3 = 0x1.1566aaf25de2cp-14; +static const double p4 = -0x1.bbd41c5d26bf1p-20; +static const double p5 = 0x1.6376972bea4d0p-25; +static const double ln2hi = 0x1.62e42fee00000p-1; +static const double ln2lo = 0x1.a39ef35793c76p-33; +static const double lnhuge = 0x1.6602b15b7ecf2p9; +static const double lntiny = -0x1.77af8ebeae354p9; +static const double invln2 = 0x1.71547652b82fep0; + +#if 0 +OLM_DLLEXPORT double exp(x) +double x; +{ + double z,hi,lo,c; + int k; + +#if !defined(vax)&&!defined(tahoe) + if(x!=x) return(x); /* x is NaN */ +#endif /* !defined(vax)&&!defined(tahoe) */ + if( x <= lnhuge ) { + if( x >= lntiny ) { + + /* argument reduction : x --> x - k*ln2 */ + + k=invln2*x+copysign(0.5,x); /* k=NINT(x/ln2) */ + + /* express x-k*ln2 as hi-lo and let x=hi-lo rounded */ + + hi=x-k*ln2hi; + x=hi-(lo=k*ln2lo); + + /* return 2^k*[1+x+x*c/(2+c)] */ + z=x*x; + c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5)))); + return scalb(1.0+(hi-(lo-(x*c)/(2.0-c))),k); + + } + /* end of x > lntiny */ + + else + /* exp(-big#) underflows to zero */ + if(finite(x)) return(scalb(1.0,-5000)); + + /* exp(-INF) is zero */ + else return(0.0); + } + /* end of x < lnhuge */ + + else + /* exp(INF) is INF, exp(+big#) overflows to INF */ + return( finite(x) ? scalb(1.0,5000) : x); +} +#endif + +/* returns exp(r = x + c) for |c| < |x| with no overlap. */ + +double __exp__D(x, c) +double x, c; +{ + double z,hi,lo; + int k; + + if (x != x) /* x is NaN */ + return(x); + if ( x <= lnhuge ) { + if ( x >= lntiny ) { + + /* argument reduction : x --> x - k*ln2 */ + z = invln2*x; + k = z + copysign(.5, x); + + /* express (x+c)-k*ln2 as hi-lo and let x=hi-lo rounded */ + + hi=(x-k*ln2hi); /* Exact. */ + x= hi - (lo = k*ln2lo-c); + /* return 2^k*[1+x+x*c/(2+c)] */ + z=x*x; + c= x - z*(p1+z*(p2+z*(p3+z*(p4+z*p5)))); + c = (x*c)/(2.0-c); + + return scalbn(1.+(hi-(lo - c)), k); + } + /* end of x > lntiny */ + + else + /* exp(-big#) underflows to zero */ + if(isfinite(x)) return(scalbn(1.0,-5000)); + + /* exp(-INF) is zero */ + else return(0.0); + } + /* end of x < lnhuge */ + + else + /* exp(INF) is INF, exp(+big#) overflows to INF */ + return( isfinite(x) ? scalbn(1.0,5000) : x); +} diff --git a/src/openlibm/bsdsrc/b_log.c b/src/openlibm/bsdsrc/b_log.c new file mode 100644 index 0000000..c20d290 --- /dev/null +++ b/src/openlibm/bsdsrc/b_log.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* @(#)log.c 8.2 (Berkeley) 11/30/93 */ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_log.c,v 1.9 2008/02/22 02:26:51 das Exp $"); + +#include + +#include "mathimpl.h" + +/* Table-driven natural logarithm. + * + * This code was derived, with minor modifications, from: + * Peter Tang, "Table-Driven Implementation of the + * Logarithm in IEEE Floating-Point arithmetic." ACM Trans. + * Math Software, vol 16. no 4, pp 378-400, Dec 1990). + * + * Calculates log(2^m*F*(1+f/F)), |f/j| <= 1/256, + * where F = j/128 for j an integer in [0, 128]. + * + * log(2^m) = log2_hi*m + log2_tail*m + * since m is an integer, the dominant term is exact. + * m has at most 10 digits (for subnormal numbers), + * and log2_hi has 11 trailing zero bits. + * + * log(F) = logF_hi[j] + logF_lo[j] is in tabular form in log_table.h + * logF_hi[] + 512 is exact. + * + * log(1+f/F) = 2*f/(2*F + f) + 1/12 * (2*f/(2*F + f))**3 + ... + * the leading term is calculated to extra precision in two + * parts, the larger of which adds exactly to the dominant + * m and F terms. + * There are two cases: + * 1. when m, j are non-zero (m | j), use absolute + * precision for the leading term. + * 2. when m = j = 0, |1-x| < 1/256, and log(x) ~= (x-1). + * In this case, use a relative precision of 24 bits. + * (This is done differently in the original paper) + * + * Special cases: + * 0 return signalling -Inf + * neg return signalling NaN + * +Inf return +Inf +*/ + +#define N 128 + +/* Table of log(Fj) = logF_head[j] + logF_tail[j], for Fj = 1+j/128. + * Used for generation of extend precision logarithms. + * The constant 35184372088832 is 2^45, so the divide is exact. + * It ensures correct reading of logF_head, even for inaccurate + * decimal-to-binary conversion routines. (Everybody gets the + * right answer for integers less than 2^53.) + * Values for log(F) were generated using error < 10^-57 absolute + * with the bc -l package. +*/ +static double A1 = .08333333333333178827; +static double A2 = .01250000000377174923; +static double A3 = .002232139987919447809; +static double A4 = .0004348877777076145742; + +static double logF_head[N+1] = { + 0., + .007782140442060381246, + .015504186535963526694, + .023167059281547608406, + .030771658666765233647, + .038318864302141264488, + .045809536031242714670, + .053244514518837604555, + .060624621816486978786, + .067950661908525944454, + .075223421237524235039, + .082443669210988446138, + .089612158689760690322, + .096729626458454731618, + .103796793681567578460, + .110814366340264314203, + .117783035656430001836, + .124703478501032805070, + .131576357788617315236, + .138402322859292326029, + .145182009844575077295, + .151916042025732167530, + .158605030176659056451, + .165249572895390883786, + .171850256926518341060, + .178407657472689606947, + .184922338493834104156, + .191394852999565046047, + .197825743329758552135, + .204215541428766300668, + .210564769107350002741, + .216873938300523150246, + .223143551314024080056, + .229374101064877322642, + .235566071312860003672, + .241719936886966024758, + .247836163904594286577, + .253915209980732470285, + .259957524436686071567, + .265963548496984003577, + .271933715484010463114, + .277868451003087102435, + .283768173130738432519, + .289633292582948342896, + .295464212893421063199, + .301261330578199704177, + .307025035294827830512, + .312755710004239517729, + .318453731118097493890, + .324119468654316733591, + .329753286372579168528, + .335355541920762334484, + .340926586970454081892, + .346466767346100823488, + .351976423156884266063, + .357455888922231679316, + .362905493689140712376, + .368325561158599157352, + .373716409793814818840, + .379078352934811846353, + .384411698910298582632, + .389716751140440464951, + .394993808240542421117, + .400243164127459749579, + .405465108107819105498, + .410659924985338875558, + .415827895143593195825, + .420969294644237379543, + .426084395310681429691, + .431173464818130014464, + .436236766774527495726, + .441274560805140936281, + .446287102628048160113, + .451274644139630254358, + .456237433481874177232, + .461175715122408291790, + .466089729924533457960, + .470979715219073113985, + .475845904869856894947, + .480688529345570714212, + .485507815781602403149, + .490303988045525329653, + .495077266798034543171, + .499827869556611403822, + .504556010751912253908, + .509261901790523552335, + .513945751101346104405, + .518607764208354637958, + .523248143765158602036, + .527867089620485785417, + .532464798869114019908, + .537041465897345915436, + .541597282432121573947, + .546132437597407260909, + .550647117952394182793, + .555141507540611200965, + .559615787935399566777, + .564070138285387656651, + .568504735352689749561, + .572919753562018740922, + .577315365035246941260, + .581691739635061821900, + .586049045003164792433, + .590387446602107957005, + .594707107746216934174, + .599008189645246602594, + .603290851438941899687, + .607555250224322662688, + .611801541106615331955, + .616029877215623855590, + .620240409751204424537, + .624433288012369303032, + .628608659422752680256, + .632766669570628437213, + .636907462236194987781, + .641031179420679109171, + .645137961373620782978, + .649227946625615004450, + .653301272011958644725, + .657358072709030238911, + .661398482245203922502, + .665422632544505177065, + .669430653942981734871, + .673422675212350441142, + .677398823590920073911, + .681359224807238206267, + .685304003098281100392, + .689233281238557538017, + .693147180560117703862 +}; + +static double logF_tail[N+1] = { + 0., + -.00000000000000543229938420049, + .00000000000000172745674997061, + -.00000000000001323017818229233, + -.00000000000001154527628289872, + -.00000000000000466529469958300, + .00000000000005148849572685810, + -.00000000000002532168943117445, + -.00000000000005213620639136504, + -.00000000000001819506003016881, + .00000000000006329065958724544, + .00000000000008614512936087814, + -.00000000000007355770219435028, + .00000000000009638067658552277, + .00000000000007598636597194141, + .00000000000002579999128306990, + -.00000000000004654729747598444, + -.00000000000007556920687451336, + .00000000000010195735223708472, + -.00000000000017319034406422306, + -.00000000000007718001336828098, + .00000000000010980754099855238, + -.00000000000002047235780046195, + -.00000000000008372091099235912, + .00000000000014088127937111135, + .00000000000012869017157588257, + .00000000000017788850778198106, + .00000000000006440856150696891, + .00000000000016132822667240822, + -.00000000000007540916511956188, + -.00000000000000036507188831790, + .00000000000009120937249914984, + .00000000000018567570959796010, + -.00000000000003149265065191483, + -.00000000000009309459495196889, + .00000000000017914338601329117, + -.00000000000001302979717330866, + .00000000000023097385217586939, + .00000000000023999540484211737, + .00000000000015393776174455408, + -.00000000000036870428315837678, + .00000000000036920375082080089, + -.00000000000009383417223663699, + .00000000000009433398189512690, + .00000000000041481318704258568, + -.00000000000003792316480209314, + .00000000000008403156304792424, + -.00000000000034262934348285429, + .00000000000043712191957429145, + -.00000000000010475750058776541, + -.00000000000011118671389559323, + .00000000000037549577257259853, + .00000000000013912841212197565, + .00000000000010775743037572640, + .00000000000029391859187648000, + -.00000000000042790509060060774, + .00000000000022774076114039555, + .00000000000010849569622967912, + -.00000000000023073801945705758, + .00000000000015761203773969435, + .00000000000003345710269544082, + -.00000000000041525158063436123, + .00000000000032655698896907146, + -.00000000000044704265010452446, + .00000000000034527647952039772, + -.00000000000007048962392109746, + .00000000000011776978751369214, + -.00000000000010774341461609578, + .00000000000021863343293215910, + .00000000000024132639491333131, + .00000000000039057462209830700, + -.00000000000026570679203560751, + .00000000000037135141919592021, + -.00000000000017166921336082431, + -.00000000000028658285157914353, + -.00000000000023812542263446809, + .00000000000006576659768580062, + -.00000000000028210143846181267, + .00000000000010701931762114254, + .00000000000018119346366441110, + .00000000000009840465278232627, + -.00000000000033149150282752542, + -.00000000000018302857356041668, + -.00000000000016207400156744949, + .00000000000048303314949553201, + -.00000000000071560553172382115, + .00000000000088821239518571855, + -.00000000000030900580513238244, + -.00000000000061076551972851496, + .00000000000035659969663347830, + .00000000000035782396591276383, + -.00000000000046226087001544578, + .00000000000062279762917225156, + .00000000000072838947272065741, + .00000000000026809646615211673, + -.00000000000010960825046059278, + .00000000000002311949383800537, + -.00000000000058469058005299247, + -.00000000000002103748251144494, + -.00000000000023323182945587408, + -.00000000000042333694288141916, + -.00000000000043933937969737844, + .00000000000041341647073835565, + .00000000000006841763641591466, + .00000000000047585534004430641, + .00000000000083679678674757695, + -.00000000000085763734646658640, + .00000000000021913281229340092, + -.00000000000062242842536431148, + -.00000000000010983594325438430, + .00000000000065310431377633651, + -.00000000000047580199021710769, + -.00000000000037854251265457040, + .00000000000040939233218678664, + .00000000000087424383914858291, + .00000000000025218188456842882, + -.00000000000003608131360422557, + -.00000000000050518555924280902, + .00000000000078699403323355317, + -.00000000000067020876961949060, + .00000000000016108575753932458, + .00000000000058527188436251509, + -.00000000000035246757297904791, + -.00000000000018372084495629058, + .00000000000088606689813494916, + .00000000000066486268071468700, + .00000000000063831615170646519, + .00000000000025144230728376072, + -.00000000000017239444525614834 +}; + +#if 0 +OLM_DLLEXPORT double +#ifdef _ANSI_SOURCE +log(double x) +#else +log(x) double x; +#endif +{ + int m, j; + double F, f, g, q, u, u2, v, zero = 0.0, one = 1.0; + volatile double u1; + + /* Catch special cases */ + if (x <= 0) + if (x == zero) /* log(0) = -Inf */ + return (-one/zero); + else /* log(neg) = NaN */ + return (zero/zero); + else if (!finite(x)) + return (x+x); /* x = NaN, Inf */ + + /* Argument reduction: 1 <= g < 2; x/2^m = g; */ + /* y = F*(1 + f/F) for |f| <= 2^-8 */ + + m = logb(x); + g = ldexp(x, -m); + if (m == -1022) { + j = logb(g), m += j; + g = ldexp(g, -j); + } + j = N*(g-1) + .5; + F = (1.0/N) * j + 1; /* F*128 is an integer in [128, 512] */ + f = g - F; + + /* Approximate expansion for log(1+f/F) ~= u + q */ + g = 1/(2*F+f); + u = 2*f*g; + v = u*u; + q = u*v*(A1 + v*(A2 + v*(A3 + v*A4))); + + /* case 1: u1 = u rounded to 2^-43 absolute. Since u < 2^-8, + * u1 has at most 35 bits, and F*u1 is exact, as F has < 8 bits. + * It also adds exactly to |m*log2_hi + log_F_head[j] | < 750 + */ + if (m | j) + u1 = u + 513, u1 -= 513; + + /* case 2: |1-x| < 1/256. The m- and j- dependent terms are zero; + * u1 = u to 24 bits. + */ + else + u1 = u, TRUNC(u1); + u2 = (2.0*(f - F*u1) - u1*f) * g; + /* u1 + u2 = 2f/(2F+f) to extra precision. */ + + /* log(x) = log(2^m*F*(1+f/F)) = */ + /* (m*log2_hi+logF_head[j]+u1) + (m*log2_lo+logF_tail[j]+q); */ + /* (exact) + (tiny) */ + + u1 += m*logF_head[N] + logF_head[j]; /* exact */ + u2 = (u2 + logF_tail[j]) + q; /* tiny */ + u2 += logF_tail[N]*m; + return (u1 + u2); +} +#endif + +/* + * Extra precision variant, returning struct {double a, b;}; + * log(x) = a+b to 63 bits, with a rounded to 26 bits. + */ +struct Double +#ifdef _ANSI_SOURCE +__log__D(double x) +#else +__log__D(x) double x; +#endif +{ + int m, j; + double F, f, g, q, u, v, u2; + volatile double u1; + struct Double r; + + /* Argument reduction: 1 <= g < 2; x/2^m = g; */ + /* y = F*(1 + f/F) for |f| <= 2^-8 */ + + m = logb(x); + g = ldexp(x, -m); + if (m == -1022) { + j = logb(g), m += j; + g = ldexp(g, -j); + } + j = N*(g-1) + .5; + F = (1.0/N) * j + 1; + f = g - F; + + g = 1/(2*F+f); + u = 2*f*g; + v = u*u; + q = u*v*(A1 + v*(A2 + v*(A3 + v*A4))); + if (m | j) + u1 = u + 513, u1 -= 513; + else + u1 = u, TRUNC(u1); + u2 = (2.0*(f - F*u1) - u1*f) * g; + + u1 += m*logF_head[N] + logF_head[j]; + + u2 += logF_tail[j]; u2 += q; + u2 += logF_tail[N]*m; + r.a = u1 + u2; /* Only difference is here */ + TRUNC(r.a); + r.b = (u1 - r.a) + u2; + return (r); +} diff --git a/src/openlibm/bsdsrc/b_tgamma.c b/src/openlibm/bsdsrc/b_tgamma.c new file mode 100644 index 0000000..f3871de --- /dev/null +++ b/src/openlibm/bsdsrc/b_tgamma.c @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* @(#)gamma.c 8.1 (Berkeley) 6/4/93 */ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/bsdsrc/b_tgamma.c,v 1.10 2008/02/22 02:26:51 das Exp $"); + +/* + * This code by P. McIlroy, Oct 1992; + * + * The financial support of UUNET Communications Services is greatfully + * acknowledged. + */ + +#include +#include + +#include "mathimpl.h" + +/* METHOD: + * x < 0: Use reflection formula, G(x) = pi/(sin(pi*x)*x*G(x)) + * At negative integers, return NaN and raise invalid. + * + * x < 6.5: + * Use argument reduction G(x+1) = xG(x) to reach the + * range [1.066124,2.066124]. Use a rational + * approximation centered at the minimum (x0+1) to + * ensure monotonicity. + * + * x >= 6.5: Use the asymptotic approximation (Stirling's formula) + * adjusted for equal-ripples: + * + * log(G(x)) ~= (x-.5)*(log(x)-1) + .5(log(2*pi)-1) + 1/x*P(1/(x*x)) + * + * Keep extra precision in multiplying (x-.5)(log(x)-1), to + * avoid premature round-off. + * + * Special values: + * -Inf: return NaN and raise invalid; + * negative integer: return NaN and raise invalid; + * other x ~< 177.79: return +-0 and raise underflow; + * +-0: return +-Inf and raise divide-by-zero; + * finite x ~> 171.63: return +Inf and raise overflow; + * +Inf: return +Inf; + * NaN: return NaN. + * + * Accuracy: tgamma(x) is accurate to within + * x > 0: error provably < 0.9ulp. + * Maximum observed in 1,000,000 trials was .87ulp. + * x < 0: + * Maximum observed error < 4ulp in 1,000,000 trials. + */ + +static double neg_gam(double); +static double small_gam(double); +static double smaller_gam(double); +static struct Double large_gam(double); +static struct Double ratfun_gam(double, double); + +/* + * Rational approximation, A0 + x*x*P(x)/Q(x), on the interval + * [1.066.., 2.066..] accurate to 4.25e-19. + */ +#define LEFT -.3955078125 /* left boundary for rat. approx */ +#define x0 .461632144968362356785 /* xmin - 1 */ + +#define a0_hi 0.88560319441088874992 +#define a0_lo -.00000000000000004996427036469019695 +#define P0 6.21389571821820863029017800727e-01 +#define P1 2.65757198651533466104979197553e-01 +#define P2 5.53859446429917461063308081748e-03 +#define P3 1.38456698304096573887145282811e-03 +#define P4 2.40659950032711365819348969808e-03 +#define Q0 1.45019531250000000000000000000e+00 +#define Q1 1.06258521948016171343454061571e+00 +#define Q2 -2.07474561943859936441469926649e-01 +#define Q3 -1.46734131782005422506287573015e-01 +#define Q4 3.07878176156175520361557573779e-02 +#define Q5 5.12449347980666221336054633184e-03 +#define Q6 -1.76012741431666995019222898833e-03 +#define Q7 9.35021023573788935372153030556e-05 +#define Q8 6.13275507472443958924745652239e-06 +/* + * Constants for large x approximation (x in [6, Inf]) + * (Accurate to 2.8*10^-19 absolute) + */ +#define lns2pi_hi 0.418945312500000 +#define lns2pi_lo -.000006779295327258219670263595 +#define Pa0 8.33333333333333148296162562474e-02 +#define Pa1 -2.77777777774548123579378966497e-03 +#define Pa2 7.93650778754435631476282786423e-04 +#define Pa3 -5.95235082566672847950717262222e-04 +#define Pa4 8.41428560346653702135821806252e-04 +#define Pa5 -1.89773526463879200348872089421e-03 +#define Pa6 5.69394463439411649408050664078e-03 +#define Pa7 -1.44705562421428915453880392761e-02 + +static const double zero = 0., one = 1.0, tiny = 1e-300; + +OLM_DLLEXPORT double +tgamma(x) + double x; +{ + struct Double u; + + if (isgreaterequal(x, 6)) { + if(x > 171.63) + return (x / zero); + u = large_gam(x); + return(__exp__D(u.a, u.b)); + } else if (isgreaterequal(x, 1.0 + LEFT + x0)) + return (small_gam(x)); + else if (isgreater(x, 1.e-17)) + return (smaller_gam(x)); + else if (isgreater(x, -1.e-17)) { + if (x != 0.0) + u.a = one - tiny; /* raise inexact */ + return (one/x); + } else if (!isfinite(x)) + return (x - x); /* x is NaN or -Inf */ + else + return (neg_gam(x)); +} +/* + * Accurate to max(ulp(1/128) absolute, 2^-66 relative) error. + */ +static struct Double +large_gam(x) + double x; +{ + double z, p; + struct Double t, u, v; + + z = one/(x*x); + p = Pa0+z*(Pa1+z*(Pa2+z*(Pa3+z*(Pa4+z*(Pa5+z*(Pa6+z*Pa7)))))); + p = p/x; + + u = __log__D(x); + u.a -= one; + v.a = (x -= .5); + TRUNC(v.a); + v.b = x - v.a; + t.a = v.a*u.a; /* t = (x-.5)*(log(x)-1) */ + t.b = v.b*u.a + x*u.b; + /* return t.a + t.b + lns2pi_hi + lns2pi_lo + p */ + t.b += lns2pi_lo; t.b += p; + u.a = lns2pi_hi + t.b; u.a += t.a; + u.b = t.a - u.a; + u.b += lns2pi_hi; u.b += t.b; + return (u); +} +/* + * Good to < 1 ulp. (provably .90 ulp; .87 ulp on 1,000,000 runs.) + * It also has correct monotonicity. + */ +static double +small_gam(x) + double x; +{ + double y, ym1, t; + struct Double yy, r; + y = x - one; + ym1 = y - one; + if (y <= 1.0 + (LEFT + x0)) { + yy = ratfun_gam(y - x0, 0); + return (yy.a + yy.b); + } + r.a = y; + TRUNC(r.a); + yy.a = r.a - one; + y = ym1; + yy.b = r.b = y - yy.a; + /* Argument reduction: G(x+1) = x*G(x) */ + for (ym1 = y-one; ym1 > LEFT + x0; y = ym1--, yy.a--) { + t = r.a*yy.a; + r.b = r.a*yy.b + y*r.b; + r.a = t; + TRUNC(r.a); + r.b += (t - r.a); + } + /* Return r*tgamma(y). */ + yy = ratfun_gam(y - x0, 0); + y = r.b*(yy.a + yy.b) + r.a*yy.b; + y += yy.a*r.a; + return (y); +} +/* + * Good on (0, 1+x0+LEFT]. Accurate to 1ulp. + */ +static double +smaller_gam(x) + double x; +{ + double t, d; + struct Double r, xx; + if (x < x0 + LEFT) { + t = x, TRUNC(t); + d = (t+x)*(x-t); + t *= t; + xx.a = (t + x), TRUNC(xx.a); + xx.b = x - xx.a; xx.b += t; xx.b += d; + t = (one-x0); t += x; + d = (one-x0); d -= t; d += x; + x = xx.a + xx.b; + } else { + xx.a = x, TRUNC(xx.a); + xx.b = x - xx.a; + t = x - x0; + d = (-x0 -t); d += x; + } + r = ratfun_gam(t, d); + d = r.a/x, TRUNC(d); + r.a -= d*xx.a; r.a -= d*xx.b; r.a += r.b; + return (d + r.a/x); +} +/* + * returns (z+c)^2 * P(z)/Q(z) + a0 + */ +static struct Double +ratfun_gam(z, c) + double z, c; +{ + double p, q; + struct Double r, t; + + q = Q0 +z*(Q1+z*(Q2+z*(Q3+z*(Q4+z*(Q5+z*(Q6+z*(Q7+z*Q8))))))); + p = P0 + z*(P1 + z*(P2 + z*(P3 + z*P4))); + + /* return r.a + r.b = a0 + (z+c)^2*p/q, with r.a truncated to 26 bits. */ + p = p/q; + t.a = z, TRUNC(t.a); /* t ~= z + c */ + t.b = (z - t.a) + c; + t.b *= (t.a + z); + q = (t.a *= t.a); /* t = (z+c)^2 */ + TRUNC(t.a); + t.b += (q - t.a); + r.a = p, TRUNC(r.a); /* r = P/Q */ + r.b = p - r.a; + t.b = t.b*p + t.a*r.b + a0_lo; + t.a *= r.a; /* t = (z+c)^2*(P/Q) */ + r.a = t.a + a0_hi, TRUNC(r.a); + r.b = ((a0_hi-r.a) + t.a) + t.b; + return (r); /* r = a0 + t */ +} + +static double +neg_gam(x) + double x; +{ + int sgn = 1; + struct Double lg, lsine; + double y, z; + + y = ceil(x); + if (y == x) /* Negative integer. */ + return ((x - x) / zero); + z = y - x; + if (z > 0.5) + z = one - z; + y = 0.5 * y; + if (y == ceil(y)) + sgn = -1; + if (z < .25) + z = sin(M_PI*z); + else + z = cos(M_PI*(0.5-z)); + /* Special case: G(1-x) = Inf; G(x) may be nonzero. */ + if (x < -170) { + if (x < -190) + return ((double)sgn*tiny*tiny); + y = one - x; /* exact: 128 < |x| < 255 */ + lg = large_gam(y); + lsine = __log__D(M_PI/z); /* = TRUNC(log(u)) + small */ + lg.a -= lsine.a; /* exact (opposite signs) */ + lg.b -= lsine.b; + y = -(lg.a + lg.b); + z = (y + lg.a) + lg.b; + y = __exp__D(y, z); + if (sgn < 0) y = -y; + return (y); + } + y = one-x; + if (one-y == x) + y = tgamma(y); + else /* 1-x is inexact */ + y = -x*tgamma(-x); + if (sgn < 0) y = -y; + return (M_PI / (y*z)); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(tgamma, tgammal); +#endif diff --git a/src/openlibm/bsdsrc/mathimpl.h b/src/openlibm/bsdsrc/mathimpl.h new file mode 100644 index 0000000..983c4eb --- /dev/null +++ b/src/openlibm/bsdsrc/mathimpl.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mathimpl.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/msun/bsdsrc/mathimpl.h,v 1.7 2005/11/18 05:03:12 bde Exp $ + */ + +#ifndef _MATHIMPL_H_ +#define _MATHIMPL_H_ + +#include "cdefs-compat.h" +#include "math_private.h" + +/* + * TRUNC() is a macro that sets the trailing 27 bits in the mantissa of an + * IEEE double variable to zero. It must be expression-like for syntactic + * reasons, and we implement this expression using an inline function + * instead of a pure macro to avoid depending on the gcc feature of + * statement-expressions. + */ +#define TRUNC(d) (_b_trunc(&(d))) + +static __inline void +_b_trunc(volatile double *_dp) +{ + //VBS + //u_int32_t _lw; + u_int32_t _lw; + + GET_LOW_WORD(_lw, *_dp); + SET_LOW_WORD(*_dp, _lw & 0xf8000000); +} + +struct Double { + double a; + double b; +}; + +/* + * Functions internal to the math package, yet not static. + */ +double __exp__D(double, double); +struct Double __log__D(double); + +#endif /* !_MATHIMPL_H_ */ diff --git a/src/openlibm/docs/CNAME b/src/openlibm/docs/CNAME new file mode 100644 index 0000000..60f23f5 --- /dev/null +++ b/src/openlibm/docs/CNAME @@ -0,0 +1 @@ +openlibm.org \ No newline at end of file diff --git a/src/openlibm/docs/images/arrow-down.png b/src/openlibm/docs/images/arrow-down.png new file mode 100644 index 0000000..5c55c6a Binary files /dev/null and b/src/openlibm/docs/images/arrow-down.png differ diff --git a/src/openlibm/docs/images/octocat-small.png b/src/openlibm/docs/images/octocat-small.png new file mode 100644 index 0000000..57c1e44 Binary files /dev/null and b/src/openlibm/docs/images/octocat-small.png differ diff --git a/src/openlibm/docs/index.html b/src/openlibm/docs/index.html new file mode 100644 index 0000000..5c84d7e --- /dev/null +++ b/src/openlibm/docs/index.html @@ -0,0 +1,94 @@ + + + + + + OpenLibm + + + + + + + +
+
+

OpenLibm

+

A high quality system independent, portable, open source libm implementation

+ + + +

This project is maintained by the Julia Project

+ + +
+
+

+OpenLibm

+ +

OpenLibm is an effort to have a high quality, portable, standalone +C mathematical library (libm). +It can be used standalone in applications and programming language +implementations.

+ +

The project was born out of a need to have a good libm for the +Julia programming langage that worked +consistently across compilers and operating systems, and in 32-bit and +64-bit environments.

+ +

+History

+ +

The OpenLibm code derives from the FreeBSD +msun and OpenBSD +libm +implementations, which in turn derive from FDLIBM +5.3. Over and above that, OpenLibm itself has received a number of patches to make it platform independent and portable.

+ +

+Platform support

+ +

OpenLibm builds on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, and +DragonFly BSD. It builds with both GCC and clang. OpenLibm supports x86, amd64, +arm, aarch64, riscv64, ppc64le, mips, wasm32, s390(x), and loongarch64. + +

+Other relevant projects

+ +
    +
  1. MUSL The libm library in the musl-libc project
  2. +
  3. FDLIBM: Freely Distributable Math Library
  4. +
  5. FreeBSD msun: FreeBSD's math library
  6. +
  7. CRlibm: Correctly Rounded mathematical library
  8. +
  9. MUSL
  10. +
  11. CORE-MATH Project
  12. +
+ +

+Acknowledgements

+ +

PowerPC support for OpenLibm was graciously sponsored by IBM. + + +

+ +
+ + + + + + diff --git a/src/openlibm/docs/javascripts/scale.fix.js b/src/openlibm/docs/javascripts/scale.fix.js new file mode 100644 index 0000000..08716c0 --- /dev/null +++ b/src/openlibm/docs/javascripts/scale.fix.js @@ -0,0 +1,20 @@ +fixScale = function(doc) { + + var addEvent = 'addEventListener', + type = 'gesturestart', + qsa = 'querySelectorAll', + scales = [1, 1], + meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; + + function fix() { + meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; + doc.removeEventListener(type, fix, true); + } + + if ((meta = meta[meta.length - 1]) && addEvent in doc) { + fix(); + scales = [.25, 1.6]; + doc[addEvent](type, fix, true); + } + +}; \ No newline at end of file diff --git a/src/openlibm/docs/params.json b/src/openlibm/docs/params.json new file mode 100644 index 0000000..cd0a5ed --- /dev/null +++ b/src/openlibm/docs/params.json @@ -0,0 +1 @@ +{"name":"OpenLibm","tagline":"A high quality system independent, portable, open source libm implementation","body":"## OpenLibm\r\n\r\n[OpenLibm](http://www.openlibm.org) is an effort to have a high quality, portable, standalone\r\nC mathematical library ([`libm`](http://en.wikipedia.org/wiki/libm)).\r\nIt can be used standalone in applications and programming language\r\nimplementations.\r\n\r\nThe project was born out of a need to have a good `libm` for the\r\n[Julia programming langage](http://www.julialang.org) that worked\r\nconsistently across compilers and operating systems, and in 32-bit and\r\n64-bit environments.\r\n\r\n### History\r\n\r\nThe OpenLibm code derives from the [FreeBSD\r\nmsun](http://svnweb.freebsd.org/base/head/lib/msun/) and [OpenBSD\r\nlibm](http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libm/src/)\r\nimplementations, which in turn derives from [FDLIBM\r\n5.3](http://www.netlib.org/fdlibm/). As a result, it includes a number\r\nof fixes and updates to FDLIBM that have accumulated over the years in\r\n`msun`, and optimized versions of many functions.\r\n\r\n### Platform support\r\n\r\nOpenLibm builds on Linux, Mac OS X, and Windows, and with little\r\neffort, should build on FreeBSD as well. It builds with both GCC and\r\nclang. Although largely tested on x86, it also includes experimental\r\nsupport for ARM. The original `msun` also includes support for mips,\r\nsparc64, powerpc, ia64, and alpha. These are present in the OpenLibm\r\nsource tree, but no attempt has been made to build any of these.\r\n\r\n### Build instructions\r\n\r\n1. `make` or `make USEGCC=1` to build with GCC. This is the default on\r\n Linux and Windows.\r\n2. `make USECLANG=1` to build with clang. This is the default on OS X.\r\n","google":"UA-28835595-4","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/src/openlibm/docs/stylesheets/pygment_trac.css b/src/openlibm/docs/stylesheets/pygment_trac.css new file mode 100644 index 0000000..c6a6452 --- /dev/null +++ b/src/openlibm/docs/stylesheets/pygment_trac.css @@ -0,0 +1,69 @@ +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/src/openlibm/docs/stylesheets/styles.css b/src/openlibm/docs/stylesheets/styles.css new file mode 100644 index 0000000..647f08d --- /dev/null +++ b/src/openlibm/docs/stylesheets/styles.css @@ -0,0 +1,423 @@ +@import url(https://fonts.googleapis.com/css?family=Arvo:400,700,400italic); + +/* MeyerWeb Reset */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + + +/* Base text styles */ + +body { + padding:10px 50px 0 0; + font-family:"Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + color: #232323; + background-color: #FBFAF7; + margin: 0; + line-height: 1.8em; + -webkit-font-smoothing: antialiased; + +} + +h1, h2, h3, h4, h5, h6 { + color:#232323; + margin:36px 0 10px; +} + +p, ul, ol, table, dl { + margin:0 0 22px; +} + +h1, h2, h3 { + font-family: Arvo, Monaco, serif; + line-height:1.3; + font-weight: normal; +} + +h1,h2, h3 { + display: block; + border-bottom: 1px solid #ccc; + padding-bottom: 5px; +} + +h1 { + font-size: 30px; +} + +h2 { + font-size: 24px; +} + +h3 { + font-size: 18px; +} + +h4, h5, h6 { + font-family: Arvo, Monaco, serif; + font-weight: 700; +} + +a { + color:#C30000; + font-weight:200; + text-decoration:none; +} + +a:hover { + text-decoration: underline; +} + +a small { + font-size: 12px; +} + +em { + font-style: italic; +} + +strong { + font-weight:700; +} + +ul { + list-style-position: inside; + list-style: disc; + padding-left: 25px; +} + +ol { + list-style-position: inside; + list-style: decimal; + padding-left: 25px; +} + +blockquote { + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +dl, dt, dd, dl p { + font-color: #444; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + border:0; + background:#ccc; + height:1px; + margin:0 0 24px; +} + +/* Images */ + +img { + position: relative; + margin: 0 auto; + max-width: 650px; + padding: 5px; + margin: 10px 0 32px 0; + border: 1px solid #ccc; +} + +p img { + display: inline; + margin: 0; + padding: 0; + vertical-align: middle; + text-align: center; + border: none; +} + +/* Code blocks */ + +code, pre { + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + color:#000; + font-size:14px; +} + +pre { + padding: 4px 12px; + background: #FDFEFB; + border-radius:4px; + border:1px solid #D7D8C8; + overflow: auto; + overflow-y: hidden; + margin-bottom: 32px; +} + + +/* Tables */ + +table { + width:100%; +} + +table { + border: 1px solid #ccc; + margin-bottom: 32px; + text-align: left; + } + +th { + font-family: 'Arvo', Helvetica, Arial, sans-serif; + font-size: 18px; + font-weight: normal; + padding: 10px; + background: #232323; + color: #FDFEFB; + } + +td { + padding: 10px; + background: #ccc; + } + + +/* Wrapper */ +.wrapper { + width:960px; +} + + +/* Header */ + +header { + background-color: #171717; + color: #FDFDFB; + width:170px; + float:left; + position:fixed; + border: 1px solid #000; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + padding: 34px 25px 22px 50px; + margin: 30px 25px 0 0; + -webkit-font-smoothing: antialiased; +} + +p.header { + font-size: 16px; +} + +h1.header { + font-family: Arvo, sans-serif; + font-size: 30px; + font-weight: 300; + line-height: 1.3em; + border-bottom: none; + margin-top: 0; +} + + +h1.header, a.header, a.name, header a{ + color: #fff; +} + +a.header { + text-decoration: underline; +} + +a.name { + white-space: nowrap; +} + +header ul { + list-style:none; + padding:0; +} + +header li { + list-style-type: none; + width:132px; + height:15px; + margin-bottom: 12px; + line-height: 1em; + padding: 6px 6px 6px 7px; + + background: #AF0011; + background: -moz-linear-gradient(top, #AF0011 0%, #820011 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); + background: -webkit-linear-gradient(top, #AF0011 0%,#820011 100%); + background: -o-linear-gradient(top, #AF0011 0%,#820011 100%); + background: -ms-linear-gradient(top, #AF0011 0%,#820011 100%); + background: linear-gradient(top, #AF0011 0%,#820011 100%); + + border-radius:4px; + border:1px solid #0D0D0D; + + -webkit-box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); + box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); + +} + +header li:hover { + background: #C3001D; + background: -moz-linear-gradient(top, #C3001D 0%, #950119 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); + background: -webkit-linear-gradient(top, #C3001D 0%,#950119 100%); + background: -o-linear-gradient(top, #C3001D 0%,#950119 100%); + background: -ms-linear-gradient(top, #C3001D 0%,#950119 100%); + background: linear-gradient(top, #C3001D 0%,#950119 100%); +} + +a.buttons { + -webkit-font-smoothing: antialiased; + background: url(../images/arrow-down.png) no-repeat; + font-weight: normal; + text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0; + padding: 2px 2px 2px 22px; + height: 30px; +} + +a.github { + background: url(../images/octocat-small.png) no-repeat 1px; +} + +a.buttons:hover { + color: #fff; + text-decoration: none; +} + + +/* Section - for main page content */ + +section { + width:650px; + float:right; + padding-bottom:50px; +} + + +/* Footer */ + +footer { + width:170px; + float:left; + position:fixed; + bottom:10px; + padding-left: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width:auto; + margin:0; + } + + header, section, footer { + float:none; + position:static; + width:auto; + } + + footer { + border-top: 1px solid #ccc; + margin:0 84px 0 50px; + padding:0; + } + + header { + padding-right:320px; + } + + section { + padding:20px 84px 20px 50px; + margin:0 0 20px; + } + + header a small { + display:inline; + } + + header ul { + position:absolute; + right:130px; + top:84px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap:break-word; + } + + header { + padding:10px 20px 0; + margin-right: 0; + } + + section { + padding:10px 0 10px 20px; + margin:0 0 30px; + } + + footer { + margin: 0 0 0 30px; + } + + header ul, header p.view { + position:static; + } +} + +@media print, screen and (max-width: 480px) { + + header ul li.download { + display:none; + } + + footer { + margin: 0 0 0 20px; + } + + footer a{ + display:block; + } + +} + +@media print { + body { + padding:0.4in; + font-size:12pt; + color:#444; + } +} \ No newline at end of file diff --git a/src/openlibm/i387/Make.files b/src/openlibm/i387/Make.files new file mode 100644 index 0000000..369c541 --- /dev/null +++ b/src/openlibm/i387/Make.files @@ -0,0 +1,21 @@ +$(CUR_SRCS) = e_exp.S e_fmod.S e_log.S e_log10.S \ + e_remainder.S e_sqrt.S s_ceil.S s_copysign.S \ + s_floor.S s_llrint.S s_logb.S s_lrint.S \ + s_remquo.S s_rint.S s_tan.S s_trunc.S + +ifneq ($(OS), WINNT) +$(CUR_SRCS) += s_scalbn.S s_scalbnf.S s_scalbnl.S +endif + +# float counterparts +$(CUR_SRCS)+= e_log10f.S e_logf.S e_remainderf.S \ + e_sqrtf.S s_ceilf.S s_copysignf.S s_floorf.S \ + s_llrintf.S s_logbf.S s_lrintf.S \ + s_remquof.S s_rintf.S s_truncf.S + +# long double counterparts +$(CUR_SRCS)+= e_remainderl.S e_sqrtl.S s_ceill.S s_copysignl.S \ + s_floorl.S s_llrintl.S \ + s_logbl.S s_lrintl.S s_remquol.S s_rintl.S s_truncl.S + +$(CUR_SRCS)+= fenv.c diff --git a/src/openlibm/i387/bsd_asm.h b/src/openlibm/i387/bsd_asm.h new file mode 100644 index 0000000..93ac617 --- /dev/null +++ b/src/openlibm/i387/bsd_asm.h @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)DEFS.h 5.1 (Berkeley) 4/23/90 + * $FreeBSD: src/sys/i386/include/asm.h,v 1.14 2007/08/22 04:26:07 jkoshy Exp $ + */ + +#ifndef _MACHINE_ASM_H_ +#define _MACHINE_ASM_H_ + +#if defined(__APPLE__) +#include "osx_asm.h" +#define CNAME(x) EXT(x) +#else +#include "cdefs-compat.h" + +#ifdef PIC +#define PIC_PROLOGUE \ + pushl %ebx; \ + call 1f; \ +1: \ + popl %ebx; \ + addl $_GLOBAL_OFFSET_TABLE_+[.-1b],%ebx +#define PIC_EPILOGUE \ + popl %ebx +#define PIC_PLT(x) x@PLT +#define PIC_GOT(x) x@GOT(%ebx) +#else +#define PIC_PROLOGUE +#define PIC_EPILOGUE +#define PIC_PLT(x) x +#define PIC_GOT(x) x +#endif + +/* + * CNAME and HIDENAME manage the relationship between symbol names in C + * and the equivalent assembly language names. CNAME is given a name as + * it would be used in a C program. It expands to the equivalent assembly + * language name. HIDENAME is given an assembly-language name, and expands + * to a possibly-modified form that will be invisible to C programs. + */ + + +/* XXX should use .p2align 4,0x90 for -m486. */ +#define _START_ENTRY .p2align 2,0x90 + +#if defined(__ELF__) +#define CNAME(csym) csym +#define HIDENAME(asmsym) .asmsym +#define _ENTRY(x) .text; _START_ENTRY; \ + .globl CNAME(x); .type CNAME(x),@function; CNAME(x): +#define END(x) .size x, . - x +#elif defined(_WIN32) +#ifndef _MSC_VER +#define END(x) .end +#define _START_ENTRY_WIN .text; _START_ENTRY +#else +#define END(x) end +#define _START_ENTRY_WIN .code; _START_ENTRY +#endif +#define CNAME(csym) _##csym +#define HIDENAME(asmsym) .asmsym +#define _ENTRY(x) _START_ENTRY_WIN; \ + .globl CNAME(x); .section .drectve; .ascii " -export:", #x; \ + .section .text; .def CNAME(x); .scl 2; .type 32; .endef; CNAME(x): +#endif + +#ifdef PROF +#define ALTENTRY(x) _ENTRY(x); \ + pushl %ebp; movl %esp,%ebp; \ + call PIC_PLT(HIDENAME(mcount)); \ + popl %ebp; \ + jmp 9f +#define ENTRY(x) _ENTRY(x); \ + pushl %ebp; movl %esp,%ebp; \ + call PIC_PLT(HIDENAME(mcount)); \ + popl %ebp; \ + 9: +#else +#define ALTENTRY(x) _ENTRY(x) +#define ENTRY(x) _ENTRY(x) +#endif + +#define RCSID(x) .text; .asciz x + +#undef __FBSDID +#define __FBSDID(s) /* nothing */ + +#endif +#endif /* !_MACHINE_ASM_H_ */ diff --git a/src/openlibm/i387/bsd_ieeefp.h b/src/openlibm/i387/bsd_ieeefp.h new file mode 100644 index 0000000..79c7bf3 --- /dev/null +++ b/src/openlibm/i387/bsd_ieeefp.h @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 2003 Peter Wemm. + * Copyright (c) 1990 Andrew Moore, Talke Studio + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#) ieeefp.h 1.0 (Berkeley) 9/23/93 + * $FreeBSD$ + */ + +#ifndef _MACHINE_IEEEFP_H_ +#define _MACHINE_IEEEFP_H_ + +/* + * Deprecated historical FPU control interface + * + * IEEE floating point type, constant and function definitions. + * XXX: FP*FLD and FP*OFF are undocumented pollution. + */ + +/* VBS + +#ifndef _SYS_CDEFS_H_ +#error this file needs sys/cdefs.h as a prerequisite +#endif + +*/ + +/* + * Rounding modes. + */ +typedef enum { + FP_RN=0, /* round to nearest */ + FP_RM, /* round down towards minus infinity */ + FP_RP, /* round up towards plus infinity */ + FP_RZ /* truncate */ +} fp_rnd_t; + +/* + * Precision (i.e., rounding precision) modes. + */ +typedef enum { + FP_PS=0, /* 24 bit (single-precision) */ + FP_PRS, /* reserved */ + FP_PD, /* 53 bit (double-precision) */ + FP_PE /* 64 bit (extended-precision) */ +} fp_prec_t; + +#define fp_except_t int + +/* + * Exception bit masks. + */ +#define FP_X_INV 0x01 /* invalid operation */ +#define FP_X_DNML 0x02 /* denormal */ +#define FP_X_DZ 0x04 /* zero divide */ +#define FP_X_OFL 0x08 /* overflow */ +#define FP_X_UFL 0x10 /* underflow */ +#define FP_X_IMP 0x20 /* (im)precision */ +#define FP_X_STK 0x40 /* stack fault */ + +/* + * FPU control word bit-field masks. + */ +#define FP_MSKS_FLD 0x3f /* exception masks field */ +#define FP_PRC_FLD 0x300 /* precision control field */ +#define FP_RND_FLD 0xc00 /* rounding control field */ + +/* + * FPU status word bit-field masks. + */ +#define FP_STKY_FLD 0x3f /* sticky flags field */ + +/* + * FPU control word bit-field offsets (shift counts). + */ +#define FP_MSKS_OFF 0 /* exception masks offset */ +#define FP_PRC_OFF 8 /* precision control offset */ +#define FP_RND_OFF 10 /* rounding control offset */ + +/* + * FPU status word bit-field offsets (shift counts). + */ +#define FP_STKY_OFF 0 /* sticky flags offset */ + +//VBS +//#ifdef __GNUCLIKE_ASM + +#define __fldcw(addr) __asm __volatile("fldcw %0" : : "m" (*(addr))) +#define __fldenv(addr) __asm __volatile("fldenv %0" : : "m" (*(addr))) +#define __fnclex() __asm __volatile("fnclex") +#define __fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) +#define __fnstenv(addr) __asm __volatile("fnstenv %0" : "=m" (*(addr))) +#define __fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) + +/* + * Load the control word. Be careful not to trap if there is a currently + * unmasked exception (ones that will become freshly unmasked are not a + * problem). This case must be handled by a save/restore of the + * environment or even of the full x87 state. Accessing the environment + * is very inefficient, so only do it when necessary. + */ +static __inline void +__fnldcw(unsigned short _cw, unsigned short _newcw) +{ + struct { + unsigned _cw; + unsigned _other[6]; + } _env; + unsigned short _sw; + + if ((_cw & FP_MSKS_FLD) != FP_MSKS_FLD) { + __fnstsw(&_sw); + if (((_sw & ~_cw) & FP_STKY_FLD) != 0) { + __fnstenv(&_env); + _env._cw = _newcw; + __fldenv(&_env); + return; + } + } + __fldcw(&_newcw); +} + +static __inline fp_rnd_t +fpgetround(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF)); +} + +static __inline fp_rnd_t +fpsetround(fp_rnd_t _m) +{ + fp_rnd_t _p; + unsigned short _cw, _newcw; + + __fnstcw(&_cw); + _p = (fp_rnd_t)((_cw & FP_RND_FLD) >> FP_RND_OFF); + _newcw = _cw & ~FP_RND_FLD; + _newcw |= (_m << FP_RND_OFF) & FP_RND_FLD; + __fnldcw(_cw, _newcw); + return (_p); +} + +//static __inline fp_prec_t +OLM_DLLEXPORT fp_prec_t +fpgetprec(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF)); +} + +//static __inline fp_prec_t +OLM_DLLEXPORT fp_prec_t +fpsetprec(fp_prec_t _m) +{ + fp_prec_t _p; + unsigned short _cw, _newcw; + + __fnstcw(&_cw); + _p = (fp_prec_t)((_cw & FP_PRC_FLD) >> FP_PRC_OFF); + _newcw = _cw & ~FP_PRC_FLD; + _newcw |= (_m << FP_PRC_OFF) & FP_PRC_FLD; + __fnldcw(_cw, _newcw); + return (_p); +} + +/* + * Get or set the exception mask. + * Note that the x87 mask bits are inverted by the API -- a mask bit of 1 + * means disable for x87 and SSE, but for fp*mask() it means enable. + */ + +static __inline fp_except_t +fpgetmask(void) +{ + unsigned short _cw; + + __fnstcw(&_cw); + return ((~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF); +} + +static __inline fp_except_t +fpsetmask(fp_except_t _m) +{ + fp_except_t _p; + unsigned short _cw, _newcw; + + __fnstcw(&_cw); + _p = (~_cw & FP_MSKS_FLD) >> FP_MSKS_OFF; + _newcw = _cw & ~FP_MSKS_FLD; + _newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD; + __fnldcw(_cw, _newcw); + return (_p); +} + +static __inline fp_except_t +fpgetsticky(void) +{ + unsigned _ex; + unsigned short _sw; + + __fnstsw(&_sw); + _ex = (_sw & FP_STKY_FLD) >> FP_STKY_OFF; + return ((fp_except_t)_ex); +} + +static __inline fp_except_t +fpresetsticky(fp_except_t _m) +{ + struct { + unsigned _cw; + unsigned _sw; + unsigned _other[5]; + } _env; + fp_except_t _p; + + _m &= FP_STKY_FLD >> FP_STKY_OFF; + _p = fpgetsticky(); + if ((_p & ~_m) == _p) + return (_p); + if ((_p & ~_m) == 0) { + __fnclex(); + return (_p); + } + __fnstenv(&_env); + _env._sw &= ~_m; + __fldenv(&_env); + return (_p); +} + +//#endif /* __GNUCLIKE_ASM */ + +#endif /* !_MACHINE_IEEEFP_H_ */ diff --git a/src/openlibm/i387/bsd_npx.h b/src/openlibm/i387/bsd_npx.h new file mode 100644 index 0000000..78c5cbe --- /dev/null +++ b/src/openlibm/i387/bsd_npx.h @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)npx.h 5.3 (Berkeley) 1/18/91 + * $FreeBSD: src/sys/i386/include/npx.h,v 1.29.2.1 2006/07/01 00:57:55 davidxu Exp $ + */ + +/* + * 287/387 NPX Coprocessor Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef _MACHINE_NPX_H_ +#define _MACHINE_NPX_H_ + +/* Environment information of floating point unit */ +struct env87 { + long en_cw; /* control word (16bits) */ + long en_sw; /* status word (16bits) */ + long en_tw; /* tag word (16bits) */ + long en_fip; /* floating point instruction pointer */ + unsigned short en_fcs; /* floating code segment selector */ + unsigned short en_opcode; /* opcode last executed (11 bits ) */ + long en_foo; /* floating operand offset */ + long en_fos; /* floating operand segment selector */ +}; + +/* Contents of each floating point accumulator */ +struct fpacc87 { +#ifdef dontdef /* too unportable */ + unsigned long fp_mantlo; /* mantissa low (31:0) */ + unsigned long fp_manthi; /* mantissa high (63:32) */ + int fp_exp:15; /* exponent */ + int fp_sgn:1; /* mantissa sign */ +#else + unsigned char fp_bytes[10]; +#endif +}; + +/* Floating point context */ +struct save87 { + struct env87 sv_env; /* floating point control/status */ + struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ + unsigned char sv_pad0[4]; /* padding for (now unused) saved status word */ + /* + * Bogus padding for emulators. Emulators should use their own + * struct and arrange to store into this struct (ending here) + * before it is inspected for ptracing or for core dumps. Some + * emulators overwrite the whole struct. We have no good way of + * knowing how much padding to leave. Leave just enough for the + * GPL emulator's i387_union (176 bytes total). + */ + unsigned char sv_pad[64]; /* padding; used by emulators */ +}; + +struct envxmm { + uint16_t en_cw; /* control word (16bits) */ + uint16_t en_sw; /* status word (16bits) */ + uint16_t en_tw; /* tag word (16bits) */ + uint16_t en_opcode; /* opcode last executed (11 bits ) */ + uint32_t en_fip; /* floating point instruction pointer */ + uint16_t en_fcs; /* floating code segment selector */ + uint16_t en_pad0; /* padding */ + uint32_t en_foo; /* floating operand offset */ + uint16_t en_fos; /* floating operand segment selector */ + uint16_t en_pad1; /* padding */ + uint32_t en_mxcsr; /* SSE sontorol/status register */ + uint32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +/* Contents of each SSE extended accumulator */ +struct xmmacc { + unsigned char xmm_bytes[16]; +}; + +struct savexmm { + struct envxmm sv_env; + struct { + struct fpacc87 fp_acc; + unsigned char fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[8]; + unsigned char sv_pad[224]; +} __attribute__((__aligned__(16))); + +union savefpu { + struct save87 sv_87; + struct savexmm sv_xmm; +}; + +/* + * The hardware default control word for i387's and later coprocessors is + * 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * We modify the affine mode bit and precision bits in this to give: + * + * affine mode for 287's (if they work at all) (1 in bitfield 1<<12) + * 53-bit precision (2 in bitfield 3<<8) + * + * 64-bit precision often gives bad results with high level languages + * because it makes the results of calculations depend on whether + * intermediate values are stored in memory or in FPU registers. + */ +#define __INITIAL_NPXCW__ 0x127F +#define __INITIAL_MXCSR__ 0x1F80 + +#ifdef _KERNEL + +#define IO_NPX 0x0F0 /* Numeric Coprocessor */ +#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ + +#define IRQ_NPX 13 + +/* full reset on some systems, NOP on others */ +#define npx_full_reset() outb(IO_NPX + 1, 0) + +int npxdna(void); +void npxdrop(void); +void npxexit(struct thread *td); +int npxformat(void); +int npxgetregs(struct thread *td, union savefpu *addr); +void npxinit(unsigned short control); +void npxsave(union savefpu *addr); +void npxsetregs(struct thread *td, union savefpu *addr); +int npxtrap(void); +#endif + +#endif /* !_MACHINE_NPX_H_ */ \ No newline at end of file diff --git a/src/openlibm/i387/e_exp.S b/src/openlibm/i387/e_exp.S new file mode 100644 index 0000000..0f03f9e --- /dev/null +++ b/src/openlibm/i387/e_exp.S @@ -0,0 +1,76 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +/* e^x = 2^(x * log2(e)) */ + +ENTRY(exp) + /* + * If x is +-Inf, then the subtraction would give Inf-Inf = NaN. + * Avoid this. Also avoid it if x is NaN for convenience. + */ + movl 8(%esp),%eax + andl $0x7fffffff,%eax + cmpl $0x7ff00000,%eax + jae x_Inf_or_NaN + + fldl 4(%esp) + + /* + * Extended precision is needed to reduce the maximum error from + * hundreds of ulps to less than 1 ulp. Switch to it if necessary. + * We may as well set the rounding mode to to-nearest and mask traps + * if we switch. + */ + fstcw 4(%esp) + movl 4(%esp),%eax + andl $0x0300,%eax + cmpl $0x0300,%eax /* RC == 0 && PC == 3? */ + je 1f /* jump if mode is good */ + movl $0x137f,8(%esp) + fldcw 8(%esp) +1: + fldl2e + fmulp /* x * log2(e) */ + fst %st(1) + frndint /* int(x * log2(e)) */ + fst %st(2) + fsubrp /* fract(x * log2(e)) */ + f2xm1 /* 2^(fract(x * log2(e))) - 1 */ + fld1 + faddp /* 2^(fract(x * log2(e))) */ + fscale /* e^x */ + fstp %st(1) + je 1f + fldcw 4(%esp) +1: + ret + +x_Inf_or_NaN: + /* + * Return 0 if x is -Inf. Otherwise just return x; when x is Inf + * this gives Inf, and when x is a NaN this gives the same result + * as (x + x) (x quieted). + */ + cmpl $0xfff00000,8(%esp) + jne x_not_minus_Inf + cmpl $0,4(%esp) + jne x_not_minus_Inf + fldz + ret + +x_not_minus_Inf: + fldl 4(%esp) + ret +END(exp) + + // + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_fmod.S b/src/openlibm/i387/e_fmod.S new file mode 100644 index 0000000..44e52e5 --- /dev/null +++ b/src/openlibm/i387/e_fmod.S @@ -0,0 +1,25 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_fmod.S,v 1.11 2011/01/07 16:13:12 kib Exp $") + +ENTRY(fmod) + fldl 12(%esp) + fldl 4(%esp) +1: fprem + fstsw %ax + sahf + jp 1b + fstp %st(1) + ret +END(fmod) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_log.S b/src/openlibm/i387/e_log.S new file mode 100644 index 0000000..ebd6ae7 --- /dev/null +++ b/src/openlibm/i387/e_log.S @@ -0,0 +1,21 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(log) + fldln2 + fldl 4(%esp) + fyl2x + ret +END(log) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_log10.S b/src/openlibm/i387/e_log10.S new file mode 100644 index 0000000..b559a74 --- /dev/null +++ b/src/openlibm/i387/e_log10.S @@ -0,0 +1,21 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log10.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(log10) + fldlg2 + fldl 4(%esp) + fyl2x + ret +END(log10) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_log10f.S b/src/openlibm/i387/e_log10f.S new file mode 100644 index 0000000..afdf1b0 --- /dev/null +++ b/src/openlibm/i387/e_log10f.S @@ -0,0 +1,22 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_log10f.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: e_log10f.S,v 1.1 1996/07/03 16:50:22 jtc Exp $") */ + +ENTRY(log10f) + fldlg2 + flds 4(%esp) + fyl2x + ret +END(log10f) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_logf.S b/src/openlibm/i387/e_logf.S new file mode 100644 index 0000000..af06fd8 --- /dev/null +++ b/src/openlibm/i387/e_logf.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_logf.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: e_logf.S,v 1.2 1996/07/06 00:15:45 jtc Exp $") */ + +ENTRY(logf) + fldln2 + flds 4(%esp) + fyl2x + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_remainder.S b/src/openlibm/i387/e_remainder.S new file mode 100644 index 0000000..2aa3113 --- /dev/null +++ b/src/openlibm/i387/e_remainder.S @@ -0,0 +1,25 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainder.S,v 1.11 2011/01/07 16:13:12 kib Exp $") + +ENTRY(remainder) + fldl 12(%esp) + fldl 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) + ret +END(remainder) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_remainderf.S b/src/openlibm/i387/e_remainderf.S new file mode 100644 index 0000000..2b7b597 --- /dev/null +++ b/src/openlibm/i387/e_remainderf.S @@ -0,0 +1,26 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainderf.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: e_remainderf.S,v 1.2 1995/05/08 23:49:47 jtc Exp $") */ + +ENTRY(remainderf) + flds 8(%esp) + flds 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) + ret +END(remainderf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_remainderl.S b/src/openlibm/i387/e_remainderl.S new file mode 100644 index 0000000..04d460b --- /dev/null +++ b/src/openlibm/i387/e_remainderl.S @@ -0,0 +1,25 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_remainderl.S,v 1.2 2011/01/07 16:13:12 kib Exp $") + +ENTRY(remainderl) + fldt 16(%esp) + fldt 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_sqrt.S b/src/openlibm/i387/e_sqrt.S new file mode 100644 index 0000000..5cd45b0 --- /dev/null +++ b/src/openlibm/i387/e_sqrt.S @@ -0,0 +1,37 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrt.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sqrt) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + andw $0xfeff,%dx /* Set precision field to 64 bits (53 bit mantissa). + We assume it's set to 0b11 (extended precision), + so zeroing out the low bit of the precision field, + will correctly set the precision */ + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldl 8(%ebp) + fsqrt + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(sqrt) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_sqrtf.S b/src/openlibm/i387/e_sqrtf.S new file mode 100644 index 0000000..05fb77f --- /dev/null +++ b/src/openlibm/i387/e_sqrtf.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrtf.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: e_sqrtf.S,v 1.2 1995/05/08 23:50:14 jtc Exp $") */ + +ENTRY(sqrtf) + flds 4(%esp) + fsqrt + ret +END(sqrtf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/e_sqrtl.S b/src/openlibm/i387/e_sqrtl.S new file mode 100644 index 0000000..5317f95 --- /dev/null +++ b/src/openlibm/i387/e_sqrtl.S @@ -0,0 +1,19 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/e_sqrtl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sqrtl) + fldt 4(%esp) + fsqrt + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/fenv.c b/src/openlibm/i387/fenv.c new file mode 100644 index 0000000..6afe766 --- /dev/null +++ b/src/openlibm/i387/fenv.c @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/i387/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $ + */ + +#include "cdefs-compat.h" +#include "types-compat.h" +#include "math_private.h" +#include "i387/bsd_npx.h" + +#define __fenv_static +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +const fenv_t __fe_dfl_env = { + __INITIAL_NPXCW__, + 0x0000, + 0x0000, + 0x1f80, + 0xffffffff, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } +}; + +enum __sse_support __has_sse = +#ifdef __SSE__ + __SSE_YES; +#else + __SSE_UNK; +#endif + +#define getfl(x) __asm __volatile("pushfl\n\tpopl %0" : "=mr" (*(x))) +#define setfl(x) __asm __volatile("pushl %0\n\tpopfl" : : "g" (x)) +#define cpuid_dx(x) __asm __volatile("pushl %%ebx\n\tmovl $1, %%eax\n\t" \ + "cpuid\n\tpopl %%ebx" \ + : "=d" (*(x)) : : "eax", "ecx") + +/* + * Test for SSE support on this processor. We need to do this because + * we need to use ldmxcsr/stmxcsr to get correct results if any part + * of the program was compiled to use SSE floating-point, but we can't + * use SSE on older processors. + */ +int +__test_sse(void) +{ + int flag, nflag; + int dx_features; + + /* Am I a 486? */ + getfl(&flag); + nflag = flag ^ 0x200000; + setfl(nflag); + getfl(&nflag); + if (flag != nflag) { + /* Not a 486, so CPUID should work. */ + cpuid_dx(&dx_features); + if (dx_features & 0x2000000) { + __has_sse = __SSE_YES; + return (1); + } + } + __has_sse = __SSE_NO; + return (0); +} + +extern inline OLM_DLLEXPORT int feclearexcept(int __excepts); +extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts); + +OLM_DLLEXPORT int +fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + fenv_t env; + uint32_t mxcsr; + + __fnstenv(&env); + env.__status &= ~excepts; + env.__status |= *flagp & excepts; + __fldenv(env); + + if (__HAS_SSE()) { + __stmxcsr(&mxcsr); + mxcsr &= ~excepts; + mxcsr |= *flagp & excepts; + __ldmxcsr(mxcsr); + } + + return (0); +} + +OLM_DLLEXPORT int +feraiseexcept(int excepts) +{ + fexcept_t ex = excepts; + + fesetexceptflag(&ex, excepts); + __fwait(); + return (0); +} + +extern inline OLM_DLLEXPORT int fetestexcept(int __excepts); +extern inline OLM_DLLEXPORT int fegetround(void); +extern inline OLM_DLLEXPORT int fesetround(int __round); + +int +fegetenv(fenv_t *envp) +{ + uint32_t mxcsr; + + __fnstenv(envp); + /* + * fnstenv masks all exceptions, so we need to restore + * the old control word to avoid this side effect. + */ + __fldcw(envp->__control); + if (__HAS_SSE()) { + __stmxcsr(&mxcsr); + __set_mxcsr(*envp, mxcsr); + } + return (0); +} + +int +feholdexcept(fenv_t *envp) +{ + uint32_t mxcsr; + + __fnstenv(envp); + __fnclex(); + if (__HAS_SSE()) { + __stmxcsr(&mxcsr); + __set_mxcsr(*envp, mxcsr); + mxcsr &= ~FE_ALL_EXCEPT; + mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + } + return (0); +} + +extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp); + +OLM_DLLEXPORT int +feupdateenv(const fenv_t *envp) +{ + uint32_t mxcsr; + uint16_t status; + + __fnstsw(&status); + if (__HAS_SSE()) + __stmxcsr(&mxcsr); + else + mxcsr = 0; + fesetenv(envp); + feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); + return (0); +} + +int +feenableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + if (__HAS_SSE()) + __stmxcsr(&mxcsr); + else + mxcsr = 0; + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control &= ~mask; + __fldcw(control); + if (__HAS_SSE()) { + mxcsr &= ~(mask << _SSE_EMASK_SHIFT); + __ldmxcsr(mxcsr); + } + return (omask); +} + +int +fedisableexcept(int mask) +{ + uint32_t mxcsr, omask; + uint16_t control; + + mask &= FE_ALL_EXCEPT; + __fnstcw(&control); + if (__HAS_SSE()) + __stmxcsr(&mxcsr); + else + mxcsr = 0; + omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control |= mask; + __fldcw(control); + if (__HAS_SSE()) { + mxcsr |= mask << _SSE_EMASK_SHIFT; + __ldmxcsr(mxcsr); + } + return (omask); +} diff --git a/src/openlibm/i387/invtrig.c b/src/openlibm/i387/invtrig.c new file mode 100644 index 0000000..4afd832 --- /dev/null +++ b/src/openlibm/i387/invtrig.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/invtrig.c,v 1.1 2008/08/02 03:56:22 das Exp $"); + +#include + +#define STRUCT_DECLS +#include "invtrig.h" + +/* + * asinl() and acosl() + */ +const LONGDOUBLE +pS0 = { 0xaaaaaaaaaaaaaaa8ULL, 0x3ffcU }, /* 1.66666666666666666631e-01L */ +pS1 = { 0xd5271b6699b48bfaULL, 0xbffdU }, /* -4.16313987993683104320e-01L */ +pS2 = { 0xbcf67ca9e9f669cfULL, 0x3ffdU }, /* 3.69068046323246813704e-01L */ +pS3 = { 0x8b7baa3d15f9830dULL, 0xbffcU }, /* -1.36213932016738603108e-01L */ +pS4 = { 0x92154b093a3bff1cULL, 0x3ff9U }, /* 1.78324189708471965733e-02L */ +pS5 = { 0xe5dd76401964508cULL, 0xbff2U }, /* -2.19216428382605211588e-04L */ +pS6 = { 0xee69c5b0fdb76951ULL, 0xbfedU }, /* -7.10526623669075243183e-06L */ +qS1 = { 0xbcaa2159c01436a0ULL, 0xc000U }, /* -2.94788392796209867269e+00L */ +qS2 = { 0xd17a73d1e1564c29ULL, 0x4000U }, /* 3.27309890266528636716e+00L */ +qS3 = { 0xd767e411c9cf4c2cULL, 0xbfffU }, /* -1.68285799854822427013e+00L */ +qS4 = { 0xc809c0dfb9b0d0b7ULL, 0x3ffdU }, /* 3.90699412641738801874e-01L */ +qS5 = { 0x80c3a2197c8ced57ULL, 0xbffaU }; /* -3.14365703596053263322e-02L */ + +/* + * atanl() + */ +const LONGDOUBLE atanhi[] = { + { 0xed63382b0dda7b45ULL, 0x3ffdU }, /* 4.63647609000806116202e-01L */ + { 0xc90fdaa22168c235ULL, 0x3ffeU }, /* 7.85398163397448309628e-01L */ + { 0xfb985e940fb4d900ULL, 0x3ffeU }, /* 9.82793723247329067960e-01L */ + { 0xc90fdaa22168c235ULL, 0x3fffU }, /* 1.57079632679489661926e+00L */ +}; + +const LONGDOUBLE atanlo[] = { + { 0xdfc88bd978751a07ULL, 0x3fbcU }, /* 1.18469937025062860669e-20L */ + { 0xece675d1fc8f8cbbULL, 0xbfbcU }, /* -1.25413940316708300586e-20L */ + { 0xf10f5e197793c283ULL, 0x3fbdU }, /* 2.55232234165405176172e-20L */ + { 0xece675d1fc8f8cbbULL, 0xbfbdU }, /* -2.50827880633416601173e-20L */ +}; + +const LONGDOUBLE aT[] = { + { 0xaaaaaaaaaaaaaa9fULL, 0x3ffdU }, /* 3.33333333333333333017e-01L */ + { 0xcccccccccccc62bcULL, 0xbffcU }, /* -1.99999999999999632011e-01L */ + { 0x9249249248b81e3fULL, 0x3ffcU }, /* 1.42857142857046531280e-01L */ + { 0xe38e38e3316f3de5ULL, 0xbffbU }, /* -1.11111111100562372733e-01L */ + { 0xba2e8b8dc280726aULL, 0x3ffbU }, /* 9.09090902935647302252e-02L */ + { 0x9d89d5b4c6847ec4ULL, 0xbffbU }, /* -7.69230552476207730353e-02L */ + { 0x8888461d3099c677ULL, 0x3ffbU }, /* 6.66661718042406260546e-02L */ + { 0xf0e8ee0f5328dc29ULL, 0xbffaU }, /* -5.88158892835030888692e-02L */ + { 0xd73ea84d24bae54aULL, 0x3ffaU }, /* 5.25499891539726639379e-02L */ + { 0xc08fa381dcd9213aULL, 0xbffaU }, /* -4.70119845393155721494e-02L */ + { 0xa54a26f4095f2a3aULL, 0x3ffaU }, /* 4.03539201366454414072e-02L */ + { 0xeea2d8d059ef3ad6ULL, 0xbff9U }, /* -2.91303858419364158725e-02L */ + { 0xcc82292ab894b051ULL, 0x3ff8U }, /* 1.24822046299269234080e-02L */ +}; + +const LONGDOUBLE +pi_lo = { 0xece675d1fc8f8cbbULL, 0xbfbeU }; /* -5.01655761266833202345e-20L */ diff --git a/src/openlibm/i387/osx_asm.h b/src/openlibm/i387/osx_asm.h new file mode 100644 index 0000000..284224c --- /dev/null +++ b/src/openlibm/i387/osx_asm.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef _I386_ASM_H_ +#define _I386_ASM_H_ + +#ifdef _KERNEL +#include +#endif /* _KERNEL */ + +#ifdef MACH_KERNEL +#include +#else /* !MACH_KERNEL */ +#define MACH_KDB 0 +#endif /* !MACH_KERNEL */ + + +#if defined(MACH_KERNEL) || defined(_KERNEL) +#include +#endif /* MACH_KERNEL || _KERNEL */ + +#if defined(__i386__) + +#define S_PC (%esp) +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) +#define S_ARG4 20(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_LINK (%ebp) +#define B_PC 4(%ebp) +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#elif defined(__x86_64__) + +#define S_PC (%rsp) + +#define FRAME pushq %rbp; movq %rsp, %rbp +#define EMARF leave + +#define B_LINK (%rbp) +#define B_PC 8(%rbp) + +#else +#error unsupported architecture +#endif + +/* There is another definition of ALIGN for .c sources */ +#ifdef ASSEMBLER +#define ALIGN 4,0x90 +#endif /* ASSEMBLER */ + +#ifndef FALIGN +#define FALIGN ALIGN +#endif + +#define LB(x,n) n +#if __STDC__ +#ifndef __NO_UNDERSCORES__ +#define LCL(x) L ## x +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : +#else +#define LCL(x) .L ## x +#define EXT(x) x +#define LEXT(x) x ## : +#endif +#define LBc(x,n) n ## : +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f +#else /* __STDC__ */ +#ifndef __NO_UNDERSCORES__ +#define LCL(x) L/**/x +#define EXT(x) _/**/x +#define LEXT(x) _/**/x/**/: +#else /* __NO_UNDERSCORES__ */ +#define LCL(x) .L/**/x +#define EXT(x) x +#define LEXT(x) x/**/: +#endif /* __NO_UNDERSCORES__ */ +#define LBc(x,n) n/**/: +#define LBb(x,n) n/**/b +#define LBf(x,n) n/**/f +#endif /* __STDC__ */ + +#define SVC .byte 0x9a; .long 0; .word 0x7 + +#define RPC_SVC .byte 0x9a; .long 0; .word 0xf + +#define String .asciz +#define Value .word +#define Times(a,b) (a*b) +#define Divide(a,b) (a/b) + +#define INB inb %dx, %al +#define OUTB outb %al, %dx +#define INL inl %dx, %eax +#define OUTL outl %eax, %dx + +#define data16 .byte 0x66 +#define addr16 .byte 0x67 + +#if !GPROF +#define MCOUNT + +#elif defined(__SHARED__) +#define MCOUNT ; .data;\ + .align ALIGN;\ + LBc(x, 8) .long 0;\ + .text;\ + Gpush;\ + Gload;\ + leal Gotoff(LBb(x,8)),%edx;\ + Egaddr(%eax,_mcount_ptr);\ + Gpop;\ + call *(%eax); + +#else /* !GPROF, !__SHARED__ */ +#define MCOUNT ; call mcount; +#endif /* GPROF */ + +#ifdef __ELF__ +#define ELF_FUNC(x) .type x,@function +#define ELF_DATA(x) .type x,@object +#define ELF_SIZE(x,s) .size x,s +#else +#define ELF_FUNC(x) +#define ELF_DATA(x) +#define ELF_SIZE(x,s) +#endif + +#define Entry(x) .globl EXT(x); ELF_FUNC(EXT(x)); .align FALIGN; LEXT(x) +#define ENTRY(x) Entry(x) MCOUNT +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + ELF_FUNC(EXT(x)); ELF_FUNC(EXT(y)); \ + .align FALIGN; LEXT(x); LEXT(y) \ + MCOUNT +#if __STDC__ +#define ASENTRY(x) .globl x; .align FALIGN; x ## : ELF_FUNC(x) MCOUNT +#else +#define ASENTRY(x) .globl x; .align FALIGN; x: ELF_FUNC(x) MCOUNT +#endif /* __STDC__ */ + +#define DATA(x) .globl EXT(x); ELF_DATA(EXT(x)); .align ALIGN; LEXT(x) + +#define End(x) ELF_SIZE(x,.-x) +#define END(x) End(EXT(x)) +#define ENDDATA(x) END(x) +#define Enddata(x) End(x) + +/* + * ELF shared library accessor macros. + * Gpush saves the %ebx register used for the GOT address + * Gpop pops %ebx if we need a GOT + * Gload loads %ebx with the GOT address if shared libraries are used + * Gcall calls an external function. + * Gotoff allows you to reference local labels. + * Gotoff2 allows you to reference local labels with an index reg. + * Gotoff3 allows you to reference local labels with an index reg & size. + * Gaddr loads up a register with an address of an external item. + * Gstack is the number of bytes that Gpush pushes on the stack. + * + * Varients of the above with E or L prefixes do EXT(name) or LCL(name) + * respectively. + */ + +#ifndef __SHARED__ +#define Gpush +#define Gpop +#define Gload +#define Gcall(func) call func +#define Gotoff(lab) lab +#define Gotoff2(l,r) l(r) +#define Gotoff3(l,r,s) l(,r,s) +#define Gaddr(to,lab) movl $lab,to +#define Gcmp(lab,reg) cmpl $lab,reg +#define Gmemload(lab,reg) movl lab,reg +#define Gmemstore(reg,lab,tmp) movl reg,lab +#define Gstack 0 + +#else +#ifdef __ELF__ /* ELF shared libraries */ +#define Gpush pushl %ebx +#define Gpop popl %ebx +#define Gload call 9f; 9: popl %ebx; addl $_GLOBAL_OFFSET_TABLE_+[.-9b],%ebx +#define Gcall(func) call EXT(func)@PLT +#define Gotoff(lab) lab@GOTOFF(%ebx) +#define Gotoff2(l,r) l@GOTOFF(%ebx,r) +#define Gotoff3(l,r,s) l@GOTOFF(%ebx,r,s) +#define Gaddr(to,lab) movl lab@GOT(%ebx),to +#define Gcmp(lab,reg) cmpl reg,lab@GOT(%ebx) +#define Gmemload(lab,reg) movl lab@GOT(%ebx),reg; movl (reg),reg +#define Gmemstore(reg,lab,tmp) movl lab@GOT(%ebx),tmp; movl reg,(tmp) +#define Gstack 4 + +#else /* ROSE shared libraries */ +#define Gpush +#define Gpop +#define Gload +#define Gcall(func) call *9f; .data; .align ALIGN; 9: .long func; .text +#define Gotoff(lab) lab +#define Gotoff2(l,r) l(r) +#define Gotoff3(l,r,s) l(,r,s) +#define Gaddr(to,lab) movl 9f,to; .data; .align ALIGN; 9: .long lab; .text +#define Gcmp(lab,reg) cmpl reg,9f; .data; .align ALIGN; 9: .long lab; .text +#define Gmemload(lab,reg) movl 9f,reg; movl (reg),reg; .data; .align ALIGN; 9: .long lab; .text +#define Gmemstore(reg,lab,tmp) movl 9f,tmp; movl reg,(tmp); .data; .align ALIGN; 9: .long lab; .text +#define Gstack 0 +#endif /* __ELF__ */ +#endif /* __SHARED__ */ + +/* Egotoff is not provided, since external symbols should not use @GOTOFF + relocations. */ +#define Egcall(func) Gcall(EXT(func)) +#define Egaddr(to,lab) Gaddr(to,EXT(lab)) +#define Egcmp(lab,reg) Gcmp(EXT(lab),reg) +#define Egmemload(lab,reg) Gmemload(EXT(lab),reg) +#define Egmemstore(reg,lab,tmp) Gmemstore(reg,EXT(lab),tmp) + +#define Lgotoff(lab) Gotoff(LCL(lab)) +#define Lgotoff2(l,r) Gotoff2(LCL(l),r) +#define Lgotoff3(l,r,s) Gotoff3(LCL(l),r,s) +#define Lgcmp(lab,reg) Gcmp(LCL(lab),reg) +#define Lgmemload(lab,reg) movl Lgotoff(lab),reg +#define Lgmemstore(reg,lab,tmp) movl reg,Lgotoff(lab) + +#ifdef ASSEMBLER +#if MACH_KDB +#include +/* + * This pseudo-assembler line is added so that there will be at least + * one N_SO entry in the symbol stable to define the current file name. + */ +#endif /* MACH_KDB */ + +#else /* NOT ASSEMBLER */ + +/* These defines are here for .c files that wish to reference global symbols + * within __asm__ statements. + */ +#ifndef __NO_UNDERSCORES__ +#define CC_SYM_PREFIX "_" +#else +#define CC_SYM_PREFIX "" +#endif /* __NO_UNDERSCORES__ */ +#endif /* ASSEMBLER */ + +/* + * The following macros make calls into C code. + * They dynamically align the stack to 16 bytes. + */ +#if defined(__i386__) +/* + * Arguments are moved (not pushed) onto the correctly aligned stack. + * NOTE: ESI is destroyed in the process, and hence cannot + * be directly used as a parameter. Users of this macro must + * independently preserve ESI (a non-volatile) if the routine is + * intended to be called from C, for instance. + */ + +#define CCALL(fn) \ + movl %esp, %esi ;\ + andl $0xFFFFFFF0, %esp ;\ + call EXT(fn) ;\ + movl %esi, %esp + +#define CCALL1(fn, arg1) \ + movl %esp, %esi ;\ + subl $4, %esp ;\ + andl $0xFFFFFFF0, %esp ;\ + movl arg1, (%esp) ;\ + call EXT(fn) ;\ + movl %esi, %esp + +#define CCALL2(fn, arg1, arg2) \ + movl %esp, %esi ;\ + subl $8, %esp ;\ + andl $0xFFFFFFF0, %esp ;\ + movl arg2, 4(%esp) ;\ + movl arg1, (%esp) ;\ + call EXT(fn) ;\ + movl %esi, %esp + +/* This variant exists to permit adjustment of the stack by "dtrace" */ +#define CCALL1WITHSP(fn, arg1) \ + movl %esp, %esi ;\ + subl $12, %esp ;\ + andl $0xFFFFFFF0, %esp ;\ + movl %esi, 8(%esp) ;\ + leal 8(%esp), %esi ;\ + movl %esi, 4(%esp) ;\ + movl arg1, (%esp) ;\ + call EXT(fn) ;\ + movl 8(%esp), %esp + +/* + * CCALL5 is used for callee functions with 3 arguments but + * where arg2 (a3:a2) and arg3 (a5:a4) are 64-bit values. + */ +#define CCALL5(fn, a1, a2, a3, a4, a5) \ + movl %esp, %esi ;\ + subl $20, %esp ;\ + andl $0xFFFFFFF0, %esp ;\ + movl a5, 16(%esp) ;\ + movl a4, 12(%esp) ;\ + movl a3, 8(%esp) ;\ + movl a2, 4(%esp) ;\ + movl a1, (%esp) ;\ + call EXT(fn) ;\ + movl %esi, %esp + +#elif defined(__x86_64__) + +/* This variant exists to permit adjustment of the stack by "dtrace" */ +#define CCALLWITHSP(fn) \ + mov %rsp, %r12 ;\ + sub $8, %rsp ;\ + and $0xFFFFFFFFFFFFFFF0, %rsp ;\ + mov %r12, (%rsp) ;\ + leaq (%rsp), %rsi ;\ + call EXT(fn) ;\ + mov (%rsp), %rsp + +#define CCALL(fn) \ + mov %rsp, %r12 ;\ + and $0xFFFFFFFFFFFFFFF0, %rsp ;\ + call EXT(fn) ;\ + mov %r12, %rsp + +#define CCALL1(fn, arg1) \ + mov arg1, %rdi ;\ + CCALL(fn) + +#define CCALL2(fn, arg1, arg2) \ + mov arg1, %rdi ;\ + CCALL(fn) + +#define CCALL3(fn, arg1, arg2, arg3) \ + mov arg1, %rdi ;\ + mov arg2, %rsi ;\ + mov arg3, %rdx ;\ + CCALL(fn) + +#else +#error unsupported architecture +#endif + +#endif /* _I386_ASM_H_ */ diff --git a/src/openlibm/i387/s_ceil.S b/src/openlibm/i387/s_ceil.S new file mode 100644 index 0000000..80de70a --- /dev/null +++ b/src/openlibm/i387/s_ceil.S @@ -0,0 +1,34 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include + +ENTRY(ceil) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0800,%dx /* round towards +oo */ + andw $0xfbff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldl 8(%ebp); /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(ceil) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_ceilf.S b/src/openlibm/i387/s_ceilf.S new file mode 100644 index 0000000..7ea898a --- /dev/null +++ b/src/openlibm/i387/s_ceilf.S @@ -0,0 +1,36 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_ceilf.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_ceilf.S,v 1.3 1995/05/08 23:52:44 jtc Exp $") */ + +ENTRY(ceilf) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0800,%dx /* round towards +oo */ + andw $0xfbff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + flds 8(%ebp); /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(ceilf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_ceill.S b/src/openlibm/i387/s_ceill.S new file mode 100644 index 0000000..838edd1 --- /dev/null +++ b/src/openlibm/i387/s_ceill.S @@ -0,0 +1,34 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_ceill.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(ceill) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0800,%dx /* round towards +oo */ + andw $0xfbff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldt 8(%ebp) /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(ceill) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_copysign.S b/src/openlibm/i387/s_copysign.S new file mode 100644 index 0000000..4386747 --- /dev/null +++ b/src/openlibm/i387/s_copysign.S @@ -0,0 +1,25 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysign.S,v 1.9 2011/01/07 16:13:12 kib Exp $") + +ENTRY(copysign) + movl 16(%esp),%edx + andl $0x80000000,%edx + movl 8(%esp),%eax + andl $0x7fffffff,%eax + orl %edx,%eax + movl %eax,8(%esp) + fldl 4(%esp) + ret +END(copysign) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_copysignf.S b/src/openlibm/i387/s_copysignf.S new file mode 100644 index 0000000..5d0169b --- /dev/null +++ b/src/openlibm/i387/s_copysignf.S @@ -0,0 +1,26 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysignf.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_copysignf.S,v 1.3 1995/05/08 23:53:25 jtc Exp $") */ + +ENTRY(copysignf) + movl 8(%esp),%edx + andl $0x80000000,%edx + movl 4(%esp),%eax + andl $0x7fffffff,%eax + orl %edx,%eax + movl %eax,4(%esp) + flds 4(%esp) + ret +END(copysignf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_copysignl.S b/src/openlibm/i387/s_copysignl.S new file mode 100644 index 0000000..1a9a06a --- /dev/null +++ b/src/openlibm/i387/s_copysignl.S @@ -0,0 +1,24 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_copysignl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(copysignl) + movl 24(%esp),%edx + andl $0x8000,%edx + movl 12(%esp),%eax + andl $0x7fff,%eax + orl %edx,%eax + movl %eax,12(%esp) + fldt 4(%esp) + ret +END(copysignl) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_cos.S b/src/openlibm/i387/s_cos.S new file mode 100644 index 0000000..4e29ec3 --- /dev/null +++ b/src/openlibm/i387/s_cos.S @@ -0,0 +1,33 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_cos.S,v 1.9 2011/01/07 16:13:12 kib Exp $") + +ENTRY(cos) + fldl 4(%esp) + fcos + fnstsw %ax + andw $0x400,%ax + jnz 1f + ret +1: fldpi + fadd %st(0) + fxch %st(1) +2: fprem1 + fnstsw %ax + andw $0x400,%ax + jnz 2b + fstp %st(1) + fcos + ret +END(cos) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_floor.S b/src/openlibm/i387/s_floor.S new file mode 100644 index 0000000..13097eb --- /dev/null +++ b/src/openlibm/i387/s_floor.S @@ -0,0 +1,35 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floor.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(floor) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0400,%dx /* round towards -oo */ + andw $0xf7ff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldl 8(%ebp); /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(floor) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_floorf.S b/src/openlibm/i387/s_floorf.S new file mode 100644 index 0000000..c3a4e09 --- /dev/null +++ b/src/openlibm/i387/s_floorf.S @@ -0,0 +1,36 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floorf.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_floorf.S,v 1.3 1995/05/09 00:04:32 jtc Exp $") */ + +ENTRY(floorf) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0400,%dx /* round towards -oo */ + andw $0xf7ff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + flds 8(%ebp); /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(floorf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_floorl.S b/src/openlibm/i387/s_floorl.S new file mode 100644 index 0000000..949116f --- /dev/null +++ b/src/openlibm/i387/s_floorl.S @@ -0,0 +1,34 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_floorl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(floorl) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0400,%dx /* round towards -oo */ + andw $0xf7ff,%dx + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldt 8(%ebp) /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(floorl) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_llrint.S b/src/openlibm/i387/s_llrint.S new file mode 100644 index 0000000..97c292e --- /dev/null +++ b/src/openlibm/i387/s_llrint.S @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(llrint) + fldl 4(%esp) + subl $8,%esp + fistpll (%esp) + popl %eax + popl %edx + ret +END(llrint) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_llrintf.S b/src/openlibm/i387/s_llrintf.S new file mode 100644 index 0000000..447e77a --- /dev/null +++ b/src/openlibm/i387/s_llrintf.S @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(llrintf) + flds 4(%esp) + subl $8,%esp + fistpll (%esp) + popl %eax + popl %edx + ret +END(llrintf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_llrintl.S b/src/openlibm/i387/s_llrintl.S new file mode 100644 index 0000000..ad6a7c9 --- /dev/null +++ b/src/openlibm/i387/s_llrintl.S @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_llrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(llrintl) + fldt 4(%esp) + subl $8,%esp + fistpll (%esp) + popl %eax + popl %edx + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_logb.S b/src/openlibm/i387/s_logb.S new file mode 100644 index 0000000..d0fc5d6 --- /dev/null +++ b/src/openlibm/i387/s_logb.S @@ -0,0 +1,21 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logb.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(logb) + fldl 4(%esp) + fxtract + fstp %st + ret +END(logb) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_logbf.S b/src/openlibm/i387/s_logbf.S new file mode 100644 index 0000000..3e3568c --- /dev/null +++ b/src/openlibm/i387/s_logbf.S @@ -0,0 +1,22 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logbf.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_logbf.S,v 1.3 1995/05/09 00:15:12 jtc Exp $") */ + +ENTRY(logbf) + flds 4(%esp) + fxtract + fstp %st + ret +END(logbf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_logbl.S b/src/openlibm/i387/s_logbl.S new file mode 100644 index 0000000..6d2de64 --- /dev/null +++ b/src/openlibm/i387/s_logbl.S @@ -0,0 +1,20 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_logbl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(logbl) + fldt 4(%esp) + fxtract + fstp %st + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_lrint.S b/src/openlibm/i387/s_lrint.S new file mode 100644 index 0000000..1e12539 --- /dev/null +++ b/src/openlibm/i387/s_lrint.S @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrint.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(lrint) + fldl 4(%esp) + subl $4,%esp + fistpl (%esp) + popl %eax + ret +END(lrint) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_lrintf.S b/src/openlibm/i387/s_lrintf.S new file mode 100644 index 0000000..b588c1a --- /dev/null +++ b/src/openlibm/i387/s_lrintf.S @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(lrintf) + flds 4(%esp) + subl $4,%esp + fistpl (%esp) + popl %eax + ret +END(lrintf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_lrintl.S b/src/openlibm/i387/s_lrintl.S new file mode 100644 index 0000000..94cc6cb --- /dev/null +++ b/src/openlibm/i387/s_lrintl.S @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_lrintl.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(lrintl) + fldt 4(%esp) + subl $4,%esp + fistpl (%esp) + popl %eax + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_remquo.S b/src/openlibm/i387/s_remquo.S new file mode 100644 index 0000000..78a588d --- /dev/null +++ b/src/openlibm/i387/s_remquo.S @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquo.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquo) + fldl 12(%esp) + fldl 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl 16(%esp),%ecx + xorl 8(%esp),%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ + movl 20(%esp),%ecx + movl %eax,(%ecx) + ret +END(remquo) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_remquof.S b/src/openlibm/i387/s_remquof.S new file mode 100644 index 0000000..8f532c3 --- /dev/null +++ b/src/openlibm/i387/s_remquof.S @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquof.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquof) + flds 8(%esp) + flds 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl 8(%esp),%ecx + xorl 4(%esp),%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ + movl 12(%esp),%ecx + movl %eax,(%ecx) + ret +END(remquof) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_remquol.S b/src/openlibm/i387/s_remquol.S new file mode 100644 index 0000000..b89563c --- /dev/null +++ b/src/openlibm/i387/s_remquol.S @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Based on public-domain remainder routine by J.T. Conklin . + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_remquol.S,v 1.2 2011/01/07 16:13:12 kib Exp $"); + +ENTRY(remquol) + fldt 16(%esp) + fldt 4(%esp) +1: fprem1 + fstsw %ax + sahf + jp 1b + fstp %st(1) +/* Extract the three low-order bits of the quotient from C0,C3,C1. */ + shrl $6,%eax + movl %eax,%ecx + andl $0x108,%eax + rorl $7,%eax + orl %eax,%ecx + roll $4,%eax + orl %ecx,%eax + andl $7,%eax +/* Negate the quotient bits if x*y<0. Avoid using an unpredictable branch. */ + movl 24(%esp),%ecx + xorl 12(%esp),%ecx + movsx %cx,%ecx + sarl $16,%ecx + sarl $16,%ecx + xorl %ecx,%eax + andl $1,%ecx + addl %ecx,%eax +/* Store the quotient and return. */ + movl 28(%esp),%ecx + movl %eax,(%ecx) + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_rint.S b/src/openlibm/i387/s_rint.S new file mode 100644 index 0000000..a8109cd --- /dev/null +++ b/src/openlibm/i387/s_rint.S @@ -0,0 +1,20 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rint.S,v 1.9 2011/01/07 16:13:12 kib Exp $") + +ENTRY(rint) + fldl 4(%esp) + frndint + ret +END(rint) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_rintf.S b/src/openlibm/i387/s_rintf.S new file mode 100644 index 0000000..184a16f --- /dev/null +++ b/src/openlibm/i387/s_rintf.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rintf.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_rintf.S,v 1.3 1995/05/09 00:17:22 jtc Exp $") */ + +ENTRY(rintf) + flds 4(%esp) + frndint + ret +END(rintf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_rintl.S b/src/openlibm/i387/s_rintl.S new file mode 100644 index 0000000..8727322 --- /dev/null +++ b/src/openlibm/i387/s_rintl.S @@ -0,0 +1,19 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_rintl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(rintl) + fldt 4(%esp) + frndint + ret + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_scalbn.S b/src/openlibm/i387/s_scalbn.S new file mode 100644 index 0000000..d690ff1 --- /dev/null +++ b/src/openlibm/i387/s_scalbn.S @@ -0,0 +1,23 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbn.S,v 1.10 2011/01/07 16:13:12 kib Exp $") + +ENTRY(scalbn) + fildl 12(%esp) + fldl 4(%esp) + fscale + fstp %st(1) + ret +END(scalbn) + +.globl CNAME(ldexp) +.set CNAME(ldexp),CNAME(scalbn) +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_scalbnf.S b/src/openlibm/i387/s_scalbnf.S new file mode 100644 index 0000000..7f4a2bc --- /dev/null +++ b/src/openlibm/i387/s_scalbnf.S @@ -0,0 +1,26 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbnf.S,v 1.4 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */ + +ENTRY(scalbnf) + fildl 8(%esp) + flds 4(%esp) + fscale + fstp %st(1) /* bug fix for fp stack overflow */ + ret +END(scalbnf) + +.globl CNAME(ldexpf) +.set CNAME(ldexpf),CNAME(scalbnf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_scalbnl.S b/src/openlibm/i387/s_scalbnl.S new file mode 100644 index 0000000..5d359eb --- /dev/null +++ b/src/openlibm/i387/s_scalbnl.S @@ -0,0 +1,26 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_scalbnl.S,v 1.3 2011/01/07 16:13:12 kib Exp $"); +/* RCSID("$NetBSD: s_scalbnf.S,v 1.4 1999/01/02 05:15:40 kristerw Exp $") */ + +ENTRY(scalbnl) + fildl 16(%esp) + fldt 4(%esp) + fscale + fstp %st(1) + ret +END(scalbnl) + +.globl CNAME(ldexpl) +.set CNAME(ldexpl),CNAME(scalbnl) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_sin.S b/src/openlibm/i387/s_sin.S new file mode 100644 index 0000000..6b71455 --- /dev/null +++ b/src/openlibm/i387/s_sin.S @@ -0,0 +1,33 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_sin.S,v 1.9 2011/01/07 16:13:12 kib Exp $") + +ENTRY(sin) + fldl 4(%esp) + fsin + fnstsw %ax + andw $0x400,%ax + jnz 1f + ret +1: fldpi + fadd %st(0) + fxch %st(1) +2: fprem1 + fnstsw %ax + andw $0x400,%ax + jnz 2b + fstp %st(1) + fsin + ret +END(sin) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_tan.S b/src/openlibm/i387/s_tan.S new file mode 100644 index 0000000..7b25c3a --- /dev/null +++ b/src/openlibm/i387/s_tan.S @@ -0,0 +1,35 @@ +/* + * Written by: + * J.T. Conklin (jtc@netbsd.org) + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_tan.S,v 1.9 2011/01/07 16:13:12 kib Exp $") + +ENTRY(tan) + fldl 4(%esp) + fptan + fnstsw %ax + andw $0x400,%ax + jnz 1f + fstp %st(0) + ret +1: fldpi + fadd %st(0) + fxch %st(1) +2: fprem1 + fstsw %ax + andw $0x400,%ax + jnz 2b + fstp %st(1) + fptan + fstp %st(0) + ret +END(tan) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_trunc.S b/src/openlibm/i387/s_trunc.S new file mode 100644 index 0000000..5422770 --- /dev/null +++ b/src/openlibm/i387/s_trunc.S @@ -0,0 +1,33 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_trunc.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(trunc) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0c00,%dx /* round towards -oo */ + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldl 8(%ebp) /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(trunc) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_truncf.S b/src/openlibm/i387/s_truncf.S new file mode 100644 index 0000000..c9d32bb --- /dev/null +++ b/src/openlibm/i387/s_truncf.S @@ -0,0 +1,33 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_truncf.S,v 1.4 2011/01/07 16:13:12 kib Exp $") + +ENTRY(truncf) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0c00,%dx /* round towards -oo */ + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + flds 8(%ebp) /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(truncf) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/i387/s_truncl.S b/src/openlibm/i387/s_truncl.S new file mode 100644 index 0000000..7152638 --- /dev/null +++ b/src/openlibm/i387/s_truncl.S @@ -0,0 +1,33 @@ +/* + * Based on code written by J.T. Conklin . + * Public domain. + */ + +#include +//__FBSDID("$FreeBSD: src/lib/msun/i387/s_truncl.S,v 1.3 2011/01/07 16:13:12 kib Exp $") + +ENTRY(truncl) + pushl %ebp + movl %esp,%ebp + subl $8,%esp + + fstcw -4(%ebp) /* store fpu control word */ + movw -4(%ebp),%dx + orw $0x0c00,%dx /* round towards -oo */ + movw %dx,-8(%ebp) + fldcw -8(%ebp) /* load modfied control word */ + + fldt 8(%ebp) /* round */ + frndint + + fldcw -4(%ebp) /* restore original control word */ + + leave + ret +END(truncl) + + +/* Enable stack protection */ +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/openlibm/include/openlibm.h b/src/openlibm/include/openlibm.h new file mode 100644 index 0000000..d851945 --- /dev/null +++ b/src/openlibm/include/openlibm.h @@ -0,0 +1,8 @@ +#ifndef OPENLIBM_H +#define OPENLIBM_H + +#include +#include +#include + +#endif /* !OPENLIBM_H */ diff --git a/src/openlibm/include/openlibm_complex.h b/src/openlibm/include/openlibm_complex.h new file mode 100644 index 0000000..7afc992 --- /dev/null +++ b/src/openlibm/include/openlibm_complex.h @@ -0,0 +1,179 @@ +/* $OpenBSD: complex.h,v 1.5 2014/03/16 18:38:30 guenther Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef OPENLIBM_USE_HOST_COMPLEX_H +#include +#else /* !OPENLIBM_USE_HOST_COMPLEX_H */ + +#ifndef OPENLIBM_COMPLEX_H +#define OPENLIBM_COMPLEX_H + +#define complex _Complex + +#define _Complex_I 1.0fi +#define I _Complex_I + +/* + * Macros that can be used to construct complex values. + * + * The C99 standard intends x+I*y to be used for this, but x+I*y is + * currently unusable in general since gcc introduces many overflow, + * underflow, sign and efficiency bugs by rewriting I*y as + * (0.0+I)*(y+0.0*I) and laboriously computing the full complex product. + * In particular, I*Inf is corrupted to NaN+I*Inf, and I*-0 is corrupted + * to -0.0+I*0.0. + * + * In C11, a CMPLX(x,y) macro was added to circumvent this limitation, + * and gcc 4.7 added a __builtin_complex feature to simplify implementation + * of CMPLX in libc, so we can take advantage of these features if they + * are available. Clang simply allows complex values to be constructed + * using a compound literal. + * + * If __builtin_complex is not available, resort to using inline + * functions instead. These can unfortunately not be used to construct + * compile-time constants. + * + * C99 specifies that complex numbers have the same representation as + * an array of two elements, where the first element is the real part + * and the second element is the imaginary part. + */ + +#ifdef __clang__ +# define CMPLXF(x, y) ((float complex){x, y}) +# define CMPLX(x, y) ((double complex){x, y}) +# define CMPLXL(x, y) ((long double complex){x, y}) +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__INTEL_COMPILER) +# define CMPLXF(x,y) __builtin_complex ((float) (x), (float) (y)) +# define CMPLX(x,y) __builtin_complex ((double) (x), (double) (y)) +# define CMPLXL(x,y) __builtin_complex ((long double) (x), (long double) (y)) +#else +static inline float complex +CMPLXF(float x, float y) +{ + union { + float a[2]; + float complex f; + } z = {{ x, y }}; + + return (z.f); +} + +static inline double complex +CMPLX(double x, double y) +{ + union { + double a[2]; + double complex f; + } z = {{ x, y }}; + + return (z.f); +} + +static inline long double complex +CMPLXL(long double x, long double y) +{ + union { + long double a[2]; + long double complex f; + } z = {{ x, y }}; + + return (z.f); +} +#endif + +/* + * Double versions of C99 functions + */ +double complex cacos(double complex); +double complex casin(double complex); +double complex catan(double complex); +double complex ccos(double complex); +double complex csin(double complex); +double complex ctan(double complex); +double complex cacosh(double complex); +double complex casinh(double complex); +double complex catanh(double complex); +double complex ccosh(double complex); +double complex csinh(double complex); +double complex ctanh(double complex); +double complex cexp(double complex); +double complex clog(double complex); +double cabs(double complex); +double complex cpow(double complex, double complex); +double complex csqrt(double complex); +double carg(double complex); +double cimag(double complex); +double complex conj(double complex); +double complex cproj(double complex); +double creal(double complex); + +/* + * Float versions of C99 functions + */ +float complex cacosf(float complex); +float complex casinf(float complex); +float complex catanf(float complex); +float complex ccosf(float complex); +float complex csinf(float complex); +float complex ctanf(float complex); +float complex cacoshf(float complex); +float complex casinhf(float complex); +float complex catanhf(float complex); +float complex ccoshf(float complex); +float complex csinhf(float complex); +float complex ctanhf(float complex); +float complex cexpf(float complex); +float complex clogf(float complex); +float cabsf(float complex); +float complex cpowf(float complex, float complex); +float complex csqrtf(float complex); +float cargf(float complex); +float cimagf(float complex); +float complex conjf(float complex); +float complex cprojf(float complex); +float crealf(float complex); + +/* + * Long double versions of C99 functions + */ +long double complex cacosl(long double complex); +long double complex casinl(long double complex); +long double complex catanl(long double complex); +long double complex ccosl(long double complex); +long double complex csinl(long double complex); +long double complex ctanl(long double complex); +long double complex cacoshl(long double complex); +long double complex casinhl(long double complex); +long double complex catanhl(long double complex); +long double complex ccoshl(long double complex); +long double complex csinhl(long double complex); +long double complex ctanhl(long double complex); +long double complex cexpl(long double complex); +long double complex clogl(long double complex); +long double cabsl(long double complex); +long double complex cpowl(long double complex, + long double complex); +long double complex csqrtl(long double complex); +long double cargl(long double complex); +long double cimagl(long double complex); +long double complex conjl(long double complex); +long double complex cprojl(long double complex); +long double creall(long double complex); + +#endif /* !OPENLIBM_COMPLEX_H */ + +#endif /* OPENLIBM_USE_HOST_COMPLEX_H */ diff --git a/src/openlibm/include/openlibm_defs.h b/src/openlibm/include/openlibm_defs.h new file mode 100644 index 0000000..8a6fa6b --- /dev/null +++ b/src/openlibm/include/openlibm_defs.h @@ -0,0 +1,14 @@ +#ifndef OPENLIBM_DEFS_H_ +#define OPENLIBM_DEFS_H_ + +#ifdef _WIN32 +# ifdef IMPORT_EXPORTS +# define OLM_DLLEXPORT __declspec(dllimport) +# else +# define OLM_DLLEXPORT __declspec(dllexport) +# endif +#else +#define OLM_DLLEXPORT __attribute__ ((visibility("default"))) +#endif + +#endif // OPENLIBM_DEFS_H_ diff --git a/src/openlibm/include/openlibm_fenv.h b/src/openlibm/include/openlibm_fenv.h new file mode 100644 index 0000000..35a5586 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv.h @@ -0,0 +1,27 @@ +#ifdef OPENLIBM_USE_HOST_FENV_H +#include +#else /* !OPENLIBM_USE_HOST_FENV_H */ + +#if defined(__aarch64__) +#include +#elif defined(__arm__) +#include +#elif defined(__x86_64__) +#include +#elif defined(__i386__) +#include +#elif defined(__powerpc__) || defined(__POWERPC__) +#include +#elif defined(__mips__) +#include +#elif defined(__s390__) +#include +#elif defined(__riscv) +#include +#elif defined(__loongarch64) +#include +#else +#error "Unsupported platform" +#endif + +#endif /* OPENLIBM_USE_HOST_FENV_H */ diff --git a/src/openlibm/include/openlibm_fenv_aarch64.h b/src/openlibm/include/openlibm_fenv_aarch64.h new file mode 100644 index 0000000..5cf0e49 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_aarch64.h @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include + +#include "cdefs-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +/* The high 32 bits contain fpcr, low 32 contain fpsr. */ +typedef uint64_t fenv_t; +typedef uint64_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x00000001 +#define FE_DIVBYZERO 0x00000002 +#define FE_OVERFLOW 0x00000004 +#define FE_UNDERFLOW 0x00000008 +#define FE_INEXACT 0x00000010 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* + * Rounding modes + * + * We can't just use the hardware bit values here, because that would + * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed. + */ +#define FE_TONEAREST 0x0 +#define FE_UPWARD 0x1 +#define FE_DOWNWARD 0x2 +#define FE_TOWARDZERO 0x3 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) +#define _ROUND_SHIFT 22 + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +/* We need to be able to map status flag positions to mask flag positions */ +#define _FPUSW_SHIFT 8 +#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) + +#define __mrs_fpcr(__r) __asm __volatile("mrs %0, fpcr" : "=r" (__r)) +#define __msr_fpcr(__r) __asm __volatile("msr fpcr, %0" : : "r" (__r)) + +#define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r)) +#define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r)) + + +__fenv_static inline int +feclearexcept(int __excepts) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + __r &= ~__excepts; + __msr_fpsr(__r); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + *__flagp = __r & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + __r &= ~__excepts; + __r |= *__flagp & __excepts; + __msr_fpsr(__r); + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + __r |= __excepts; + __msr_fpsr(__r); + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + return (__r & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + fenv_t __r; + + __mrs_fpcr(__r); + return ((__r >> _ROUND_SHIFT) & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + fenv_t __r; + + if (__round & ~_ROUND_MASK) + return (-1); + __mrs_fpcr(__r); + __r &= ~(_ROUND_MASK << _ROUND_SHIFT); + __r |= __round << _ROUND_SHIFT; + __msr_fpcr(__r); + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + uint64_t fpcr; + uint64_t fpsr; + + __mrs_fpcr(fpcr); + __mrs_fpsr(fpsr); + *__envp = fpsr | (fpcr << 32); + + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fenv_t __r; + + __mrs_fpcr(__r); + *__envp = __r << 32; + __r &= ~(_ENABLE_MASK); + __msr_fpcr(__r); + + __mrs_fpsr(__r); + *__envp |= (uint32_t)__r; + __r &= ~(_ENABLE_MASK); + __msr_fpsr(__r); + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __msr_fpcr((*__envp) >> 32); + __msr_fpsr((fenv_t)(uint32_t)*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t __r; + + __mrs_fpsr(__r); + fesetenv(__envp); + feraiseexcept(__r & FE_ALL_EXCEPT); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +static inline int +feenableexcept(int __mask) +{ + fenv_t __old_r, __new_r; + + __mrs_fpcr(__old_r); + __new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); + __msr_fpcr(__new_r); + return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fedisableexcept(int __mask) +{ + fenv_t __old_r, __new_r; + + __mrs_fpcr(__old_r); + __new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); + __msr_fpcr(__new_r); + return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fegetexcept(void) +{ + fenv_t __r; + + __mrs_fpcr(__r); + return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_amd64.h b/src/openlibm/include/openlibm_fenv_amd64.h new file mode 100644 index 0000000..c6db210 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_amd64.h @@ -0,0 +1,223 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/amd64/fenv.h,v 1.8 2011/10/10 15:43:09 das Exp $ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include +#include "cdefs-compat.h" +#include "types-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef struct { + struct { + uint32_t __control; + uint32_t __status; + uint32_t __tag; + char __other[16]; + } __x87; + uint32_t __mxcsr; +} fenv_t; + +typedef uint16_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_DOWNWARD 0x0400 +#define FE_UPWARD 0x0800 +#define FE_TOWARDZERO 0x0c00 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +/* + * As compared to the x87 control word, the SSE unit's control word + * has the rounding control bits offset by 3 and the exception mask + * bits offset by 7. + */ +#define _SSE_ROUND_SHIFT 3 +#define _SSE_EMASK_SHIFT 7 + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +#define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw)) +#define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env)) +#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \ + : "st", "st(1)", "st(2)", "st(3)", "st(4)", \ + "st(5)", "st(6)", "st(7)") +#define __fnclex() __asm __volatile("fnclex") +#define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env))) +#define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw))) +#define __fnstsw(__sw) __asm __volatile("fnstsw %0" : "=am" (*(__sw))) +#define __fwait() __asm __volatile("fwait") +#define __ldmxcsr(__csr) __asm __volatile("ldmxcsr %0" : : "m" (__csr)) +#define __stmxcsr(__csr) __asm __volatile("stmxcsr %0" : "=m" (*(__csr))) + +__fenv_static __attribute__((always_inline)) inline int +feclearexcept(int __excepts) +{ + fenv_t __env; + + if (__excepts == FE_ALL_EXCEPT) { + __fnclex(); + } else { + __fnstenv(&__env.__x87); + __env.__x87.__status &= ~__excepts; + __fldenv(__env.__x87); + } + __stmxcsr(&__env.__mxcsr); + __env.__mxcsr &= ~__excepts; + __ldmxcsr(__env.__mxcsr); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + uint32_t __mxcsr; + uint16_t __status; + + __stmxcsr(&__mxcsr); + __fnstsw(&__status); + *__flagp = (__mxcsr | __status) & __excepts; + return (0); +} + +OLM_DLLEXPORT int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +OLM_DLLEXPORT int feraiseexcept(int __excepts); + +__fenv_static __attribute__((always_inline)) inline int +fetestexcept(int __excepts) +{ + uint32_t __mxcsr; + uint16_t __status; + + __stmxcsr(&__mxcsr); + __fnstsw(&__status); + return ((__status | __mxcsr) & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + uint16_t __control; + + /* + * We assume that the x87 and the SSE unit agree on the + * rounding mode. Reading the control word on the x87 turns + * out to be about 5 times faster than reading it on the SSE + * unit on an Opteron 244. + */ + __fnstcw(&__control); + return (__control & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + uint32_t __mxcsr; + uint16_t __control; + + if (__round & ~_ROUND_MASK) + return (-1); + + __fnstcw(&__control); + __control &= ~_ROUND_MASK; + __control |= __round; + __fldcw(__control); + + __stmxcsr(&__mxcsr); + __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT); + __mxcsr |= __round << _SSE_ROUND_SHIFT; + __ldmxcsr(__mxcsr); + + return (0); +} + +OLM_DLLEXPORT int fegetenv(fenv_t *__envp); +OLM_DLLEXPORT int feholdexcept(fenv_t *__envp); + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + /* + * XXX Using fldenvx() instead of fldenv() tells the compiler that this + * instruction clobbers the i387 register stack. This happens because + * we restore the tag word from the saved environment. Normally, this + * would happen anyway and we wouldn't care, because the ABI allows + * function calls to clobber the i387 regs. However, fesetenv() is + * inlined, so we need to be more careful. + */ + __fldenvx(__envp->__x87); + __ldmxcsr(__envp->__mxcsr); + return (0); +} + +OLM_DLLEXPORT int feupdateenv(const fenv_t *__envp); + +#if __BSD_VISIBLE + +OLM_DLLEXPORT int feenableexcept(int __mask); +OLM_DLLEXPORT int fedisableexcept(int __mask); + +/* We currently provide no external definition of fegetexcept(). */ +static inline int +fegetexcept(void) +{ + uint16_t __control; + + /* + * We assume that the masks for the x87 and the SSE unit are + * the same. + */ + __fnstcw(&__control); + return (~__control & FE_ALL_EXCEPT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_arm.h b/src/openlibm/include/openlibm_fenv_arm.h new file mode 100644 index 0000000..8223a01 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_arm.h @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/arm/fenv.h,v 1.6 2011/10/10 15:43:09 das Exp $ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include + +#include "cdefs-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef uint32_t fenv_t; +typedef uint32_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x0001 +#define FE_DIVBYZERO 0x0002 +#define FE_OVERFLOW 0x0004 +#define FE_UNDERFLOW 0x0008 +#define FE_INEXACT 0x0010 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_TOWARDZERO 0x0001 +#define FE_UPWARD 0x0002 +#define FE_DOWNWARD 0x0003 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +/* We need to be able to map status flag positions to mask flag positions */ +#define _FPUSW_SHIFT 16 +#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT) + +/* Test for hardware support for ARM floating point operations, explicitly +checking for float and double support, see "ARM C Language Extensions", 6.5.1 */ +#if defined(__ARM_FP) && (__ARM_FP & 0x0C) != 0 +#define __rfs(__fpsr) __asm __volatile("vmrs %0,fpscr" : "=&r" (*(__fpsr))) +#define __wfs(__fpsr) __asm __volatile("vmsr fpscr,%0" : : "r" (__fpsr)) +#else +#define __rfs(__fpsr) (*(__fpsr) = 0) +#define __wfs(__fpsr) +#endif + +__fenv_static inline int +feclearexcept(int __excepts) +{ + fexcept_t __fpsr; + + __rfs(&__fpsr); + __fpsr &= ~__excepts; + __wfs(__fpsr); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fpsr; + + __rfs(&__fpsr); + *__flagp = __fpsr & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fpsr; + + __rfs(&__fpsr); + __fpsr &= ~__excepts; + __fpsr |= *__flagp & __excepts; + __wfs(__fpsr); + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + fexcept_t __ex = __excepts; + + fesetexceptflag(&__ex, __excepts); /* XXX */ + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t __fpsr; + + __rfs(&__fpsr); + return (__fpsr & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + + /* + * Apparently, the rounding mode is specified as part of the + * instruction format on ARM, so the dynamic rounding mode is + * indeterminate. Some FPUs may differ. + */ + return (-1); +} + +__fenv_static inline int +fesetround(int __round) +{ + + return (-1); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + + __rfs(__envp); + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fenv_t __env; + + __rfs(&__env); + *__envp = __env; + __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); + __wfs(__env); + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __wfs(*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t __fpsr; + + __rfs(&__fpsr); + __wfs(*__envp); + feraiseexcept(__fpsr & FE_ALL_EXCEPT); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +static inline int +feenableexcept(int __mask) +{ + fenv_t __old_fpsr, __new_fpsr; + + __rfs(&__old_fpsr); + __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT; + __wfs(__new_fpsr); + return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fedisableexcept(int __mask) +{ + fenv_t __old_fpsr, __new_fpsr; + + __rfs(&__old_fpsr); + __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT); + __wfs(__new_fpsr); + return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fegetexcept(void) +{ + fenv_t __fpsr; + + __rfs(&__fpsr); + return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_i387.h b/src/openlibm/include/openlibm_fenv_i387.h new file mode 100644 index 0000000..ec4eb87 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_i387.h @@ -0,0 +1,260 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/i387/fenv.h,v 1.8 2011/10/10 15:43:09 das Exp $ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include "openlibm_defs.h" +#include "cdefs-compat.h" +#include "types-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +/* + * To preserve binary compatibility with FreeBSD 5.3, we pack the + * mxcsr into some reserved fields, rather than changing sizeof(fenv_t). + */ +typedef struct { + uint16_t __control; + uint16_t __mxcsr_hi; + uint16_t __status; + uint16_t __mxcsr_lo; + uint32_t __tag; + char __other[16]; +} fenv_t; + +#define __get_mxcsr(env) (((env).__mxcsr_hi << 16) | \ + ((env).__mxcsr_lo)) +#define __set_mxcsr(env, x) do { \ + (env).__mxcsr_hi = (uint32_t)(x) >> 16; \ + (env).__mxcsr_lo = (uint16_t)(x); \ +} while (0) + +typedef uint16_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_DOWNWARD 0x0400 +#define FE_UPWARD 0x0800 +#define FE_TOWARDZERO 0x0c00 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +/* + * As compared to the x87 control word, the SSE unit's control word + * has the rounding control bits offset by 3 and the exception mask + * bits offset by 7. + */ +#define _SSE_ROUND_SHIFT 3 +#define _SSE_EMASK_SHIFT 7 + +__BEGIN_DECLS + +/* After testing for SSE support once, we cache the result in __has_sse. */ +enum __sse_support { __SSE_YES, __SSE_NO, __SSE_UNK }; +OLM_DLLEXPORT extern enum __sse_support __has_sse; +OLM_DLLEXPORT int __test_sse(void); +#ifdef __SSE__ +#define __HAS_SSE() 1 +#else +#define __HAS_SSE() (__has_sse == __SSE_YES || \ + (__has_sse == __SSE_UNK && __test_sse())) +#endif + +/* Default floating-point environment */ +OLM_DLLEXPORT extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +#define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw)) +#define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env)) +#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \ + : "st", "st(1)", "st(2)", "st(3)", "st(4)", \ + "st(5)", "st(6)", "st(7)") +#define __fnclex() __asm __volatile("fnclex") +#define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env))) +#define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw))) +#define __fnstsw(__sw) __asm __volatile("fnstsw %0" : "=am" (*(__sw))) +#define __fwait() __asm __volatile("fwait") +#define __ldmxcsr(__csr) __asm __volatile("ldmxcsr %0" : : "m" (__csr)) +#define __stmxcsr(__csr) __asm __volatile("stmxcsr %0" : "=m" (*(__csr))) + +__fenv_static inline int +feclearexcept(int __excepts) +{ + fenv_t __env; + uint32_t __mxcsr; + + if (__excepts == FE_ALL_EXCEPT) { + __fnclex(); + } else { + __fnstenv(&__env); + __env.__status &= ~__excepts; + __fldenv(__env); + } + if (__HAS_SSE()) { + __stmxcsr(&__mxcsr); + __mxcsr &= ~__excepts; + __ldmxcsr(__mxcsr); + } + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + uint32_t __mxcsr; + uint16_t __status; + + __fnstsw(&__status); + if (__HAS_SSE()) + __stmxcsr(&__mxcsr); + else + __mxcsr = 0; + *__flagp = (__mxcsr | __status) & __excepts; + return (0); +} + +OLM_DLLEXPORT int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +OLM_DLLEXPORT int feraiseexcept(int __excepts); + +__fenv_static inline int +fetestexcept(int __excepts) +{ + uint32_t __mxcsr; + uint16_t __status; + + __fnstsw(&__status); + if (__HAS_SSE()) + __stmxcsr(&__mxcsr); + else + __mxcsr = 0; + return ((__status | __mxcsr) & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + uint16_t __control; + + /* + * We assume that the x87 and the SSE unit agree on the + * rounding mode. Reading the control word on the x87 turns + * out to be about 5 times faster than reading it on the SSE + * unit on an Opteron 244. + */ + __fnstcw(&__control); + return (__control & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + uint32_t __mxcsr; + uint16_t __control; + + if (__round & ~_ROUND_MASK) + return (-1); + + __fnstcw(&__control); + __control &= ~_ROUND_MASK; + __control |= __round; + __fldcw(__control); + + if (__HAS_SSE()) { + __stmxcsr(&__mxcsr); + __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT); + __mxcsr |= __round << _SSE_ROUND_SHIFT; + __ldmxcsr(__mxcsr); + } + + return (0); +} + +OLM_DLLEXPORT int fegetenv(fenv_t *__envp); +OLM_DLLEXPORT int feholdexcept(fenv_t *__envp); + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + fenv_t __env = *__envp; + uint32_t __mxcsr; + + __mxcsr = __get_mxcsr(__env); + __set_mxcsr(__env, 0xffffffff); + /* + * XXX Using fldenvx() instead of fldenv() tells the compiler that this + * instruction clobbers the i387 register stack. This happens because + * we restore the tag word from the saved environment. Normally, this + * would happen anyway and we wouldn't care, because the ABI allows + * function calls to clobber the i387 regs. However, fesetenv() is + * inlined, so we need to be more careful. + */ + __fldenvx(__env); + if (__HAS_SSE()) + __ldmxcsr(__mxcsr); + return (0); +} + +OLM_DLLEXPORT int feupdateenv(const fenv_t *__envp); + +#if __BSD_VISIBLE + +OLM_DLLEXPORT int feenableexcept(int __mask); +OLM_DLLEXPORT int fedisableexcept(int __mask); + +/* We currently provide no external definition of fegetexcept(). */ +static inline int +fegetexcept(void) +{ + uint16_t __control; + + /* + * We assume that the masks for the x87 and the SSE unit are + * the same. + */ + __fnstcw(&__control); + return (~__control & FE_ALL_EXCEPT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_loongarch64.h b/src/openlibm/include/openlibm_fenv_loongarch64.h new file mode 100644 index 0000000..cfaf020 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_loongarch64.h @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2023 Yifan An + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include +#include "cdefs-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef uint32_t fenv_t; +typedef uint32_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x100000 +#define FE_DIVBYZERO 0x080000 +#define FE_OVERFLOW 0x040000 +#define FE_UNDERFLOW 0x020000 +#define FE_INEXACT 0x010000 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_TOWARDZERO 0x0100 +#define FE_DOWNWARD 0x0200 +#define FE_UPWARD 0x0300 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +#define _FPU_MASK_V 0x10 +#define _FPU_MASK_Z 0x08 +#define _FPU_MASK_O 0x04 +#define _FPU_MASK_U 0x02 +#define _FPU_MASK_I 0x01 + +#define _FPUSW_SHIFT 16 +#define _ENABLE_MASK (_FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O | _FPU_MASK_U | _FPU_MASK_I) + +#define __rfs(__fpsr) __asm __volatile("movfcsr2gr %0,$r0" : "=r"(__fpsr)) +#define __wfs(__fpsr) __asm __volatile("movgr2fcsr $r0,%0" : : "r"(__fpsr)) + +__fenv_static inline int +feclearexcept(int __excepts) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + __fpsr &= ~__excepts; + __wfs(__fpsr); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + *__flagp = __fpsr & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + __fpsr &= ~__excepts; + __fpsr |= *__flagp & __excepts; + __wfs(__fpsr); + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + fexcept_t __ex = __excepts; + + fesetexceptflag(&__ex, __excepts); /* XXX */ + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + return (__fpsr & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + return __fpsr & _ROUND_MASK; +} + +__fenv_static inline int +fesetround(int __round) +{ + fexcept_t __fpsr; + if ((__round & ~_ROUND_MASK) != 0) + return 1; + + __rfs(__fpsr); + __fpsr &= ~_ROUND_MASK; + __fpsr |= __round; + __wfs(__fpsr); + + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + __rfs(*__envp); + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fenv_t __env; + + __rfs(__env); + *__envp = __env; + __env &= ~(FE_ALL_EXCEPT | _FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O | _FPU_MASK_U | _FPU_MASK_I); + __wfs(__env); + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + __wfs(*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t __fpsr; + + __rfs(__fpsr); + __wfs(*__envp); + feraiseexcept(__fpsr & FE_ALL_EXCEPT); + return (0); +} + +#if __BSD_VISIBLE + +static inline int +feenableexcept(int __mask) +{ + fenv_t __old_fpsr, __new_fpsr; + + __rfs(__new_fpsr); + __old_fpsr = (__new_fpsr & _ENABLE_MASK) << _FPUSW_SHIFT; + __new_fpsr |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT; + __wfs(__new_fpsr); + return __old_fpsr; +} + +static inline int +fedisableexcept(int __mask) +{ + fenv_t __old_fpsr, __new_fpsr; + + __rfs(__new_fpsr); + __old_fpsr = (__new_fpsr & _ENABLE_MASK) << _FPUSW_SHIFT; + __new_fpsr &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT); + __wfs(__new_fpsr); + return __old_fpsr; +} + +static inline int +fegetexcept(void) +{ + fenv_t __fpsr; + + __rfs(__fpsr); + return ((__fpsr & _ENABLE_MASK) << _FPUSW_SHIFT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ \ No newline at end of file diff --git a/src/openlibm/include/openlibm_fenv_mips.h b/src/openlibm/include/openlibm_fenv_mips.h new file mode 100644 index 0000000..980252f --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_mips.h @@ -0,0 +1,278 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include +#include "cdefs-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef uint32_t fenv_t; +typedef uint32_t fexcept_t; + +/* Exception flags */ +#ifdef __mips_soft_float +#define _FPUSW_SHIFT 16 +#define FE_INVALID 0x0001 +#define FE_DIVBYZERO 0x0002 +#define FE_OVERFLOW 0x0004 +#define FE_UNDERFLOW 0x0008 +#define FE_INEXACT 0x0010 +#else +#define _FCSR_CAUSE_SHIFT 10 +#define FE_INVALID 0x0040 +#define FE_DIVBYZERO 0x0020 +#define FE_OVERFLOW 0x0010 +#define FE_UNDERFLOW 0x0008 +#define FE_INEXACT 0x0004 +#endif +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_TOWARDZERO 0x0001 +#define FE_UPWARD 0x0002 +#define FE_DOWNWARD 0x0003 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +/* We need to be able to map status flag positions to mask flag positions */ +#define _ENABLE_SHIFT 5 +#define _ENABLE_MASK (FE_ALL_EXCEPT << _ENABLE_SHIFT) + +#ifndef __mips_soft_float +#define __cfc1(__fcsr) __asm __volatile("cfc1 %0, $31" : "=r" (__fcsr)) +#define __ctc1(__fcsr) __asm __volatile("ctc1 %0, $31" :: "r" (__fcsr)) +#endif + +#ifdef __mips_soft_float +int feclearexcept(int __excepts); +int fegetexceptflag(fexcept_t *__flagp, int __excepts); +int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +int feraiseexcept(int __excepts); +int fetestexcept(int __excepts); +int fegetround(void); +int fesetround(int __round); +int fegetenv(fenv_t *__envp); +int feholdexcept(fenv_t *__envp); +int fesetenv(const fenv_t *__envp); +int feupdateenv(const fenv_t *__envp); +#else +__fenv_static inline int +feclearexcept(int __excepts) +{ + fexcept_t fcsr; + + __excepts &= FE_ALL_EXCEPT; + __cfc1(fcsr); + fcsr &= ~(__excepts | (__excepts << _FCSR_CAUSE_SHIFT)); + __ctc1(fcsr); + + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t fcsr; + + __excepts &= FE_ALL_EXCEPT; + __cfc1(fcsr); + *__flagp = fcsr & __excepts; + + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t fcsr; + + __excepts &= FE_ALL_EXCEPT; + __cfc1(fcsr); + fcsr &= ~__excepts; + fcsr |= *__flagp & __excepts; + __ctc1(fcsr); + + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + fexcept_t fcsr; + + __excepts &= FE_ALL_EXCEPT; + __cfc1(fcsr); + fcsr |= __excepts | (__excepts << _FCSR_CAUSE_SHIFT); + __ctc1(fcsr); + + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t fcsr; + + __excepts &= FE_ALL_EXCEPT; + __cfc1(fcsr); + + return (fcsr & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + fexcept_t fcsr; + + __cfc1(fcsr); + + return (fcsr & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + fexcept_t fcsr; + + if (__round & ~_ROUND_MASK) + return (-1); + + __cfc1(fcsr); + fcsr &= ~_ROUND_MASK; + fcsr |= __round; + __ctc1(fcsr); + + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + + __cfc1(*__envp); + + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fexcept_t fcsr; + + __cfc1(fcsr); + *__envp = fcsr; + fcsr &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); + __ctc1(fcsr); + + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __ctc1(*__envp); + + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t fcsr; + + __cfc1(fcsr); + fesetenv(__envp); + feraiseexcept(fcsr); + + return (0); +} +#endif /* !__mips_soft_float */ + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +#ifdef __mips_soft_float +int feenableexcept(int __mask); +int fedisableexcept(int __mask); +int fegetexcept(void); +#else +static inline int +feenableexcept(int __mask) +{ + fenv_t __old_fcsr, __new_fcsr; + + __cfc1(__old_fcsr); + __new_fcsr = __old_fcsr | (__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT; + __ctc1(__new_fcsr); + + return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fedisableexcept(int __mask) +{ + fenv_t __old_fcsr, __new_fcsr; + + __cfc1(__old_fcsr); + __new_fcsr = __old_fcsr & ~((__mask & FE_ALL_EXCEPT) << _ENABLE_SHIFT); + __ctc1(__new_fcsr); + + return ((__old_fcsr >> _ENABLE_SHIFT) & FE_ALL_EXCEPT); +} + +static inline int +fegetexcept(void) +{ + fexcept_t fcsr; + + __cfc1(fcsr); + + return ((fcsr & _ENABLE_MASK) >> _ENABLE_SHIFT); +} + +#endif /* !__mips_soft_float */ + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_powerpc.h b/src/openlibm/include/openlibm_fenv_powerpc.h new file mode 100644 index 0000000..232ea83 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_powerpc.h @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef __uint32_t fenv_t; +typedef __uint32_t fexcept_t; + +/* Exception flags */ +#define FE_INEXACT 0x02000000 +#define FE_DIVBYZERO 0x04000000 +#define FE_UNDERFLOW 0x08000000 +#define FE_OVERFLOW 0x10000000 +#define FE_INVALID 0x20000000 /* all types of invalid FP ops */ + +/* + * The PowerPC architecture has extra invalid flags that indicate the + * specific type of invalid operation occurred. These flags may be + * tested, set, and cleared---but not masked---separately. All of + * these bits are cleared when FE_INVALID is cleared, but only + * FE_VXSOFT is set when FE_INVALID is explicitly set in software. + */ +#define FE_VXCVI 0x00000100 /* invalid integer convert */ +#define FE_VXSQRT 0x00000200 /* square root of a negative */ +#define FE_VXSOFT 0x00000400 /* software-requested exception */ +#define FE_VXVC 0x00080000 /* ordered comparison involving NaN */ +#define FE_VXIMZ 0x00100000 /* inf * 0 */ +#define FE_VXZDZ 0x00200000 /* 0 / 0 */ +#define FE_VXIDI 0x00400000 /* inf / inf */ +#define FE_VXISI 0x00800000 /* inf - inf */ +#define FE_VXSNAN 0x01000000 /* operation on a signalling NaN */ +#define FE_ALL_INVALID (FE_VXCVI | FE_VXSQRT | FE_VXSOFT | FE_VXVC | \ + FE_VXIMZ | FE_VXZDZ | FE_VXIDI | FE_VXISI | \ + FE_VXSNAN | FE_INVALID) +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_ALL_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_TOWARDZERO 0x0001 +#define FE_UPWARD 0x0002 +#define FE_DOWNWARD 0x0003 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +/* We need to be able to map status flag positions to mask flag positions */ +#define _FPUSW_SHIFT 22 +#define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ + FE_OVERFLOW | FE_UNDERFLOW) >> _FPUSW_SHIFT) + +#ifndef _SOFT_FLOAT +#define __mffs(__env) __asm __volatile("mffs %0" : "=f" (*(__env))) +#define __mtfsf(__env) __asm __volatile("mtfsf 255,%0" : : "f" (__env)) +#else +#define __mffs(__env) +#define __mtfsf(__env) +#endif + +union __fpscr { + double __d; + struct { +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + fenv_t __reg; + __uint32_t __junk; +#else + __uint32_t __junk; + fenv_t __reg; +#endif + } __bits; +}; + +__fenv_static inline int +feclearexcept(int __excepts) +{ + union __fpscr __r; + + if (__excepts & FE_INVALID) + __excepts |= FE_ALL_INVALID; + __mffs(&__r.__d); + __r.__bits.__reg &= ~__excepts; + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + union __fpscr __r; + + __mffs(&__r.__d); + *__flagp = __r.__bits.__reg & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + union __fpscr __r; + + if (__excepts & FE_INVALID) + __excepts |= FE_ALL_EXCEPT; + __mffs(&__r.__d); + __r.__bits.__reg &= ~__excepts; + __r.__bits.__reg |= *__flagp & __excepts; + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + union __fpscr __r; + + if (__excepts & FE_INVALID) + __excepts |= FE_VXSOFT; + __mffs(&__r.__d); + __r.__bits.__reg |= __excepts; + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + union __fpscr __r; + + __mffs(&__r.__d); + return (__r.__bits.__reg & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + union __fpscr __r; + + __mffs(&__r.__d); + return (__r.__bits.__reg & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + union __fpscr __r; + + if (__round & ~_ROUND_MASK) + return (-1); + __mffs(&__r.__d); + __r.__bits.__reg &= ~_ROUND_MASK; + __r.__bits.__reg |= __round; + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + union __fpscr __r; + + __mffs(&__r.__d); + *__envp = __r.__bits.__reg; + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + union __fpscr __r; + + __mffs(&__r.__d); + *__envp = __r.__d; + __r.__bits.__reg &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + union __fpscr __r; + + __r.__bits.__reg = *__envp; + __mtfsf(__r.__d); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + union __fpscr __r; + + __mffs(&__r.__d); + __r.__bits.__reg &= FE_ALL_EXCEPT; + __r.__bits.__reg |= *__envp; + __mtfsf(__r.__d); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +static inline int +feenableexcept(int __mask) +{ + union __fpscr __r; + fenv_t __oldmask; + + __mffs(&__r.__d); + __oldmask = __r.__bits.__reg; + __r.__bits.__reg |= (__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT; + __mtfsf(__r.__d); + return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT); +} + +static inline int +fedisableexcept(int __mask) +{ + union __fpscr __r; + fenv_t __oldmask; + + __mffs(&__r.__d); + __oldmask = __r.__bits.__reg; + __r.__bits.__reg &= ~((__mask & FE_ALL_EXCEPT) >> _FPUSW_SHIFT); + __mtfsf(__r.__d); + return ((__oldmask & _ENABLE_MASK) << _FPUSW_SHIFT); +} + +static inline int +fegetexcept(void) +{ + union __fpscr __r; + + __mffs(&__r.__d); + return ((__r.__bits.__reg & _ENABLE_MASK) << _FPUSW_SHIFT); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_riscv.h b/src/openlibm/include/openlibm_fenv_riscv.h new file mode 100644 index 0000000..e8ce78e --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_riscv.h @@ -0,0 +1,261 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * Copyright (c) 2015-2016 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/lib/msun/riscv/fenv.h 332792 2018-04-19 20:36:15Z brooks $ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include +#include "cdefs-compat.h" + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef uint64_t fenv_t; +typedef uint64_t fexcept_t; + +/* Exception flags */ +#define FE_INVALID 0x0010 +#define FE_DIVBYZERO 0x0008 +#define FE_OVERFLOW 0x0004 +#define FE_UNDERFLOW 0x0002 +#define FE_INEXACT 0x0001 +#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | \ + FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* + * RISC-V Rounding modes + */ +#define _ROUND_SHIFT 5 +#define FE_TONEAREST (0x00 << _ROUND_SHIFT) +#define FE_TOWARDZERO (0x01 << _ROUND_SHIFT) +#define FE_DOWNWARD (0x02 << _ROUND_SHIFT) +#define FE_UPWARD (0x03 << _ROUND_SHIFT) +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +#if !defined(__riscv_float_abi_soft) && !defined(__riscv_float_abi_double) +#if defined(__riscv_float_abi_single) +#error single precision floating point ABI not supported +#else +#error compiler did not set soft/hard float macros +#endif +#endif + +#ifndef __riscv_float_abi_soft +#define __rfs(__fcsr) __asm __volatile("csrr %0, fcsr" : "=r" (__fcsr)) +#define __wfs(__fcsr) __asm __volatile("csrw fcsr, %0" :: "r" (__fcsr)) +#endif + +#ifdef __riscv_float_abi_soft +int feclearexcept(int __excepts); +int fegetexceptflag(fexcept_t *__flagp, int __excepts); +int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +int feraiseexcept(int __excepts); +int fetestexcept(int __excepts); +int fegetround(void); +int fesetround(int __round); +int fegetenv(fenv_t *__envp); +int feholdexcept(fenv_t *__envp); +int fesetenv(const fenv_t *__envp); +int feupdateenv(const fenv_t *__envp); +#else +__fenv_static inline int +feclearexcept(int __excepts) +{ + + __asm __volatile("csrc fflags, %0" :: "r"(__excepts)); + + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fcsr; + + __rfs(__fcsr); + *__flagp = __fcsr & __excepts; + + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t __fcsr; + + __fcsr = *__flagp; + __asm __volatile("csrc fflags, %0" :: "r"(__excepts)); + __asm __volatile("csrs fflags, %0" :: "r"(__fcsr & __excepts)); + + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + + __asm __volatile("csrs fflags, %0" :: "r"(__excepts)); + + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t __fcsr; + + __rfs(__fcsr); + + return (__fcsr & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + fexcept_t __fcsr; + + __rfs(__fcsr); + + return (__fcsr & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + fexcept_t __fcsr; + + if (__round & ~_ROUND_MASK) + return (-1); + + __rfs(__fcsr); + __fcsr &= ~_ROUND_MASK; + __fcsr |= __round; + __wfs(__fcsr); + + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + + __rfs(*__envp); + + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + + /* No exception traps. */ + + return (-1); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __wfs(*__envp); + + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t __fcsr; + + __rfs(__fcsr); + __wfs(*__envp); + feraiseexcept(__fcsr & FE_ALL_EXCEPT); + + return (0); +} +#endif /* !__riscv_float_abi_soft */ + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +#ifdef __riscv_float_abi_soft +int feenableexcept(int __mask); +int fedisableexcept(int __mask); +int fegetexcept(void); +#else +static inline int +feenableexcept(int __mask) +{ + + /* No exception traps. */ + + return (-1); +} + +static inline int +fedisableexcept(int __mask) +{ + + /* No exception traps. */ + + return (0); +} + +static inline int +fegetexcept(void) +{ + + /* No exception traps. */ + + return (0); +} +#endif /* !__riscv_float_abi_soft */ + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_fenv_s390.h b/src/openlibm/include/openlibm_fenv_s390.h new file mode 100644 index 0000000..84ef080 --- /dev/null +++ b/src/openlibm/include/openlibm_fenv_s390.h @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2016 Dan Horák + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include + +#ifndef __fenv_static +#define __fenv_static static +#endif + +typedef __uint32_t fenv_t; +typedef __uint32_t fexcept_t; + +/* Exception flags */ +#define FE_INEXACT 0x080000 +#define FE_UNDERFLOW 0x100000 +#define FE_OVERFLOW 0x200000 +#define FE_DIVBYZERO 0x400000 +#define FE_INVALID 0x800000 /* all types of invalid FP ops */ + +#define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW) + +/* Rounding modes */ +#define FE_TONEAREST 0x0000 +#define FE_TOWARDZERO 0x0001 +#define FE_UPWARD 0x0002 +#define FE_DOWNWARD 0x0003 +#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ + FE_UPWARD | FE_TOWARDZERO) + +__BEGIN_DECLS + +/* Default floating-point environment */ +extern const fenv_t __fe_dfl_env; +#define FE_DFL_ENV (&__fe_dfl_env) + +/* We need to be able to map status flag positions to mask flag positions */ +#define _FPC_EXC_MASK_SHIFT 8 +#define _ENABLE_MASK ((FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ + FE_OVERFLOW | FE_UNDERFLOW) << _FPC_EXC_MASK_SHIFT) + +/* Macros for accessing the hardware control word. */ +#define _FPU_GETCW(cw) __asm__ __volatile__ ("efpc %0,0" : "=d" (cw)) +#define _FPU_SETCW(cw) __asm__ __volatile__ ("sfpc %0,0" : : "d" (cw)) + +__fenv_static inline int +feclearexcept(int __excepts) +{ + fexcept_t __r; + + if (__excepts & FE_INVALID) + __excepts |= FE_ALL_EXCEPT; + _FPU_GETCW(__r); + __r &= ~__excepts; + _FPU_SETCW(__r); + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + *__flagp = __r & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + fexcept_t __r; + + if (__excepts & FE_INVALID) + __excepts |= FE_ALL_EXCEPT; + _FPU_GETCW(__r); + __r &= ~__excepts; + __r |= *__flagp & __excepts; + _FPU_SETCW(__r); + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + __r |= __excepts; + _FPU_SETCW(__r); + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + return (__r & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + return (__r & _ROUND_MASK); +} + +__fenv_static inline int +fesetround(int __round) +{ + fexcept_t __r; + + if (__round & ~_ROUND_MASK) + return (-1); + + _FPU_GETCW(__r); + __r &= ~_ROUND_MASK; + __r |= __round; + _FPU_SETCW(__r); + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + _FPU_GETCW(*__envp); + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + *__envp = __r; + __r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK); + _FPU_SETCW(__r); + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + _FPU_SETCW(*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + __r &= FE_ALL_EXCEPT; + __r |= *__envp; + _FPU_SETCW(__r); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +static inline int +feenableexcept(int __mask) +{ + fenv_t __r; + fenv_t __oldmask; + + _FPU_GETCW(__r); + __oldmask = __r; + __r |= (__mask & FE_ALL_EXCEPT) << _FPC_EXC_MASK_SHIFT; + _FPU_SETCW(__r); + return ((__oldmask & _ENABLE_MASK) >> _FPC_EXC_MASK_SHIFT); +} + +static inline int +fedisableexcept(int __mask) +{ + fenv_t __r; + fenv_t __oldmask; + + _FPU_GETCW(__r); + __oldmask = __r; + __r &= ~((__mask & FE_ALL_EXCEPT) << _FPC_EXC_MASK_SHIFT); + _FPU_SETCW(__r); + return ((__oldmask & _ENABLE_MASK) >> _FPC_EXC_MASK_SHIFT); +} + +static inline int +fegetexcept(void) +{ + fexcept_t __r; + + _FPU_GETCW(__r); + return (__r & (_ENABLE_MASK >> _FPC_EXC_MASK_SHIFT)); +} + +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_FENV_H_ */ diff --git a/src/openlibm/include/openlibm_math.h b/src/openlibm/include/openlibm_math.h new file mode 100644 index 0000000..701ad70 --- /dev/null +++ b/src/openlibm/include/openlibm_math.h @@ -0,0 +1,493 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD: src/lib/msun/src/openlibm.h,v 1.82 2011/11/12 19:55:48 theraven Exp $ + */ + +#ifdef OPENLIBM_USE_HOST_MATH_H +#include +#else /* !OPENLIBM_USE_HOST_MATH_H */ + +#include + +#ifndef OPENLIBM_MATH_H +#define OPENLIBM_MATH_H + +#if (defined(_WIN32) || defined (_MSC_VER)) && !defined(__WIN32__) + #define __WIN32__ +#endif + +#if !defined(__arm__) && !defined(__wasm__) +#define OLM_LONG_DOUBLE +#endif + +#ifndef __pure2 +#define __pure2 +#endif + +/* + * ANSI/POSIX + */ +extern const union __infinity_un { + unsigned char __uc[8]; + double __ud; +} __infinity; + +extern const union __nan_un { + unsigned char __uc[sizeof(float)]; + float __uf; +} __nan; + +/* VBS +#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) +#define __MATH_BUILTIN_CONSTANTS +#endif + +#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER) +#define __MATH_BUILTIN_RELOPS +#endif +*/ + +//VBS begin +#define __MATH_BUILTIN_CONSTANTS +#define __MATH_BUILTIN_RELOPS +#ifndef __ISO_C_VISIBLE +#define __ISO_C_VISIBLE 1999 +#endif +//VBS end + +#ifdef __MATH_BUILTIN_CONSTANTS +#define HUGE_VAL __builtin_huge_val() +#else +#define HUGE_VAL (__infinity.__ud) +#endif + +#if __ISO_C_VISIBLE >= 1999 +#define FP_ILOGB0 (-INT_MAX) +#define FP_ILOGBNAN INT_MAX + +#ifdef __MATH_BUILTIN_CONSTANTS +#define HUGE_VALF __builtin_huge_valf() +#define HUGE_VALL __builtin_huge_vall() +#define INFINITY __builtin_inff() +#define NAN __builtin_nanf("") +#else +#define HUGE_VALF (float)HUGE_VAL +#define HUGE_VALL (long double)HUGE_VAL +#define INFINITY HUGE_VALF +#define NAN (__nan.__uf) +#endif /* __MATH_BUILTIN_CONSTANTS */ + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling MATH_ERREXCEPT + +#define FP_FAST_FMAF 1 +#ifdef __ia64__ +#define FP_FAST_FMA 1 +#define FP_FAST_FMAL 1 +#endif + +/* Symbolic constants to classify floating point numbers. */ +#define FP_INFINITE 0x01 +#define FP_NAN 0x02 +#define FP_NORMAL 0x04 +#define FP_SUBNORMAL 0x08 +#define FP_ZERO 0x10 +#define fpclassify(x) \ + ((sizeof (x) == sizeof (float)) ? __fpclassifyf(x) \ + : (sizeof (x) == sizeof (double)) ? __fpclassifyd(x) \ + : __fpclassifyl(x)) + +#define isfinite(x) \ + ((sizeof (x) == sizeof (float)) ? __isfinitef(x) \ + : (sizeof (x) == sizeof (double)) ? __isfinite(x) \ + : __isfinitel(x)) +#define isinf(x) \ + ((sizeof (x) == sizeof (float)) ? __isinff(x) \ + : (sizeof (x) == sizeof (double)) ? isinf(x) \ + : __isinfl(x)) +#define isnan(x) \ + ((sizeof (x) == sizeof (float)) ? __isnanf(x) \ + : (sizeof (x) == sizeof (double)) ? isnan(x) \ + : __isnanl(x)) +#define isnormal(x) \ + ((sizeof (x) == sizeof (float)) ? __isnormalf(x) \ + : (sizeof (x) == sizeof (double)) ? __isnormal(x) \ + : __isnormall(x)) + +#ifdef __MATH_BUILTIN_RELOPS +#define isgreater(x, y) __builtin_isgreater((x), (y)) +#define isgreaterequal(x, y) __builtin_isgreaterequal((x), (y)) +#define isless(x, y) __builtin_isless((x), (y)) +#define islessequal(x, y) __builtin_islessequal((x), (y)) +#define islessgreater(x, y) __builtin_islessgreater((x), (y)) +#define isunordered(x, y) __builtin_isunordered((x), (y)) +#else +#define isgreater(x, y) (!isunordered((x), (y)) && (x) > (y)) +#define isgreaterequal(x, y) (!isunordered((x), (y)) && (x) >= (y)) +#define isless(x, y) (!isunordered((x), (y)) && (x) < (y)) +#define islessequal(x, y) (!isunordered((x), (y)) && (x) <= (y)) +#define islessgreater(x, y) (!isunordered((x), (y)) && \ + ((x) > (y) || (y) > (x))) +#define isunordered(x, y) (isnan(x) || isnan(y)) +#endif /* __MATH_BUILTIN_RELOPS */ + +#define signbit(x) \ + ((sizeof (x) == sizeof (float)) ? __signbitf(x) \ + : (sizeof (x) == sizeof (double)) ? __signbit(x) \ + : __signbitl(x)) + +//VBS +//typedef __double_t double_t; +//typedef __float_t float_t; +#endif /* __ISO_C_VISIBLE >= 1999 */ + +/* + * XOPEN/SVID + */ +#if __BSD_VISIBLE || __XSI_VISIBLE +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log 2e */ +#define M_LOG10E 0.43429448190325182765 /* log 10e */ +#define M_LN2 0.69314718055994530942 /* log e2 */ +#define M_LN10 2.30258509299404568402 /* log e10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#define MAXFLOAT ((float)3.40282346638528860e+38) + +#ifndef OPENLIBM_ONLY_THREAD_SAFE +OLM_DLLEXPORT extern int signgam; +#endif +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if __BSD_VISIBLE +#if 0 +/* Old value from 4.4BSD-Lite openlibm.h; this is probably better. */ +#define HUGE HUGE_VAL +#else +#define HUGE MAXFLOAT +#endif +#endif /* __BSD_VISIBLE */ + +/* + * Most of these functions depend on the rounding mode and have the side + * effect of raising floating-point exceptions, so they are not declared + * as __pure2. In C99, FENV_ACCESS affects the purity of these functions. + */ + +#if defined(__cplusplus) +extern "C" { +#endif +/* Symbol present when OpenLibm is used. */ +int isopenlibm(void); + +/* + * ANSI/POSIX + */ +OLM_DLLEXPORT int __fpclassifyd(double) __pure2; +OLM_DLLEXPORT int __fpclassifyf(float) __pure2; +OLM_DLLEXPORT int __fpclassifyl(long double) __pure2; +OLM_DLLEXPORT int __isfinitef(float) __pure2; +OLM_DLLEXPORT int __isfinite(double) __pure2; +OLM_DLLEXPORT int __isfinitel(long double) __pure2; +OLM_DLLEXPORT int __isinff(float) __pure2; +OLM_DLLEXPORT int __isinfl(long double) __pure2; +OLM_DLLEXPORT int __isnanf(float) __pure2; +OLM_DLLEXPORT int __isnanl(long double) __pure2; +OLM_DLLEXPORT int __isnormalf(float) __pure2; +OLM_DLLEXPORT int __isnormal(double) __pure2; +OLM_DLLEXPORT int __isnormall(long double) __pure2; +OLM_DLLEXPORT int __signbit(double) __pure2; +OLM_DLLEXPORT int __signbitf(float) __pure2; +OLM_DLLEXPORT int __signbitl(long double) __pure2; + +OLM_DLLEXPORT double acos(double); +OLM_DLLEXPORT double asin(double); +OLM_DLLEXPORT double atan(double); +OLM_DLLEXPORT double atan2(double, double); +OLM_DLLEXPORT double cos(double); +OLM_DLLEXPORT double sin(double); +OLM_DLLEXPORT double tan(double); + +OLM_DLLEXPORT double cosh(double); +OLM_DLLEXPORT double sinh(double); +OLM_DLLEXPORT double tanh(double); + +OLM_DLLEXPORT double exp(double); +OLM_DLLEXPORT double frexp(double, int *); /* fundamentally !__pure2 */ +OLM_DLLEXPORT double ldexp(double, int); +OLM_DLLEXPORT double log(double); +OLM_DLLEXPORT double log10(double); +OLM_DLLEXPORT double modf(double, double *); /* fundamentally !__pure2 */ + +OLM_DLLEXPORT double pow(double, double); +OLM_DLLEXPORT double sqrt(double); + +OLM_DLLEXPORT double ceil(double); +OLM_DLLEXPORT double fabs(double) __pure2; +OLM_DLLEXPORT double floor(double); +OLM_DLLEXPORT double fmod(double, double); + +/* + * These functions are not in C90. + */ +#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE +OLM_DLLEXPORT double acosh(double); +OLM_DLLEXPORT double asinh(double); +OLM_DLLEXPORT double atanh(double); +OLM_DLLEXPORT double cbrt(double); +OLM_DLLEXPORT double erf(double); +OLM_DLLEXPORT double erfc(double); +OLM_DLLEXPORT double exp2(double); +OLM_DLLEXPORT double expm1(double); +OLM_DLLEXPORT double fma(double, double, double); +OLM_DLLEXPORT double hypot(double, double); +OLM_DLLEXPORT int ilogb(double) __pure2; +OLM_DLLEXPORT int (isinf)(double) __pure2; +OLM_DLLEXPORT int (isnan)(double) __pure2; +OLM_DLLEXPORT double lgamma(double); +OLM_DLLEXPORT long long llrint(double); +OLM_DLLEXPORT long long llround(double); +OLM_DLLEXPORT double log1p(double); +OLM_DLLEXPORT double log2(double); +OLM_DLLEXPORT double logb(double); +OLM_DLLEXPORT long lrint(double); +OLM_DLLEXPORT long lround(double); +OLM_DLLEXPORT double nan(const char *) __pure2; +OLM_DLLEXPORT double nextafter(double, double); +OLM_DLLEXPORT double remainder(double, double); +OLM_DLLEXPORT double remquo(double, double, int *); +OLM_DLLEXPORT double rint(double); +#endif /* __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE */ + +#if __BSD_VISIBLE || __XSI_VISIBLE +OLM_DLLEXPORT double j0(double); +OLM_DLLEXPORT double j1(double); +OLM_DLLEXPORT double jn(int, double); +OLM_DLLEXPORT double y0(double); +OLM_DLLEXPORT double y1(double); +OLM_DLLEXPORT double yn(int, double); +#endif /* __BSD_VISIBLE || __XSI_VISIBLE */ + +#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 1999 +OLM_DLLEXPORT double copysign(double, double) __pure2; +OLM_DLLEXPORT double fdim(double, double); +OLM_DLLEXPORT double fmax(double, double) __pure2; +OLM_DLLEXPORT double fmin(double, double) __pure2; +OLM_DLLEXPORT double nearbyint(double); +OLM_DLLEXPORT double round(double); +OLM_DLLEXPORT double scalbln(double, long); +OLM_DLLEXPORT double scalbn(double, int); +OLM_DLLEXPORT double tgamma(double); +OLM_DLLEXPORT double trunc(double); +#endif + +/* + * BSD math library entry points + */ +#if __BSD_VISIBLE +OLM_DLLEXPORT int isinff(float) __pure2; +OLM_DLLEXPORT int isnanf(float) __pure2; + +/* + * Reentrant version of lgamma; passes signgam back by reference as the + * second argument; user must allocate space for signgam. + */ +OLM_DLLEXPORT double lgamma_r(double, int *); + +/* + * Single sine/cosine function. + */ +OLM_DLLEXPORT void sincos(double, double *, double *); +#endif /* __BSD_VISIBLE */ + +/* float versions of ANSI/POSIX functions */ +#if __ISO_C_VISIBLE >= 1999 +OLM_DLLEXPORT float acosf(float); +OLM_DLLEXPORT float asinf(float); +OLM_DLLEXPORT float atanf(float); +OLM_DLLEXPORT float atan2f(float, float); +OLM_DLLEXPORT float cosf(float); +OLM_DLLEXPORT float sinf(float); +OLM_DLLEXPORT float tanf(float); + +OLM_DLLEXPORT float coshf(float); +OLM_DLLEXPORT float sinhf(float); +OLM_DLLEXPORT float tanhf(float); + +OLM_DLLEXPORT float exp2f(float); +OLM_DLLEXPORT float expf(float); +OLM_DLLEXPORT float expm1f(float); +OLM_DLLEXPORT float frexpf(float, int *); /* fundamentally !__pure2 */ +OLM_DLLEXPORT int ilogbf(float) __pure2; +OLM_DLLEXPORT float ldexpf(float, int); +OLM_DLLEXPORT float log10f(float); +OLM_DLLEXPORT float log1pf(float); +OLM_DLLEXPORT float log2f(float); +OLM_DLLEXPORT float logf(float); +OLM_DLLEXPORT float modff(float, float *); /* fundamentally !__pure2 */ + +OLM_DLLEXPORT float powf(float, float); +OLM_DLLEXPORT float sqrtf(float); + +OLM_DLLEXPORT float ceilf(float); +OLM_DLLEXPORT float fabsf(float) __pure2; +OLM_DLLEXPORT float floorf(float); +OLM_DLLEXPORT float fmodf(float, float); +OLM_DLLEXPORT float roundf(float); + +OLM_DLLEXPORT float erff(float); +OLM_DLLEXPORT float erfcf(float); +OLM_DLLEXPORT float hypotf(float, float); +OLM_DLLEXPORT float lgammaf(float); +OLM_DLLEXPORT float tgammaf(float); + +OLM_DLLEXPORT float acoshf(float); +OLM_DLLEXPORT float asinhf(float); +OLM_DLLEXPORT float atanhf(float); +OLM_DLLEXPORT float cbrtf(float); +OLM_DLLEXPORT float logbf(float); +OLM_DLLEXPORT float copysignf(float, float) __pure2; +OLM_DLLEXPORT long long llrintf(float); +OLM_DLLEXPORT long long llroundf(float); +OLM_DLLEXPORT long lrintf(float); +OLM_DLLEXPORT long lroundf(float); +OLM_DLLEXPORT float nanf(const char *) __pure2; +OLM_DLLEXPORT float nearbyintf(float); +OLM_DLLEXPORT float nextafterf(float, float); +OLM_DLLEXPORT float remainderf(float, float); +OLM_DLLEXPORT float remquof(float, float, int *); +OLM_DLLEXPORT float rintf(float); +OLM_DLLEXPORT float scalblnf(float, long); +OLM_DLLEXPORT float scalbnf(float, int); +OLM_DLLEXPORT float truncf(float); + +OLM_DLLEXPORT float fdimf(float, float); +OLM_DLLEXPORT float fmaf(float, float, float); +OLM_DLLEXPORT float fmaxf(float, float) __pure2; +OLM_DLLEXPORT float fminf(float, float) __pure2; +#endif + +/* + * float versions of BSD math library entry points + */ +#if __BSD_VISIBLE +OLM_DLLEXPORT float dremf(float, float); +OLM_DLLEXPORT float j0f(float); +OLM_DLLEXPORT float j1f(float); +OLM_DLLEXPORT float jnf(int, float); +OLM_DLLEXPORT float y0f(float); +OLM_DLLEXPORT float y1f(float); +OLM_DLLEXPORT float ynf(int, float); + +/* + * Float versions of reentrant version of lgamma; passes signgam back by + * reference as the second argument; user must allocate space for signgam. + */ +OLM_DLLEXPORT float lgammaf_r(float, int *); + +/* + * Single sine/cosine function. + */ +OLM_DLLEXPORT void sincosf(float, float *, float *); +#endif /* __BSD_VISIBLE */ + +/* + * long double versions of ISO/POSIX math functions + */ +#if __ISO_C_VISIBLE >= 1999 +OLM_DLLEXPORT long double acoshl(long double); +OLM_DLLEXPORT long double acosl(long double); +OLM_DLLEXPORT long double asinhl(long double); +OLM_DLLEXPORT long double asinl(long double); +OLM_DLLEXPORT long double atan2l(long double, long double); +OLM_DLLEXPORT long double atanhl(long double); +OLM_DLLEXPORT long double atanl(long double); +OLM_DLLEXPORT long double cbrtl(long double); +OLM_DLLEXPORT long double ceill(long double); +OLM_DLLEXPORT long double copysignl(long double, long double) __pure2; +OLM_DLLEXPORT long double coshl(long double); +OLM_DLLEXPORT long double cosl(long double); +OLM_DLLEXPORT long double erfcl(long double); +OLM_DLLEXPORT long double erfl(long double); +OLM_DLLEXPORT long double exp2l(long double); +OLM_DLLEXPORT long double expl(long double); +OLM_DLLEXPORT long double expm1l(long double); +OLM_DLLEXPORT long double fabsl(long double) __pure2; +OLM_DLLEXPORT long double fdiml(long double, long double); +OLM_DLLEXPORT long double floorl(long double); +OLM_DLLEXPORT long double fmal(long double, long double, long double); +OLM_DLLEXPORT long double fmaxl(long double, long double) __pure2; +OLM_DLLEXPORT long double fminl(long double, long double) __pure2; +OLM_DLLEXPORT long double fmodl(long double, long double); +OLM_DLLEXPORT long double frexpl(long double value, int *); /* fundamentally !__pure2 */ +OLM_DLLEXPORT long double hypotl(long double, long double); +OLM_DLLEXPORT int ilogbl(long double) __pure2; +OLM_DLLEXPORT long double ldexpl(long double, int); +OLM_DLLEXPORT long double lgammal(long double); +OLM_DLLEXPORT long long llrintl(long double); +OLM_DLLEXPORT long long llroundl(long double); +OLM_DLLEXPORT long double log10l(long double); +OLM_DLLEXPORT long double log1pl(long double); +OLM_DLLEXPORT long double log2l(long double); +OLM_DLLEXPORT long double logbl(long double); +OLM_DLLEXPORT long double logl(long double); +OLM_DLLEXPORT long lrintl(long double); +OLM_DLLEXPORT long lroundl(long double); +OLM_DLLEXPORT long double modfl(long double, long double *); /* fundamentally !__pure2 */ +OLM_DLLEXPORT long double nanl(const char *) __pure2; +OLM_DLLEXPORT long double nearbyintl(long double); +OLM_DLLEXPORT long double nextafterl(long double, long double); +OLM_DLLEXPORT double nexttoward(double, long double); +OLM_DLLEXPORT float nexttowardf(float, long double); +OLM_DLLEXPORT long double nexttowardl(long double, long double); +OLM_DLLEXPORT long double powl(long double, long double); +OLM_DLLEXPORT long double remainderl(long double, long double); +OLM_DLLEXPORT long double remquol(long double, long double, int *); +OLM_DLLEXPORT long double rintl(long double); +OLM_DLLEXPORT long double roundl(long double); +OLM_DLLEXPORT long double scalblnl(long double, long); +OLM_DLLEXPORT long double scalbnl(long double, int); +OLM_DLLEXPORT long double sinhl(long double); +OLM_DLLEXPORT long double sinl(long double); +OLM_DLLEXPORT long double sqrtl(long double); +OLM_DLLEXPORT long double tanhl(long double); +OLM_DLLEXPORT long double tanl(long double); +OLM_DLLEXPORT long double tgammal(long double); +OLM_DLLEXPORT long double truncl(long double); +#endif /* __ISO_C_VISIBLE >= 1999 */ + +/* Reentrant version of lgammal. */ +#if __BSD_VISIBLE +OLM_DLLEXPORT long double lgammal_r(long double, int *); + +/* + * Single sine/cosine function. + */ +OLM_DLLEXPORT void sincosl(long double, long double *, long double *); +#endif /* __BSD_VISIBLE */ + +#if defined(__cplusplus) +} +#endif +#endif /* !OPENLIBM_MATH_H */ + +#endif /* OPENLIBM_USE_HOST_MATH_H */ diff --git a/src/openlibm/ld128/Make.files b/src/openlibm/ld128/Make.files new file mode 100644 index 0000000..1198cfb --- /dev/null +++ b/src/openlibm/ld128/Make.files @@ -0,0 +1,13 @@ +$(CUR_SRCS) += invtrig.c \ + e_acoshl.c e_powl.c k_tanl.c s_exp2l.c \ + e_atanhl.c e_lgammal_r.c e_sinhl.c s_asinhl.c s_expm1l.c \ + e_coshl.c e_log10l.c e_tgammal.c \ + e_expl.c e_log2l.c k_cosl.c s_log1pl.c s_tanhl.c \ + e_logl.c k_sinl.c s_erfl.c + +# s_remquol.c e_fmodl.c s_truncl.c +# e_hypotl.c s_floorl.c s_nextafterl.c s_ceill.c s_modfl.c + +ifneq ($(OS), WINNT) +$(CUR_SRCS) += s_nanl.c +endif diff --git a/src/openlibm/ld128/e_acoshl.c b/src/openlibm/ld128/e_acoshl.c new file mode 100644 index 0000000..e7cfd03 --- /dev/null +++ b/src/openlibm/ld128/e_acoshl.c @@ -0,0 +1,58 @@ +/* @(#)e_acosh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* acoshl(x) + * Method : + * Based on + * acoshl(x) = logl [ x + sqrtl(x*x-1) ] + * we have + * acoshl(x) := logl(x)+ln2, if x is large; else + * acoshl(x) := logl(2x-1/(sqrtl(x*x-1)+x)) if x>2; else + * acoshl(x) := log1pl(t+sqrtl(2.0*t+t*t)); where t=x-1. + * + * Special cases: + * acoshl(x) is NaN with signal if x<1. + * acoshl(NaN) is NaN without signal. + */ + +#include + +#include "math_private.h" + +static const long double +one = 1.0, +ln2 = 0.6931471805599453094172321214581766L; + +long double +acoshl(long double x) +{ + long double t; + u_int64_t lx; + int64_t hx; + GET_LDOUBLE_WORDS64(hx,lx,x); + if(hx<0x3fff000000000000LL) { /* x < 1 */ + return (x-x)/(x-x); + } else if(hx >=0x4035000000000000LL) { /* x > 2**54 */ + if(hx >=0x7fff000000000000LL) { /* x is inf of NaN */ + return x+x; + } else + return logl(x)+ln2; /* acoshl(huge)=logl(2x) */ + } else if(((hx-0x3fff000000000000LL)|lx)==0) { + return 0.0L; /* acosh(1) = 0 */ + } else if (hx > 0x4000000000000000LL) { /* 2**28 > x > 2 */ + t=x*x; + return logl(2.0L*x-one/(x+sqrtl(t-one))); + } else { /* 1=0.5 + * 1 2x x + * atanhl(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + * 2 1 - x 1 - x + * + * For x<0.5 + * atanhl(x) = 0.5*log1pl(2x+2x*x/(1-x)) + * + * Special cases: + * atanhl(x) is NaN if |x| > 1 with signal; + * atanhl(NaN) is that NaN with no signal; + * atanhl(+-1) is +-INF with signal. + * + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0L, huge = 1e4900L; + +static const long double zero = 0.0L; + +long double +atanhl(long double x) +{ + long double t; + u_int32_t jx, ix; + ieee_quad_shape_type u; + + u.value = x; + jx = u.parts32.mswhi; + ix = jx & 0x7fffffff; + u.parts32.mswhi = ix; + if (ix >= 0x3fff0000) /* |x| >= 1.0 or infinity or NaN */ + { + if (u.value == one) + return x/zero; + else + return (x-x)/(x-x); + } + if(ix<0x3fc60000 && (huge+x)>zero) return x; /* x < 2^-57 */ + + if(ix<0x3ffe0000) { /* x < 0.5 */ + t = u.value+u.value; + t = 0.5*log1pl(t+t*u.value/(one-u.value)); + } else + t = 0.5*log1pl((u.value+u.value)/(one-u.value)); + if(jx & 0x80000000) return -t; else return t; +} diff --git a/src/openlibm/ld128/e_coshl.c b/src/openlibm/ld128/e_coshl.c new file mode 100644 index 0000000..955c378 --- /dev/null +++ b/src/openlibm/ld128/e_coshl.c @@ -0,0 +1,105 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* coshl(x) + * Method : + * mathematically coshl(x) if defined to be (exp(x)+exp(-x))/2 + * 1. Replace x by |x| (coshl(x) = coshl(-x)). + * 2. + * [ exp(x) - 1 ]^2 + * 0 <= x <= ln2/2 : coshl(x) := 1 + ------------------- + * 2*exp(x) + * + * exp(x) + 1/exp(x) + * ln2/2 <= x <= 22 : coshl(x) := ------------------- + * 2 + * 22 <= x <= lnovft : coshl(x) := expl(x)/2 + * lnovft <= x <= ln2ovft: coshl(x) := expl(x/2)/2 * expl(x/2) + * ln2ovft < x : coshl(x) := huge*huge (overflow) + * + * Special cases: + * coshl(x) is |x| if x is +INF, -INF, or NaN. + * only coshl(0)=1 is exact for finite x. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, half = 0.5, huge = 1.0e4900L, +ovf_thresh = 1.1357216553474703894801348310092223067821E4L; + +long double +coshl(long double x) +{ + long double t, w; + int32_t ex; + ieee_quad_shape_type u; + + u.value = x; + ex = u.parts32.mswhi & 0x7fffffff; + + /* Absolute value of x. */ + u.parts32.mswhi = ex; + + /* x is INF or NaN */ + if (ex >= 0x7fff0000) + return x * x; + + /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */ + if (ex < 0x3ffd62e4) /* 0.3465728759765625 */ + { + t = expm1l (u.value); + w = one + t; + if (ex < 0x3fb80000) /* |x| < 2^-116 */ + return w; /* cosh(tiny) = 1 */ + + return one + (t * t) / (w + w); + } + + /* |x| in [0.5*ln2,40], return (exp(|x|)+1/exp(|x|)/2; */ + if (ex < 0x40044000) + { + t = expl (u.value); + return half * t + half / t; + } + + /* |x| in [22, ln(maxdouble)] return half*exp(|x|) */ + if (ex <= 0x400c62e3) /* 11356.375 */ + return half * expl (u.value); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (u.value <= ovf_thresh) + { + w = expl (half * u.value); + t = half * w; + return t * w; + } + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge * huge; +} diff --git a/src/openlibm/ld128/e_expl.c b/src/openlibm/ld128/e_expl.c new file mode 100644 index 0000000..24c7b50 --- /dev/null +++ b/src/openlibm/ld128/e_expl.c @@ -0,0 +1,145 @@ +/* $OpenBSD: e_expl.c,v 1.3 2013/11/12 20:35:18 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* expl.c + * + * Exponential function, 128-bit long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 2/3 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-MAXLOG 100,000 2.6e-34 8.6e-35 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +/* Exponential function */ + +#include +#include + +#include "math_private.h" + +/* Pade' coefficients for exp(x) - 1 + Theoretical peak relative error = 2.2e-37, + relative peak error spread = 9.2e-38 + */ +static long double P[5] = { + 3.279723985560247033712687707263393506266E-10L, + 6.141506007208645008909088812338454698548E-7L, + 2.708775201978218837374512615596512792224E-4L, + 3.508710990737834361215404761139478627390E-2L, + 9.999999999999999999999999999999999998502E-1L +}; +static long double Q[6] = { + 2.980756652081995192255342779918052538681E-12L, + 1.771372078166251484503904874657985291164E-8L, + 1.504792651814944826817779302637284053660E-5L, + 3.611828913847589925056132680618007270344E-3L, + 2.368408864814233538909747618894558968880E-1L, + 2.000000000000000000000000000000000000150E0L +}; +/* C1 + C2 = ln 2 */ +static const long double C1 = -6.93145751953125E-1L; +static const long double C2 = -1.428606820309417232121458176568075500134E-6L; + +static const long double LOG2EL = 1.442695040888963407359924681001892137426646L; +static const long double MAXLOGL = 1.1356523406294143949491931077970764891253E4L; +static const long double MINLOGL = -1.143276959615573793352782661133116431383730e4L; +static const long double huge = 0x1p10000L; +#if 0 /* XXX Prevent gcc from erroneously constant folding this. */ +static const long double twom10000 = 0x1p-10000L; +#else +static volatile long double twom10000 = 0x1p-10000L; +#endif + +long double +expl(long double x) +{ +long double px, xx; +int n; + +if( x > MAXLOGL) + return (huge*huge); /* overflow */ + +if( x < MINLOGL ) + return (twom10000*twom10000); /* underflow */ + +/* Express e**x = e**g 2**n + * = e**g e**( n loge(2) ) + * = e**( g + n loge(2) ) + */ +px = floorl( LOG2EL * x + 0.5L ); /* floor() truncates toward -infinity. */ +n = px; +x += px * C1; +x += px * C2; +/* rational approximation for exponential + * of the fractional part: + * e**x = 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + */ +xx = x * x; +px = x * __polevll( xx, P, 4 ); +xx = __polevll( xx, Q, 5 ); +x = px/( xx - px ); +x = 1.0L + x + x; + +x = ldexpl( x, n ); +return(x); +} diff --git a/src/openlibm/ld128/e_fmodl.c b/src/openlibm/ld128/e_fmodl.c new file mode 100644 index 0000000..698fa3a --- /dev/null +++ b/src/openlibm/ld128/e_fmodl.c @@ -0,0 +1,129 @@ +/* @(#)e_fmod.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * fmodl(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, Zero[] = {0.0, -0.0,}; + +long double +fmodl(long double x, long double y) +{ + int64_t n,hx,hy,hz,ix,iy,sx,i; + u_int64_t lx,ly,lz; + + GET_LDOUBLE_WORDS64(hx,lx,x); + GET_LDOUBLE_WORDS64(hy,ly,y); + sx = hx&0x8000000000000000ULL; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffffffffffffLL; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7fff000000000000LL)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>63))>0x7fff000000000000LL)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx>63]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x0001000000000000LL) { /* subnormal x */ + if(hx==0) { + for (ix = -16431, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -16382, i=hx<<15; i>0; i<<=1) ix -=1; + } + } else ix = (hx>>48)-0x3fff; + + /* determine iy = ilogb(y) */ + if(hy<0x0001000000000000LL) { /* subnormal y */ + if(hy==0) { + for (iy = -16431, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -16382, i=hy<<15; i>0; i<<=1) iy -=1; + } + } else iy = (hy>>48)-0x3fff; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -16382) + hx = 0x0001000000000000LL|(0x0000ffffffffffffLL&hx); + else { /* subnormal x, shift x to normal */ + n = -16382-ix; + if(n<=63) { + hx = (hx<>(64-n)); + lx <<= n; + } else { + hx = lx<<(n-64); + lx = 0; + } + } + if(iy >= -16382) + hy = 0x0001000000000000LL|(0x0000ffffffffffffLL&hy); + else { /* subnormal y, shift y to normal */ + n = -16382-iy; + if(n<=63) { + hy = (hy<>(64-n)); + ly <<= n; + } else { + hy = ly<<(n-64); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx>63); lx = lx+lx;} + else { + if((hz|lz)==0) /* return sign(x)*0 */ + return Zero[(u_int64_t)sx>>63]; + hx = hz+hz+(lz>>63); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[(u_int64_t)sx>>63]; + while(hx<0x0001000000000000LL) { /* normalize x */ + hx = hx+hx+(lx>>63); lx = lx+lx; + iy -= 1; + } + if(iy>= -16382) { /* normalize output */ + hx = ((hx-0x0001000000000000LL)|((iy+16383)<<48)); + SET_LDOUBLE_WORDS64(x,hx|sx,lx); + } else { /* subnormal output */ + n = -16382 - iy; + if(n<=48) { + lx = (lx>>n)|((u_int64_t)hx<<(64-n)); + hx >>= n; + } else if (n<=63) { + lx = (hx<<(64-n))|(lx>>n); hx = sx; + } else { + lx = hx>>(n-64); hx = sx; + } + SET_LDOUBLE_WORDS64(x,hx|sx,lx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/src/openlibm/ld128/e_hypotl.c b/src/openlibm/ld128/e_hypotl.c new file mode 100644 index 0000000..1cdf3d8 --- /dev/null +++ b/src/openlibm/ld128/e_hypotl.c @@ -0,0 +1,122 @@ +/* @(#)e_hypot.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* hypotl(x,y) + * + * Method : + * If (assume round-to-nearest) z=x*x+y*y + * has error less than sqrtl(2)/2 ulp, than + * sqrtl(z) has error less than 1 ulp (exercise). + * + * So, compute sqrtl(x*x+y*y) with some care as + * follows to get the error below 1 ulp: + * + * Assume x>y>0; + * (if possible, set rounding to round-to-nearest) + * 1. if x > 2y use + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + * where x1 = x with lower 64 bits cleared, x2 = x-x1; else + * 2. if x <= 2y use + * t1*yy1+((x-y)*(x-y)+(t1*y2+t2*y)) + * where t1 = 2x with lower 64 bits cleared, t2 = 2x-t1, + * yy1= y with lower 64 bits chopped, y2 = y-yy1. + * + * NOTE: scaling may be necessary if some argument is too + * large or too tiny + * + * Special cases: + * hypotl(x,y) is INF if x or y is +INF or -INF; else + * hypotl(x,y) is NAN if x or y is NAN. + * + * Accuracy: + * hypotl(x,y) returns sqrtl(x^2+y^2) with error less + * than 1 ulps (units in the last place) + */ + +#include + +#include "math_private.h" + +long double +hypotl(long double x, long double y) +{ + long double a,b,t1,t2,yy1,y2,w; + int64_t j,k,ha,hb; + + GET_LDOUBLE_MSW64(ha,x); + ha &= 0x7fffffffffffffffLL; + GET_LDOUBLE_MSW64(hb,y); + hb &= 0x7fffffffffffffffLL; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + SET_LDOUBLE_MSW64(a,ha); /* a <- |a| */ + SET_LDOUBLE_MSW64(b,hb); /* b <- |b| */ + if((ha-hb)>0x78000000000000LL) {return a+b;} /* x/y > 2**120 */ + k=0; + if(ha > 0x5f3f000000000000LL) { /* a>2**8000 */ + if(ha >= 0x7fff000000000000LL) { /* Inf or NaN */ + u_int64_t low; + w = a+b; /* for sNaN */ + GET_LDOUBLE_LSW64(low,a); + if(((ha&0xffffffffffffLL)|low)==0) w = a; + GET_LDOUBLE_LSW64(low,b); + if(((hb^0x7fff000000000000LL)|low)==0) w = b; + return w; + } + /* scale a and b by 2**-9600 */ + ha -= 0x2580000000000000LL; + hb -= 0x2580000000000000LL; k += 9600; + SET_LDOUBLE_MSW64(a,ha); + SET_LDOUBLE_MSW64(b,hb); + } + if(hb < 0x20bf000000000000LL) { /* b < 2**-8000 */ + if(hb <= 0x0000ffffffffffffLL) { /* subnormal b or 0 */ + u_int64_t low; + GET_LDOUBLE_LSW64(low,b); + if((hb|low)==0) return a; + t1=0; + SET_LDOUBLE_MSW64(t1,0x7ffd000000000000LL); /* t1=2^16382 */ + b *= t1; + a *= t1; + k -= 16382; + } else { /* scale a and b by 2^9600 */ + ha += 0x2580000000000000LL; /* a *= 2^9600 */ + hb += 0x2580000000000000LL; /* b *= 2^9600 */ + k -= 9600; + SET_LDOUBLE_MSW64(a,ha); + SET_LDOUBLE_MSW64(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = 0; + SET_LDOUBLE_MSW64(t1,ha); + t2 = a-t1; + w = sqrtl(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + yy1 = 0; + SET_LDOUBLE_MSW64(yy1,hb); + y2 = b - yy1; + t1 = 0; + SET_LDOUBLE_MSW64(t1,ha+0x0001000000000000LL); + t2 = a - t1; + w = sqrtl(t1*yy1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int64_t high; + t1 = 1.0L; + GET_LDOUBLE_MSW64(high,t1); + SET_LDOUBLE_MSW64(t1,high+(k<<48)); + return t1*w; + } else return w; +} diff --git a/src/openlibm/ld128/e_lgammal_r.c b/src/openlibm/ld128/e_lgammal_r.c new file mode 100644 index 0000000..dd8ea5d --- /dev/null +++ b/src/openlibm/ld128/e_lgammal_r.c @@ -0,0 +1,1037 @@ +/* $OpenBSD: e_lgammal.c,v 1.3 2011/07/09 05:29:06 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* lgammal_r + * + * Natural logarithm of gamma function + * + * + * + * SYNOPSIS: + * + * long double x, y, lgammal_r(); + * int signgam; + * + * y = lgammal_r(x, &signgam); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of the absolute + * value of the gamma function of the argument. + * The sign (+1 or -1) of the gamma function is returned through signgamp. + * + * The positive domain is partitioned into numerous segments for approximation. + * For x > 10, + * log gamma(x) = (x - 0.5) log(x) - x + log sqrt(2 pi) + 1/x R(1/x^2) + * Near the minimum at x = x0 = 1.46... the approximation is + * log gamma(x0 + z) = log gamma(x0) + z^2 P(z)/Q(z) + * for small z. + * Elsewhere between 0 and 10, + * log gamma(n + z) = log gamma(n) + z P(z)/Q(z) + * for various selected n and small z. + * + * The cosecant reflection formula is employed for negative arguments. + * + * + * + * ACCURACY: + * + * + * arithmetic domain # trials peak rms + * Relative error: + * IEEE 10, 30 100000 3.9e-34 9.8e-35 + * IEEE 0, 10 100000 3.8e-34 5.3e-35 + * Absolute error: + * IEEE -10, 0 100000 8.0e-34 8.0e-35 + * IEEE -30, -10 100000 4.4e-34 1.0e-34 + * IEEE -100, 100 100000 1.0e-34 + * + * The absolute error criterion is the same as relative error + * when the function magnitude is greater than one but it is absolute + * when the magnitude is less than one. + * + */ + +#include + +#include "math_private.h" + +static const long double PIL = 3.1415926535897932384626433832795028841972E0L; +static const long double MAXLGM = 1.0485738685148938358098967157129705071571E4928L; +static const long double one = 1.0L; +static const long double huge = 1.0e4000L; + +/* log gamma(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x P(1/x^2) + 1/x <= 0.0741 (x >= 13.495...) + Peak relative error 1.5e-36 */ +static const long double ls2pi = 9.1893853320467274178032973640561763986140E-1L; +#define NRASY 12 +static const long double RASY[NRASY + 1] = +{ + 8.333333333333333333333333333310437112111E-2L, + -2.777777777777777777777774789556228296902E-3L, + 7.936507936507936507795933938448586499183E-4L, + -5.952380952380952041799269756378148574045E-4L, + 8.417508417507928904209891117498524452523E-4L, + -1.917526917481263997778542329739806086290E-3L, + 6.410256381217852504446848671499409919280E-3L, + -2.955064066900961649768101034477363301626E-2L, + 1.796402955865634243663453415388336954675E-1L, + -1.391522089007758553455753477688592767741E0L, + 1.326130089598399157988112385013829305510E1L, + -1.420412699593782497803472576479997819149E2L, + 1.218058922427762808938869872528846787020E3L +}; + + +/* log gamma(x+13) = log gamma(13) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 12.5 <= x+13 <= 13.5 + Peak relative error 1.1e-36 */ +static const long double lgam13a = 1.9987213134765625E1L; +static const long double lgam13b = 1.3608962611495173623870550785125024484248E-6L; +#define NRN13 7 +static const long double RN13[NRN13 + 1] = +{ + 8.591478354823578150238226576156275285700E11L, + 2.347931159756482741018258864137297157668E11L, + 2.555408396679352028680662433943000804616E10L, + 1.408581709264464345480765758902967123937E9L, + 4.126759849752613822953004114044451046321E7L, + 6.133298899622688505854211579222889943778E5L, + 3.929248056293651597987893340755876578072E3L, + 6.850783280018706668924952057996075215223E0L +}; +#define NRD13 6 +static const long double RD13[NRD13 + 1] = +{ + 3.401225382297342302296607039352935541669E11L, + 8.756765276918037910363513243563234551784E10L, + 8.873913342866613213078554180987647243903E9L, + 4.483797255342763263361893016049310017973E8L, + 1.178186288833066430952276702931512870676E7L, + 1.519928623743264797939103740132278337476E5L, + 7.989298844938119228411117593338850892311E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+12) = log gamma(12) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 11.5 <= x+12 <= 12.5 + Peak relative error 4.1e-36 */ +static const long double lgam12a = 1.75023040771484375E1L; +static const long double lgam12b = 3.7687254483392876529072161996717039575982E-6L; +#define NRN12 7 +static const long double RN12[NRN12 + 1] = +{ + 4.709859662695606986110997348630997559137E11L, + 1.398713878079497115037857470168777995230E11L, + 1.654654931821564315970930093932954900867E10L, + 9.916279414876676861193649489207282144036E8L, + 3.159604070526036074112008954113411389879E7L, + 5.109099197547205212294747623977502492861E5L, + 3.563054878276102790183396740969279826988E3L, + 6.769610657004672719224614163196946862747E0L +}; +#define NRD12 6 +static const long double RD12[NRD12 + 1] = +{ + 1.928167007860968063912467318985802726613E11L, + 5.383198282277806237247492369072266389233E10L, + 5.915693215338294477444809323037871058363E9L, + 3.241438287570196713148310560147925781342E8L, + 9.236680081763754597872713592701048455890E6L, + 1.292246897881650919242713651166596478850E5L, + 7.366532445427159272584194816076600211171E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+11) = log gamma(11) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 10.5 <= x+11 <= 11.5 + Peak relative error 1.8e-35 */ +static const long double lgam11a = 1.5104400634765625E1L; +static const long double lgam11b = 1.1938309890295225709329251070371882250744E-5L; +#define NRN11 7 +static const long double RN11[NRN11 + 1] = +{ + 2.446960438029415837384622675816736622795E11L, + 7.955444974446413315803799763901729640350E10L, + 1.030555327949159293591618473447420338444E10L, + 6.765022131195302709153994345470493334946E8L, + 2.361892792609204855279723576041468347494E7L, + 4.186623629779479136428005806072176490125E5L, + 3.202506022088912768601325534149383594049E3L, + 6.681356101133728289358838690666225691363E0L +}; +#define NRD11 6 +static const long double RD11[NRD11 + 1] = +{ + 1.040483786179428590683912396379079477432E11L, + 3.172251138489229497223696648369823779729E10L, + 3.806961885984850433709295832245848084614E9L, + 2.278070344022934913730015420611609620171E8L, + 7.089478198662651683977290023829391596481E6L, + 1.083246385105903533237139380509590158658E5L, + 6.744420991491385145885727942219463243597E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+10) = log gamma(10) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 9.5 <= x+10 <= 10.5 + Peak relative error 5.4e-37 */ +static const long double lgam10a = 1.280181884765625E1L; +static const long double lgam10b = 8.6324252196112077178745667061642811492557E-6L; +#define NRN10 7 +static const long double RN10[NRN10 + 1] = +{ + -1.239059737177249934158597996648808363783E14L, + -4.725899566371458992365624673357356908719E13L, + -7.283906268647083312042059082837754850808E12L, + -5.802855515464011422171165179767478794637E11L, + -2.532349691157548788382820303182745897298E10L, + -5.884260178023777312587193693477072061820E8L, + -6.437774864512125749845840472131829114906E6L, + -2.350975266781548931856017239843273049384E4L +}; +#define NRD10 7 +static const long double RD10[NRD10 + 1] = +{ + -5.502645997581822567468347817182347679552E13L, + -1.970266640239849804162284805400136473801E13L, + -2.819677689615038489384974042561531409392E12L, + -2.056105863694742752589691183194061265094E11L, + -8.053670086493258693186307810815819662078E9L, + -1.632090155573373286153427982504851867131E8L, + -1.483575879240631280658077826889223634921E6L, + -4.002806669713232271615885826373550502510E3L + /* 1.0E0L */ +}; + + +/* log gamma(x+9) = log gamma(9) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 8.5 <= x+9 <= 9.5 + Peak relative error 3.6e-36 */ +static const long double lgam9a = 1.06045989990234375E1L; +static const long double lgam9b = 3.9037218127284172274007216547549861681400E-6L; +#define NRN9 7 +static const long double RN9[NRN9 + 1] = +{ + -4.936332264202687973364500998984608306189E13L, + -2.101372682623700967335206138517766274855E13L, + -3.615893404644823888655732817505129444195E12L, + -3.217104993800878891194322691860075472926E11L, + -1.568465330337375725685439173603032921399E10L, + -4.073317518162025744377629219101510217761E8L, + -4.983232096406156139324846656819246974500E6L, + -2.036280038903695980912289722995505277253E4L +}; +#define NRD9 7 +static const long double RD9[NRD9 + 1] = +{ + -2.306006080437656357167128541231915480393E13L, + -9.183606842453274924895648863832233799950E12L, + -1.461857965935942962087907301194381010380E12L, + -1.185728254682789754150068652663124298303E11L, + -5.166285094703468567389566085480783070037E9L, + -1.164573656694603024184768200787835094317E8L, + -1.177343939483908678474886454113163527909E6L, + -3.529391059783109732159524500029157638736E3L + /* 1.0E0L */ +}; + + +/* log gamma(x+8) = log gamma(8) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 7.5 <= x+8 <= 8.5 + Peak relative error 2.4e-37 */ +static const long double lgam8a = 8.525146484375E0L; +static const long double lgam8b = 1.4876690414300165531036347125050759667737E-5L; +#define NRN8 8 +static const long double RN8[NRN8 + 1] = +{ + 6.600775438203423546565361176829139703289E11L, + 3.406361267593790705240802723914281025800E11L, + 7.222460928505293914746983300555538432830E10L, + 8.102984106025088123058747466840656458342E9L, + 5.157620015986282905232150979772409345927E8L, + 1.851445288272645829028129389609068641517E7L, + 3.489261702223124354745894067468953756656E5L, + 2.892095396706665774434217489775617756014E3L, + 6.596977510622195827183948478627058738034E0L +}; +#define NRD8 7 +static const long double RD8[NRD8 + 1] = +{ + 3.274776546520735414638114828622673016920E11L, + 1.581811207929065544043963828487733970107E11L, + 3.108725655667825188135393076860104546416E10L, + 3.193055010502912617128480163681842165730E9L, + 1.830871482669835106357529710116211541839E8L, + 5.790862854275238129848491555068073485086E6L, + 9.305213264307921522842678835618803553589E4L, + 6.216974105861848386918949336819572333622E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+7) = log gamma(7) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 6.5 <= x+7 <= 7.5 + Peak relative error 3.2e-36 */ +static const long double lgam7a = 6.5792388916015625E0L; +static const long double lgam7b = 1.2320408538495060178292903945321122583007E-5L; +#define NRN7 8 +static const long double RN7[NRN7 + 1] = +{ + 2.065019306969459407636744543358209942213E11L, + 1.226919919023736909889724951708796532847E11L, + 2.996157990374348596472241776917953749106E10L, + 3.873001919306801037344727168434909521030E9L, + 2.841575255593761593270885753992732145094E8L, + 1.176342515359431913664715324652399565551E7L, + 2.558097039684188723597519300356028511547E5L, + 2.448525238332609439023786244782810774702E3L, + 6.460280377802030953041566617300902020435E0L +}; +#define NRD7 7 +static const long double RD7[NRD7 + 1] = +{ + 1.102646614598516998880874785339049304483E11L, + 6.099297512712715445879759589407189290040E10L, + 1.372898136289611312713283201112060238351E10L, + 1.615306270420293159907951633566635172343E9L, + 1.061114435798489135996614242842561967459E8L, + 3.845638971184305248268608902030718674691E6L, + 7.081730675423444975703917836972720495507E4L, + 5.423122582741398226693137276201344096370E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+6) = log gamma(6) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 5.5 <= x+6 <= 6.5 + Peak relative error 6.2e-37 */ +static const long double lgam6a = 4.7874908447265625E0L; +static const long double lgam6b = 8.9805548349424770093452324304839959231517E-7L; +#define NRN6 8 +static const long double RN6[NRN6 + 1] = +{ + -3.538412754670746879119162116819571823643E13L, + -2.613432593406849155765698121483394257148E13L, + -8.020670732770461579558867891923784753062E12L, + -1.322227822931250045347591780332435433420E12L, + -1.262809382777272476572558806855377129513E11L, + -7.015006277027660872284922325741197022467E9L, + -2.149320689089020841076532186783055727299E8L, + -3.167210585700002703820077565539658995316E6L, + -1.576834867378554185210279285358586385266E4L +}; +#define NRD6 8 +static const long double RD6[NRD6 + 1] = +{ + -2.073955870771283609792355579558899389085E13L, + -1.421592856111673959642750863283919318175E13L, + -4.012134994918353924219048850264207074949E12L, + -6.013361045800992316498238470888523722431E11L, + -5.145382510136622274784240527039643430628E10L, + -2.510575820013409711678540476918249524123E9L, + -6.564058379709759600836745035871373240904E7L, + -7.861511116647120540275354855221373571536E5L, + -2.821943442729620524365661338459579270561E3L + /* 1.0E0L */ +}; + + +/* log gamma(x+5) = log gamma(5) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 4.5 <= x+5 <= 5.5 + Peak relative error 3.4e-37 */ +static const long double lgam5a = 3.17803955078125E0L; +static const long double lgam5b = 1.4279566695619646941601297055408873990961E-5L; +#define NRN5 9 +static const long double RN5[NRN5 + 1] = +{ + 2.010952885441805899580403215533972172098E11L, + 1.916132681242540921354921906708215338584E11L, + 7.679102403710581712903937970163206882492E10L, + 1.680514903671382470108010973615268125169E10L, + 2.181011222911537259440775283277711588410E9L, + 1.705361119398837808244780667539728356096E8L, + 7.792391565652481864976147945997033946360E6L, + 1.910741381027985291688667214472560023819E5L, + 2.088138241893612679762260077783794329559E3L, + 6.330318119566998299106803922739066556550E0L +}; +#define NRD5 8 +static const long double RD5[NRD5 + 1] = +{ + 1.335189758138651840605141370223112376176E11L, + 1.174130445739492885895466097516530211283E11L, + 4.308006619274572338118732154886328519910E10L, + 8.547402888692578655814445003283720677468E9L, + 9.934628078575618309542580800421370730906E8L, + 6.847107420092173812998096295422311820672E7L, + 2.698552646016599923609773122139463150403E6L, + 5.526516251532464176412113632726150253215E4L, + 4.772343321713697385780533022595450486932E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+4) = log gamma(4) + x P(x)/Q(x) + -0.5 <= x <= 0.5 + 3.5 <= x+4 <= 4.5 + Peak relative error 6.7e-37 */ +static const long double lgam4a = 1.791748046875E0L; +static const long double lgam4b = 1.1422353055000812477358380702272722990692E-5L; +#define NRN4 9 +static const long double RN4[NRN4 + 1] = +{ + -1.026583408246155508572442242188887829208E13L, + -1.306476685384622809290193031208776258809E13L, + -7.051088602207062164232806511992978915508E12L, + -2.100849457735620004967624442027793656108E12L, + -3.767473790774546963588549871673843260569E11L, + -4.156387497364909963498394522336575984206E10L, + -2.764021460668011732047778992419118757746E9L, + -1.036617204107109779944986471142938641399E8L, + -1.895730886640349026257780896972598305443E6L, + -1.180509051468390914200720003907727988201E4L +}; +#define NRD4 9 +static const long double RD4[NRD4 + 1] = +{ + -8.172669122056002077809119378047536240889E12L, + -9.477592426087986751343695251801814226960E12L, + -4.629448850139318158743900253637212801682E12L, + -1.237965465892012573255370078308035272942E12L, + -1.971624313506929845158062177061297598956E11L, + -1.905434843346570533229942397763361493610E10L, + -1.089409357680461419743730978512856675984E9L, + -3.416703082301143192939774401370222822430E7L, + -4.981791914177103793218433195857635265295E5L, + -2.192507743896742751483055798411231453733E3L + /* 1.0E0L */ +}; + + +/* log gamma(x+3) = log gamma(3) + x P(x)/Q(x) + -0.25 <= x <= 0.5 + 2.75 <= x+3 <= 3.5 + Peak relative error 6.0e-37 */ +static const long double lgam3a = 6.93145751953125E-1L; +static const long double lgam3b = 1.4286068203094172321214581765680755001344E-6L; + +#define NRN3 9 +static const long double RN3[NRN3 + 1] = +{ + -4.813901815114776281494823863935820876670E11L, + -8.425592975288250400493910291066881992620E11L, + -6.228685507402467503655405482985516909157E11L, + -2.531972054436786351403749276956707260499E11L, + -6.170200796658926701311867484296426831687E10L, + -9.211477458528156048231908798456365081135E9L, + -8.251806236175037114064561038908691305583E8L, + -4.147886355917831049939930101151160447495E7L, + -1.010851868928346082547075956946476932162E6L, + -8.333374463411801009783402800801201603736E3L +}; +#define NRD3 9 +static const long double RD3[NRD3 + 1] = +{ + -5.216713843111675050627304523368029262450E11L, + -8.014292925418308759369583419234079164391E11L, + -5.180106858220030014546267824392678611990E11L, + -1.830406975497439003897734969120997840011E11L, + -3.845274631904879621945745960119924118925E10L, + -4.891033385370523863288908070309417710903E9L, + -3.670172254411328640353855768698287474282E8L, + -1.505316381525727713026364396635522516989E7L, + -2.856327162923716881454613540575964890347E5L, + -1.622140448015769906847567212766206894547E3L + /* 1.0E0L */ +}; + + +/* log gamma(x+2.5) = log gamma(2.5) + x P(x)/Q(x) + -0.125 <= x <= 0.25 + 2.375 <= x+2.5 <= 2.75 */ +static const long double lgam2r5a = 2.8466796875E-1L; +static const long double lgam2r5b = 1.4901722919159632494669682701924320137696E-5L; +#define NRN2r5 8 +static const long double RN2r5[NRN2r5 + 1] = +{ + -4.676454313888335499356699817678862233205E9L, + -9.361888347911187924389905984624216340639E9L, + -7.695353600835685037920815799526540237703E9L, + -3.364370100981509060441853085968900734521E9L, + -8.449902011848163568670361316804900559863E8L, + -1.225249050950801905108001246436783022179E8L, + -9.732972931077110161639900388121650470926E6L, + -3.695711763932153505623248207576425983573E5L, + -4.717341584067827676530426007495274711306E3L +}; +#define NRD2r5 8 +static const long double RD2r5[NRD2r5 + 1] = +{ + -6.650657966618993679456019224416926875619E9L, + -1.099511409330635807899718829033488771623E10L, + -7.482546968307837168164311101447116903148E9L, + -2.702967190056506495988922973755870557217E9L, + -5.570008176482922704972943389590409280950E8L, + -6.536934032192792470926310043166993233231E7L, + -4.101991193844953082400035444146067511725E6L, + -1.174082735875715802334430481065526664020E5L, + -9.932840389994157592102947657277692978511E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+2) = x P(x)/Q(x) + -0.125 <= x <= +0.375 + 1.875 <= x+2 <= 2.375 + Peak relative error 4.6e-36 */ +#define NRN2 9 +static const long double RN2[NRN2 + 1] = +{ + -3.716661929737318153526921358113793421524E9L, + -1.138816715030710406922819131397532331321E10L, + -1.421017419363526524544402598734013569950E10L, + -9.510432842542519665483662502132010331451E9L, + -3.747528562099410197957514973274474767329E9L, + -8.923565763363912474488712255317033616626E8L, + -1.261396653700237624185350402781338231697E8L, + -9.918402520255661797735331317081425749014E6L, + -3.753996255897143855113273724233104768831E5L, + -4.778761333044147141559311805999540765612E3L +}; +#define NRD2 9 +static const long double RD2[NRD2 + 1] = +{ + -8.790916836764308497770359421351673950111E9L, + -2.023108608053212516399197678553737477486E10L, + -1.958067901852022239294231785363504458367E10L, + -1.035515043621003101254252481625188704529E10L, + -3.253884432621336737640841276619272224476E9L, + -6.186383531162456814954947669274235815544E8L, + -6.932557847749518463038934953605969951466E7L, + -4.240731768287359608773351626528479703758E6L, + -1.197343995089189188078944689846348116630E5L, + -1.004622911670588064824904487064114090920E3L +/* 1.0E0 */ +}; + + +/* log gamma(x+1.75) = log gamma(1.75) + x P(x)/Q(x) + -0.125 <= x <= +0.125 + 1.625 <= x+1.75 <= 1.875 + Peak relative error 9.2e-37 */ +static const long double lgam1r75a = -8.441162109375E-2L; +static const long double lgam1r75b = 1.0500073264444042213965868602268256157604E-5L; +#define NRN1r75 8 +static const long double RN1r75[NRN1r75 + 1] = +{ + -5.221061693929833937710891646275798251513E7L, + -2.052466337474314812817883030472496436993E8L, + -2.952718275974940270675670705084125640069E8L, + -2.132294039648116684922965964126389017840E8L, + -8.554103077186505960591321962207519908489E7L, + -1.940250901348870867323943119132071960050E7L, + -2.379394147112756860769336400290402208435E6L, + -1.384060879999526222029386539622255797389E5L, + -2.698453601378319296159355612094598695530E3L +}; +#define NRD1r75 8 +static const long double RD1r75[NRD1r75 + 1] = +{ + -2.109754689501705828789976311354395393605E8L, + -5.036651829232895725959911504899241062286E8L, + -4.954234699418689764943486770327295098084E8L, + -2.589558042412676610775157783898195339410E8L, + -7.731476117252958268044969614034776883031E7L, + -1.316721702252481296030801191240867486965E7L, + -1.201296501404876774861190604303728810836E6L, + -5.007966406976106636109459072523610273928E4L, + -6.155817990560743422008969155276229018209E2L + /* 1.0E0L */ +}; + + +/* log gamma(x+x0) = y0 + x^2 P(x)/Q(x) + -0.0867 <= x <= +0.1634 + 1.374932... <= x+x0 <= 1.625032... + Peak relative error 4.0e-36 */ +static const long double x0a = 1.4616241455078125L; +static const long double x0b = 7.9994605498412626595423257213002588621246E-6L; +static const long double y0a = -1.21490478515625E-1L; +static const long double y0b = 4.1879797753919044854428223084178486438269E-6L; +#define NRN1r5 8 +static const long double RN1r5[NRN1r5 + 1] = +{ + 6.827103657233705798067415468881313128066E5L, + 1.910041815932269464714909706705242148108E6L, + 2.194344176925978377083808566251427771951E6L, + 1.332921400100891472195055269688876427962E6L, + 4.589080973377307211815655093824787123508E5L, + 8.900334161263456942727083580232613796141E4L, + 9.053840838306019753209127312097612455236E3L, + 4.053367147553353374151852319743594873771E2L, + 5.040631576303952022968949605613514584950E0L +}; +#define NRD1r5 8 +static const long double RD1r5[NRD1r5 + 1] = +{ + 1.411036368843183477558773688484699813355E6L, + 4.378121767236251950226362443134306184849E6L, + 5.682322855631723455425929877581697918168E6L, + 3.999065731556977782435009349967042222375E6L, + 1.653651390456781293163585493620758410333E6L, + 4.067774359067489605179546964969435858311E5L, + 5.741463295366557346748361781768833633256E4L, + 4.226404539738182992856094681115746692030E3L, + 1.316980975410327975566999780608618774469E2L, + /* 1.0E0L */ +}; + + +/* log gamma(x+1.25) = log gamma(1.25) + x P(x)/Q(x) + -.125 <= x <= +.125 + 1.125 <= x+1.25 <= 1.375 + Peak relative error = 4.9e-36 */ +static const long double lgam1r25a = -9.82818603515625E-2L; +static const long double lgam1r25b = 1.0023929749338536146197303364159774377296E-5L; +#define NRN1r25 9 +static const long double RN1r25[NRN1r25 + 1] = +{ + -9.054787275312026472896002240379580536760E4L, + -8.685076892989927640126560802094680794471E4L, + 2.797898965448019916967849727279076547109E5L, + 6.175520827134342734546868356396008898299E5L, + 5.179626599589134831538516906517372619641E5L, + 2.253076616239043944538380039205558242161E5L, + 5.312653119599957228630544772499197307195E4L, + 6.434329437514083776052669599834938898255E3L, + 3.385414416983114598582554037612347549220E2L, + 4.907821957946273805080625052510832015792E0L +}; +#define NRD1r25 8 +static const long double RD1r25[NRD1r25 + 1] = +{ + 3.980939377333448005389084785896660309000E5L, + 1.429634893085231519692365775184490465542E6L, + 2.145438946455476062850151428438668234336E6L, + 1.743786661358280837020848127465970357893E6L, + 8.316364251289743923178092656080441655273E5L, + 2.355732939106812496699621491135458324294E5L, + 3.822267399625696880571810137601310855419E4L, + 3.228463206479133236028576845538387620856E3L, + 1.152133170470059555646301189220117965514E2L + /* 1.0E0L */ +}; + + +/* log gamma(x + 1) = x P(x)/Q(x) + 0.0 <= x <= +0.125 + 1.0 <= x+1 <= 1.125 + Peak relative error 1.1e-35 */ +#define NRN1 8 +static const long double RN1[NRN1 + 1] = +{ + -9.987560186094800756471055681088744738818E3L, + -2.506039379419574361949680225279376329742E4L, + -1.386770737662176516403363873617457652991E4L, + 1.439445846078103202928677244188837130744E4L, + 2.159612048879650471489449668295139990693E4L, + 1.047439813638144485276023138173676047079E4L, + 2.250316398054332592560412486630769139961E3L, + 1.958510425467720733041971651126443864041E2L, + 4.516830313569454663374271993200291219855E0L +}; +#define NRD1 7 +static const long double RD1[NRD1 + 1] = +{ + 1.730299573175751778863269333703788214547E4L, + 6.807080914851328611903744668028014678148E4L, + 1.090071629101496938655806063184092302439E5L, + 9.124354356415154289343303999616003884080E4L, + 4.262071638655772404431164427024003253954E4L, + 1.096981664067373953673982635805821283581E4L, + 1.431229503796575892151252708527595787588E3L, + 7.734110684303689320830401788262295992921E1L + /* 1.0E0 */ +}; + + +/* log gamma(x + 1) = x P(x)/Q(x) + -0.125 <= x <= 0 + 0.875 <= x+1 <= 1.0 + Peak relative error 7.0e-37 */ +#define NRNr9 8 +static const long double RNr9[NRNr9 + 1] = +{ + 4.441379198241760069548832023257571176884E5L, + 1.273072988367176540909122090089580368732E6L, + 9.732422305818501557502584486510048387724E5L, + -5.040539994443998275271644292272870348684E5L, + -1.208719055525609446357448132109723786736E6L, + -7.434275365370936547146540554419058907156E5L, + -2.075642969983377738209203358199008185741E5L, + -2.565534860781128618589288075109372218042E4L, + -1.032901669542994124131223797515913955938E3L, +}; +#define NRDr9 8 +static const long double RDr9[NRDr9 + 1] = +{ + -7.694488331323118759486182246005193998007E5L, + -3.301918855321234414232308938454112213751E6L, + -5.856830900232338906742924836032279404702E6L, + -5.540672519616151584486240871424021377540E6L, + -3.006530901041386626148342989181721176919E6L, + -9.350378280513062139466966374330795935163E5L, + -1.566179100031063346901755685375732739511E5L, + -1.205016539620260779274902967231510804992E4L, + -2.724583156305709733221564484006088794284E2L +/* 1.0E0 */ +}; + + +/* Evaluate P[n] x^n + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +neval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + +/* Evaluate x^n+1 + P[n] x^(n) + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +deval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = x + *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + +long double +lgammal_r(long double x, int *signgamp) +{ + long double p, q, w, z, nx; + int i, nn; + + *signgamp = 1; + + if (!isfinite (x)) + return x * x; + + if (x == 0.0L) + { + if (signbit (x)) + *signgamp = -1; + return one / fabsl (x); + } + + if (x < 0.0L) + { + q = -x; + p = floorl (q); + if (p == q) + return (one / (p - p)); + i = p; + if ((i & 1) == 0) + *signgamp = -1; + else + *signgamp = 1; + z = q - p; + if (z > 0.5L) + { + p += 1.0L; + z = p - q; + } + z = q * sinl (PIL * z); + if (z == 0.0L) + return (*signgamp * huge * huge); + w = lgammal (q); + z = logl (PIL / z) - w; + return (z); + } + + if (x < 13.5L) + { + p = 0.0L; + nx = floorl (x + 0.5L); + nn = nx; + switch (nn) + { + case 0: + /* log gamma (x + 1) = log(x) + log gamma(x) */ + if (x <= 0.125) + { + p = x * neval (x, RN1, NRN1) / deval (x, RD1, NRD1); + } + else if (x <= 0.375) + { + z = x - 0.25L; + p = z * neval (z, RN1r25, NRN1r25) / deval (z, RD1r25, NRD1r25); + p += lgam1r25b; + p += lgam1r25a; + } + else if (x <= 0.625) + { + z = x + (1.0L - x0a); + z = z - x0b; + p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5); + p = p * z * z; + p = p + y0b; + p = p + y0a; + } + else if (x <= 0.875) + { + z = x - 0.75L; + p = z * neval (z, RN1r75, NRN1r75) / deval (z, RD1r75, NRD1r75); + p += lgam1r75b; + p += lgam1r75a; + } + else + { + z = x - 1.0L; + p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2); + } + p = p - logl (x); + break; + + case 1: + if (x < 0.875L) + { + if (x <= 0.625) + { + z = x + (1.0L - x0a); + z = z - x0b; + p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5); + p = p * z * z; + p = p + y0b; + p = p + y0a; + } + else if (x <= 0.875) + { + z = x - 0.75L; + p = z * neval (z, RN1r75, NRN1r75) + / deval (z, RD1r75, NRD1r75); + p += lgam1r75b; + p += lgam1r75a; + } + else + { + z = x - 1.0L; + p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2); + } + p = p - logl (x); + } + else if (x < 1.0L) + { + z = x - 1.0L; + p = z * neval (z, RNr9, NRNr9) / deval (z, RDr9, NRDr9); + } + else if (x == 1.0L) + p = 0.0L; + else if (x <= 1.125L) + { + z = x - 1.0L; + p = z * neval (z, RN1, NRN1) / deval (z, RD1, NRD1); + } + else if (x <= 1.375) + { + z = x - 1.25L; + p = z * neval (z, RN1r25, NRN1r25) / deval (z, RD1r25, NRD1r25); + p += lgam1r25b; + p += lgam1r25a; + } + else + { + /* 1.375 <= x+x0 <= 1.625 */ + z = x - x0a; + z = z - x0b; + p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5); + p = p * z * z; + p = p + y0b; + p = p + y0a; + } + break; + + case 2: + if (x < 1.625L) + { + z = x - x0a; + z = z - x0b; + p = neval (z, RN1r5, NRN1r5) / deval (z, RD1r5, NRD1r5); + p = p * z * z; + p = p + y0b; + p = p + y0a; + } + else if (x < 1.875L) + { + z = x - 1.75L; + p = z * neval (z, RN1r75, NRN1r75) / deval (z, RD1r75, NRD1r75); + p += lgam1r75b; + p += lgam1r75a; + } + else if (x == 2.0L) + p = 0.0L; + else if (x < 2.375L) + { + z = x - 2.0L; + p = z * neval (z, RN2, NRN2) / deval (z, RD2, NRD2); + } + else + { + z = x - 2.5L; + p = z * neval (z, RN2r5, NRN2r5) / deval (z, RD2r5, NRD2r5); + p += lgam2r5b; + p += lgam2r5a; + } + break; + + case 3: + if (x < 2.75) + { + z = x - 2.5L; + p = z * neval (z, RN2r5, NRN2r5) / deval (z, RD2r5, NRD2r5); + p += lgam2r5b; + p += lgam2r5a; + } + else + { + z = x - 3.0L; + p = z * neval (z, RN3, NRN3) / deval (z, RD3, NRD3); + p += lgam3b; + p += lgam3a; + } + break; + + case 4: + z = x - 4.0L; + p = z * neval (z, RN4, NRN4) / deval (z, RD4, NRD4); + p += lgam4b; + p += lgam4a; + break; + + case 5: + z = x - 5.0L; + p = z * neval (z, RN5, NRN5) / deval (z, RD5, NRD5); + p += lgam5b; + p += lgam5a; + break; + + case 6: + z = x - 6.0L; + p = z * neval (z, RN6, NRN6) / deval (z, RD6, NRD6); + p += lgam6b; + p += lgam6a; + break; + + case 7: + z = x - 7.0L; + p = z * neval (z, RN7, NRN7) / deval (z, RD7, NRD7); + p += lgam7b; + p += lgam7a; + break; + + case 8: + z = x - 8.0L; + p = z * neval (z, RN8, NRN8) / deval (z, RD8, NRD8); + p += lgam8b; + p += lgam8a; + break; + + case 9: + z = x - 9.0L; + p = z * neval (z, RN9, NRN9) / deval (z, RD9, NRD9); + p += lgam9b; + p += lgam9a; + break; + + case 10: + z = x - 10.0L; + p = z * neval (z, RN10, NRN10) / deval (z, RD10, NRD10); + p += lgam10b; + p += lgam10a; + break; + + case 11: + z = x - 11.0L; + p = z * neval (z, RN11, NRN11) / deval (z, RD11, NRD11); + p += lgam11b; + p += lgam11a; + break; + + case 12: + z = x - 12.0L; + p = z * neval (z, RN12, NRN12) / deval (z, RD12, NRD12); + p += lgam12b; + p += lgam12a; + break; + + case 13: + z = x - 13.0L; + p = z * neval (z, RN13, NRN13) / deval (z, RD13, NRD13); + p += lgam13b; + p += lgam13a; + break; + } + return p; + } + + if (x > MAXLGM) + return (*signgamp * huge * huge); + + q = ls2pi - x; + q = (x - 0.5L) * logl (x) + q; + if (x > 1.0e18L) + return (q); + + p = 1.0L / (x * x); + q += neval (p, RASY, NRASY) / x; + return (q); +} diff --git a/src/openlibm/ld128/e_log10l.c b/src/openlibm/ld128/e_log10l.c new file mode 100644 index 0000000..9448101 --- /dev/null +++ b/src/openlibm/ld128/e_log10l.c @@ -0,0 +1,255 @@ +/* $OpenBSD: e_log10l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log10l.c + * + * Common logarithm, 128-bit long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 2.3e-34 4.9e-35 + * IEEE exp(+-10000) 30000 1.0e-34 4.1e-35 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + */ + +#include + +#include "math_private.h" + +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 5.3e-37, + * relative peak error spread = 2.3e-14 + */ +static const long double P[13] = +{ + 1.313572404063446165910279910527789794488E4L, + 7.771154681358524243729929227226708890930E4L, + 2.014652742082537582487669938141683759923E5L, + 3.007007295140399532324943111654767187848E5L, + 2.854829159639697837788887080758954924001E5L, + 1.797628303815655343403735250238293741397E5L, + 7.594356839258970405033155585486712125861E4L, + 2.128857716871515081352991964243375186031E4L, + 3.824952356185897735160588078446136783779E3L, + 4.114517881637811823002128927449878962058E2L, + 2.321125933898420063925789532045674660756E1L, + 4.998469661968096229986658302195402690910E-1L, + 1.538612243596254322971797716843006400388E-6L +}; +static const long double Q[12] = +{ + 3.940717212190338497730839731583397586124E4L, + 2.626900195321832660448791748036714883242E5L, + 7.777690340007566932935753241556479363645E5L, + 1.347518538384329112529391120390701166528E6L, + 1.514882452993549494932585972882995548426E6L, + 1.158019977462989115839826904108208787040E6L, + 6.132189329546557743179177159925690841200E5L, + 2.248234257620569139969141618556349415120E5L, + 5.605842085972455027590989944010492125825E4L, + 9.147150349299596453976674231612674085381E3L, + 9.104928120962988414618126155557301584078E2L, + 4.839208193348159620282142911143429644326E1L +/* 1.000000000000000000000000000000000000000E0L, */ +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 1.1e-35, + * relative peak error spread 1.1e-9 + */ +static const long double R[6] = +{ + 1.418134209872192732479751274970992665513E5L, + -8.977257995689735303686582344659576526998E4L, + 2.048819892795278657810231591630928516206E4L, + -2.024301798136027039250415126250455056397E3L, + 8.057002716646055371965756206836056074715E1L, + -8.828896441624934385266096344596648080902E-1L +}; +static const long double S[6] = +{ + 1.701761051846631278975701529965589676574E6L, + -1.332535117259762928288745111081235577029E6L, + 4.001557694070773974936904547424676279307E5L, + -5.748542087379434595104154610899551484314E4L, + 3.998526750980007367835804959888064681098E3L, + -1.186359407982897997337150403816839480438E2L +/* 1.000000000000000000000000000000000000000E0L, */ +}; + +static const long double +/* log10(2) */ +L102A = 0.3125L, +L102B = -1.14700043360188047862611052755069732318101185E-2L, +/* log10(e) */ +L10EA = 0.5L, +L10EB = -6.570551809674817234887108108339491770560299E-2L, +/* sqrt(2)/2 */ +SQRTH = 7.071067811865475244008443621048490392848359E-1L; + + + +/* Evaluate P[n] x^n + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +neval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + +/* Evaluate x^n+1 + P[n] x^(n) + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +deval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = x + *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + + +long double +log10l(long double x) +{ + long double z; + long double y; + int e; + int64_t hx, lx; + +/* Test for domain */ + GET_LDOUBLE_WORDS64 (hx, lx, x); + if (((hx & 0x7fffffffffffffffLL) | lx) == 0) + return (-1.0L / (x - x)); + if (hx < 0) + return (x - x) / (x - x); + if (hx >= 0x7fff000000000000LL) + return (x + x); + +/* separate mantissa from exponent */ + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl (x, &e); + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if ((e > 2) || (e < -2)) + { + if (x < SQRTH) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } + else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } + x = z / y; + z = x * x; + y = x * (z * neval (z, R, 5) / deval (z, S, 5)); + goto done; + } + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + + if (x < SQRTH) + { + e -= 1; + x = 2.0 * x - 1.0L; /* 2x - 1 */ + } + else + { + x = x - 1.0L; + } + z = x * x; + y = x * (z * neval (x, P, 12) / deval (x, Q, 11)); + y = y - 0.5 * z; + +done: + + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + */ + z = y * L10EB; + z += x * L10EB; + z += e * L102B; + z += y * L10EA; + z += x * L10EA; + z += e * L102A; + return (z); +} diff --git a/src/openlibm/ld128/e_log2l.c b/src/openlibm/ld128/e_log2l.c new file mode 100644 index 0000000..2ce4d94 --- /dev/null +++ b/src/openlibm/ld128/e_log2l.c @@ -0,0 +1,248 @@ +/* $OpenBSD: e_log2l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log2l.c + * Base 2 logarithm, 128-bit long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 100,000 2.6e-34 4.9e-35 + * IEEE exp(+-10000) 100,000 9.6e-35 4.0e-35 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + */ + +#include + +#include "math_private.h" + +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 5.3e-37, + * relative peak error spread = 2.3e-14 + */ +static const long double P[13] = +{ + 1.313572404063446165910279910527789794488E4L, + 7.771154681358524243729929227226708890930E4L, + 2.014652742082537582487669938141683759923E5L, + 3.007007295140399532324943111654767187848E5L, + 2.854829159639697837788887080758954924001E5L, + 1.797628303815655343403735250238293741397E5L, + 7.594356839258970405033155585486712125861E4L, + 2.128857716871515081352991964243375186031E4L, + 3.824952356185897735160588078446136783779E3L, + 4.114517881637811823002128927449878962058E2L, + 2.321125933898420063925789532045674660756E1L, + 4.998469661968096229986658302195402690910E-1L, + 1.538612243596254322971797716843006400388E-6L +}; +static const long double Q[12] = +{ + 3.940717212190338497730839731583397586124E4L, + 2.626900195321832660448791748036714883242E5L, + 7.777690340007566932935753241556479363645E5L, + 1.347518538384329112529391120390701166528E6L, + 1.514882452993549494932585972882995548426E6L, + 1.158019977462989115839826904108208787040E6L, + 6.132189329546557743179177159925690841200E5L, + 2.248234257620569139969141618556349415120E5L, + 5.605842085972455027590989944010492125825E4L, + 9.147150349299596453976674231612674085381E3L, + 9.104928120962988414618126155557301584078E2L, + 4.839208193348159620282142911143429644326E1L +/* 1.000000000000000000000000000000000000000E0L, */ +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 1.1e-35, + * relative peak error spread 1.1e-9 + */ +static const long double R[6] = +{ + 1.418134209872192732479751274970992665513E5L, + -8.977257995689735303686582344659576526998E4L, + 2.048819892795278657810231591630928516206E4L, + -2.024301798136027039250415126250455056397E3L, + 8.057002716646055371965756206836056074715E1L, + -8.828896441624934385266096344596648080902E-1L +}; +static const long double S[6] = +{ + 1.701761051846631278975701529965589676574E6L, + -1.332535117259762928288745111081235577029E6L, + 4.001557694070773974936904547424676279307E5L, + -5.748542087379434595104154610899551484314E4L, + 3.998526750980007367835804959888064681098E3L, + -1.186359407982897997337150403816839480438E2L +/* 1.000000000000000000000000000000000000000E0L, */ +}; + +static const long double +/* log2(e) - 1 */ +LOG2EA = 4.4269504088896340735992468100189213742664595E-1L, +/* sqrt(2)/2 */ +SQRTH = 7.071067811865475244008443621048490392848359E-1L; + + +/* Evaluate P[n] x^n + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +neval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + +/* Evaluate x^n+1 + P[n] x^(n) + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +deval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = x + *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + + +long double +log2l(long double x) +{ + long double z; + long double y; + int e; + int64_t hx, lx; + +/* Test for domain */ + GET_LDOUBLE_WORDS64 (hx, lx, x); + if (((hx & 0x7fffffffffffffffLL) | lx) == 0) + return (-1.0L / (x - x)); + if (hx < 0) + return (x - x) / (x - x); + if (hx >= 0x7fff000000000000LL) + return (x + x); + +/* separate mantissa from exponent */ + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl (x, &e); + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if ((e > 2) || (e < -2)) + { + if (x < SQRTH) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } + else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } + x = z / y; + z = x * x; + y = x * (z * neval (z, R, 5) / deval (z, S, 5)); + goto done; + } + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + + if (x < SQRTH) + { + e -= 1; + x = 2.0 * x - 1.0L; /* 2x - 1 */ + } + else + { + x = x - 1.0L; + } + z = x * x; + y = x * (z * neval (x, P, 12) / deval (x, Q, 11)); + y = y - 0.5 * z; + +done: + +/* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return (z); +} diff --git a/src/openlibm/ld128/e_logl.c b/src/openlibm/ld128/e_logl.c new file mode 100644 index 0000000..f6da91f --- /dev/null +++ b/src/openlibm/ld128/e_logl.c @@ -0,0 +1,283 @@ +/* $OpenBSD: e_logl.c,v 1.1 2011/07/06 00:02:42 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* logl.c + * + * Natural logarithm for 128-bit long double precision. + * + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. Use of a lookup table increases the speed of the routine. + * The program uses logarithms tabulated at intervals of 1/128 to + * cover the domain from approximately 0.7 to 1.4. + * + * On the interval [-1/128, +1/128] the logarithm of 1+x is approximated by + * log(1+x) = x - 0.5 x^2 + x^3 P(x) . + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.875, 1.125 100000 1.2e-34 4.1e-35 + * IEEE 0.125, 8 100000 1.2e-34 4.1e-35 + * + * + * WARNING: + * + * This program uses integer operations on bit fields of floating-point + * numbers. It does not work with data structures other than the + * structure assumed. + * + */ + +#include + +#include "math_private.h" + +/* log(1+x) = x - .5 x^2 + x^3 l(x) + -.0078125 <= x <= +.0078125 + peak relative error 1.2e-37 */ +static const long double +l3 = 3.333333333333333333333333333333336096926E-1L, +l4 = -2.499999999999999999999999999486853077002E-1L, +l5 = 1.999999999999999999999999998515277861905E-1L, +l6 = -1.666666666666666666666798448356171665678E-1L, +l7 = 1.428571428571428571428808945895490721564E-1L, +l8 = -1.249999999999999987884655626377588149000E-1L, +l9 = 1.111111111111111093947834982832456459186E-1L, +l10 = -1.000000000000532974938900317952530453248E-1L, +l11 = 9.090909090915566247008015301349979892689E-2L, +l12 = -8.333333211818065121250921925397567745734E-2L, +l13 = 7.692307559897661630807048686258659316091E-2L, +l14 = -7.144242754190814657241902218399056829264E-2L, +l15 = 6.668057591071739754844678883223432347481E-2L; + +/* Lookup table of ln(t) - (t-1) + t = 0.5 + (k+26)/128) + k = 0, ..., 91 */ +static const long double logtbl[92] = { +-5.5345593589352099112142921677820359632418E-2L, +-5.2108257402767124761784665198737642086148E-2L, +-4.8991686870576856279407775480686721935120E-2L, +-4.5993270766361228596215288742353061431071E-2L, +-4.3110481649613269682442058976885699556950E-2L, +-4.0340872319076331310838085093194799765520E-2L, +-3.7682072451780927439219005993827431503510E-2L, +-3.5131785416234343803903228503274262719586E-2L, +-3.2687785249045246292687241862699949178831E-2L, +-3.0347913785027239068190798397055267411813E-2L, +-2.8110077931525797884641940838507561326298E-2L, +-2.5972247078357715036426583294246819637618E-2L, +-2.3932450635346084858612873953407168217307E-2L, +-2.1988775689981395152022535153795155900240E-2L, +-2.0139364778244501615441044267387667496733E-2L, +-1.8382413762093794819267536615342902718324E-2L, +-1.6716169807550022358923589720001638093023E-2L, +-1.5138929457710992616226033183958974965355E-2L, +-1.3649036795397472900424896523305726435029E-2L, +-1.2244881690473465543308397998034325468152E-2L, +-1.0924898127200937840689817557742469105693E-2L, +-9.6875626072830301572839422532631079809328E-3L, +-8.5313926245226231463436209313499745894157E-3L, +-7.4549452072765973384933565912143044991706E-3L, +-6.4568155251217050991200599386801665681310E-3L, +-5.5356355563671005131126851708522185605193E-3L, +-4.6900728132525199028885749289712348829878E-3L, +-3.9188291218610470766469347968659624282519E-3L, +-3.2206394539524058873423550293617843896540E-3L, +-2.5942708080877805657374888909297113032132E-3L, +-2.0385211375711716729239156839929281289086E-3L, +-1.5522183228760777967376942769773768850872E-3L, +-1.1342191863606077520036253234446621373191E-3L, +-7.8340854719967065861624024730268350459991E-4L, +-4.9869831458030115699628274852562992756174E-4L, +-2.7902661731604211834685052867305795169688E-4L, +-1.2335696813916860754951146082826952093496E-4L, +-3.0677461025892873184042490943581654591817E-5L, +#define ZERO logtbl[38] + 0.0000000000000000000000000000000000000000E0L, +-3.0359557945051052537099938863236321874198E-5L, +-1.2081346403474584914595395755316412213151E-4L, +-2.7044071846562177120083903771008342059094E-4L, +-4.7834133324631162897179240322783590830326E-4L, +-7.4363569786340080624467487620270965403695E-4L, +-1.0654639687057968333207323853366578860679E-3L, +-1.4429854811877171341298062134712230604279E-3L, +-1.8753781835651574193938679595797367137975E-3L, +-2.3618380914922506054347222273705859653658E-3L, +-2.9015787624124743013946600163375853631299E-3L, +-3.4938307889254087318399313316921940859043E-3L, +-4.1378413103128673800485306215154712148146E-3L, +-4.8328735414488877044289435125365629849599E-3L, +-5.5782063183564351739381962360253116934243E-3L, +-6.3731336597098858051938306767880719015261E-3L, +-7.2169643436165454612058905294782949315193E-3L, +-8.1090214990427641365934846191367315083867E-3L, +-9.0486422112807274112838713105168375482480E-3L, +-1.0035177140880864314674126398350812606841E-2L, +-1.1067990155502102718064936259435676477423E-2L, +-1.2146457974158024928196575103115488672416E-2L, +-1.3269969823361415906628825374158424754308E-2L, +-1.4437927104692837124388550722759686270765E-2L, +-1.5649743073340777659901053944852735064621E-2L, +-1.6904842527181702880599758489058031645317E-2L, +-1.8202661505988007336096407340750378994209E-2L, +-1.9542647000370545390701192438691126552961E-2L, +-2.0924256670080119637427928803038530924742E-2L, +-2.2346958571309108496179613803760727786257E-2L, +-2.3810230892650362330447187267648486279460E-2L, +-2.5313561699385640380910474255652501521033E-2L, +-2.6856448685790244233704909690165496625399E-2L, +-2.8438398935154170008519274953860128449036E-2L, +-3.0058928687233090922411781058956589863039E-2L, +-3.1717563112854831855692484086486099896614E-2L, +-3.3413836095418743219397234253475252001090E-2L, +-3.5147290019036555862676702093393332533702E-2L, +-3.6917475563073933027920505457688955423688E-2L, +-3.8723951502862058660874073462456610731178E-2L, +-4.0566284516358241168330505467000838017425E-2L, +-4.2444048996543693813649967076598766917965E-2L, +-4.4356826869355401653098777649745233339196E-2L, +-4.6304207416957323121106944474331029996141E-2L, +-4.8285787106164123613318093945035804818364E-2L, +-5.0301169421838218987124461766244507342648E-2L, +-5.2349964705088137924875459464622098310997E-2L, +-5.4431789996103111613753440311680967840214E-2L, +-5.6546268881465384189752786409400404404794E-2L, +-5.8693031345788023909329239565012647817664E-2L, +-6.0871713627532018185577188079210189048340E-2L, +-6.3081958078862169742820420185833800925568E-2L, +-6.5323413029406789694910800219643791556918E-2L, +-6.7595732653791419081537811574227049288168E-2L +}; + +/* ln(2) = ln2a + ln2b with extended precision. */ +static const long double + ln2a = 6.93145751953125e-1L, + ln2b = 1.4286068203094172321214581765680755001344E-6L; + +long double +logl(long double x) +{ + long double z, y, w; + ieee_quad_shape_type u, t; + unsigned int m; + int k, e; + + u.value = x; + m = u.parts32.mswhi; + + /* Check for IEEE special cases. */ + k = m & 0x7fffffff; + /* log(0) = -infinity. */ + if ((k | u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0) + { + return -0.5L / ZERO; + } + /* log ( x < 0 ) = NaN */ + if (m & 0x80000000) + { + return (x - x) / ZERO; + } + /* log (infinity or NaN) */ + if (k >= 0x7fff0000) + { + return x + x; + } + + /* Extract exponent and reduce domain to 0.703125 <= u < 1.40625 */ + e = (int) (m >> 16) - (int) 0x3ffe; + m &= 0xffff; + u.parts32.mswhi = m | 0x3ffe0000; + m |= 0x10000; + /* Find lookup table index k from high order bits of the significand. */ + if (m < 0x16800) + { + k = (m - 0xff00) >> 9; + /* t is the argument 0.5 + (k+26)/128 + of the nearest item to u in the lookup table. */ + t.parts32.mswhi = 0x3fff0000 + (k << 9); + t.parts32.mswlo = 0; + t.parts32.lswhi = 0; + t.parts32.lswlo = 0; + u.parts32.mswhi += 0x10000; + e -= 1; + k += 64; + } + else + { + k = (m - 0xfe00) >> 10; + t.parts32.mswhi = 0x3ffe0000 + (k << 10); + t.parts32.mswlo = 0; + t.parts32.lswhi = 0; + t.parts32.lswlo = 0; + } + /* On this interval the table is not used due to cancellation error. */ + if ((x <= 1.0078125L) && (x >= 0.9921875L)) + { + z = x - 1.0L; + k = 64; + t.value = 1.0L; + e = 0; + } + else + { + /* log(u) = log( t u/t ) = log(t) + log(u/t) + log(t) is tabulated in the lookup table. + Express log(u/t) = log(1+z), where z = u/t - 1 = (u-t)/t. + cf. Cody & Waite. */ + z = (u.value - t.value) / t.value; + } + /* Series expansion of log(1+z). */ + w = z * z; + y = ((((((((((((l15 * z + + l14) * z + + l13) * z + + l12) * z + + l11) * z + + l10) * z + + l9) * z + + l8) * z + + l7) * z + + l6) * z + + l5) * z + + l4) * z + + l3) * z * w; + y -= 0.5 * w; + y += e * ln2b; /* Base 2 exponent offset times ln(2). */ + y += z; + y += logtbl[k-26]; /* log(t) - (t-1) */ + y += (t.value - 1.0L); + y += e * ln2a; + return y; +} diff --git a/src/openlibm/ld128/e_powl.c b/src/openlibm/ld128/e_powl.c new file mode 100644 index 0000000..430b261 --- /dev/null +++ b/src/openlibm/ld128/e_powl.c @@ -0,0 +1,439 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* powl(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 113-53 = 60 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + */ + +#include + +#include "math_private.h" + +static const long double bp[] = { + 1.0L, + 1.5L, +}; + +/* log_2(1.5) */ +static const long double dp_h[] = { + 0.0, + 5.8496250072115607565592654282227158546448E-1L +}; + +/* Low part of log_2(1.5) */ +static const long double dp_l[] = { + 0.0, + 1.0579781240112554492329533686862998106046E-16L +}; + +static const long double zero = 0.0L, + one = 1.0L, + two = 2.0L, + two113 = 1.0384593717069655257060992658440192E34L, + huge = 1.0e3000L, + tiny = 1.0e-3000L; + +/* 3/2 log x = 3 z + z^3 + z^3 (z^2 R(z^2)) + z = (x-1)/(x+1) + 1 <= x <= 1.25 + Peak relative error 2.3e-37 */ +static const long double LN[] = +{ + -3.0779177200290054398792536829702930623200E1L, + 6.5135778082209159921251824580292116201640E1L, + -4.6312921812152436921591152809994014413540E1L, + 1.2510208195629420304615674658258363295208E1L, + -9.9266909031921425609179910128531667336670E-1L +}; +static const long double LD[] = +{ + -5.129862866715009066465422805058933131960E1L, + 1.452015077564081884387441590064272782044E2L, + -1.524043275549860505277434040464085593165E2L, + 7.236063513651544224319663428634139768808E1L, + -1.494198912340228235853027849917095580053E1L + /* 1.0E0 */ +}; + +/* exp(x) = 1 + x - x / (1 - 2 / (x - x^2 R(x^2))) + 0 <= x <= 0.5 + Peak relative error 5.7e-38 */ +static const long double PN[] = +{ + 5.081801691915377692446852383385968225675E8L, + 9.360895299872484512023336636427675327355E6L, + 4.213701282274196030811629773097579432957E4L, + 5.201006511142748908655720086041570288182E1L, + 9.088368420359444263703202925095675982530E-3L, +}; +static const long double PD[] = +{ + 3.049081015149226615468111430031590411682E9L, + 1.069833887183886839966085436512368982758E8L, + 8.259257717868875207333991924545445705394E5L, + 1.872583833284143212651746812884298360922E3L, + /* 1.0E0 */ +}; + +static const long double + /* ln 2 */ + lg2 = 6.9314718055994530941723212145817656807550E-1L, + lg2_h = 6.9314718055994528622676398299518041312695E-1L, + lg2_l = 2.3190468138462996154948554638754786504121E-17L, + ovt = 8.0085662595372944372e-0017L, + /* 2/(3*log(2)) */ + cp = 9.6179669392597560490661645400126142495110E-1L, + cp_h = 9.6179669392597555432899980587535537779331E-1L, + cp_l = 5.0577616648125906047157785230014751039424E-17L; + +long double +powl(long double x, long double y) +{ + long double z, ax, z_h, z_l, p_h, p_l; + long double yy1, t1, t2, r, s, t, u, v, w; + long double s2, s_h, s_l, t_h, t_l; + int32_t i, j, k, yisint, n; + u_int32_t ix, iy; + int32_t hx, hy; + ieee_quad_shape_type o, p, q; + + p.value = x; + hx = p.parts32.mswhi; + ix = hx & 0x7fffffff; + + q.value = y; + hy = q.parts32.mswhi; + iy = hy & 0x7fffffff; + + + /* y==zero: x**0 = 1 */ + if ((iy | q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0) + return one; + + /* 1.0**y = 1; -1.0**+-Inf = 1 */ + if (x == one) + return one; + if (x == -1.0L && iy == 0x7fff0000 + && (q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0) + return one; + + /* +-NaN return x+y */ + if ((ix > 0x7fff0000) + || ((ix == 0x7fff0000) + && ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) != 0)) + || (iy > 0x7fff0000) + || ((iy == 0x7fff0000) + && ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) != 0))) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) + { + if (iy >= 0x40700000) /* 2^113 */ + yisint = 2; /* even integer y */ + else if (iy >= 0x3fff0000) /* 1.0 */ + { + if (floorl (y) == y) + { + z = 0.5 * y; + if (floorl (z) == z) + yisint = 2; + else + yisint = 1; + } + } + } + + /* special value of y */ + if ((q.parts32.mswlo | q.parts32.lswhi | q.parts32.lswlo) == 0) + { + if (iy == 0x7fff0000) /* y is +-inf */ + { + if (((ix - 0x3fff0000) | p.parts32.mswlo | p.parts32.lswhi | + p.parts32.lswlo) == 0) + return y - y; /* +-1**inf is NaN */ + else if (ix >= 0x3fff0000) /* (|x|>1)**+-inf = inf,0 */ + return (hy >= 0) ? y : zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy < 0) ? -y : zero; + } + if (iy == 0x3fff0000) + { /* y is +-1 */ + if (hy < 0) + return one / x; + else + return x; + } + if (hy == 0x40000000) + return x * x; /* y is 2 */ + if (hy == 0x3ffe0000) + { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtl (x); + } + } + + ax = fabsl (x); + /* special value of x */ + if ((p.parts32.mswlo | p.parts32.lswhi | p.parts32.lswlo) == 0) + { + if (ix == 0x7fff0000 || ix == 0 || ix == 0x3fff0000) + { + z = ax; /*x is +-0,+-inf,+-1 */ + if (hy < 0) + z = one / z; /* z = (1/|x|) */ + if (hx < 0) + { + if (((ix - 0x3fff0000) | yisint) == 0) + { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } + else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* (x<0)**(non-int) is NaN */ + if (((((u_int32_t) hx >> 31) - 1) | yisint) == 0) + return (x - x) / (x - x); + + /* |y| is huge. + 2^-16495 = 1/2 of smallest representable value. + If (1 - 1/131072)^y underflows, y > 1.4986e9 */ + if (iy > 0x401d654b) + { + /* if (1 - 2^-113)^y underflows, y > 1.1873e38 */ + if (iy > 0x407d654b) + { + if (ix <= 0x3ffeffff) + return (hy < 0) ? huge * huge : tiny * tiny; + if (ix >= 0x3fff0000) + return (hy > 0) ? huge * huge : tiny * tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3ffeffff) + return (hy < 0) ? huge * huge : tiny * tiny; + if (ix > 0x3fff0000) + return (hy > 0) ? huge * huge : tiny * tiny; + } + + n = 0; + /* take care subnormal number */ + if (ix < 0x00010000) + { + ax *= two113; + n -= 113; + o.value = ax; + ix = o.parts32.mswhi; + } + n += ((ix) >> 16) - 0x3fff; + j = ix & 0x0000ffff; + /* determine interval */ + ix = j | 0x3fff0000; /* normalize ix */ + if (j <= 0x3988) + k = 0; /* |x|> 31) - 1) | (yisint - 1)) == 0) + s = -one; /* (-ve)**(odd int) */ + + /* split up y into yy1+y2 and compute (yy1+y2)*(t1+t2) */ + yy1 = y; + o.value = yy1; + o.parts32.lswlo = 0; + o.parts32.lswhi &= 0xf8000000; + yy1 = o.value; + p_l = (y - yy1) * t1 + y * t2; + p_h = yy1 * t1; + z = p_l + p_h; + o.value = z; + j = o.parts32.mswhi; + if (j >= 0x400d0000) /* z >= 16384 */ + { + /* if z > 16384 */ + if (((j - 0x400d0000) | o.parts32.mswlo | o.parts32.lswhi | + o.parts32.lswlo) != 0) + return s * huge * huge; /* overflow */ + else + { + if (p_l + ovt > z - p_h) + return s * huge * huge; /* overflow */ + } + } + else if ((j & 0x7fffffff) >= 0x400d01b9) /* z <= -16495 */ + { + /* z < -16495 */ + if (((j - 0xc00d01bc) | o.parts32.mswlo | o.parts32.lswhi | + o.parts32.lswlo) + != 0) + return s * tiny * tiny; /* underflow */ + else + { + if (p_l <= z - p_h) + return s * tiny * tiny; /* underflow */ + } + } + /* compute 2**(p_h+p_l) */ + i = j & 0x7fffffff; + k = (i >> 16) - 0x3fff; + n = 0; + if (i > 0x3ffe0000) + { /* if |z| > 0.5, set n = [z+0.5] */ + n = floorl (z + 0.5L); + t = n; + p_h -= t; + } + t = p_l + p_h; + o.value = t; + o.parts32.lswlo = 0; + o.parts32.lswhi &= 0xf8000000; + t = o.value; + u = t * lg2_h; + v = (p_l - (t - p_h)) * lg2 + t * lg2_l; + z = u + v; + w = v - (z - u); + /* exp(z) */ + t = z * z; + u = PN[0] + t * (PN[1] + t * (PN[2] + t * (PN[3] + t * PN[4]))); + v = PD[0] + t * (PD[1] + t * (PD[2] + t * (PD[3] + t))); + t1 = z - t * u / v; + r = (z * t1) / (t1 - two) - (w + z * w); + z = one - (r - z); + o.value = z; + j = o.parts32.mswhi; + j += (n << 16); + if ((j >> 16) <= 0) + z = scalbnl (z, n); /* subnormal output */ + else + { + o.parts32.mswhi = j; + z = o.value; + } + return s * z; +} diff --git a/src/openlibm/ld128/e_rem_pio2l.h b/src/openlibm/ld128/e_rem_pio2l.h new file mode 100644 index 0000000..5224245 --- /dev/null +++ b/src/openlibm/ld128/e_rem_pio2l.h @@ -0,0 +1,144 @@ +/* From: @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/e_rem_pio2l.h,v 1.2 2011/05/30 19:41:28 kargl Exp $"); + +/* ld128 version of __ieee754_rem_pio2l(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include +#include + +#include "math_private.h" +#include "fpmath.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +/* + * XXX need to verify that nonzero integer multiples of pi/2 within the + * range get no closer to a long double than 2**-140, or that + * ilogb(x) + ilogb(min_delta) < 45 - -140. + */ +/* + * invpio2: 113 bits of 2/pi + * pio2_1: first 68 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 68 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 68 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +two24 = 1.67772160000000000000e+07; /* 0x41700000, 0x00000000 */ + +static const long double +invpio2 = 6.3661977236758134307553505349005747e-01L, /* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ +pio2_1 = 1.5707963267948966192292994253909555e+00L, /* 0x1921fb54442d18469800000000000.0p-112 */ +pio2_1t = 2.0222662487959507323996846200947577e-21L, /* 0x13198a2e03707344a4093822299f3.0p-181 */ +pio2_2 = 2.0222662487959507323994779168837751e-21L, /* 0x13198a2e03707344a400000000000.0p-181 */ +pio2_2t = 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df531d89cd91.0p-254 */ +pio2_3 = 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */ +pio2_3t = -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */ + +//VBS +//static inline __always_inline int +//__ieee754_rem_pio2l(long double x, long double *y) + +static inline int +__ieee754_rem_pio2l(long double x, long double *y) +{ + union IEEEl2bits u,u1; + long double z,w,t,r,fn; + double tx[5],ty[3]; + int64_t n; + int e0,ex,i,j,nx; + int16_t expsign; + + u.e = x; + expsign = u.xbits.expsign; + ex = expsign & 0x7fff; + if (ex < BIAS + 45 || ex == BIAS + 45 && + u.bits.manh < 0x921fb54442d1LL) { + /* |x| ~< 2^45*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = x*invpio2+0x1.8p112; + fn = fn-0x1.8p112; +#ifdef HAVE_EFFICIENT_I64RINT + n = i64rint(fn); +#else + n = fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 180 bit */ + { + union IEEEl2bits u2; + int ex1; + j = ex; + y[0] = r-w; + u2.e = y[0]; + ex1 = u2.xbits.expsign & 0x7fff; + i = j-ex1; + if(i>51) { /* 2nd iteration needed, good to 248 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + u2.e = y[0]; + ex1 = u2.xbits.expsign & 0x7fff; + i = j-ex1; + if(i>119) { /* 3rd iteration need, 316 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + return n; + } + /* + * all other (large) arguments + */ + if(ex==0x7fff) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + u1.e = x; + e0 = ex - BIAS - 23; /* e0 = ilogb(|x|)-23; */ + u1.xbits.expsign = ex - e0; + z = u1.e; + for(i=0;i<4;i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[4] = z; + nx = 5; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,ty,e0,nx,3); + t = (long double)ty[2] + ty[1]; + r = t + ty[0]; + w = ty[0] - (r - t); + if(expsign<0) {y[0] = -r; y[1] = -w; return -n;} + y[0] = r; y[1] = w; return n; +} diff --git a/src/openlibm/ld128/e_sinhl.c b/src/openlibm/ld128/e_sinhl.c new file mode 100644 index 0000000..3bfdb5d --- /dev/null +++ b/src/openlibm/ld128/e_sinhl.c @@ -0,0 +1,104 @@ +/* @(#)e_sinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* sinhl(x) + * Method : + * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + * 1. Replace x by |x| (sinhl(-x) = -sinhl(x)). + * 2. + * E + E/(E+1) + * 0 <= x <= 25 : sinhl(x) := --------------, E=expm1l(x) + * 2 + * + * 25 <= x <= lnovft : sinhl(x) := expl(x)/2 + * lnovft <= x <= ln2ovft: sinhl(x) := expl(x/2)/2 * expl(x/2) + * ln2ovft < x : sinhl(x) := x*shuge (overflow) + * + * Special cases: + * sinhl(x) is |x| if x is +INF, -INF, or NaN. + * only sinhl(0)=0 is exact for finite x. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, shuge = 1.0e4931L, +ovf_thresh = 1.1357216553474703894801348310092223067821E4L; + +long double +sinhl(long double x) +{ + long double t, w, h; + u_int32_t jx, ix; + ieee_quad_shape_type u; + + /* Words of |x|. */ + u.value = x; + jx = u.parts32.mswhi; + ix = jx & 0x7fffffff; + + /* x is INF or NaN */ + if (ix >= 0x7fff0000) + return x + x; + + h = 0.5; + if (jx & 0x80000000) + h = -h; + + /* Absolute value of x. */ + u.parts32.mswhi = ix; + + /* |x| in [0,40], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix <= 0x40044000) + { + if (ix < 0x3fc60000) /* |x| < 2^-57 */ + if (shuge + x > one) + return x; /* sinh(tiny) = tiny with inexact */ + t = expm1l (u.value); + if (ix < 0x3fff0000) + return h * (2.0 * t - t * t / (t + one)); + return h * (t + t / (t + one)); + } + + /* |x| in [40, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix <= 0x400c62e3) /* 11356.375 */ + return h * expl (u.value); + + /* |x| in [log(maxdouble), overflowthreshold] + Overflow threshold is log(2 * maxdouble). */ + if (u.value <= ovf_thresh) + { + w = expl (0.5 * u.value); + t = h * w; + return t * w; + } + + /* |x| > overflowthreshold, sinhl(x) overflow */ + return x * shuge; +} diff --git a/src/openlibm/ld128/e_tgammal.c b/src/openlibm/ld128/e_tgammal.c new file mode 100644 index 0000000..6c78c24 --- /dev/null +++ b/src/openlibm/ld128/e_tgammal.c @@ -0,0 +1,39 @@ +/* $OpenBSD: e_tgammal.c,v 1.1 2011/07/06 00:02:42 martynas Exp $ */ + +/* + * Copyright (c) 2011 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "math_private.h" + +long double +tgammal(long double x) +{ + int64_t i0,i1; + + GET_LDOUBLE_WORDS64(i0,i1,x); + if (((i0&0x7fffffffffffffffLL)|i1) == 0) + return (1.0/x); + + if (i0<0 && (u_int64_t)i0<0xffff000000000000ULL && rintl(x)==x) + return (x-x)/(x-x); + + if (i0==0xffff000000000000ULL && i1==0) + return (x-x); + + return expl(lgammal(x)); +} diff --git a/src/openlibm/ld128/invtrig.c b/src/openlibm/ld128/invtrig.c new file mode 100644 index 0000000..5a869c2 --- /dev/null +++ b/src/openlibm/ld128/invtrig.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/invtrig.c,v 1.1 2008/07/31 22:41:26 das Exp $"); + +#include "ld128/invtrig.h" + +/* + * asinl() and acosl() + */ +const long double +pS0 = 1.66666666666666666666666666666700314e-01L, +pS1 = -7.32816946414566252574527475428622708e-01L, +pS2 = 1.34215708714992334609030036562143589e+00L, +pS3 = -1.32483151677116409805070261790752040e+00L, +pS4 = 7.61206183613632558824485341162121989e-01L, +pS5 = -2.56165783329023486777386833928147375e-01L, +pS6 = 4.80718586374448793411019434585413855e-02L, +pS7 = -4.42523267167024279410230886239774718e-03L, +pS8 = 1.44551535183911458253205638280410064e-04L, +pS9 = -2.10558957916600254061591040482706179e-07L, +qS1 = -4.84690167848739751544716485245697428e+00L, +qS2 = 9.96619113536172610135016921140206980e+00L, +qS3 = -1.13177895428973036660836798461641458e+01L, +qS4 = 7.74004374389488266169304117714658761e+00L, +qS5 = -3.25871986053534084709023539900339905e+00L, +qS6 = 8.27830318881232209752469022352928864e-01L, +qS7 = -1.18768052702942805423330715206348004e-01L, +qS8 = 8.32600764660522313269101537926539470e-03L, +qS9 = -1.99407384882605586705979504567947007e-04L; + +/* + * atanl() + */ +const long double atanhi[] = { + 4.63647609000806116214256231461214397e-01L, + 7.85398163397448309615660845819875699e-01L, + 9.82793723247329067985710611014666038e-01L, + 1.57079632679489661923132169163975140e+00L, +}; + +const long double atanlo[] = { + 4.89509642257333492668618435220297706e-36L, + 2.16795253253094525619926100651083806e-35L, + -2.31288434538183565909319952098066272e-35L, + 4.33590506506189051239852201302167613e-35L, +}; + +const long double aT[] = { + 3.33333333333333333333333333333333125e-01L, + -1.99999999999999999999999999999180430e-01L, + 1.42857142857142857142857142125269827e-01L, + -1.11111111111111111111110834490810169e-01L, + 9.09090909090909090908522355708623681e-02L, + -7.69230769230769230696553844935357021e-02L, + 6.66666666666666660390096773046256096e-02L, + -5.88235294117646671706582985209643694e-02L, + 5.26315789473666478515847092020327506e-02L, + -4.76190476189855517021024424991436144e-02L, + 4.34782608678695085948531993458097026e-02L, + -3.99999999632663469330634215991142368e-02L, + 3.70370363987423702891250829918659723e-02L, + -3.44827496515048090726669907612335954e-02L, + 3.22579620681420149871973710852268528e-02L, + -3.03020767654269261041647570626778067e-02L, + 2.85641979882534783223403715930946138e-02L, + -2.69824879726738568189929461383741323e-02L, + 2.54194698498808542954187110873675769e-02L, + -2.35083879708189059926183138130183215e-02L, + 2.04832358998165364349957325067131428e-02L, + -1.54489555488544397858507248612362957e-02L, + 8.64492360989278761493037861575248038e-03L, + -2.58521121597609872727919154569765469e-03L, +}; + +const long double pi_lo = 8.67181013012378102479704402604335225e-35L; diff --git a/src/openlibm/ld128/invtrig.h b/src/openlibm/ld128/invtrig.h new file mode 100644 index 0000000..c85a615 --- /dev/null +++ b/src/openlibm/ld128/invtrig.h @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/ld128/invtrig.h,v 1.1 2008/07/31 22:41:26 das Exp $ + */ + +#include + +#include "fpmath.h" + +#define BIAS (LDBL_MAX_EXP - 1) +#define MANH_SIZE (LDBL_MANH_SIZE + 1) + +/* Approximation thresholds. */ +#define ASIN_LINEAR (BIAS - 56) /* 2**-56 */ +#define ACOS_CONST (BIAS - 113) /* 2**-113 */ +#define ATAN_CONST (BIAS + 113) /* 2**113 */ +#define ATAN_LINEAR (BIAS - 56) /* 2**-56 */ + +/* 0.95 */ +#define THRESH ((0xe666666666666666ULL>>(64-(MANH_SIZE-1)))|LDBL_NBIT) + +/* Constants shared by the long double inverse trig functions. */ +#define pS0 _ItL_pS0 +#define pS1 _ItL_pS1 +#define pS2 _ItL_pS2 +#define pS3 _ItL_pS3 +#define pS4 _ItL_pS4 +#define pS5 _ItL_pS5 +#define pS6 _ItL_pS6 +#define pS7 _ItL_pS7 +#define pS8 _ItL_pS8 +#define pS9 _ItL_pS9 +#define qS1 _ItL_qS1 +#define qS2 _ItL_qS2 +#define qS3 _ItL_qS3 +#define qS4 _ItL_qS4 +#define qS5 _ItL_qS5 +#define qS6 _ItL_qS6 +#define qS7 _ItL_qS7 +#define qS8 _ItL_qS8 +#define qS9 _ItL_qS9 +#define atanhi _ItL_atanhi +#define atanlo _ItL_atanlo +#define aT _ItL_aT +#define pi_lo _ItL_pi_lo + +#define pio2_hi atanhi[3] +#define pio2_lo atanlo[3] +#define pio4_hi atanhi[1] + +/* Constants shared by the long double inverse trig functions. */ +extern const long double pS0, pS1, pS2, pS3, pS4, pS5, pS6, pS7, pS8, pS9; +extern const long double qS1, qS2, qS3, qS4, qS5, qS6, qS7, qS8, qS9; +extern const long double atanhi[], atanlo[], aT[]; +extern const long double pi_lo; + +static inline long double +P(long double x) +{ + + return (x * (pS0 + x * (pS1 + x * (pS2 + x * (pS3 + x * \ + (pS4 + x * (pS5 + x * (pS6 + x * (pS7 + x * (pS8 + x * \ + pS9)))))))))); +} + +static inline long double +Q(long double x) +{ + + return (1.0 + x * (qS1 + x * (qS2 + x * (qS3 + x * (qS4 + x * \ + (qS5 + x * (qS6 + x * (qS7 + x * (qS8 + x * qS9))))))))); +} + +static inline long double +T_even(long double x) +{ + + return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * \ + (aT[8] + x * (aT[10] + x * (aT[12] + x * (aT[14] + x * \ + (aT[16] + x * (aT[18] + x * (aT[20] + x * aT[22]))))))))))); +} + +static inline long double +T_odd(long double x) +{ + + return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * \ + (aT[9] + x * (aT[11] + x * (aT[13] + x * (aT[15] + x * \ + (aT[17] + x * (aT[19] + x * (aT[21] + x * aT[23]))))))))))); +} diff --git a/src/openlibm/ld128/k_cosl.c b/src/openlibm/ld128/k_cosl.c new file mode 100644 index 0000000..37666dc --- /dev/null +++ b/src/openlibm/ld128/k_cosl.c @@ -0,0 +1,61 @@ +/* From: @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_cosl.c,v 1.1 2008/02/17 07:32:31 das Exp $"); + +/* + * ld128 version of k_cos.c. See ../src/k_cos.c for most comments. + */ + +#include "math_private.h" + +/* + * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]: + * |cos(x) - c(x))| < 2**-122.0 + * + * 113-bit precision requires more care than 64-bit precision, since + * simple methods give a minimax polynomial with coefficient for x^2 + * that is 1 ulp below 0.5, but we want it to be precisely 0.5. See + * ../ld80/k_cosl.c for more details. + */ +static const double +one = 1.0; + +static const long double +C1 = 0.04166666666666666666666666666666658424671L, +C2 = -0.001388888888888888888888888888863490893732L, +C3 = 0.00002480158730158730158730158600795304914210L, +C4 = -0.2755731922398589065255474947078934284324e-6L, +C5 = 0.2087675698786809897659225313136400793948e-8L, +C6 = -0.1147074559772972315817149986812031204775e-10L, +C7 = 0.4779477332386808976875457937252120293400e-13L; + +static const double +C8 = -0.1561920696721507929516718307820958119868e-15, +C9 = 0.4110317413744594971475941557607804508039e-18, +C10 = -0.8896592467191938803288521958313920156409e-21, +C11 = 0.1601061435794535138244346256065192782581e-23; + +long double +__kernel_cosl(long double x, long double y) +{ + long double hz,z,r,w; + + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*(C7+ + z*(C8+z*(C9+z*(C10+z*C11)))))))))); + hz = 0.5*z; + w = one-hz; + return w + (((one-w)-hz) + (z*r-x*y)); +} diff --git a/src/openlibm/ld128/k_sinl.c b/src/openlibm/ld128/k_sinl.c new file mode 100644 index 0000000..1079159 --- /dev/null +++ b/src/openlibm/ld128/k_sinl.c @@ -0,0 +1,59 @@ +/* From: @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_sinl.c,v 1.1 2008/02/17 07:32:31 das Exp $"); + +/* + * ld128 version of k_sin.c. See ../src/k_sin.c for most comments. + */ + +#include "math_private.h" + +static const double +half = 0.5; + +/* + * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37] + * |sin(x)/x - s(x)| < 2**-122.1 + * + * See ../ld80/k_cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.16666666666666666666666666666666666606732416116558L, +S2 = 0.0083333333333333333333333333333331135404851288270047L, +S3 = -0.00019841269841269841269841269839935785325638310428717L, +S4 = 0.27557319223985890652557316053039946268333231205686e-5L, +S5 = -0.25052108385441718775048214826384312253862930064745e-7L, +S6 = 0.16059043836821614596571832194524392581082444805729e-9L, +S7 = -0.76471637318198151807063387954939213287488216303768e-12L, +S8 = 0.28114572543451292625024967174638477283187397621303e-14L; + +static const double +S9 = -0.82206352458348947812512122163446202498005154296863e-17, +S10 = 0.19572940011906109418080609928334380560135358385256e-19, +S11 = -0.38680813379701966970673724299207480965452616911420e-22, +S12 = 0.64038150078671872796678569586315881020659912139412e-25; + +long double +__kernel_sinl(long double x, long double y, int iy) +{ + long double z,r,v; + + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*(S8+ + z*(S9+z*(S10+z*(S11+z*S12))))))))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/openlibm/ld128/k_tanl.c b/src/openlibm/ld128/k_tanl.c new file mode 100644 index 0000000..7255076 --- /dev/null +++ b/src/openlibm/ld128/k_tanl.c @@ -0,0 +1,120 @@ +/* From: @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/k_tanl.c,v 1.1 2008/02/17 07:32:31 das Exp $"); + +/* + * ld128 version of k_tan.c. See ../src/k_tan.c for most comments. + */ + +#include + +#include "math_private.h" + +/* + * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37] + * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37) + * + * See ../ld80/k_cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0x1.5555555555555555555555555553p-2L, +T5 = 0x1.1111111111111111111111111eb5p-3L, +T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L, +T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L, +T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L, +T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L, +T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L, +T17 = 0x1.355824803674477dfcf726649efep-11L, +T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L, +T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L, +T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L, +T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L, +T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L, +T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L, +T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L, +T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L, +T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L, +T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L, +pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, +pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L; + +static const double +T39 = 0.000000028443389121318352, /* 0x1e8a7592977938.0p-78 */ +T41 = 0.000000011981013102001973, /* 0x19baa1b1223219.0p-79 */ +T43 = 0.0000000038303578044958070, /* 0x107385dfb24529.0p-80 */ +T45 = 0.0000000034664378216909893, /* 0x1dc6c702a05262.0p-81 */ +T47 = -0.0000000015090641701997785, /* -0x19ecef3569ebb6.0p-82 */ +T49 = 0.0000000029449552300483952, /* 0x194c0668da786a.0p-81 */ +T51 = -0.0000000022006995706097711, /* -0x12e763b8845268.0p-81 */ +T53 = 0.0000000015468200913196612, /* 0x1a92fc98c29554.0p-82 */ +T55 = -0.00000000061311613386849674, /* -0x151106cbc779a9.0p-83 */ +T57 = 1.4912469681508012e-10; /* 0x147edbdba6f43a.0p-85 */ + +long double +__kernel_tanl(long double x, long double y, int iy) { + long double z, r, v, w, s; + long double osign; + int i; + + iy = (iy == 1 ? -1 : 1); /* XXX recover original interface */ + osign = (x >= 0 ? 1.0 : -1.0); /* XXX slow, probably wrong for -0 */ + if (fabsl(x) >= 0.67434) { + if (x < 0) { + x = -x; + y = -y; + } + z = pio4 - x; + w = pio4lo - y; + x = z + w; + y = 0.0; + i = 1; + } else + i = 0; + z = x * x; + w = z * z; + r = T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + + w * (T25 + w * (T29 + w * (T33 + + w * (T37 + w * (T41 + w * (T45 + w * (T49 + w * (T53 + + w * T57)))))))))))); + v = z * (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + + w * (T27 + w * (T31 + w * (T35 + + w * (T39 + w * (T43 + w * (T47 + w * (T51 + w * T55)))))))))))); + s = z * x; + r = y + z * (s * (r + v) + y); + r += T3 * s; + w = x + r; + if (i == 1) { + v = (long double) iy; + return osign * + (v - 2.0 * (x - (w * w / (w + v) - r))); + } + if (iy == 1) + return w; + else { + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + long double a, t; + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); + } +} diff --git a/src/openlibm/ld128/s_asinhl.c b/src/openlibm/ld128/s_asinhl.c new file mode 100644 index 0000000..29791e8 --- /dev/null +++ b/src/openlibm/ld128/s_asinhl.c @@ -0,0 +1,69 @@ +/* @(#)s_asinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* asinhl(x) + * Method : + * Based on + * asinhl(x) = signl(x) * logl [ |x| + sqrtl(x*x+1) ] + * we have + * asinhl(x) := x if 1+x*x=1, + * := signl(x)*(logl(x)+ln2)) for large |x|, else + * := signl(x)*logl(2|x|+1/(|x|+sqrtl(x*x+1))) if|x|>2, else + * := signl(x)*log1pl(|x| + x^2/(1 + sqrtl(1+x^2))) + */ + +#include + +#include "math_private.h" + +static const long double + one = 1.0L, + ln2 = 6.931471805599453094172321214581765681e-1L, + huge = 1.0e+4900L; + +long double +asinhl(long double x) +{ + long double t, w; + int32_t ix, sign; + ieee_quad_shape_type u; + + u.value = x; + sign = u.parts32.mswhi; + ix = sign & 0x7fffffff; + if (ix == 0x7fff0000) + return x + x; /* x is inf or NaN */ + if (ix < 0x3fc70000) + { /* |x| < 2^ -56 */ + if (huge + x > one) + return x; /* return x inexact except 0 */ + } + u.parts32.mswhi = ix; + if (ix > 0x40350000) + { /* |x| > 2 ^ 54 */ + w = logl (u.value) + ln2; + } + else if (ix >0x40000000) + { /* 2^ 54 > |x| > 2.0 */ + t = u.value; + w = logl (2.0 * t + one / (sqrtl (x * x + one) + t)); + } + else + { /* 2.0 > |x| > 2 ^ -56 */ + t = x * x; + w = log1pl (u.value + t / (one + sqrtl (one + t))); + } + if (sign & 0x80000000) + return -w; + else + return w; +} diff --git a/src/openlibm/ld128/s_ceill.c b/src/openlibm/ld128/s_ceill.c new file mode 100644 index 0000000..719e7fc --- /dev/null +++ b/src/openlibm/ld128/s_ceill.c @@ -0,0 +1,69 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * ceill(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceil(x). + */ + +#include + +#include "math_private.h" + +static const long double huge = 1.0e4930L; + +long double +ceill(long double x) +{ + int64_t i0,i1,jj0; + u_int64_t i,j; + GET_LDOUBLE_WORDS64(i0,i1,x); + jj0 = ((i0>>48)&0x7fff)-0x3fff; + if(jj0<48) { + if(jj0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x8000000000000000ULL;i1=0;} + else if((i0|i1)!=0) { i0=0x3fff000000000000ULL;i1=0;} + } + } else { + i = (0x0000ffffffffffffULL)>>jj0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x0001000000000000LL)>>jj0; + i0 &= (~i); i1=0; + } + } + } else if (jj0>111) { + if(jj0==0x4000) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = -1ULL>>(jj0-48); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(jj0==48) i0+=1; + else { + j = i1+(1LL<<(112-jj0)); + if(j + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. erf(x) = x + x*R(x^2) for |x| in [0, 7/8] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. + * + * 1a. erf(x) = 1 - erfc(x), for |x| > 1.0 + * erfc(x) = 1 - erf(x) if |x| < 1/4 + * + * 2. For |x| in [7/8, 1], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(s + c) = sign(x) * (c + P1(s)/Q1(s)) + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1/4, 5/4], + * erfc(s + const) = erfc(const) + s P1(s)/Q1(s) + * for const = 1/4, 3/8, ..., 9/8 + * and 0 <= s <= 1/8 . + * + * 4. For x in [5/4, 107], + * erfc(x) = (1/x)*exp(-x*x-0.5625 + R(z)) + * z=1/x^2 + * The interval is partitioned into several segments + * of width 1/8 in 1/x. + * + * Note1: + * To compute exp(-x*x-0.5625+R/S), let s be a single + * precision number and s := x; then + * -x*x = -s*s + (s-x)*(s+x) + * exp(-x*x-0.5626+R/S) = + * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S); + * Note2: + * Here 4 and 5 make use of the asymptotic series + * exp(-x*x) + * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ) + * x*sqrt(pi) + * + * 5. For inf > x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include + +#include "math_private.h" + +/* Evaluate P[n] x^n + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +neval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + +/* Evaluate x^n+1 + P[n] x^(n) + P[n-1] x^(n-1) + ... + P[0] */ + +static long double +deval (long double x, const long double *p, int n) +{ + long double y; + + p += n; + y = x + *p--; + do + { + y = y * x + *p--; + } + while (--n > 0); + return y; +} + + + +static const long double +tiny = 1e-4931L, + one = 1.0L, + two = 2.0L, + /* 2/sqrt(pi) - 1 */ + efx = 1.2837916709551257389615890312154517168810E-1L, + /* 8 * (2/sqrt(pi) - 1) */ + efx8 = 1.0270333367641005911692712249723613735048E0L; + + +/* erf(x) = x + x R(x^2) + 0 <= x <= 7/8 + Peak relative error 1.8e-35 */ +#define NTN1 8 +static const long double TN1[NTN1 + 1] = +{ + -3.858252324254637124543172907442106422373E10L, + 9.580319248590464682316366876952214879858E10L, + 1.302170519734879977595901236693040544854E10L, + 2.922956950426397417800321486727032845006E9L, + 1.764317520783319397868923218385468729799E8L, + 1.573436014601118630105796794840834145120E7L, + 4.028077380105721388745632295157816229289E5L, + 1.644056806467289066852135096352853491530E4L, + 3.390868480059991640235675479463287886081E1L +}; +#define NTD1 8 +static const long double TD1[NTD1 + 1] = +{ + -3.005357030696532927149885530689529032152E11L, + -1.342602283126282827411658673839982164042E11L, + -2.777153893355340961288511024443668743399E10L, + -3.483826391033531996955620074072768276974E9L, + -2.906321047071299585682722511260895227921E8L, + -1.653347985722154162439387878512427542691E7L, + -6.245520581562848778466500301865173123136E5L, + -1.402124304177498828590239373389110545142E4L, + -1.209368072473510674493129989468348633579E2L +/* 1.0E0 */ +}; + + +/* erf(z+1) = erf_const + P(z)/Q(z) + -.125 <= z <= 0 + Peak relative error 7.3e-36 */ +static const long double erf_const = 0.845062911510467529296875L; +#define NTN2 8 +static const long double TN2[NTN2 + 1] = +{ + -4.088889697077485301010486931817357000235E1L, + 7.157046430681808553842307502826960051036E3L, + -2.191561912574409865550015485451373731780E3L, + 2.180174916555316874988981177654057337219E3L, + 2.848578658049670668231333682379720943455E2L, + 1.630362490952512836762810462174798925274E2L, + 6.317712353961866974143739396865293596895E0L, + 2.450441034183492434655586496522857578066E1L, + 5.127662277706787664956025545897050896203E-1L +}; +#define NTD2 8 +static const long double TD2[NTD2 + 1] = +{ + 1.731026445926834008273768924015161048885E4L, + 1.209682239007990370796112604286048173750E4L, + 1.160950290217993641320602282462976163857E4L, + 5.394294645127126577825507169061355698157E3L, + 2.791239340533632669442158497532521776093E3L, + 8.989365571337319032943005387378993827684E2L, + 2.974016493766349409725385710897298069677E2L, + 6.148192754590376378740261072533527271947E1L, + 1.178502892490738445655468927408440847480E1L + /* 1.0E0 */ +}; + + +/* erfc(x + 0.25) = erfc(0.25) + x R(x) + 0 <= x < 0.125 + Peak relative error 1.4e-35 */ +#define NRNr13 8 +static const long double RNr13[NRNr13 + 1] = +{ + -2.353707097641280550282633036456457014829E3L, + 3.871159656228743599994116143079870279866E2L, + -3.888105134258266192210485617504098426679E2L, + -2.129998539120061668038806696199343094971E1L, + -8.125462263594034672468446317145384108734E1L, + 8.151549093983505810118308635926270319660E0L, + -5.033362032729207310462422357772568553670E0L, + -4.253956621135136090295893547735851168471E-2L, + -8.098602878463854789780108161581050357814E-2L +}; +#define NRDr13 7 +static const long double RDr13[NRDr13 + 1] = +{ + 2.220448796306693503549505450626652881752E3L, + 1.899133258779578688791041599040951431383E2L, + 1.061906712284961110196427571557149268454E3L, + 7.497086072306967965180978101974566760042E1L, + 2.146796115662672795876463568170441327274E2L, + 1.120156008362573736664338015952284925592E1L, + 2.211014952075052616409845051695042741074E1L, + 6.469655675326150785692908453094054988938E-1L + /* 1.0E0 */ +}; +/* erfc(0.25) = C13a + C13b to extra precision. */ +static const long double C13a = 0.723663330078125L; +static const long double C13b = 1.0279753638067014931732235184287934646022E-5L; + + +/* erfc(x + 0.375) = erfc(0.375) + x R(x) + 0 <= x < 0.125 + Peak relative error 1.2e-35 */ +#define NRNr14 8 +static const long double RNr14[NRNr14 + 1] = +{ + -2.446164016404426277577283038988918202456E3L, + 6.718753324496563913392217011618096698140E2L, + -4.581631138049836157425391886957389240794E2L, + -2.382844088987092233033215402335026078208E1L, + -7.119237852400600507927038680970936336458E1L, + 1.313609646108420136332418282286454287146E1L, + -6.188608702082264389155862490056401365834E0L, + -2.787116601106678287277373011101132659279E-2L, + -2.230395570574153963203348263549700967918E-2L +}; +#define NRDr14 7 +static const long double RDr14[NRDr14 + 1] = +{ + 2.495187439241869732696223349840963702875E3L, + 2.503549449872925580011284635695738412162E2L, + 1.159033560988895481698051531263861842461E3L, + 9.493751466542304491261487998684383688622E1L, + 2.276214929562354328261422263078480321204E2L, + 1.367697521219069280358984081407807931847E1L, + 2.276988395995528495055594829206582732682E1L, + 7.647745753648996559837591812375456641163E-1L + /* 1.0E0 */ +}; +/* erfc(0.375) = C14a + C14b to extra precision. */ +static const long double C14a = 0.5958709716796875L; +static const long double C14b = 1.2118885490201676174914080878232469565953E-5L; + +/* erfc(x + 0.5) = erfc(0.5) + x R(x) + 0 <= x < 0.125 + Peak relative error 4.7e-36 */ +#define NRNr15 8 +static const long double RNr15[NRNr15 + 1] = +{ + -2.624212418011181487924855581955853461925E3L, + 8.473828904647825181073831556439301342756E2L, + -5.286207458628380765099405359607331669027E2L, + -3.895781234155315729088407259045269652318E1L, + -6.200857908065163618041240848728398496256E1L, + 1.469324610346924001393137895116129204737E1L, + -6.961356525370658572800674953305625578903E0L, + 5.145724386641163809595512876629030548495E-3L, + 1.990253655948179713415957791776180406812E-2L +}; +#define NRDr15 7 +static const long double RDr15[NRDr15 + 1] = +{ + 2.986190760847974943034021764693341524962E3L, + 5.288262758961073066335410218650047725985E2L, + 1.363649178071006978355113026427856008978E3L, + 1.921707975649915894241864988942255320833E2L, + 2.588651100651029023069013885900085533226E2L, + 2.628752920321455606558942309396855629459E1L, + 2.455649035885114308978333741080991380610E1L, + 1.378826653595128464383127836412100939126E0L + /* 1.0E0 */ +}; +/* erfc(0.5) = C15a + C15b to extra precision. */ +static const long double C15a = 0.4794921875L; +static const long double C15b = 7.9346869534623172533461080354712635484242E-6L; + +/* erfc(x + 0.625) = erfc(0.625) + x R(x) + 0 <= x < 0.125 + Peak relative error 5.1e-36 */ +#define NRNr16 8 +static const long double RNr16[NRNr16 + 1] = +{ + -2.347887943200680563784690094002722906820E3L, + 8.008590660692105004780722726421020136482E2L, + -5.257363310384119728760181252132311447963E2L, + -4.471737717857801230450290232600243795637E1L, + -4.849540386452573306708795324759300320304E1L, + 1.140885264677134679275986782978655952843E1L, + -6.731591085460269447926746876983786152300E0L, + 1.370831653033047440345050025876085121231E-1L, + 2.022958279982138755020825717073966576670E-2L, +}; +#define NRDr16 7 +static const long double RDr16[NRDr16 + 1] = +{ + 3.075166170024837215399323264868308087281E3L, + 8.730468942160798031608053127270430036627E2L, + 1.458472799166340479742581949088453244767E3L, + 3.230423687568019709453130785873540386217E2L, + 2.804009872719893612081109617983169474655E2L, + 4.465334221323222943418085830026979293091E1L, + 2.612723259683205928103787842214809134746E1L, + 2.341526751185244109722204018543276124997E0L, + /* 1.0E0 */ +}; +/* erfc(0.625) = C16a + C16b to extra precision. */ +static const long double C16a = 0.3767547607421875L; +static const long double C16b = 4.3570693945275513594941232097252997287766E-6L; + +/* erfc(x + 0.75) = erfc(0.75) + x R(x) + 0 <= x < 0.125 + Peak relative error 1.7e-35 */ +#define NRNr17 8 +static const long double RNr17[NRNr17 + 1] = +{ + -1.767068734220277728233364375724380366826E3L, + 6.693746645665242832426891888805363898707E2L, + -4.746224241837275958126060307406616817753E2L, + -2.274160637728782675145666064841883803196E1L, + -3.541232266140939050094370552538987982637E1L, + 6.988950514747052676394491563585179503865E0L, + -5.807687216836540830881352383529281215100E0L, + 3.631915988567346438830283503729569443642E-1L, + -1.488945487149634820537348176770282391202E-2L +}; +#define NRDr17 7 +static const long double RDr17[NRDr17 + 1] = +{ + 2.748457523498150741964464942246913394647E3L, + 1.020213390713477686776037331757871252652E3L, + 1.388857635935432621972601695296561952738E3L, + 3.903363681143817750895999579637315491087E2L, + 2.784568344378139499217928969529219886578E2L, + 5.555800830216764702779238020065345401144E1L, + 2.646215470959050279430447295801291168941E1L, + 2.984905282103517497081766758550112011265E0L, + /* 1.0E0 */ +}; +/* erfc(0.75) = C17a + C17b to extra precision. */ +static const long double C17a = 0.2888336181640625L; +static const long double C17b = 1.0748182422368401062165408589222625794046E-5L; + + +/* erfc(x + 0.875) = erfc(0.875) + x R(x) + 0 <= x < 0.125 + Peak relative error 2.2e-35 */ +#define NRNr18 8 +static const long double RNr18[NRNr18 + 1] = +{ + -1.342044899087593397419622771847219619588E3L, + 6.127221294229172997509252330961641850598E2L, + -4.519821356522291185621206350470820610727E2L, + 1.223275177825128732497510264197915160235E1L, + -2.730789571382971355625020710543532867692E1L, + 4.045181204921538886880171727755445395862E0L, + -4.925146477876592723401384464691452700539E0L, + 5.933878036611279244654299924101068088582E-1L, + -5.557645435858916025452563379795159124753E-2L +}; +#define NRDr18 7 +static const long double RDr18[NRDr18 + 1] = +{ + 2.557518000661700588758505116291983092951E3L, + 1.070171433382888994954602511991940418588E3L, + 1.344842834423493081054489613250688918709E3L, + 4.161144478449381901208660598266288188426E2L, + 2.763670252219855198052378138756906980422E2L, + 5.998153487868943708236273854747564557632E1L, + 2.657695108438628847733050476209037025318E1L, + 3.252140524394421868923289114410336976512E0L, + /* 1.0E0 */ +}; +/* erfc(0.875) = C18a + C18b to extra precision. */ +static const long double C18a = 0.215911865234375L; +static const long double C18b = 1.3073705765341685464282101150637224028267E-5L; + +/* erfc(x + 1.0) = erfc(1.0) + x R(x) + 0 <= x < 0.125 + Peak relative error 1.6e-35 */ +#define NRNr19 8 +static const long double RNr19[NRNr19 + 1] = +{ + -1.139180936454157193495882956565663294826E3L, + 6.134903129086899737514712477207945973616E2L, + -4.628909024715329562325555164720732868263E2L, + 4.165702387210732352564932347500364010833E1L, + -2.286979913515229747204101330405771801610E1L, + 1.870695256449872743066783202326943667722E0L, + -4.177486601273105752879868187237000032364E0L, + 7.533980372789646140112424811291782526263E-1L, + -8.629945436917752003058064731308767664446E-2L +}; +#define NRDr19 7 +static const long double RDr19[NRDr19 + 1] = +{ + 2.744303447981132701432716278363418643778E3L, + 1.266396359526187065222528050591302171471E3L, + 1.466739461422073351497972255511919814273E3L, + 4.868710570759693955597496520298058147162E2L, + 2.993694301559756046478189634131722579643E2L, + 6.868976819510254139741559102693828237440E1L, + 2.801505816247677193480190483913753613630E1L, + 3.604439909194350263552750347742663954481E0L, + /* 1.0E0 */ +}; +/* erfc(1.0) = C19a + C19b to extra precision. */ +static const long double C19a = 0.15728759765625L; +static const long double C19b = 1.1609394035130658779364917390740703933002E-5L; + +/* erfc(x + 1.125) = erfc(1.125) + x R(x) + 0 <= x < 0.125 + Peak relative error 3.6e-36 */ +#define NRNr20 8 +static const long double RNr20[NRNr20 + 1] = +{ + -9.652706916457973956366721379612508047640E2L, + 5.577066396050932776683469951773643880634E2L, + -4.406335508848496713572223098693575485978E2L, + 5.202893466490242733570232680736966655434E1L, + -1.931311847665757913322495948705563937159E1L, + -9.364318268748287664267341457164918090611E-2L, + -3.306390351286352764891355375882586201069E0L, + 7.573806045289044647727613003096916516475E-1L, + -9.611744011489092894027478899545635991213E-2L +}; +#define NRDr20 7 +static const long double RDr20[NRDr20 + 1] = +{ + 3.032829629520142564106649167182428189014E3L, + 1.659648470721967719961167083684972196891E3L, + 1.703545128657284619402511356932569292535E3L, + 6.393465677731598872500200253155257708763E2L, + 3.489131397281030947405287112726059221934E2L, + 8.848641738570783406484348434387611713070E1L, + 3.132269062552392974833215844236160958502E1L, + 4.430131663290563523933419966185230513168E0L + /* 1.0E0 */ +}; +/* erfc(1.125) = C20a + C20b to extra precision. */ +static const long double C20a = 0.111602783203125L; +static const long double C20b = 8.9850951672359304215530728365232161564636E-6L; + +/* erfc(1/x) = 1/x exp (-1/x^2 - 0.5625 + R(1/x^2)) + 7/8 <= 1/x < 1 + Peak relative error 1.4e-35 */ +#define NRNr8 9 +static const long double RNr8[NRNr8 + 1] = +{ + 3.587451489255356250759834295199296936784E1L, + 5.406249749087340431871378009874875889602E2L, + 2.931301290625250886238822286506381194157E3L, + 7.359254185241795584113047248898753470923E3L, + 9.201031849810636104112101947312492532314E3L, + 5.749697096193191467751650366613289284777E3L, + 1.710415234419860825710780802678697889231E3L, + 2.150753982543378580859546706243022719599E2L, + 8.740953582272147335100537849981160931197E0L, + 4.876422978828717219629814794707963640913E-2L +}; +#define NRDr8 8 +static const long double RDr8[NRDr8 + 1] = +{ + 6.358593134096908350929496535931630140282E1L, + 9.900253816552450073757174323424051765523E2L, + 5.642928777856801020545245437089490805186E3L, + 1.524195375199570868195152698617273739609E4L, + 2.113829644500006749947332935305800887345E4L, + 1.526438562626465706267943737310282977138E4L, + 5.561370922149241457131421914140039411782E3L, + 9.394035530179705051609070428036834496942E2L, + 6.147019596150394577984175188032707343615E1L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp (-1/x^2 - 0.5625 + R(1/x^2)) + 0.75 <= 1/x <= 0.875 + Peak relative error 2.0e-36 */ +#define NRNr7 9 +static const long double RNr7[NRNr7 + 1] = +{ + 1.686222193385987690785945787708644476545E1L, + 1.178224543567604215602418571310612066594E3L, + 1.764550584290149466653899886088166091093E4L, + 1.073758321890334822002849369898232811561E5L, + 3.132840749205943137619839114451290324371E5L, + 4.607864939974100224615527007793867585915E5L, + 3.389781820105852303125270837910972384510E5L, + 1.174042187110565202875011358512564753399E5L, + 1.660013606011167144046604892622504338313E4L, + 6.700393957480661937695573729183733234400E2L +}; +#define NRDr7 9 +static const long double RDr7[NRDr7 + 1] = +{ +-1.709305024718358874701575813642933561169E3L, +-3.280033887481333199580464617020514788369E4L, +-2.345284228022521885093072363418750835214E5L, +-8.086758123097763971926711729242327554917E5L, +-1.456900414510108718402423999575992450138E6L, +-1.391654264881255068392389037292702041855E6L, +-6.842360801869939983674527468509852583855E5L, +-1.597430214446573566179675395199807533371E5L, +-1.488876130609876681421645314851760773480E4L, +-3.511762950935060301403599443436465645703E2L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 5/8 <= 1/x < 3/4 + Peak relative error 1.9e-35 */ +#define NRNr6 9 +static const long double RNr6[NRNr6 + 1] = +{ + 1.642076876176834390623842732352935761108E0L, + 1.207150003611117689000664385596211076662E2L, + 2.119260779316389904742873816462800103939E3L, + 1.562942227734663441801452930916044224174E4L, + 5.656779189549710079988084081145693580479E4L, + 1.052166241021481691922831746350942786299E5L, + 9.949798524786000595621602790068349165758E4L, + 4.491790734080265043407035220188849562856E4L, + 8.377074098301530326270432059434791287601E3L, + 4.506934806567986810091824791963991057083E2L +}; +#define NRDr6 9 +static const long double RDr6[NRDr6 + 1] = +{ +-1.664557643928263091879301304019826629067E2L, +-3.800035902507656624590531122291160668452E3L, +-3.277028191591734928360050685359277076056E4L, +-1.381359471502885446400589109566587443987E5L, +-3.082204287382581873532528989283748656546E5L, +-3.691071488256738343008271448234631037095E5L, +-2.300482443038349815750714219117566715043E5L, +-6.873955300927636236692803579555752171530E4L, +-8.262158817978334142081581542749986845399E3L, +-2.517122254384430859629423488157361983661E2L + /* 1.00 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 1/2 <= 1/x < 5/8 + Peak relative error 4.6e-36 */ +#define NRNr5 10 +static const long double RNr5[NRNr5 + 1] = +{ +-3.332258927455285458355550878136506961608E-3L, +-2.697100758900280402659586595884478660721E-1L, +-6.083328551139621521416618424949137195536E0L, +-6.119863528983308012970821226810162441263E1L, +-3.176535282475593173248810678636522589861E2L, +-8.933395175080560925809992467187963260693E2L, +-1.360019508488475978060917477620199499560E3L, +-1.075075579828188621541398761300910213280E3L, +-4.017346561586014822824459436695197089916E2L, +-5.857581368145266249509589726077645791341E1L, +-2.077715925587834606379119585995758954399E0L +}; +#define NRDr5 9 +static const long double RDr5[NRDr5 + 1] = +{ + 3.377879570417399341550710467744693125385E-1L, + 1.021963322742390735430008860602594456187E1L, + 1.200847646592942095192766255154827011939E2L, + 7.118915528142927104078182863387116942836E2L, + 2.318159380062066469386544552429625026238E3L, + 4.238729853534009221025582008928765281620E3L, + 4.279114907284825886266493994833515580782E3L, + 2.257277186663261531053293222591851737504E3L, + 5.570475501285054293371908382916063822957E2L, + 5.142189243856288981145786492585432443560E1L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 3/8 <= 1/x < 1/2 + Peak relative error 2.0e-36 */ +#define NRNr4 10 +static const long double RNr4[NRNr4 + 1] = +{ + 3.258530712024527835089319075288494524465E-3L, + 2.987056016877277929720231688689431056567E-1L, + 8.738729089340199750734409156830371528862E0L, + 1.207211160148647782396337792426311125923E2L, + 8.997558632489032902250523945248208224445E2L, + 3.798025197699757225978410230530640879762E3L, + 9.113203668683080975637043118209210146846E3L, + 1.203285891339933238608683715194034900149E4L, + 8.100647057919140328536743641735339740855E3L, + 2.383888249907144945837976899822927411769E3L, + 2.127493573166454249221983582495245662319E2L +}; +#define NRDr4 10 +static const long double RDr4[NRDr4 + 1] = +{ +-3.303141981514540274165450687270180479586E-1L, +-1.353768629363605300707949368917687066724E1L, +-2.206127630303621521950193783894598987033E2L, +-1.861800338758066696514480386180875607204E3L, +-8.889048775872605708249140016201753255599E3L, +-2.465888106627948210478692168261494857089E4L, +-3.934642211710774494879042116768390014289E4L, +-3.455077258242252974937480623730228841003E4L, +-1.524083977439690284820586063729912653196E4L, +-2.810541887397984804237552337349093953857E3L, +-1.343929553541159933824901621702567066156E2L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 1/4 <= 1/x < 3/8 + Peak relative error 8.4e-37 */ +#define NRNr3 11 +static const long double RNr3[NRNr3 + 1] = +{ +-1.952401126551202208698629992497306292987E-6L, +-2.130881743066372952515162564941682716125E-4L, +-8.376493958090190943737529486107282224387E-3L, +-1.650592646560987700661598877522831234791E-1L, +-1.839290818933317338111364667708678163199E0L, +-1.216278715570882422410442318517814388470E1L, +-4.818759344462360427612133632533779091386E1L, +-1.120994661297476876804405329172164436784E2L, +-1.452850765662319264191141091859300126931E2L, +-9.485207851128957108648038238656777241333E1L, +-2.563663855025796641216191848818620020073E1L, +-1.787995944187565676837847610706317833247E0L +}; +#define NRDr3 10 +static const long double RDr3[NRDr3 + 1] = +{ + 1.979130686770349481460559711878399476903E-4L, + 1.156941716128488266238105813374635099057E-2L, + 2.752657634309886336431266395637285974292E-1L, + 3.482245457248318787349778336603569327521E0L, + 2.569347069372696358578399521203959253162E1L, + 1.142279000180457419740314694631879921561E2L, + 3.056503977190564294341422623108332700840E2L, + 4.780844020923794821656358157128719184422E2L, + 4.105972727212554277496256802312730410518E2L, + 1.724072188063746970865027817017067646246E2L, + 2.815939183464818198705278118326590370435E1L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 1/8 <= 1/x < 1/4 + Peak relative error 1.5e-36 */ +#define NRNr2 11 +static const long double RNr2[NRNr2 + 1] = +{ +-2.638914383420287212401687401284326363787E-8L, +-3.479198370260633977258201271399116766619E-6L, +-1.783985295335697686382487087502222519983E-4L, +-4.777876933122576014266349277217559356276E-3L, +-7.450634738987325004070761301045014986520E-2L, +-7.068318854874733315971973707247467326619E-1L, +-4.113919921935944795764071670806867038732E0L, +-1.440447573226906222417767283691888875082E1L, +-2.883484031530718428417168042141288943905E1L, +-2.990886974328476387277797361464279931446E1L, +-1.325283914915104866248279787536128997331E1L, +-1.572436106228070195510230310658206154374E0L +}; +#define NRDr2 10 +static const long double RDr2[NRDr2 + 1] = +{ + 2.675042728136731923554119302571867799673E-6L, + 2.170997868451812708585443282998329996268E-4L, + 7.249969752687540289422684951196241427445E-3L, + 1.302040375859768674620410563307838448508E-1L, + 1.380202483082910888897654537144485285549E0L, + 8.926594113174165352623847870299170069350E0L, + 3.521089584782616472372909095331572607185E1L, + 8.233547427533181375185259050330809105570E1L, + 1.072971579885803033079469639073292840135E2L, + 6.943803113337964469736022094105143158033E1L, + 1.775695341031607738233608307835017282662E1L + /* 1.0E0 */ +}; + +/* erfc(1/x) = 1/x exp(-1/x^2 - 0.5625 + R(1/x^2)) + 1/128 <= 1/x < 1/8 + Peak relative error 2.2e-36 */ +#define NRNr1 9 +static const long double RNr1[NRNr1 + 1] = +{ +-4.250780883202361946697751475473042685782E-8L, +-5.375777053288612282487696975623206383019E-6L, +-2.573645949220896816208565944117382460452E-4L, +-6.199032928113542080263152610799113086319E-3L, +-8.262721198693404060380104048479916247786E-2L, +-6.242615227257324746371284637695778043982E-1L, +-2.609874739199595400225113299437099626386E0L, +-5.581967563336676737146358534602770006970E0L, +-5.124398923356022609707490956634280573882E0L, +-1.290865243944292370661544030414667556649E0L +}; +#define NRDr1 8 +static const long double RDr1[NRDr1 + 1] = +{ + 4.308976661749509034845251315983612976224E-6L, + 3.265390126432780184125233455960049294580E-4L, + 9.811328839187040701901866531796570418691E-3L, + 1.511222515036021033410078631914783519649E-1L, + 1.289264341917429958858379585970225092274E0L, + 6.147640356182230769548007536914983522270E0L, + 1.573966871337739784518246317003956180750E1L, + 1.955534123435095067199574045529218238263E1L, + 9.472613121363135472247929109615785855865E0L + /* 1.0E0 */ +}; + + +long double +erfl(long double x) +{ + long double a, y, z; + int32_t i, ix, sign; + ieee_quad_shape_type u; + + u.value = x; + sign = u.parts32.mswhi; + ix = sign & 0x7fffffff; + + if (ix >= 0x7fff0000) + { /* erf(nan)=nan */ + i = ((sign & 0xffff0000) >> 31) << 1; + return (long double) (1 - i) + one / x; /* erf(+-inf)=+-1 */ + } + + if (ix >= 0x3fff0000) /* |x| >= 1.0 */ + { + y = erfcl (x); + return (one - y); + /* return (one - erfcl (x)); */ + } + u.parts32.mswhi = ix; + a = u.value; + z = x * x; + if (ix < 0x3ffec000) /* a < 0.875 */ + { + if (ix < 0x3fc60000) /* |x|<2**-57 */ + { + if (ix < 0x00080000) + return 0.125 * (8.0 * x + efx8 * x); /*avoid underflow */ + return x + efx * x; + } + y = a + a * neval (z, TN1, NTN1) / deval (z, TD1, NTD1); + } + else + { + a = a - one; + y = erf_const + neval (a, TN2, NTN2) / deval (a, TD2, NTD2); + } + + if (sign & 0x80000000) /* x < 0 */ + y = -y; + return( y ); +} + +long double +erfcl(long double x) +{ + long double y, z, p, r; + int32_t i, ix, sign; + ieee_quad_shape_type u; + + u.value = x; + sign = u.parts32.mswhi; + ix = sign & 0x7fffffff; + u.parts32.mswhi = ix; + + if (ix >= 0x7fff0000) + { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (long double) (((u_int32_t) sign >> 31) << 1) + one / x; + } + + if (ix < 0x3ffd0000) /* |x| <1/4 */ + { + if (ix < 0x3f8d0000) /* |x|<2**-114 */ + return one - x; + return one - erfl (x); + } + if (ix < 0x3fff4000) /* 1.25 */ + { + x = u.value; + i = 8.0 * x; + switch (i) + { + case 2: + z = x - 0.25L; + y = C13b + z * neval (z, RNr13, NRNr13) / deval (z, RDr13, NRDr13); + y += C13a; + break; + case 3: + z = x - 0.375L; + y = C14b + z * neval (z, RNr14, NRNr14) / deval (z, RDr14, NRDr14); + y += C14a; + break; + case 4: + z = x - 0.5L; + y = C15b + z * neval (z, RNr15, NRNr15) / deval (z, RDr15, NRDr15); + y += C15a; + break; + case 5: + z = x - 0.625L; + y = C16b + z * neval (z, RNr16, NRNr16) / deval (z, RDr16, NRDr16); + y += C16a; + break; + case 6: + z = x - 0.75L; + y = C17b + z * neval (z, RNr17, NRNr17) / deval (z, RDr17, NRDr17); + y += C17a; + break; + case 7: + z = x - 0.875L; + y = C18b + z * neval (z, RNr18, NRNr18) / deval (z, RDr18, NRDr18); + y += C18a; + break; + case 8: + z = x - 1.0L; + y = C19b + z * neval (z, RNr19, NRNr19) / deval (z, RDr19, NRDr19); + y += C19a; + break; + case 9: + z = x - 1.125L; + y = C20b + z * neval (z, RNr20, NRNr20) / deval (z, RDr20, NRDr20); + y += C20a; + break; + } + if (sign & 0x80000000) + y = 2.0L - y; + return y; + } + /* 1.25 < |x| < 107 */ + if (ix < 0x4005ac00) + { + /* x < -9 */ + if ((ix >= 0x40022000) && (sign & 0x80000000)) + return two - tiny; + + x = fabsl (x); + z = one / (x * x); + i = 8.0 / x; + switch (i) + { + default: + case 0: + p = neval (z, RNr1, NRNr1) / deval (z, RDr1, NRDr1); + break; + case 1: + p = neval (z, RNr2, NRNr2) / deval (z, RDr2, NRDr2); + break; + case 2: + p = neval (z, RNr3, NRNr3) / deval (z, RDr3, NRDr3); + break; + case 3: + p = neval (z, RNr4, NRNr4) / deval (z, RDr4, NRDr4); + break; + case 4: + p = neval (z, RNr5, NRNr5) / deval (z, RDr5, NRDr5); + break; + case 5: + p = neval (z, RNr6, NRNr6) / deval (z, RDr6, NRDr6); + break; + case 6: + p = neval (z, RNr7, NRNr7) / deval (z, RDr7, NRDr7); + break; + case 7: + p = neval (z, RNr8, NRNr8) / deval (z, RDr8, NRDr8); + break; + } + u.value = x; + u.parts32.lswlo = 0; + u.parts32.lswhi &= 0xfe000000; + z = u.value; + r = expl (-z * z - 0.5625) * + expl ((z - x) * (z + x) + p); + if ((sign & 0x80000000) == 0) + return r / x; + else + return two - r / x; + } + else + { + if ((sign & 0x80000000) == 0) + return tiny * tiny; + else + return two - tiny; + } +} diff --git a/src/openlibm/ld128/s_exp2l.c b/src/openlibm/ld128/s_exp2l.c new file mode 100644 index 0000000..c5f997f --- /dev/null +++ b/src/openlibm/ld128/s_exp2l.c @@ -0,0 +1,431 @@ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld128/s_exp2l.c,v 1.3 2008/02/13 10:44:44 bde Exp $"); + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +#define BIAS (LDBL_MAX_EXP - 1) +#define EXPMASK (BIAS + LDBL_MAX_EXP) + +#if 0 /* XXX Prevent gcc from erroneously constant folding this. */ +static const long double twom10000 = 0x1p-10000L; +#else +static volatile long double twom10000 = 0x1p-10000L; +#endif + +static const long double + huge = 0x1p10000L, + P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double + P7 = 0x1.ffcbfc588b041p-17, + P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, + P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, + 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, + 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, + 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, + 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, + 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, + 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, + 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, + 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, + 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, + 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, + 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, + 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, + 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, + 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, + 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, + 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, + 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, + 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, + 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, + 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, + 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, + 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, + 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, + 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, + 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, + 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, + 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, + 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, + 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, + 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, + 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, + 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, + 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, + 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, + 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, + 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, + 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, + 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, + 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, + 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, + 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, + 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, + 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, + 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, + 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, + 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, + 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, + 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, + 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, + 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, + 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, + 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, + 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, + 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, + 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, + 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, + 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, + 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, + 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, + 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, + 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, + 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, + 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, + 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, + -0x1.5d00p-106, + 0x1.8e90p-102, + -0x1.5340p-103, + 0x1.1bd0p-102, + -0x1.4600p-105, + -0x1.7a40p-104, + 0x1.d590p-102, + -0x1.d590p-101, + 0x1.b100p-103, + -0x1.0d80p-105, + 0x1.6b00p-103, + -0x1.9f00p-105, + 0x1.c400p-103, + 0x1.e120p-103, + -0x1.c100p-104, + -0x1.9d20p-103, + 0x1.a800p-108, + 0x1.4c00p-106, + -0x1.9500p-106, + 0x1.6900p-105, + -0x1.29d0p-100, + 0x1.4c60p-103, + 0x1.13a0p-102, + -0x1.5b60p-103, + -0x1.1c40p-103, + 0x1.db80p-102, + 0x1.91a0p-102, + 0x1.dc00p-105, + 0x1.44c0p-104, + 0x1.9710p-102, + 0x1.8760p-103, + -0x1.a720p-103, + 0x1.ed20p-103, + -0x1.49c0p-102, + -0x1.e000p-111, + 0x1.86a0p-103, + 0x1.2b40p-103, + -0x1.b400p-108, + 0x1.1280p-99, + -0x1.02d8p-102, + -0x1.e3d0p-103, + -0x1.b080p-105, + -0x1.f100p-107, + -0x1.16c0p-105, + -0x1.1190p-103, + -0x1.a7d2p-100, + 0x1.3450p-103, + -0x1.67c0p-105, + 0x1.4b80p-104, + -0x1.c4e0p-103, + 0x1.6000p-108, + -0x1.3f60p-105, + 0x1.93f0p-104, + 0x1.5fe0p-105, + 0x1.6f80p-107, + -0x1.7600p-106, + 0x1.21e0p-106, + -0x1.3a40p-106, + -0x1.40c0p-104, + -0x1.9860p-105, + -0x1.5d40p-108, + -0x1.1d70p-106, + 0x1.2760p-105, + 0x0.0000p+0, + 0x1.21e2p-104, + -0x1.9520p-108, + -0x1.5720p-106, + -0x1.4810p-106, + -0x1.be00p-109, + 0x1.0080p-105, + -0x1.5780p-108, + -0x1.d460p-105, + -0x1.6140p-105, + 0x1.4630p-104, + 0x1.ad50p-103, + 0x1.82e0p-105, + 0x1.1d3cp-101, + 0x1.6100p-107, + 0x1.ec30p-104, + 0x1.f200p-108, + 0x1.0b40p-103, + 0x1.3660p-102, + 0x1.d9d0p-103, + -0x1.02d0p-102, + 0x1.b070p-103, + 0x1.b9c0p-104, + -0x1.01c0p-103, + -0x1.dfe0p-103, + 0x1.1b60p-104, + -0x1.ae94p-101, + -0x1.3340p-104, + 0x1.b3d8p-102, + -0x1.6e40p-105, + -0x1.3670p-103, + 0x1.c140p-104, + 0x1.1840p-101, + 0x1.1ab0p-102, + -0x1.a400p-104, + 0x1.1f00p-104, + -0x1.7180p-103, + 0x1.4ce0p-102, + 0x1.9200p-107, + -0x1.54c0p-103, + 0x1.1b80p-105, + -0x1.1828p-101, + 0x1.5720p-102, + -0x1.a060p-100, + 0x1.9160p-102, + 0x1.a280p-104, + 0x1.3400p-107, + 0x1.2b20p-102, + 0x1.7800p-108, + 0x1.cfd0p-101, + 0x1.2ef0p-102, + -0x1.2760p-99, + 0x1.b380p-104, + 0x1.0048p-101, + -0x1.60b0p-102, + 0x1.a1ccp-100, + -0x1.a640p-104, + -0x1.08a0p-101, + 0x1.7e60p-102, + 0x1.22c0p-103, + -0x1.7200p-106, + 0x1.f0f0p-102, + 0x1.eb4ep-99, + 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +OLM_DLLEXPORT long double +exp2l(long double x) +{ + union IEEEl2bits u, v; + long double r, t, twopk, twopkp10000, z; + uint32_t hx, ix, i0; + int k; + + u.e = x; + + /* Filter out exceptional cases. */ + hx = u.xbits.expsign; + ix = hx & EXPMASK; + if (ix >= BIAS + 14) { /* |x| >= 16384 */ + if (ix == BIAS + LDBL_MAX_EXP) { + if (u.xbits.manh != 0 + || u.xbits.manl != 0 + || (hx & 0x8000) == 0) + return (x + x); /* x is NaN or +Inf */ + else + return (0.0); /* x is -Inf */ + } + if (x >= 16384) + return (huge * huge); /* overflow */ + if (x <= -16495) + return (twom10000 * twom10000); /* underflow */ + } else if (ix <= BIAS - 115) { /* |x| < 0x1p-115 */ + return (1.0 + x); + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + * + * XXX If the exponent is negative, the computation of k depends on + * '>>' doing sign extension. + */ + u.e = x + redux; + i0 = (u.bits.manl & 0xffffffff) + TBLSIZE / 2; + k = (int)i0 >> TBLBITS; + i0 = i0 & (TBLSIZE - 1); + u.e -= redux; + z = x - u.e; + v.xbits.manh = 0; + v.xbits.manl = 0; + if (k >= LDBL_MIN_EXP) { + v.xbits.expsign = LDBL_MAX_EXP - 1 + k; + twopk = v.e; + } else { + v.xbits.expsign = LDBL_MAX_EXP - 1 + k + 10000; + twopkp10000 = v.e; + } + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; /* exp2t[i0] */ + z -= eps[i0]; /* eps[i0] */ + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6 + + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + /* Scale by 2**k. */ + if(k >= LDBL_MIN_EXP) { + if (k == LDBL_MAX_EXP) + return (r * 2.0 * 0x1p16383L); + return (r * twopk); + } else { + return (r * twopkp10000 * twom10000); + } +} diff --git a/src/openlibm/ld128/s_expm1l.c b/src/openlibm/ld128/s_expm1l.c new file mode 100644 index 0000000..1c22696 --- /dev/null +++ b/src/openlibm/ld128/s_expm1l.c @@ -0,0 +1,162 @@ +/* $OpenBSD: s_expm1l.c,v 1.1 2011/07/06 00:02:42 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* expm1l.c + * + * Exponential function, minus 1 + * 128-bit long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus one. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -79,+MAXLOG 100,000 1.7e-34 4.5e-35 + * + */ + +#include +#include + +#include "math_private.h" + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 8.1e-36 */ + +static const long double + P0 = 2.943520915569954073888921213330863757240E8L, + P1 = -5.722847283900608941516165725053359168840E7L, + P2 = 8.944630806357575461578107295909719817253E6L, + P3 = -7.212432713558031519943281748462837065308E5L, + P4 = 4.578962475841642634225390068461943438441E4L, + P5 = -1.716772506388927649032068540558788106762E3L, + P6 = 4.401308817383362136048032038528753151144E1L, + P7 = -4.888737542888633647784737721812546636240E-1L, + Q0 = 1.766112549341972444333352727998584753865E9L, + Q1 = -7.848989743695296475743081255027098295771E8L, + Q2 = 1.615869009634292424463780387327037251069E8L, + Q3 = -2.019684072836541751428967854947019415698E7L, + Q4 = 1.682912729190313538934190635536631941751E6L, + Q5 = -9.615511549171441430850103489315371768998E4L, + Q6 = 3.697714952261803935521187272204485251835E3L, + Q7 = -8.802340681794263968892934703309274564037E1L, + /* Q8 = 1.000000000000000000000000000000000000000E0 */ +/* C1 + C2 = ln 2 */ + + C1 = 6.93145751953125E-1L, + C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln (2^16384 * (1 - 2^-113)) */ + maxlog = 1.1356523406294143949491931077970764891253E4L, +/* ln 2^-114 */ + minarg = -7.9018778583833765273564461846232128760607E1L, big = 1e4932L; + + +long double +expm1l(long double x) +{ + long double px, qx, xx; + int32_t ix, sign; + ieee_quad_shape_type u; + int k; + + /* Detect infinity and NaN. */ + u.value = x; + ix = u.parts32.mswhi; + sign = ix & 0x80000000; + ix &= 0x7fffffff; + if (ix >= 0x7fff0000) + { + /* Infinity. */ + if (((ix & 0xffff) | u.parts32.mswlo | u.parts32.lswhi | + u.parts32.lswlo) == 0) + { + if (sign) + return -1.0L; + else + return x; + } + /* NaN. No invalid exception. */ + return x; + } + + /* expm1(+- 0) = +- 0. */ + if ((ix == 0) && (u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0) + return x; + + /* Overflow. */ + if (x > maxlog) + return (big * big); + + /* Minimum value. */ + if (x < minarg) + return (4.0/big - 1.0L); + + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + xx = C1 + C2; /* ln 2. */ + px = floorl (0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2). */ + px = (((((((P7 * x + + P6) * x + + P5) * x + P4) * x + P3) * x + P2) * x + P1) * x + P0) * x; + + qx = (((((((x + + Q7) * x + + Q6) * x + Q5) * x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 + = 2^k qx + 2^k - 1. */ + + px = ldexpl (1.0L, k); + x = px * qx + (px - 1.0); + return x; +} diff --git a/src/openlibm/ld128/s_floorl.c b/src/openlibm/ld128/s_floorl.c new file mode 100644 index 0000000..f00dcfa --- /dev/null +++ b/src/openlibm/ld128/s_floorl.c @@ -0,0 +1,71 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * floorl(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include + +#include "math_private.h" + +static const long double huge = 1.0e4930L; + +long double +floorl(long double x) +{ + int64_t i0,i1,jj0; + u_int64_t i,j; + GET_LDOUBLE_WORDS64(i0,i1,x); + jj0 = ((i0>>48)&0x7fff)-0x3fff; + if(jj0<48) { + if(jj0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) { + if(i0>=0) + return 0.0L; + else if(((i0&0x7fffffffffffffffLL)|i1)!=0) + return -1.0L; + } + } else { + i = (0x0000ffffffffffffULL)>>jj0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x0001000000000000LL)>>jj0; + i0 &= (~i); i1=0; + } + } + } else if (jj0>111) { + if(jj0==0x4000) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = -1ULL>>(jj0-48); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) { + if(jj0==48) i0+=1; + else { + j = i1+(1LL<<(112-jj0)); + if(j + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log1pl.c + * + * Relative error logarithm + * Natural logarithm of 1+x, 128-bit long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(w-1)/(w+1), + * + * log(w) = z + z^3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1, 8 100000 1.9e-34 4.3e-35 + */ + +#include + +#include "math_private.h" + +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= 1+x < sqrt(2) + * Theoretical peak relative error = 5.3e-37, + * relative peak error spread = 2.3e-14 + */ +static const long double + P12 = 1.538612243596254322971797716843006400388E-6L, + P11 = 4.998469661968096229986658302195402690910E-1L, + P10 = 2.321125933898420063925789532045674660756E1L, + P9 = 4.114517881637811823002128927449878962058E2L, + P8 = 3.824952356185897735160588078446136783779E3L, + P7 = 2.128857716871515081352991964243375186031E4L, + P6 = 7.594356839258970405033155585486712125861E4L, + P5 = 1.797628303815655343403735250238293741397E5L, + P4 = 2.854829159639697837788887080758954924001E5L, + P3 = 3.007007295140399532324943111654767187848E5L, + P2 = 2.014652742082537582487669938141683759923E5L, + P1 = 7.771154681358524243729929227226708890930E4L, + P0 = 1.313572404063446165910279910527789794488E4L, + /* Q12 = 1.000000000000000000000000000000000000000E0L, */ + Q11 = 4.839208193348159620282142911143429644326E1L, + Q10 = 9.104928120962988414618126155557301584078E2L, + Q9 = 9.147150349299596453976674231612674085381E3L, + Q8 = 5.605842085972455027590989944010492125825E4L, + Q7 = 2.248234257620569139969141618556349415120E5L, + Q6 = 6.132189329546557743179177159925690841200E5L, + Q5 = 1.158019977462989115839826904108208787040E6L, + Q4 = 1.514882452993549494932585972882995548426E6L, + Q3 = 1.347518538384329112529391120390701166528E6L, + Q2 = 7.777690340007566932935753241556479363645E5L, + Q1 = 2.626900195321832660448791748036714883242E5L, + Q0 = 3.940717212190338497730839731583397586124E4L; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 1.1e-35, + * relative peak error spread 1.1e-9 + */ +static const long double + R5 = -8.828896441624934385266096344596648080902E-1L, + R4 = 8.057002716646055371965756206836056074715E1L, + R3 = -2.024301798136027039250415126250455056397E3L, + R2 = 2.048819892795278657810231591630928516206E4L, + R1 = -8.977257995689735303686582344659576526998E4L, + R0 = 1.418134209872192732479751274970992665513E5L, + /* S6 = 1.000000000000000000000000000000000000000E0L, */ + S5 = -1.186359407982897997337150403816839480438E2L, + S4 = 3.998526750980007367835804959888064681098E3L, + S3 = -5.748542087379434595104154610899551484314E4L, + S2 = 4.001557694070773974936904547424676279307E5L, + S1 = -1.332535117259762928288745111081235577029E6L, + S0 = 1.701761051846631278975701529965589676574E6L; + +/* C1 + C2 = ln 2 */ +static const long double C1 = 6.93145751953125E-1L; +static const long double C2 = 1.428606820309417232121458176568075500134E-6L; + +static const long double sqrth = 0.7071067811865475244008443621048490392848L; +/* ln (2^16384 * (1 - 2^-113)) */ +static const long double zero = 0.0L; + +long double +log1pl(long double xm1) +{ + long double x, y, z, r, s; + ieee_quad_shape_type u; + int32_t hx; + int e; + + /* Test for NaN or infinity input. */ + u.value = xm1; + hx = u.parts32.mswhi; + if (hx >= 0x7fff0000) + return xm1; + + /* log1p(+- 0) = +- 0. */ + if (((hx & 0x7fffffff) == 0) + && (u.parts32.mswlo | u.parts32.lswhi | u.parts32.lswlo) == 0) + return xm1; + + x = xm1 + 1.0L; + + /* log1p(-1) = -inf */ + if (x <= 0.0L) + { + if (x == 0.0L) + return (-1.0L / (x - x)); + else + return (zero / (x - x)); + } + + /* Separate mantissa from exponent. */ + + /* Use frexp used so that denormal numbers will be handled properly. */ + x = frexpl (x, &e); + + /* Logarithm using log(x) = z + z^3 P(z^2)/Q(z^2), + where z = 2(x-1)/x+1). */ + if ((e > 2) || (e < -2)) + { + if (x < sqrth) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } + else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } + x = z / y; + z = x * x; + r = ((((R5 * z + + R4) * z + + R3) * z + + R2) * z + + R1) * z + + R0; + s = (((((z + + S5) * z + + S4) * z + + S3) * z + + S2) * z + + S1) * z + + S0; + z = x * (z * r / s); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return (z); + } + + + /* Logarithm using log(1+x) = x - .5x^2 + x^3 P(x)/Q(x). */ + + if (x < sqrth) + { + e -= 1; + if (e != 0) + x = 2.0L * x - 1.0L; /* 2x - 1 */ + else + x = xm1; + } + else + { + if (e != 0) + x = x - 1.0L; + else + x = xm1; + } + z = x * x; + r = (((((((((((P12 * x + + P11) * x + + P10) * x + + P9) * x + + P8) * x + + P7) * x + + P6) * x + + P5) * x + + P4) * x + + P3) * x + + P2) * x + + P1) * x + + P0; + s = (((((((((((x + + Q11) * x + + Q10) * x + + Q9) * x + + Q8) * x + + Q7) * x + + Q6) * x + + Q5) * x + + Q4) * x + + Q3) * x + + Q2) * x + + Q1) * x + + Q0; + y = x * (z * r / s); + y = y + e * C2; + z = y - 0.5L * z; + z = z + x; + z = z + e * C1; + return (z); +} diff --git a/src/openlibm/ld128/s_modfl.c b/src/openlibm/ld128/s_modfl.c new file mode 100644 index 0000000..bd18cba --- /dev/null +++ b/src/openlibm/ld128/s_modfl.c @@ -0,0 +1,73 @@ +/* @(#)s_modf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modfl(long double x, long double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0; + +long double +modfl(long double x, long double *iptr) +{ + int64_t i0,i1,jj0; + u_int64_t i; + GET_LDOUBLE_WORDS64(i0,i1,x); + jj0 = ((i0>>48)&0x7fff)-0x3fff; /* exponent of x */ + if(jj0<48) { /* integer part in high x */ + if(jj0<0) { /* |x|<1 */ + /* *iptr = +-0 */ + SET_LDOUBLE_WORDS64(*iptr,i0&0x8000000000000000ULL,0); + return x; + } else { + i = (0x0000ffffffffffffLL)>>jj0; + if(((i0&i)|i1)==0) { /* x is integral */ + *iptr = x; + /* return +-0 */ + SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0); + return x; + } else { + SET_LDOUBLE_WORDS64(*iptr,i0&(~i),0); + return x - *iptr; + } + } + } else if (jj0>111) { /* no fraction part */ + *iptr = x*one; + /* We must handle NaNs separately. */ + if (jj0 == 0x4000 && ((i0 & 0x0000ffffffffffffLL) | i1)) + return x*one; + /* return +-0 */ + SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0); + return x; + } else { /* fraction part in low x */ + i = -1ULL>>(jj0-48); + if((i1&i)==0) { /* x is integral */ + *iptr = x; + /* return +-0 */ + SET_LDOUBLE_WORDS64(x,i0&0x8000000000000000ULL,0); + return x; + } else { + SET_LDOUBLE_WORDS64(*iptr,i0,i1&(~i)); + return x - *iptr; + } + } +} diff --git a/src/openlibm/ld128/s_nanl.c b/src/openlibm/ld128/s_nanl.c new file mode 100644 index 0000000..4dcdb4e --- /dev/null +++ b/src/openlibm/ld128/s_nanl.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/ld128/s_nanl.c,v 1.3 2008/03/02 20:16:55 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT long double +nanl(const char *s) +{ + union { + union IEEEl2bits ieee; + uint32_t bits[4]; + } u; + + __scan_nan(u.bits, 4, s); + u.ieee.bits.exp = 0x7fff; + u.ieee.bits.manh |= 1ULL << 47; /* make it a quiet NaN */ + return (u.ieee.e); +} diff --git a/src/openlibm/ld128/s_nextafterl.c b/src/openlibm/ld128/s_nextafterl.c new file mode 100644 index 0000000..af667a0 --- /dev/null +++ b/src/openlibm/ld128/s_nextafterl.c @@ -0,0 +1,72 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + * nextafterl(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include + +#include "math_private.h" + +long double +nextafterl(long double x, long double y) +{ + int64_t hx,hy,ix,iy; + u_int64_t lx,ly; + + GET_LDOUBLE_WORDS64(hx,lx,x); + GET_LDOUBLE_WORDS64(hy,ly,y); + ix = hx&0x7fffffffffffffffLL; /* |x| */ + iy = hy&0x7fffffffffffffffLL; /* |y| */ + + if(((ix>=0x7fff000000000000LL)&&((ix-0x7fff000000000000LL)|lx)!=0) || /* x is nan */ + ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0)) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if((ix|lx)==0) { /* x == 0 */ + volatile long double u; + SET_LDOUBLE_WORDS64(x,hy&0x8000000000000000ULL,1);/* return +-minsubnormal */ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(hx>=0) { /* x > 0 */ + if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */ + if(lx==0) hx--; + lx--; + } else { /* x < y, x += ulp */ + lx++; + if(lx==0) hx++; + } + } else { /* x < 0 */ + if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */ + if(lx==0) hx--; + lx--; + } else { /* x > y, x += ulp */ + lx++; + if(lx==0) hx++; + } + } + hy = hx&0x7fff000000000000LL; + if(hy==0x7fff000000000000LL) return x+x;/* overflow */ + if(hy==0) { + volatile long double u = x*x; /* underflow */ + } + SET_LDOUBLE_WORDS64(x,hx,lx); + return x; +} + +__strong_alias(nexttowardl, nextafterl); diff --git a/src/openlibm/ld128/s_nexttoward.c b/src/openlibm/ld128/s_nexttoward.c new file mode 100644 index 0000000..a9ff797 --- /dev/null +++ b/src/openlibm/ld128/s_nexttoward.c @@ -0,0 +1,85 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + * nexttoward(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include +#include + +#include "math_private.h" + +double +nexttoward(double x, long double y) +{ + int32_t hx,ix; + int64_t hy,iy; + u_int32_t lx; + u_int64_t ly; + + EXTRACT_WORDS(hx,lx,x); + GET_LDOUBLE_WORDS64(hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffffffffffffLL; /* |y| */ + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ + ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0)) + /* y is nan */ + return x+y; + if((long double) x==y) return y; /* x=y, return y */ + if((ix|lx)==0) { /* x == 0 */ + volatile double u; + INSERT_WORDS(x,(u_int32_t)((hy>>32)&0x80000000),1);/* return +-minsub */ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(hx>=0) { /* x > 0 */ + if (hy<0||(ix>>20)>(iy>>48)-0x3c00 + || ((ix>>20)==(iy>>48)-0x3c00 + && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL) + || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL) + && (lx&0xf)>(ly>>60))))) { /* x > y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } else { /* x < 0 */ + if (hy>=0||(ix>>20)>(iy>>48)-0x3c00 + || ((ix>>20)==(iy>>48)-0x3c00 + && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL) + || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL) + && (lx&0xf)>(ly>>60))))) { /* x < y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } + hy = hx&0x7ff00000; + if(hy>=0x7ff00000) { + x = x+x; /* overflow */ + return x; + } + if(hy<0x00100000) { + volatile double u = x*x; /* underflow */ + } + INSERT_WORDS(x,hx,lx); + return x; +} diff --git a/src/openlibm/ld128/s_nexttowardf.c b/src/openlibm/ld128/s_nexttowardf.c new file mode 100644 index 0000000..61387ac --- /dev/null +++ b/src/openlibm/ld128/s_nexttowardf.c @@ -0,0 +1,65 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +#include "math_private.h" + +float +nexttowardf(float x, long double y) +{ + int32_t hx,ix; + int64_t hy,iy; + u_int64_t ly; + + GET_FLOAT_WORD(hx,x); + GET_LDOUBLE_WORDS64(hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffffffffffffLL; /* |y| */ + + if((ix>0x7f800000) || /* x is nan */ + ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0)) + /* y is nan */ + return x+y; + if((long double) x==y) return y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + volatile float u; + SET_FLOAT_WORD(x,(u_int32_t)((hy>>32)&0x80000000)|1);/* return +-minsub*/ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(hx>=0) { /* x > 0 */ + if(hy<0||(ix>>23)>(iy>>48)-0x3f80 + || ((ix>>23)==(iy>>48)-0x3f80 + && (ix&0x7fffff)>((hy>>25)&0x7fffff))) {/* x > y, x -= ulp */ + hx -= 1; + } else { /* x < y, x += ulp */ + hx += 1; + } + } else { /* x < 0 */ + if(hy>=0||(ix>>23)>(iy>>48)-0x3f80 + || ((ix>>23)==(iy>>48)-0x3f80 + && (ix&0x7fffff)>((hy>>25)&0x7fffff))) {/* x < y, x -= ulp */ + hx -= 1; + } else { /* x > y, x += ulp */ + hx += 1; + } + } + hy = hx&0x7f800000; + if(hy>=0x7f800000) return x+x; /* overflow */ + if(hy<0x00800000) { + volatile float u = x*x; /* underflow */ + } + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/src/openlibm/ld128/s_remquol.c b/src/openlibm/ld128/s_remquol.c new file mode 100644 index 0000000..f56ce4f --- /dev/null +++ b/src/openlibm/ld128/s_remquol.c @@ -0,0 +1,168 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +#include +#include +#include + +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define LDBL_NBIT 0 +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS (EXT_FRACHBITS + EXT_FRACHMBITS) +#else +#define LDBL_NBIT 0x80000000 +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (EXT_FRACHBITS + EXT_FRACHMBITS - 1) +#endif + +#define MANL_SHIFT (EXT_FRACLMBITS + EXT_FRACLBITS - 1) + +static const long double Zero[] = {0.0L, -0.0L}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +long double +remquol(long double x, long double y, int *quo) +{ + int64_t hx,hz,hy,_hx; + uint64_t lx,ly,lz; + uint64_t sx,sxy; + int ix,iy,n,q; + + GET_LDOUBLE_WORDS64(hx,lx,x); + GET_LDOUBLE_WORDS64(hy,ly,y); + sx = (hx>>48)&0x8000; + sxy = sx ^ ((hy>>48)&0x8000); + hx &= 0x7fffffffffffffffLL; /* |x| */ + hy &= 0x7fffffffffffffffLL; /* |y| */ + SET_LDOUBLE_WORDS64(x,hx,lx); + SET_LDOUBLE_WORDS64(y,hy,ly); + + /* purge off exception values */ + if((hy|ly)==0 || /* y=0 */ + ((hx>>48) == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + ((hy>>48) == BIAS + LDBL_MAX_EXP && + (((hy&0x0000ffffffffffffLL)&~LDBL_NBIT)|ly)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if((hx>>48)<=(hy>>48)) { + if(((hx>>48)<(hy>>48)) || + ((hx&0x0000ffffffffffffLL)<=(hy&0x0000ffffffffffffLL) && + ((hx&0x0000ffffffffffffLL)<(hy&0x0000ffffffffffffLL) || + lx>48) == 0) { /* subnormal x */ + x *= 0x1.0p512; + GET_LDOUBLE_WORDS64(hx,lx,x); + ix = (hx>>48) - (BIAS + 512); + } else { + ix = (hx>>48) - BIAS; + } + + /* determine iy = ilogb(y) */ + if((hy>>48) == 0) { /* subnormal y */ + y *= 0x1.0p512; + GET_LDOUBLE_WORDS64(hy,ly,y); + iy = (hy>>48) - (BIAS + 512); + } else { + iy = (hy>>48) - BIAS; + } + + /* set up {hx,lx}, {hy,ly} and align y to x */ + _hx = SET_NBIT(hx) & 0x0000ffffffffffffLL; + hy = SET_NBIT(hy); + + /* fix point fmod */ + n = ix - iy; + q = 0; + + while(n--) { + hz=_hx-hy;lz=lx-ly; if(lx>MANL_SHIFT); lx = lx+lx;} + else {_hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;} + q <<= 1; + } + hz=_hx-hy;lz=lx-ly; if(lx=0) {_hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((_hx|lx)==0) { /* return sign(x)*0 */ + *quo = (sxy ? -q : q); + return Zero[sx!=0]; + } + while(_hx<(1ULL<>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + hx = (hx&0xffff000000000000LL) | (_hx&0x0000ffffffffffffLL); + if (iy < LDBL_MIN_EXP) { + hx = (hx&0x0000ffffffffffffLL) | (uint64_t)(iy + BIAS + 512)<<48; + SET_LDOUBLE_WORDS64(x,hx,lx); + x *= 0x1p-512; + GET_LDOUBLE_WORDS64(hx,lx,x); + } else { + hx = (hx&0x0000ffffffffffffLL) | (uint64_t)(iy + BIAS)<<48; + } + hx &= 0x7fffffffffffffffLL; + SET_LDOUBLE_WORDS64(x,hx,lx); +fixup: + y = fabsl(y); + if (y < LDBL_MIN * 2) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + + GET_LDOUBLE_MSW64(hx,x); + hx ^= sx; + SET_LDOUBLE_MSW64(x,hx); + + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/src/openlibm/ld128/s_tanhl.c b/src/openlibm/ld128/s_tanhl.c new file mode 100644 index 0000000..f8e6291 --- /dev/null +++ b/src/openlibm/ld128/s_tanhl.c @@ -0,0 +1,105 @@ +/* @(#)s_tanh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* tanhl(x) + * Return the Hyperbolic Tangent of x + * + * Method : + * x -x + * e - e + * 0. tanhl(x) is defined to be ----------- + * x -x + * e + e + * 1. reduce x to non-negative by tanhl(-x) = -tanhl(x). + * 2. 0 <= x <= 2**-57 : tanhl(x) := x*(one+x) + * -t + * 2**-57 < x <= 1 : tanhl(x) := -----; t = expm1l(-2x) + * t + 2 + * 2 + * 1 <= x <= 40.0 : tanhl(x) := 1- ----- ; t=expm1l(2x) + * t + 2 + * 40.0 < x <= INF : tanhl(x) := 1. + * + * Special cases: + * tanhl(NaN) is NaN; + * only tanhl(0)=0 is exact for finite argument. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, two = 2.0, tiny = 1.0e-4900L; + +long double +tanhl(long double x) +{ + long double t, z; + u_int32_t jx, ix; + ieee_quad_shape_type u; + + /* Words of |x|. */ + u.value = x; + jx = u.parts32.mswhi; + ix = jx & 0x7fffffff; + /* x is INF or NaN */ + if (ix >= 0x7fff0000) + { + /* for NaN it's not important which branch: tanhl(NaN) = NaN */ + if (jx & 0x80000000) + return one / x - one; /* tanhl(-inf)= -1; */ + else + return one / x + one; /* tanhl(+inf)=+1 */ + } + + /* |x| < 40 */ + if (ix < 0x40044000) + { + if (u.value == 0) + return x; /* x == +- 0 */ + if (ix < 0x3fc60000) /* |x| < 2^-57 */ + return x * (one + tiny); /* tanh(small) = small */ + u.parts32.mswhi = ix; /* Absolute value of x. */ + if (ix >= 0x3fff0000) + { /* |x| >= 1 */ + t = expm1l (two * u.value); + z = one - two / (t + two); + } + else + { + t = expm1l (-two * u.value); + z = -t / (t + two); + } + /* |x| > 40, return +-1 */ + } + else + { + z = one - tiny; /* raised inexact flag */ + } + return (jx & 0x80000000) ? -z : z; +} diff --git a/src/openlibm/ld128/s_truncl.c b/src/openlibm/ld128/s_truncl.c new file mode 100644 index 0000000..a0d8bd5 --- /dev/null +++ b/src/openlibm/ld128/s_truncl.c @@ -0,0 +1,72 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +/* + * truncl(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncl(x). + */ + +#include +#include + +#include +#include +#include + +#include "math_private.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (EXT_FRACHBITS + EXT_FRACHMBITS + 1) +#else +#define MANH_SIZE (EXT_FRACHBITS + EXT_FRACHMBITS) +#endif + +static const long double huge = 1.0e300; +static const float zero[] = { 0.0, -0.0 }; + +long double +truncl(long double x) +{ + int e; + int64_t ix0, ix1; + + GET_LDOUBLE_WORDS64(ix0,ix1,x); + e = ((ix0>>48)&0x7fff) - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + return (zero[((ix0>>48)&0x8000)!=0]); + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((ix0 & m) | ix1) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) { /* raise inexact flag */ + ix0 &= ~m; + ix1 = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((ix1 & m) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) /* raise inexact flag */ + ix1 &= ~m; + } + SET_LDOUBLE_WORDS64(x,ix0,ix1); + return (x); +} diff --git a/src/openlibm/ld80/Make.files b/src/openlibm/ld80/Make.files new file mode 100644 index 0000000..1198cfb --- /dev/null +++ b/src/openlibm/ld80/Make.files @@ -0,0 +1,13 @@ +$(CUR_SRCS) += invtrig.c \ + e_acoshl.c e_powl.c k_tanl.c s_exp2l.c \ + e_atanhl.c e_lgammal_r.c e_sinhl.c s_asinhl.c s_expm1l.c \ + e_coshl.c e_log10l.c e_tgammal.c \ + e_expl.c e_log2l.c k_cosl.c s_log1pl.c s_tanhl.c \ + e_logl.c k_sinl.c s_erfl.c + +# s_remquol.c e_fmodl.c s_truncl.c +# e_hypotl.c s_floorl.c s_nextafterl.c s_ceill.c s_modfl.c + +ifneq ($(OS), WINNT) +$(CUR_SRCS) += s_nanl.c +endif diff --git a/src/openlibm/ld80/e_acoshl.c b/src/openlibm/ld80/e_acoshl.c new file mode 100644 index 0000000..35758bb --- /dev/null +++ b/src/openlibm/ld80/e_acoshl.c @@ -0,0 +1,57 @@ +/* @(#)e_acosh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* acoshl(x) + * Method : + * Based on + * acoshl(x) = logl [ x + sqrtl(x*x-1) ] + * we have + * acoshl(x) := logl(x)+ln2, if x is large; else + * acoshl(x) := logl(2x-1/(sqrtl(x*x-1)+x)) if x>2; else + * acoshl(x) := log1pl(t+sqrtl(2.0*t+t*t)); where t=x-1. + * + * Special cases: + * acoshl(x) is NaN with signal if x<1. + * acoshl(NaN) is NaN without signal. + */ + +#include + +#include "math_private.h" + +static const long double +one = 1.0, +ln2 = 6.931471805599453094287e-01L; /* 0x3FFE, 0xB17217F7, 0xD1CF79AC */ + +long double +acoshl(long double x) +{ + long double t; + u_int32_t se,i0,i1; + GET_LDOUBLE_WORDS(se,i0,i1,x); + if(se<0x3fff || se & 0x8000) { /* x < 1 */ + return (x-x)/(x-x); + } else if(se >=0x401d) { /* x > 2**30 */ + if(se >=0x7fff) { /* x is inf of NaN */ + return x+x; + } else + return logl(x)+ln2; /* acoshl(huge)=logl(2x) */ + } else if(((se-0x3fff)|i0|i1)==0) { + return 0.0; /* acosh(1) = 0 */ + } else if (se > 0x4000) { /* 2**28 > x > 2 */ + t=x*x; + return logl(2.0*x-one/(x+sqrtl(t-one))); + } else { /* 1=0.5 + * 1 2x x + * atanhl(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + * 2 1 - x 1 - x + * + * For x<0.5 + * atanhl(x) = 0.5*log1pl(2x+2x*x/(1-x)) + * + * Special cases: + * atanhl(x) is NaN if |x| > 1 with signal; + * atanhl(NaN) is that NaN with no signal; + * atanhl(+-1) is +-INF with signal. + * + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, huge = 1e4900L; + +static const long double zero = 0.0; + +long double +atanhl(long double x) +{ + long double t; + int32_t ix; + u_int32_t se,i0,i1; + GET_LDOUBLE_WORDS(se,i0,i1,x); + ix = se&0x7fff; + if ((ix+((((i0&0x7fffffff)|i1)|(-((i0&0x7fffffff)|i1)))>>31))>0x3fff) + /* |x|>1 */ + return (x-x)/(x-x); + if(ix==0x3fff) + return x/zero; + if(ix<0x3fe3&&(huge+x)>zero) return x; /* x<2**-28 */ + SET_LDOUBLE_EXP(x,ix); + if(ix<0x3ffe) { /* x < 0.5 */ + t = x+x; + t = 0.5*log1pl(t+t*x/(one-x)); + } else + t = 0.5*log1pl((x+x)/(one-x)); + if(se<=0x7fff) return t; else return -t; +} diff --git a/src/openlibm/ld80/e_coshl.c b/src/openlibm/ld80/e_coshl.c new file mode 100644 index 0000000..a0fb9b5 --- /dev/null +++ b/src/openlibm/ld80/e_coshl.c @@ -0,0 +1,83 @@ +/* @(#)e_cosh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* coshl(x) + * Method : + * mathematically coshl(x) if defined to be (exp(x)+exp(-x))/2 + * 1. Replace x by |x| (coshl(x) = coshl(-x)). + * 2. + * [ exp(x) - 1 ]^2 + * 0 <= x <= ln2/2 : coshl(x) := 1 + ------------------- + * 2*exp(x) + * + * exp(x) + 1/exp(x) + * ln2/2 <= x <= 22 : coshl(x) := ------------------- + * 2 + * 22 <= x <= lnovft : coshl(x) := expl(x)/2 + * lnovft <= x <= ln2ovft: coshl(x) := expl(x/2)/2 * expl(x/2) + * ln2ovft < x : coshl(x) := huge*huge (overflow) + * + * Special cases: + * coshl(x) is |x| if x is +INF, -INF, or NaN. + * only coshl(0)=1 is exact for finite x. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, half=0.5, huge = 1.0e4900L; + +long double +coshl(long double x) +{ + long double t,w; + int32_t ex; + u_int32_t mx,lx; + + /* High word of |x|. */ + GET_LDOUBLE_WORDS(ex,mx,lx,x); + ex &= 0x7fff; + + /* x is INF or NaN */ + if(ex==0x7fff) return x*x; + + /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expl(|x|)) */ + if(ex < 0x3ffd || (ex == 0x3ffd && mx < 0xb17217f7u)) { + t = expm1l(fabsl(x)); + w = one+t; + if (ex<0x3fbc) return w; /* cosh(tiny) = 1 */ + return one+(t*t)/(w+w); + } + + /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ + if (ex < 0x4003 || (ex == 0x4003 && mx < 0xb0000000u)) { + t = expl(fabsl(x)); + return half*t+half/t; + } + + /* |x| in [22, ln(maxdouble)] return half*exp(|x|) */ + if (ex < 0x400c || (ex == 0x400c && mx < 0xb1700000u)) + return half*expl(fabsl(x)); + + /* |x| in [log(maxdouble), log(2*maxdouble)) */ + if (ex == 0x400c && (mx < 0xb174ddc0u + || (mx == 0xb174ddc0u && lx < 0x31aec0ebu))) + { + w = expl(half*fabsl(x)); + t = half*w; + return t*w; + } + + /* |x| >= log(2*maxdouble), cosh(x) overflow */ + return huge*huge; +} diff --git a/src/openlibm/ld80/e_expl.c b/src/openlibm/ld80/e_expl.c new file mode 100644 index 0000000..db0d1ca --- /dev/null +++ b/src/openlibm/ld80/e_expl.c @@ -0,0 +1,131 @@ +/* $OpenBSD: e_expl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* expl.c + * + * Exponential function, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 2/3 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-10000 50000 1.12e-19 2.81e-20 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +/* Exponential function */ + +#include + +#include "math_private.h" + +static long double P[3] = { + 1.2617719307481059087798E-4L, + 3.0299440770744196129956E-2L, + 9.9999999999999999991025E-1L, +}; +static long double Q[4] = { + 3.0019850513866445504159E-6L, + 2.5244834034968410419224E-3L, + 2.2726554820815502876593E-1L, + 2.0000000000000000000897E0L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOG2EL = 1.4426950408889634073599E0L; + +long double +expl(long double x) +{ +long double px, xx; +int n; + +if( isnan(x) ) + return(x); +if( x > MAXLOGL) + return( INFINITY ); + +if( x < MINLOGL ) + return(0.0L); + +/* Express e**x = e**g 2**n + * = e**g e**( n loge(2) ) + * = e**( g + n loge(2) ) + */ +px = floorl( LOG2EL * x + 0.5L ); /* floor() truncates toward -infinity. */ +n = px; +x -= px * C1; +x -= px * C2; + + +/* rational approximation for exponential + * of the fractional part: + * e**x = 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + */ +xx = x * x; +px = x * __polevll( xx, P, 2 ); +x = px/( __polevll( xx, Q, 3 ) - px ); +x = 1.0L + ldexpl( x, 1 ); + +x = ldexpl( x, n ); +return(x); +} diff --git a/src/openlibm/ld80/e_fmodl.c b/src/openlibm/ld80/e_fmodl.c new file mode 100644 index 0000000..ec792e3 --- /dev/null +++ b/src/openlibm/ld80/e_fmodl.c @@ -0,0 +1,142 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +//#include + +#include +#include +#include + +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define LDBL_NBIT 0 +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS EXT_FRACHBITS +#else +#define LDBL_NBIT 0x80000000 +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (EXT_FRACHBITS - 1) +#endif + +#define MANL_SHIFT (EXT_FRACLBITS - 1) + +static const long double one = 1.0, Zero[] = {0.0, -0.0,}; + +/* + * fmodl(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +long double +fmodl(long double x, long double y) +{ + union { + long double e; + struct ieee_ext bits; + } ux, uy; + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + uint32_t hy; + uint32_t lx,ly,lz; + int ix,iy,n,sx; + + ux.e = x; + uy.e = y; + sx = ux.bits.ext_sign; + + /* purge off exception values */ + if((uy.bits.ext_exp|uy.bits.ext_frach|uy.bits.ext_fracl)==0 || /* y=0 */ + (ux.bits.ext_exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (uy.bits.ext_exp == BIAS + LDBL_MAX_EXP && + ((uy.bits.ext_frach&~LDBL_NBIT)|uy.bits.ext_fracl)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(ux.bits.ext_exp<=uy.bits.ext_exp) { + if((ux.bits.ext_exp>MANL_SHIFT); lx = lx+lx;} + else { + if ((hz|lz)==0) /* return sign(x)*0 */ + return Zero[sx]; + hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[sx]; + while(hx<(1ULL<>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + ux.bits.ext_frach = hx; /* The mantissa is truncated here if needed. */ + ux.bits.ext_fracl = lx; + if (iy < LDBL_MIN_EXP) { + ux.bits.ext_exp = iy + (BIAS + 512); + ux.e *= 0x1p-512; + } else { + ux.bits.ext_exp = iy + BIAS; + } + x = ux.e * one; /* create necessary signal */ + return x; /* exact output */ +} diff --git a/src/openlibm/ld80/e_hypotl.c b/src/openlibm/ld80/e_hypotl.c new file mode 100644 index 0000000..e6faa22 --- /dev/null +++ b/src/openlibm/ld80/e_hypotl.c @@ -0,0 +1,122 @@ +/* @(#)e_hypot.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* hypotl(x,y) + * + * Method : + * If (assume round-to-nearest) z=x*x+y*y + * has error less than sqrt(2)/2 ulp, than + * sqrt(z) has error less than 1 ulp (exercise). + * + * So, compute sqrt(x*x+y*y) with some care as + * follows to get the error below 1 ulp: + * + * Assume x>y>0; + * (if possible, set rounding to round-to-nearest) + * 1. if x > 2y use + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + * where x1 = x with lower 32 bits cleared, x2 = x-x1; else + * 2. if x <= 2y use + * t1*yy1+((x-y)*(x-y)+(t1*y2+t2*y)) + * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, + * yy1= y with lower 32 bits chopped, y2 = y-yy1. + * + * NOTE: scaling may be necessary if some argument is too + * large or too tiny + * + * Special cases: + * hypot(x,y) is INF if x or y is +INF or -INF; else + * hypot(x,y) is NAN if x or y is NAN. + * + * Accuracy: + * hypot(x,y) returns sqrt(x^2+y^2) with error less + * than 1 ulps (units in the last place) + */ + +#include + +#include "math_private.h" + +long double +hypotl(long double x, long double y) +{ + long double a,b,t1,t2,yy1,y2,w; + u_int32_t j,k,ea,eb; + + GET_LDOUBLE_EXP(ea,x); + ea &= 0x7fff; + GET_LDOUBLE_EXP(eb,y); + eb &= 0x7fff; + if(eb > ea) {a=y;b=x;j=ea; ea=eb;eb=j;} else {a=x;b=y;} + SET_LDOUBLE_EXP(a,ea); /* a <- |a| */ + SET_LDOUBLE_EXP(b,eb); /* b <- |b| */ + if((ea-eb)>0x46) {return a+b;} /* x/y > 2**70 */ + k=0; + if(ea > 0x5f3f) { /* a>2**8000 */ + if(ea == 0x7fff) { /* Inf or NaN */ + u_int32_t es,high,low; + w = a+b; /* for sNaN */ + GET_LDOUBLE_WORDS(es,high,low,a); + if(((high&0x7fffffff)|low)==0) w = a; + GET_LDOUBLE_WORDS(es,high,low,b); + if(((eb^0x7fff)|(high&0x7fffffff)|low)==0) w = b; + return w; + } + /* scale a and b by 2**-9600 */ + ea -= 0x2580; eb -= 0x2580; k += 9600; + SET_LDOUBLE_EXP(a,ea); + SET_LDOUBLE_EXP(b,eb); + } + if(eb < 0x20bf) { /* b < 2**-8000 */ + if(eb == 0) { /* subnormal b or 0 */ + u_int32_t es,high,low; + GET_LDOUBLE_WORDS(es,high,low,b); + if((high|low)==0) return a; + SET_LDOUBLE_WORDS(t1, 0x7ffd, 0, 0); /* t1=2^16382 */ + b *= t1; + a *= t1; + k -= 16382; + } else { /* scale a and b by 2^9600 */ + ea += 0x2580; /* a *= 2^9600 */ + eb += 0x2580; /* b *= 2^9600 */ + k -= 9600; + SET_LDOUBLE_EXP(a,ea); + SET_LDOUBLE_EXP(b,eb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + u_int32_t high; + GET_LDOUBLE_MSW(high,a); + SET_LDOUBLE_WORDS(t1,ea,high,0); + t2 = a-t1; + w = sqrtl(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + u_int32_t high; + GET_LDOUBLE_MSW(high,b); + a = a+a; + SET_LDOUBLE_WORDS(yy1,eb,high,0); + y2 = b - yy1; + GET_LDOUBLE_MSW(high,a); + SET_LDOUBLE_WORDS(t1,ea+1,high,0); + t2 = a - t1; + w = sqrtl(t1*yy1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int32_t es; + t1 = 1.0; + GET_LDOUBLE_EXP(es,t1); + SET_LDOUBLE_EXP(t1,es+k); + return t1*w; + } else return w; +} diff --git a/src/openlibm/ld80/e_lgammal_r.c b/src/openlibm/ld80/e_lgammal_r.c new file mode 100644 index 0000000..0af5420 --- /dev/null +++ b/src/openlibm/ld80/e_lgammal_r.c @@ -0,0 +1,425 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* lgammal_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#include + +#include "math_private.h" + +static const long double + half = 0.5L, + one = 1.0L, + pi = 3.14159265358979323846264L, + two63 = 9.223372036854775808e18L, + + /* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ + a0 = -6.343246574721079391729402781192128239938E2L, + a1 = 1.856560238672465796768677717168371401378E3L, + a2 = 2.404733102163746263689288466865843408429E3L, + a3 = 8.804188795790383497379532868917517596322E2L, + a4 = 1.135361354097447729740103745999661157426E2L, + a5 = 3.766956539107615557608581581190400021285E0L, + + b0 = 8.214973713960928795704317259806842490498E3L, + b1 = 1.026343508841367384879065363925870888012E4L, + b2 = 4.553337477045763320522762343132210919277E3L, + b3 = 8.506975785032585797446253359230031874803E2L, + b4 = 6.042447899703295436820744186992189445813E1L, + /* b5 = 1.000000000000000000000000000000000000000E0 */ + + + tc = 1.4616321449683623412626595423257213284682E0L, + tf = -1.2148629053584961146050602565082954242826E-1,/* double precision */ +/* tt = (tail of tf), i.e. tf + tt has extended precision. */ + tt = 3.3649914684731379602768989080467587736363E-18L, + /* lgam ( 1.4616321449683623412626595423257213284682E0 ) = +-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + + /* lgam (x + tc) = tf + tt + x g(x)/h(x) + - 0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ + g0 = 3.645529916721223331888305293534095553827E-18L, + g1 = 5.126654642791082497002594216163574795690E3L, + g2 = 8.828603575854624811911631336122070070327E3L, + g3 = 5.464186426932117031234820886525701595203E3L, + g4 = 1.455427403530884193180776558102868592293E3L, + g5 = 1.541735456969245924860307497029155838446E2L, + g6 = 4.335498275274822298341872707453445815118E0L, + + h0 = 1.059584930106085509696730443974495979641E4L, + h1 = 2.147921653490043010629481226937850618860E4L, + h2 = 1.643014770044524804175197151958100656728E4L, + h3 = 5.869021995186925517228323497501767586078E3L, + h4 = 9.764244777714344488787381271643502742293E2L, + h5 = 6.442485441570592541741092969581997002349E1L, + /* h6 = 1.000000000000000000000000000000000000000E0 */ + + + /* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ + u0 = -8.886217500092090678492242071879342025627E1L, + u1 = 6.840109978129177639438792958320783599310E2L, + u2 = 2.042626104514127267855588786511809932433E3L, + u3 = 1.911723903442667422201651063009856064275E3L, + u4 = 7.447065275665887457628865263491667767695E2L, + u5 = 1.132256494121790736268471016493103952637E2L, + u6 = 4.484398885516614191003094714505960972894E0L, + + v0 = 1.150830924194461522996462401210374632929E3L, + v1 = 3.399692260848747447377972081399737098610E3L, + v2 = 3.786631705644460255229513563657226008015E3L, + v3 = 1.966450123004478374557778781564114347876E3L, + v4 = 4.741359068914069299837355438370682773122E2L, + v5 = 4.508989649747184050907206782117647852364E1L, + /* v6 = 1.000000000000000000000000000000000000000E0 */ + + + /* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ + s0 = 1.454726263410661942989109455292824853344E6L, + s1 = -3.901428390086348447890408306153378922752E6L, + s2 = -6.573568698209374121847873064292963089438E6L, + s3 = -3.319055881485044417245964508099095984643E6L, + s4 = -7.094891568758439227560184618114707107977E5L, + s5 = -6.263426646464505837422314539808112478303E4L, + s6 = -1.684926520999477529949915657519454051529E3L, + + r0 = -1.883978160734303518163008696712983134698E7L, + r1 = -2.815206082812062064902202753264922306830E7L, + r2 = -1.600245495251915899081846093343626358398E7L, + r3 = -4.310526301881305003489257052083370058799E6L, + r4 = -5.563807682263923279438235987186184968542E5L, + r5 = -3.027734654434169996032905158145259713083E4L, + r6 = -4.501995652861105629217250715790764371267E2L, + /* r6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 + w0 = LS2PI - 0.5 */ + w0 = 4.189385332046727417803e-1L, + w1 = 8.333333333333331447505E-2L, + w2 = -2.777777777750349603440E-3L, + w3 = 7.936507795855070755671E-4L, + w4 = -5.952345851765688514613E-4L, + w5 = 8.412723297322498080632E-4L, + w6 = -1.880801938119376907179E-3L, + w7 = 4.885026142432270781165E-3L; + +static const long double zero = 0.0L; + +static long double +sin_pi(long double x) +{ + long double y, z; + int n, ix; + u_int32_t se, i0, i1; + + GET_LDOUBLE_WORDS (se, i0, i1, x); + ix = se & 0x7fff; + ix = (ix << 16) | (i0 >> 16); + if (ix < 0x3ffd8000) /* 0.25 */ + return sinl (pi * x); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorl (y); + if (z != y) + { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floorl(y)); /* y = |x| mod 2.0 */ + n = (int) (y*4.0); + } + else + { + if (ix >= 0x403f8000) /* 2^64 */ + { + y = zero; n = 0; /* y must be even */ + } + else + { + if (ix < 0x403e8000) /* 2^63 */ + z = y + two63; /* exact */ + GET_LDOUBLE_WORDS (se, i0, i1, z); + n = i1 & 1; + y = n; + n <<= 2; + } + } + + switch (n) + { + case 0: + y = sinl (pi * y); + break; + case 1: + case 2: + y = cosl (pi * (half - y)); + break; + case 3: + case 4: + y = sinl (pi * (one - y)); + break; + case 5: + case 6: + y = -cosl (pi * (y - 1.5)); + break; + default: + y = sinl (pi * (y - 2.0)); + break; + } + return -y; +} + + +long double +lgammal_r(long double x, int *signgamp) +{ + long double t, y, z, nadj, p, p1, p2, q, r, w; + int i, ix; + u_int32_t se, i0, i1; + + *signgamp = 1; + GET_LDOUBLE_WORDS (se, i0, i1, x); + ix = se & 0x7fff; + + if ((ix | i0 | i1) == 0) + { + if (se & 0x8000) + *signgamp = -1; + return one / fabsl (x); + } + + ix = (ix << 16) | (i0 >> 16); + + /* purge off +-inf, NaN, +-0, and negative arguments */ + if (ix >= 0x7fff0000) + return x * x; + + if (ix < 0x3fc08000) /* 2^-63 */ + { /* |x|<2**-63, return -log(|x|) */ + if (se & 0x8000) + { + *signgamp = -1; + return -logl (-x); + } + else + return -logl (x); + } + if (se & 0x8000) + { + t = sin_pi (x); + if (t == zero) + return one / fabsl (t); /* -integer */ + nadj = logl (pi / fabsl (t * x)); + if (t < zero) + *signgamp = -1; + x = -x; + } + + /* purge off 1 and 2 */ + if ((((ix - 0x3fff8000) | i0 | i1) == 0) + || (((ix - 0x40008000) | i0 | i1) == 0)) + r = 0; + else if (ix < 0x40008000) /* 2.0 */ + { + /* x < 2.0 */ + if (ix <= 0x3ffee666) /* 8.99993896484375e-1 */ + { + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl (x); + if (ix >= 0x3ffebb4a) /* 7.31597900390625e-1 */ + { + y = x - one; + i = 0; + } + else if (ix >= 0x3ffced33)/* 2.31639862060546875e-1 */ + { + y = x - (tc - one); + i = 1; + } + else + { + /* x < 0.23 */ + y = x; + i = 2; + } + } + else + { + r = zero; + if (ix >= 0x3fffdda6) /* 1.73162841796875 */ + { + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } + else if (ix >= 0x3fff9da6)/* 1.23162841796875 */ + { + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } + else + { + /* [0.9, 1.23] */ + y = x - one; + i = 2; + } + } + switch (i) + { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += half * y + y * p1/p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1/p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-half * y + p1 / p2); + } + } + else if (ix < 0x40028000) /* 8.0 */ + { + /* x < 8.0 */ + i = (int) x; + t = zero; + y = x - (double) i; + p = y * + (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = half * y + p / q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) + { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl (z); + break; + } + } + else if (ix < 0x40418000) /* 2^66 */ + { + /* 8.0 <= x < 2**66 */ + t = logl (x); + z = one / x; + y = z * z; + w = w0 + z * (w1 + + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - half) * (t - one) + w; + } + else + /* 2**66 <= x <= inf */ + r = x * (logl (x) - one); + if (se & 0x8000) + r = nadj - r; + return r; +} diff --git a/src/openlibm/ld80/e_log10l.c b/src/openlibm/ld80/e_log10l.c new file mode 100644 index 0000000..bb6cd7d --- /dev/null +++ b/src/openlibm/ld80/e_log10l.c @@ -0,0 +1,205 @@ +/* $OpenBSD: e_log10l.c,v 1.2 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log10l.c + * + * Common logarithm, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include + +#include "math_private.h" + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ + +static long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double +log10l(long double x) +{ +long double y; +volatile long double z; +int e; + +if( isnan(x) ) + return(x); +/* Test for domain */ +if( x <= 0.0L ) + { + if( x == 0.0L ) + return (-1.0L / (x - x)); + else + return (x - x) / (x - x); + } +if( x == INFINITY ) + return(INFINITY); +/* separate mantissa from exponent */ + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ +x = frexpl( x, &e ); + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } +x = z / y; +z = x*x; +y = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) ); +goto done; +} + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexpl( x, 1 ) - 1.0L; /* 2x - 1 */ + } +else + { + x = x - 1.0L; + } +z = x*x; +y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 7 ) ); +y = y - ldexpl( z, -1 ); /* -0.5x^2 + ... */ + +done: + +/* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ +z = y * (L10EB); +z += x * (L10EB); +z += e * (L102B); +z += y * (L10EA); +z += x * (L10EA); +z += e * (L102A); + +return( z ); +} diff --git a/src/openlibm/ld80/e_log2l.c b/src/openlibm/ld80/e_log2l.c new file mode 100644 index 0000000..6ff6fe9 --- /dev/null +++ b/src/openlibm/ld80/e_log2l.c @@ -0,0 +1,199 @@ +/* $OpenBSD: e_log2l.c,v 1.2 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log2l.c + * + * Base 2 logarithm, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns -INFINITY + * log domain: x < 0; returns NAN + */ + +#include + +#include "math_private.h" + +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double +log2l(long double x) +{ +volatile long double z; +long double y; +int e; + +if( isnan(x) ) + return(x); +if( x == INFINITY ) + return(x); +/* Test for domain */ +if( x <= 0.0L ) + { + if( x == 0.0L ) + return( -INFINITY ); + else + return( NAN ); + } + +/* separate mantissa from exponent */ + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ +x = frexpl( x, &e ); + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } +x = z / y; +z = x*x; +y = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) ); +goto done; +} + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexpl( x, 1 ) - 1.0L; /* 2x - 1 */ + } +else + { + x = x - 1.0L; + } +z = x*x; +y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 7 ) ); +y = y - ldexpl( z, -1 ); /* -0.5x^2 + ... */ + +done: + +/* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ +z = y * LOG2EA; +z += x * LOG2EA; +z += y; +z += x; +z += e; +return( z ); +} diff --git a/src/openlibm/ld80/e_logl.c b/src/openlibm/ld80/e_logl.c new file mode 100644 index 0000000..4722014 --- /dev/null +++ b/src/openlibm/ld80/e_logl.c @@ -0,0 +1,190 @@ +/* $OpenBSD: e_logl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* logl.c + * + * Natural logarithm, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 8.71e-20 2.75e-20 + * IEEE exp(+-10000) 100000 5.39e-20 2.34e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns -INFINITY + * log domain: x < 0; returns NAN + */ + +#include + +#include "math_private.h" + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ + +static long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double +logl(long double x) +{ +long double y, z; +int e; + +if( isnan(x) ) + return(x); +if( x == INFINITY ) + return(x); +/* Test for domain */ +if( x <= 0.0L ) + { + if( x == 0.0L ) + return( -INFINITY ); + else + return( NAN ); + } + +/* separate mantissa from exponent */ + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ +x = frexpl( x, &e ); + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } +x = z / y; +z = x*x; +z = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) ); +z = z + e * C2; +z = z + x; +z = z + e * C1; +return( z ); +} + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexpl( x, 1 ) - 1.0L; /* 2x - 1 */ + } +else + { + x = x - 1.0L; + } +z = x*x; +y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 6 ) ); +y = y + e * C2; +z = y - ldexpl( z, -1 ); /* y - 0.5 * z */ +/* Note, the sum of above terms does not exceed x/4, + * so it contributes at most about 1/4 lsb to the error. + */ +z = z + x; +z = z + e * C1; /* This sum has an error of 1/2 lsb. */ +return( z ); +} diff --git a/src/openlibm/ld80/e_powl.c b/src/openlibm/ld80/e_powl.c new file mode 100644 index 0000000..dcb2b45 --- /dev/null +++ b/src/openlibm/ld80/e_powl.c @@ -0,0 +1,615 @@ +/* $OpenBSD: e_powl.c,v 1.5 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* powl.c + * + * Power function, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, z, powl(); + * + * z = powl( x, y ); + * + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/32 and pseudo extended precision arithmetic to + * obtain several extra bits of accuracy in both the logarithm + * and the exponential. + * + * + * + * ACCURACY: + * + * The relative error of pow(x,y) can be estimated + * by y dl ln(2), where dl is the absolute error of + * the internally computed base 2 logarithm. At the ends + * of the approximation interval the logarithm equal 1/32 + * and its relative error is about 1 lsb = 1.1e-19. Hence + * the predicted relative error in the result is 2.3e-21 y . + * + * Relative error: + * arithmetic domain # trials peak rms + * + * IEEE +-1000 40000 2.8e-18 3.7e-19 + * .001 < x < 1000, with log(x) uniformly distributed. + * -1000 < y < 1000, y uniformly distributed. + * + * IEEE 0,8700 60000 6.5e-18 1.0e-18 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +#include +#include + +#include "math_private.h" + +/* Table size */ +#define NXT 32 +/* log2(Table size) */ +#define LNXT 5 + +/* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) + * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 + */ +static long double P[] = { + 8.3319510773868690346226E-4L, + 4.9000050881978028599627E-1L, + 1.7500123722550302671919E0L, + 1.4000100839971580279335E0L, +}; +static long double Q[] = { +/* 1.0000000000000000000000E0L,*/ + 5.2500282295834889175431E0L, + 8.4000598057587009834666E0L, + 4.2000302519914740834728E0L, +}; +/* A[i] = 2^(-i/32), rounded to IEEE long double precision. + * If i is even, A[i] + B[i/2] gives additional accuracy. + */ +static long double A[33] = { + 1.0000000000000000000000E0L, + 9.7857206208770013448287E-1L, + 9.5760328069857364691013E-1L, + 9.3708381705514995065011E-1L, + 9.1700404320467123175367E-1L, + 8.9735453750155359320742E-1L, + 8.7812608018664974155474E-1L, + 8.5930964906123895780165E-1L, + 8.4089641525371454301892E-1L, + 8.2287773907698242225554E-1L, + 8.0524516597462715409607E-1L, + 7.8799042255394324325455E-1L, + 7.7110541270397041179298E-1L, + 7.5458221379671136985669E-1L, + 7.3841307296974965571198E-1L, + 7.2259040348852331001267E-1L, + 7.0710678118654752438189E-1L, + 6.9195494098191597746178E-1L, + 6.7712777346844636413344E-1L, + 6.6261832157987064729696E-1L, + 6.4841977732550483296079E-1L, + 6.3452547859586661129850E-1L, + 6.2092890603674202431705E-1L, + 6.0762367999023443907803E-1L, + 5.9460355750136053334378E-1L, + 5.8186242938878875689693E-1L, + 5.6939431737834582684856E-1L, + 5.5719337129794626814472E-1L, + 5.4525386633262882960438E-1L, + 5.3357020033841180906486E-1L, + 5.2213689121370692017331E-1L, + 5.1094857432705833910408E-1L, + 5.0000000000000000000000E-1L, +}; +static long double B[17] = { + 0.0000000000000000000000E0L, + 2.6176170809902549338711E-20L, +-1.0126791927256478897086E-20L, + 1.3438228172316276937655E-21L, + 1.2207982955417546912101E-20L, +-6.3084814358060867200133E-21L, + 1.3164426894366316434230E-20L, +-1.8527916071632873716786E-20L, + 1.8950325588932570796551E-20L, + 1.5564775779538780478155E-20L, + 6.0859793637556860974380E-21L, +-2.0208749253662532228949E-20L, + 1.4966292219224761844552E-20L, + 3.3540909728056476875639E-21L, +-8.6987564101742849540743E-22L, +-1.2327176863327626135542E-20L, + 0.0000000000000000000000E0L, +}; + +/* 2^x = 1 + x P(x), + * on the interval -1/32 <= x <= 0 + */ +static long double R[] = { + 1.5089970579127659901157E-5L, + 1.5402715328927013076125E-4L, + 1.3333556028915671091390E-3L, + 9.6181291046036762031786E-3L, + 5.5504108664798463044015E-2L, + 2.4022650695910062854352E-1L, + 6.9314718055994530931447E-1L, +}; + +#define douba(k) A[k] +#define doubb(k) B[k] +#define MEXP (NXT*16384.0L) +/* The following if denormal numbers are supported, else -MEXP: */ +#define MNEXP (-NXT*(16384.0L+64.0L)) +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOGE2L = 6.9314718055994530941723E-1L; +static volatile long double z; +static long double w, W, Wa, Wb, ya, yb, u; +static const long double huge = 0x1p10000L; +#if 0 /* XXX Prevent gcc from erroneously constant folding this. */ +static const long double twom10000 = 0x1p-10000L; +#else +static volatile long double twom10000 = 0x1p-10000L; +#endif + +static long double reducl( long double ); +static long double powil ( long double, int ); + +long double +powl(long double x, long double y) +{ +/* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ +int i, nflg, iyflg, yoddint; +long e; + +if( y == 0.0L ) + return( 1.0L ); + +if( x == 1.0L ) + return( 1.0L ); + +if( isnan(x) ) + return( x ); +if( isnan(y) ) + return( y ); + +if( y == 1.0L ) + return( x ); + +if( !isfinite(y) && x == -1.0L ) + return( 1.0L ); + +if( y >= LDBL_MAX ) + { + if( x > 1.0L ) + return( INFINITY ); + if( x > 0.0L && x < 1.0L ) + return( 0.0L ); + if( x < -1.0L ) + return( INFINITY ); + if( x > -1.0L && x < 0.0L ) + return( 0.0L ); + } +if( y <= -LDBL_MAX ) + { + if( x > 1.0L ) + return( 0.0L ); + if( x > 0.0L && x < 1.0L ) + return( INFINITY ); + if( x < -1.0L ) + return( 0.0L ); + if( x > -1.0L && x < 0.0L ) + return( INFINITY ); + } +if( x >= LDBL_MAX ) + { + if( y > 0.0L ) + return( INFINITY ); + return( 0.0L ); + } + +w = floorl(y); +/* Set iyflg to 1 if y is an integer. */ +iyflg = 0; +if( w == y ) + iyflg = 1; + +/* Test for odd integer y. */ +yoddint = 0; +if( iyflg ) + { + ya = fabsl(y); + ya = floorl(0.5L * ya); + yb = 0.5L * fabsl(w); + if( ya != yb ) + yoddint = 1; + } + +if( x <= -LDBL_MAX ) + { + if( y > 0.0L ) + { + if( yoddint ) + return( -INFINITY ); + return( INFINITY ); + } + if( y < 0.0L ) + { + if( yoddint ) + return( -0.0L ); + return( 0.0 ); + } + } + + +nflg = 0; /* flag = 1 if x<0 raised to integer power */ +if( x <= 0.0L ) + { + if( x == 0.0L ) + { + if( y < 0.0 ) + { + if( signbit(x) && yoddint ) + return( -INFINITY ); + return( INFINITY ); + } + if( y > 0.0 ) + { + if( signbit(x) && yoddint ) + return( -0.0L ); + return( 0.0 ); + } + if( y == 0.0L ) + return( 1.0L ); /* 0**0 */ + else + return( 0.0L ); /* 0**y */ + } + else + { + if( iyflg == 0 ) + return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ + nflg = 1; + } + } + +/* Integer power of an integer. */ + +if( iyflg ) + { + i = w; + w = floorl(x); + if( (w == x) && (fabsl(y) < 32768.0) ) + { + w = powil( x, (int) y ); + return( w ); + } + } + + +if( nflg ) + x = fabsl(x); + +/* separate significand from exponent */ +x = frexpl( x, &i ); +e = i; + +/* find significand in antilog table A[] */ +i = 1; +if( x <= douba(17) ) + i = 17; +if( x <= douba(i+8) ) + i += 8; +if( x <= douba(i+4) ) + i += 4; +if( x <= douba(i+2) ) + i += 2; +if( x >= douba(1) ) + i = -1; +i += 1; + + +/* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ +x -= douba(i); +x -= doubb(i/2); +x /= douba(i); + + +/* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ +z = x*x; +w = x * ( z * __polevll( x, P, 3 ) / __p1evll( x, Q, 3 ) ); +w = w - ldexpl( z, -1 ); /* w - 0.5 * z */ + +/* Convert to base 2 logarithm: + * multiply by log2(e) = 1 + LOG2EA + */ +z = LOG2EA * w; +z += w; +z += LOG2EA * x; +z += x; + +/* Compute exponent term of the base 2 logarithm. */ +w = -i; +w = ldexpl( w, -LNXT ); /* divide by NXT */ +w += e; +/* Now base 2 log of x is w + z. */ + +/* Multiply base 2 log by y, in extended precision. */ + +/* separate y into large part ya + * and small part yb less than 1/NXT + */ +ya = reducl(y); +yb = y - ya; + +/* (w+z)(ya+yb) + * = w*ya + w*yb + z*y + */ +F = z * y + w * yb; +Fa = reducl(F); +Fb = F - Fa; + +G = Fa + w * ya; +Ga = reducl(G); +Gb = G - Ga; + +H = Fb + Gb; +Ha = reducl(H); +w = ldexpl( Ga+Ha, LNXT ); + +/* Test the power of 2 for overflow */ +if( w > MEXP ) + return (huge * huge); /* overflow */ + +if( w < MNEXP ) + return (twom10000 * twom10000); /* underflow */ + +e = w; +Hb = H - Ha; + +if( Hb > 0.0L ) + { + e += 1; + Hb -= (1.0L/NXT); /*0.0625L;*/ + } + +/* Now the product y * log2(x) = Hb + e/NXT. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ +z = Hb * __polevll( Hb, R, 6 ); /* z = 2**Hb - 1 */ + +/* Express e/NXT as an integer plus a negative number of (1/NXT)ths. + * Find lookup table entry for the fractional power of 2. + */ +if( e < 0 ) + i = 0; +else + i = 1; +i = e/NXT + i; +e = NXT*i - e; +w = douba( e ); +z = w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ +z = z + w; +z = ldexpl( z, i ); /* multiply by integer power of 2 */ + +if( nflg ) + { +/* For negative x, + * find out if the integer exponent + * is odd or even. + */ + w = ldexpl( y, -1 ); + w = floorl(w); + w = ldexpl( w, 1 ); + if( w != y ) + z = -z; /* odd exponent */ + } + +return( z ); +} + + +/* Find a multiple of 1/NXT that is within 1/NXT of x. */ +static long double +reducl(long double x) +{ +long double t; + +t = ldexpl( x, LNXT ); +t = floorl( t ); +t = ldexpl( t, -LNXT ); +return(t); +} + +/* powil.c + * + * Real raised to integer power, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, powil(); + * int n; + * + * y = powil( x, n ); + * + * + * + * DESCRIPTION: + * + * Returns argument x raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * + * ACCURACY: + * + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * IEEE .001,1000 -1022,1023 50000 4.3e-17 7.8e-18 + * IEEE 1,2 -1022,1023 20000 3.9e-17 7.6e-18 + * IEEE .99,1.01 0,8700 10000 3.6e-16 7.2e-17 + * + * Returns MAXNUM on overflow, zero on underflow. + * + */ + +static long double +powil(long double x, int nn) +{ +long double ww, y; +long double s; +int n, e, sign, asign, lx; + +if( x == 0.0L ) + { + if( nn == 0 ) + return( 1.0L ); + else if( nn < 0 ) + return( LDBL_MAX ); + else + return( 0.0L ); + } + +if( nn == 0 ) + return( 1.0L ); + + +if( x < 0.0L ) + { + asign = -1; + x = -x; + } +else + asign = 0; + + +if( nn < 0 ) + { + sign = -1; + n = -nn; + } +else + { + sign = 1; + n = nn; + } + +/* Overflow detection */ + +/* Calculate approximate logarithm of answer */ +s = x; +s = frexpl( s, &lx ); +e = (lx - 1)*n; +if( (e == 0) || (e > 64) || (e < -64) ) + { + s = (s - 7.0710678118654752e-1L) / (s + 7.0710678118654752e-1L); + s = (2.9142135623730950L * s - 0.5L + lx) * nn * LOGE2L; + } +else + { + s = LOGE2L * e; + } + +if( s > MAXLOGL ) + return (huge * huge); /* overflow */ + +if( s < MINLOGL ) + return (twom10000 * twom10000); /* underflow */ +/* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ +if( s < (-MAXLOGL+2.0L) ) + { + x = 1.0L/x; + sign = -sign; + } + +/* First bit of the power */ +if( n & 1 ) + y = x; + +else + { + y = 1.0L; + asign = 0; + } + +ww = x; +n >>= 1; +while( n ) + { + ww = ww * ww; /* arg to the 2-to-the-kth power */ + if( n & 1 ) /* if that bit is set, then include in product */ + y *= ww; + n >>= 1; + } + +if( asign ) + y = -y; /* odd power of negative number */ +if( sign < 0 ) + y = 1.0L/y; +return(y); +} diff --git a/src/openlibm/ld80/e_rem_pio2l.h b/src/openlibm/ld80/e_rem_pio2l.h new file mode 100644 index 0000000..c44ad48 --- /dev/null +++ b/src/openlibm/ld80/e_rem_pio2l.h @@ -0,0 +1,152 @@ +/* From: @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/e_rem_pio2l.h,v 1.3 2011/06/18 13:56:33 benl Exp $"); + +/* ld80 version of __ieee754_rem_pio2l(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include +#include + +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +/* + * invpio2: 64 bits of 2/pi + * pio2_1: first 39 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 39 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 39 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ +pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ +pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ + +#if defined(__amd64__) || defined(__i386__) +/* Long double constants are slow on these arches, and broken on i386. */ +static const volatile double +invpio2hi = 6.3661977236758138e-01, /* 0x145f306dc9c883.0p-53 */ +invpio2lo = -3.9356538861223811e-17, /* -0x16b00000000000.0p-107 */ +pio2_1thi = -1.0746346554971943e-12, /* -0x12e7b9676733af.0p-92 */ +pio2_1tlo = 8.8451028997905949e-29, /* 0x1c080000000000.0p-146 */ +pio2_2thi = 6.3683171635109499e-25, /* 0x18a2e03707344a.0p-133 */ +pio2_2tlo = 2.3183081793789774e-41, /* 0x10280000000000.0p-187 */ +pio2_3thi = -2.7529965190440717e-37, /* -0x176b7ed8fbbacc.0p-174 */ +pio2_3tlo = -4.2006647512740502e-54; /* -0x19c00000000000.0p-230 */ +#define invpio2 ((long double)invpio2hi + invpio2lo) +#define pio2_1t ((long double)pio2_1thi + pio2_1tlo) +#define pio2_2t ((long double)pio2_2thi + pio2_2tlo) +#define pio2_3t ((long double)pio2_3thi + pio2_3tlo) +#else +static const long double +invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ +pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ +pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ +pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ +#endif + +//VBS +//static inline __always_inline int +//__ieee754_rem_pio2l(long double x, long double *y) + +static inline int +__ieee754_rem_pio2l(long double x, long double *y) +{ + union IEEEl2bits u,u1; + long double z,w,t,r,fn; + double tx[3],ty[2]; + int e0,ex,i,j,nx,n; + int16_t expsign; + + u.e = x; + expsign = u.xbits.expsign; + ex = expsign & 0x7fff; + if (ex < BIAS + 25 || (ex == BIAS + 25 && u.bits.manh < 0xc90fdaa2)) { + /* |x| ~< 2^25*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = x*invpio2+0x1.8p63; + fn = fn-0x1.8p63; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 102 bit */ + { + union IEEEl2bits u2; + int ex1; + j = ex; + y[0] = r-w; + u2.e = y[0]; + ex1 = u2.xbits.expsign & 0x7fff; + i = j-ex1; + if(i>22) { /* 2nd iteration needed, good to 141 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + u2.e = y[0]; + ex1 = u2.xbits.expsign & 0x7fff; + i = j-ex1; + if(i>61) { /* 3rd iteration need, 180 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + return n; + } + /* + * all other (large) arguments + */ + if(ex==0x7fff) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + u1.e = x; + e0 = ex - BIAS - 23; /* e0 = ilogb(|x|)-23; */ + u1.xbits.expsign = ex - e0; + z = u1.e; + for(i=0;i<2;i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,ty,e0,nx,2); + r = (long double)ty[0] + ty[1]; + w = ty[1] - (r - ty[0]); + if(expsign<0) {y[0] = -r; y[1] = -w; return -n;} + y[0] = r; y[1] = w; return n; +} diff --git a/src/openlibm/ld80/e_sinhl.c b/src/openlibm/ld80/e_sinhl.c new file mode 100644 index 0000000..cb45204 --- /dev/null +++ b/src/openlibm/ld80/e_sinhl.c @@ -0,0 +1,76 @@ +/* @(#)e_sinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* sinhl(x) + * Method : + * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + * 1. Replace x by |x| (sinhl(-x) = -sinhl(x)). + * 2. + * E + E/(E+1) + * 0 <= x <= 25 : sinhl(x) := --------------, E=expm1l(x) + * 2 + * + * 25 <= x <= lnovft : sinhl(x) := expl(x)/2 + * lnovft <= x <= ln2ovft: sinhl(x) := expl(x/2)/2 * expl(x/2) + * ln2ovft < x : sinhl(x) := x*shuge (overflow) + * + * Special cases: + * sinhl(x) is |x| if x is +INF, -INF, or NaN. + * only sinhl(0)=0 is exact for finite x. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0, shuge = 1.0e4931L; + +long double +sinhl(long double x) +{ + long double t,w,h; + u_int32_t jx,ix,i0,i1; + + /* Words of |x|. */ + GET_LDOUBLE_WORDS(jx,i0,i1,x); + ix = jx&0x7fff; + + /* x is INF or NaN */ + if(ix==0x7fff) return x+x; + + h = 0.5; + if (jx & 0x8000) h = -h; + /* |x| in [0,25], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x4003 || (ix == 0x4003 && i0 <= 0xc8000000)) { /* |x|<25 */ + if (ix<0x3fdf) /* |x|<2**-32 */ + if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ + t = expm1l(fabsl(x)); + if(ix<0x3fff) return h*(2.0*t-t*t/(t+one)); + return h*(t+t/(t+one)); + } + + /* |x| in [25, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix < 0x400c || (ix == 0x400c && i0 < 0xb17217f7)) + return h*expl(fabsl(x)); + + /* |x| in [log(maxdouble), overflowthreshold] */ + if (ix<0x400c || (ix == 0x400c && (i0 < 0xb174ddc0 + || (i0 == 0xb174ddc0 + && i1 <= 0x31aec0ea)))) { + w = expl(0.5*fabsl(x)); + t = h*w; + return t*w; + } + + /* |x| > overflowthreshold, sinhl(x) overflow */ + return x*shuge; +} diff --git a/src/openlibm/ld80/e_tgammal.c b/src/openlibm/ld80/e_tgammal.c new file mode 100644 index 0000000..036061c --- /dev/null +++ b/src/openlibm/ld80/e_tgammal.c @@ -0,0 +1,313 @@ +/* $OpenBSD: e_tgammal.c,v 1.4 2013/11/12 20:35:19 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* tgammal.c + * + * Gamma function + * + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is correctly + * signed. This variable is also filled in by the logarithmic gamma + * function lgamma(). + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include +#include + +#include "math_private.h" + +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ + +static long double P[8] = { + 4.212760487471622013093E-5L, + 4.542931960608009155600E-4L, + 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, + 1.113062816019361559013E-1L, + 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, + 1.000000000000000000009E0L, +}; +static long double Q[9] = { +-1.397148517476170440917E-5L, + 2.346584059160635244282E-4L, +-1.237799246653152231188E-3L, +-7.955933682494738320586E-4L, + 2.773706565840072979165E-2L, +-4.633887671244534213831E-2L, +-2.243510905670329164562E-1L, + 4.150160950588455434583E-1L, + 9.999999999999999999908E-1L, +}; + +/* +static long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ + +static long double STIR[9] = { + 7.147391378143610789273E-4L, +-2.363848809501759061727E-5L, +-5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, + 7.840334842744753003862E-4L, +-2.294719747873185405699E-4L, +-2.681327161876304418288E-3L, + 3.472222222230075327854E-3L, + 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ + +static long double S[9] = { +-1.193945051381510095614E-3L, + 7.220599478036909672331E-3L, +-9.622023360406271645744E-3L, +-4.219773360705915470089E-2L, + 1.665386113720805206758E-1L, +-4.200263503403344054473E-2L, +-6.558780715202540684668E-1L, + 5.772156649015328608253E-1L, + 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ + +static long double SN[9] = { + 1.133374167243894382010E-3L, + 7.220837261893170325704E-3L, + 9.621911155035976733706E-3L, +-4.219773343731191721664E-2L, +-1.665386113944413519335E-1L, +-4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, + 5.772156649015328608727E-1L, +-1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +static long double stirf ( long double ); + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) +{ +long double y, w, v; + +w = 1.0L/x; +/* For large x, use rational coefficients from the analytical expansion. */ +if( x > 1024.0L ) + w = (((((6.97281375836585777429E-5L * w + + 7.84039221720066627474E-4L) * w + - 2.29472093621399176955E-4L) * w + - 2.68132716049382716049E-3L) * w + + 3.47222222222222222222E-3L) * w + + 8.33333333333333333333E-2L) * w + + 1.0L; +else + w = 1.0L + w * __polevll( w, STIR, 8 ); +y = expl(x); +if( x > MAXSTIR ) + { /* Avoid overflow in pow() */ + v = powl( x, 0.5L * x - 0.25L ); + y = v * (v / y); + } +else + { + y = powl( x, x - 0.5L ) / y; + } +y = SQTPI * y * w; +return( y ); +} + +long double +tgammal(long double x) +{ +long double p, q, z; +int i; + +if( isnan(x) ) + return(NAN); +if(x == INFINITY) + return(INFINITY); +if(x == -INFINITY) + return(x - x); +if( x == 0.0L ) + return( 1.0L / x ); +q = fabsl(x); + +if( q > 13.0L ) + { + int sign = 1; + if( q > MAXGAML ) + goto goverf; + if( x < 0.0L ) + { + p = floorl(q); + if( p == q ) + return (x - x) / (x - x); + i = p; + if( (i & 1) == 0 ) + sign = -1; + z = q - p; + if( z > 0.5L ) + { + p += 1.0L; + z = q - p; + } + z = q * sinl( PIL * z ); + z = fabsl(z) * stirf(q); + if( z <= PIL/LDBL_MAX ) + { +goverf: + return( sign * INFINITY); + } + z = PIL/z; + } + else + { + z = stirf(x); + } + return( sign * z ); + } + +z = 1.0L; +while( x >= 3.0L ) + { + x -= 1.0L; + z *= x; + } + +while( x < -0.03125L ) + { + z /= x; + x += 1.0L; + } + +if( x <= 0.03125L ) + goto small; + +while( x < 2.0L ) + { + z /= x; + x += 1.0L; + } + +if( x == 2.0L ) + return(z); + +x -= 2.0L; +p = __polevll( x, P, 7 ); +q = __polevll( x, Q, 8 ); +z = z * p / q; +return z; + +small: +if( x == 0.0L ) + return (x - x) / (x - x); +else + { + if( x < 0.0L ) + { + x = -x; + q = z / (x * __polevll( x, SN, 8 )); + } + else + q = z / (x * __polevll( x, S, 8 )); + } +return q; +} diff --git a/src/openlibm/ld80/invtrig.c b/src/openlibm/ld80/invtrig.c new file mode 100644 index 0000000..15692ad --- /dev/null +++ b/src/openlibm/ld80/invtrig.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/invtrig.c,v 1.1 2008/07/31 22:41:26 das Exp $"); + +#include "ld80/invtrig.h" + +/* + * asinl() and acosl() + */ +const long double +pS0 = 1.66666666666666666631e-01L, +pS1 = -4.16313987993683104320e-01L, +pS2 = 3.69068046323246813704e-01L, +pS3 = -1.36213932016738603108e-01L, +pS4 = 1.78324189708471965733e-02L, +pS5 = -2.19216428382605211588e-04L, +pS6 = -7.10526623669075243183e-06L, +qS1 = -2.94788392796209867269e+00L, +qS2 = 3.27309890266528636716e+00L, +qS3 = -1.68285799854822427013e+00L, +qS4 = 3.90699412641738801874e-01L, +qS5 = -3.14365703596053263322e-02L; + +/* + * atanl() + */ +const long double atanhi[] = { + 4.63647609000806116202e-01L, + 7.85398163397448309628e-01L, + 9.82793723247329067960e-01L, + 1.57079632679489661926e+00L, +}; + +const long double atanlo[] = { + 1.18469937025062860669e-20L, + -1.25413940316708300586e-20L, + 2.55232234165405176172e-20L, + -2.50827880633416601173e-20L, +}; + +const long double aT[] = { + 3.33333333333333333017e-01L, + -1.99999999999999632011e-01L, + 1.42857142857046531280e-01L, + -1.11111111100562372733e-01L, + 9.09090902935647302252e-02L, + -7.69230552476207730353e-02L, + 6.66661718042406260546e-02L, + -5.88158892835030888692e-02L, + 5.25499891539726639379e-02L, + -4.70119845393155721494e-02L, + 4.03539201366454414072e-02L, + -2.91303858419364158725e-02L, + 1.24822046299269234080e-02L, +}; + +const long double pi_lo = -5.01655761266833202345e-20L; diff --git a/src/openlibm/ld80/invtrig.h b/src/openlibm/ld80/invtrig.h new file mode 100644 index 0000000..3d543e9 --- /dev/null +++ b/src/openlibm/ld80/invtrig.h @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/ld80/invtrig.h,v 1.2 2008/08/02 03:56:22 das Exp $ + */ + +#include + +#include + +#define BIAS (LDBL_MAX_EXP - 1) +#define MANH_SIZE LDBL_MANH_SIZE + +/* Approximation thresholds. */ +#define ASIN_LINEAR (BIAS - 32) /* 2**-32 */ +#define ACOS_CONST (BIAS - 65) /* 2**-65 */ +#define ATAN_CONST (BIAS + 65) /* 2**65 */ +#define ATAN_LINEAR (BIAS - 32) /* 2**-32 */ + +/* 0.95 */ +#define THRESH ((0xe666666666666666ULL>>(64-(MANH_SIZE-1)))|LDBL_NBIT) + +/* Constants shared by the long double inverse trig functions. */ +#define pS0 _ItL_pS0 +#define pS1 _ItL_pS1 +#define pS2 _ItL_pS2 +#define pS3 _ItL_pS3 +#define pS4 _ItL_pS4 +#define pS5 _ItL_pS5 +#define pS6 _ItL_pS6 +#define qS1 _ItL_qS1 +#define qS2 _ItL_qS2 +#define qS3 _ItL_qS3 +#define qS4 _ItL_qS4 +#define qS5 _ItL_qS5 +#define atanhi _ItL_atanhi +#define atanlo _ItL_atanlo +#define aT _ItL_aT +#define pi_lo _ItL_pi_lo + +#define pio2_hi atanhi[3] +#define pio2_lo atanlo[3] +#define pio4_hi atanhi[1] + +#ifdef STRUCT_DECLS +typedef struct longdouble { + uint64_t mant; + uint16_t expsign; +} LONGDOUBLE; +#else +typedef long double LONGDOUBLE; +#endif + +extern const LONGDOUBLE pS0, pS1, pS2, pS3, pS4, pS5, pS6; +extern const LONGDOUBLE qS1, qS2, qS3, qS4, qS5; +extern const LONGDOUBLE atanhi[], atanlo[], aT[]; +extern const LONGDOUBLE pi_lo; + +#ifndef STRUCT_DECLS + +static inline long double +P(long double x) +{ + + return (x * (pS0 + x * (pS1 + x * (pS2 + x * (pS3 + x * \ + (pS4 + x * (pS5 + x * pS6))))))); +} + +static inline long double +Q(long double x) +{ + + return (1.0 + x * (qS1 + x * (qS2 + x * (qS3 + x * (qS4 + x * qS5))))); +} + +static inline long double +T_even(long double x) +{ + + return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * \ + (aT[8] + x * (aT[10] + x * aT[12])))))); +} + +static inline long double +T_odd(long double x) +{ + + return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * \ + (aT[9] + x * aT[11]))))); +} + +#endif diff --git a/src/openlibm/ld80/k_cosl.c b/src/openlibm/ld80/k_cosl.c new file mode 100644 index 0000000..403da9d --- /dev/null +++ b/src/openlibm/ld80/k_cosl.c @@ -0,0 +1,78 @@ +/* From: @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_cosl.c,v 1.1 2008/02/17 07:32:14 das Exp $"); + +/* + * ld80 version of k_cos.c. See ../src/k_cos.c for most comments. + */ + +#include "math_private.h" + +/* + * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]: + * |cos(x) - c(x)| < 2**-75.1 + * + * The coefficients of c(x) were generated by a pari-gp script using + * a Remez algorithm that searches for the best higher coefficients + * after rounding leading coefficients to a specified precision. + * + * Simpler methods like Chebyshev or basic Remez barely suffice for + * cos() in 64-bit precision, because we want the coefficient of x^2 + * to be precisely -0.5 so that multiplying by it is exact, and plain + * rounding of the coefficients of a good polynomial approximation only + * gives this up to about 64-bit precision. Plain rounding also gives + * a mediocre approximation for the coefficient of x^4, but a rounding + * error of 0.5 ulps for this coefficient would only contribute ~0.01 + * ulps to the final error, so this is unimportant. Rounding errors in + * higher coefficients are even less important. + * + * In fact, coefficients above the x^4 one only need to have 53-bit + * precision, and this is more efficient. We get this optimization + * almost for free from the complications needed to search for the best + * higher coefficients. + */ +static const double +one = 1.0; + +#if defined(__amd64__) || defined(__i386__) +/* Long double constants are slow on these arches, and broken on i386. */ +static const volatile double +C1hi = 0.041666666666666664, /* 0x15555555555555.0p-57 */ +C1lo = 2.2598839032744733e-18; /* 0x14d80000000000.0p-111 */ +#define C1 ((long double)C1hi + C1lo) +#else +static const long double +C1 = 0.0416666666666666666136L; /* 0xaaaaaaaaaaaaaa9b.0p-68 */ +#endif + +static const double +C2 = -0.0013888888888888874, /* -0x16c16c16c16c10.0p-62 */ +C3 = 0.000024801587301571716, /* 0x1a01a01a018e22.0p-68 */ +C4 = -0.00000027557319215507120, /* -0x127e4fb7602f22.0p-74 */ +C5 = 0.0000000020876754400407278, /* 0x11eed8caaeccf1.0p-81 */ +C6 = -1.1470297442401303e-11, /* -0x19393412bd1529.0p-89 */ +C7 = 4.7383039476436467e-14; /* 0x1aac9d9af5c43e.0p-97 */ + +long double +__kernel_cosl(long double x, long double y) +{ + long double hz,z,r,w; + + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*C7)))))); + hz = 0.5*z; + w = one-hz; + return w + (((one-w)-hz) + (z*r-x*y)); +} diff --git a/src/openlibm/ld80/k_sinl.c b/src/openlibm/ld80/k_sinl.c new file mode 100644 index 0000000..792baf6 --- /dev/null +++ b/src/openlibm/ld80/k_sinl.c @@ -0,0 +1,62 @@ +/* From: @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_sinl.c,v 1.1 2008/02/17 07:32:14 das Exp $"); + +/* + * ld80 version of k_sin.c. See ../src/k_sin.c for most comments. + */ + +#include "math_private.h" + +static const double +half = 0.5; + +/* + * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22] + * |sin(x)/x - s(x)| < 2**-72.1 + * + * See ../ld80/k_cosl.c for more details about the polynomial. + */ +#if defined(__amd64__) || defined(__i386__) +/* Long double constants are slow on these arches, and broken on i386. */ +static const volatile double +S1hi = -0.16666666666666666, /* -0x15555555555555.0p-55 */ +S1lo = -9.2563760475949941e-18; /* -0x15580000000000.0p-109 */ +#define S1 ((long double)S1hi + S1lo) +#else +static const long double +S1 = -0.166666666666666666671L; /* -0xaaaaaaaaaaaaaaab.0p-66 */ +#endif + +static const double +S2 = 0.0083333333333333332, /* 0x11111111111111.0p-59 */ +S3 = -0.00019841269841269427, /* -0x1a01a01a019f81.0p-65 */ +S4 = 0.0000027557319223597490, /* 0x171de3a55560f7.0p-71 */ +S5 = -0.000000025052108218074604, /* -0x1ae64564f16cad.0p-78 */ +S6 = 1.6059006598854211e-10, /* 0x161242b90243b5.0p-85 */ +S7 = -7.6429779983024564e-13, /* -0x1ae42ebd1b2e00.0p-93 */ +S8 = 2.6174587166648325e-15; /* 0x179372ea0b3f64.0p-101 */ + +long double +__kernel_sinl(long double x, long double y, int iy) +{ + long double z,r,v; + + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*S8))))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/openlibm/ld80/k_tanl.c b/src/openlibm/ld80/k_tanl.c new file mode 100644 index 0000000..691c952 --- /dev/null +++ b/src/openlibm/ld80/k_tanl.c @@ -0,0 +1,125 @@ +/* From: @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/k_tanl.c,v 1.3 2008/02/18 15:39:52 bde Exp $"); + +/* + * ld80 version of k_tan.c. See ../src/k_tan.c for most comments. + */ + +#include + +#include "math_private.h" + +/* + * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22] + * |tan(x)/x - t(x)| < 2**-71.9 + * + * See k_cosl.c for more details about the polynomial. + */ +#if defined(__amd64__) || defined(__i386__) +/* Long double constants are slow on these arches, and broken on i386. */ +static const volatile double +T3hi = 0.33333333333333331, /* 0x15555555555555.0p-54 */ +T3lo = 1.8350121769317163e-17, /* 0x15280000000000.0p-108 */ +T5hi = 0.13333333333333336, /* 0x11111111111112.0p-55 */ +T5lo = 1.3051083651294260e-17, /* 0x1e180000000000.0p-109 */ +T7hi = 0.053968253968250494, /* 0x1ba1ba1ba1b827.0p-57 */ +T7lo = 3.1509625637859973e-18, /* 0x1d100000000000.0p-111 */ +pio4_hi = 0.78539816339744828, /* 0x1921fb54442d18.0p-53 */ +pio4_lo = 3.0628711372715500e-17, /* 0x11a80000000000.0p-107 */ +pio4lo_hi = -1.2541394031670831e-20, /* -0x1d9cceba3f91f2.0p-119 */ +pio4lo_lo = 6.1493048227390915e-37; /* 0x1a280000000000.0p-173 */ +#define T3 ((long double)T3hi + T3lo) +#define T5 ((long double)T5hi + T5lo) +#define T7 ((long double)T7hi + T7lo) +#define pio4 ((long double)pio4_hi + pio4_lo) +#define pio4lo ((long double)pio4lo_hi + pio4lo_lo) +#else +static const long double +T3 = 0.333333333333333333180L, /* 0xaaaaaaaaaaaaaaa5.0p-65 */ +T5 = 0.133333333333333372290L, /* 0x88888888888893c3.0p-66 */ +T7 = 0.0539682539682504975744L, /* 0xdd0dd0dd0dc13ba2.0p-68 */ +pio4 = 0.785398163397448309628L, /* 0xc90fdaa22168c235.0p-64 */ +pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */ +#endif + +static const double +T9 = 0.021869488536312216, /* 0x1664f4882cc1c2.0p-58 */ +T11 = 0.0088632355256619590, /* 0x1226e355c17612.0p-59 */ +T13 = 0.0035921281113786528, /* 0x1d6d3d185d7ff8.0p-61 */ +T15 = 0.0014558334756312418, /* 0x17da354aa3f96b.0p-62 */ +T17 = 0.00059003538700862256, /* 0x13559358685b83.0p-63 */ +T19 = 0.00023907843576635544, /* 0x1f56242026b5be.0p-65 */ +T21 = 0.000097154625656538905, /* 0x1977efc26806f4.0p-66 */ +T23 = 0.000038440165747303162, /* 0x14275a09b3ceac.0p-67 */ +T25 = 0.000018082171885432524, /* 0x12f5e563e5487e.0p-68 */ +T27 = 0.0000024196006108814377, /* 0x144c0d80cc6896.0p-71 */ +T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ +T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ +T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ + +long double +__kernel_tanl(long double x, long double y, int iy) { + long double z, r, v, w, s; + long double osign; + int i; + + iy = (iy == 1 ? -1 : 1); /* XXX recover original interface */ + osign = (x >= 0 ? 1.0 : -1.0); /* XXX slow, probably wrong for -0 */ + if (fabsl(x) >= 0.67434) { + if (x < 0) { + x = -x; + y = -y; + } + z = pio4 - x; + w = pio4lo - y; + x = z + w; + y = 0.0; + i = 1; + } else + i = 0; + z = x * x; + w = z * z; + r = T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + + w * (T25 + w * (T29 + w * T33)))))); + v = z * (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + + w * (T27 + w * T31)))))); + s = z * x; + r = y + z * (s * (r + v) + y); + r += T3 * s; + w = x + r; + if (i == 1) { + v = (long double) iy; + return osign * + (v - 2.0 * (x - (w * w / (w + v) - r))); + } + if (iy == 1) + return w; + else { + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + long double a, t; + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); + } +} diff --git a/src/openlibm/ld80/s_asinhl.c b/src/openlibm/ld80/s_asinhl.c new file mode 100644 index 0000000..0453a9c --- /dev/null +++ b/src/openlibm/ld80/s_asinhl.c @@ -0,0 +1,54 @@ +/* @(#)s_asinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* asinhl(x) + * Method : + * Based on + * asinhl(x) = signl(x) * logl [ |x| + sqrtl(x*x+1) ] + * we have + * asinhl(x) := x if 1+x*x=1, + * := signl(x)*(logl(x)+ln2)) for large |x|, else + * := signl(x)*logl(2|x|+1/(|x|+sqrtl(x*x+1))) if|x|>2, else + * := signl(x)*log1pl(|x| + x^2/(1 + sqrtl(1+x^2))) + */ + +#include + +#include "math_private.h" + +static const long double +one = 1.000000000000000000000e+00L, /* 0x3FFF, 0x00000000, 0x00000000 */ +ln2 = 6.931471805599453094287e-01L, /* 0x3FFE, 0xB17217F7, 0xD1CF79AC */ +huge= 1.000000000000000000e+4900L; + +long double +asinhl(long double x) +{ + long double t,w; + int32_t hx,ix; + GET_LDOUBLE_EXP(hx,x); + ix = hx&0x7fff; + if(ix==0x7fff) return x+x; /* x is inf or NaN */ + if(ix< 0x3fde) { /* |x|<2**-34 */ + if(huge+x>one) return x; /* return x inexact except 0 */ + } + if(ix>0x4020) { /* |x| > 2**34 */ + w = logl(fabsl(x))+ln2; + } else if (ix>0x4000) { /* 2**34 > |x| > 2.0 */ + t = fabsl(x); + w = logl(2.0*t+one/(sqrtl(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1pl(fabsl(x)+t/(one+sqrtl(one+t))); + } + if(hx&0x8000) return -w; else return w; +} diff --git a/src/openlibm/ld80/s_ceill.c b/src/openlibm/ld80/s_ceill.c new file mode 100644 index 0000000..9a3e805 --- /dev/null +++ b/src/openlibm/ld80/s_ceill.c @@ -0,0 +1,78 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * ceill(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceil(x). + */ + +#include + +#include "math_private.h" + +static const long double huge = 1.0e4930L; + +long double +ceill(long double x) +{ + int32_t i1,jj0; + u_int32_t i,j,se,i0,sx; + GET_LDOUBLE_WORDS(se,i0,i1,x); + sx = (se>>15)&1; + jj0 = (se&0x7fff)-0x3fff; + if(jj0<31) { + if(jj0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(sx) {se=0x8000;i0=0;i1=0;} + else if((i0|i1)!=0) { se=0x3fff;i0=0;i1=0;} + } + } else { + i = (0x7fffffff)>>jj0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(sx==0) { + if (jj0>0 && (i0+(0x80000000>>jj0))>i0) + i0+=0x80000000>>jj0; + else + { + i = 0x7fffffff; + ++se; + } + } + i0 &= (~i); i1=0; + } + } + } else if (jj0>62) { + if(jj0==0x4000) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(jj0-31); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(sx==0) { + if(jj0==31) i0+=1; + else { + j = i1 + (1<<(63-jj0)); + if(j + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z)) + * z=1/x^2 + * erf(x) = 1 - erfc(x) + * + * 4. For x in [1/0.35,107] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z)) + * if -6.666 x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + + +#include + +#include "math_private.h" + +static const long double +tiny = 1e-4931L, + half = 0.5L, + one = 1.0L, + two = 2.0L, + /* c = (float)0.84506291151 */ + erx = 0.845062911510467529296875L, +/* + * Coefficients for approximation to erf on [0,0.84375] + */ + /* 2/sqrt(pi) - 1 */ + efx = 1.2837916709551257389615890312154517168810E-1L, + /* 8 * (2/sqrt(pi) - 1) */ + efx8 = 1.0270333367641005911692712249723613735048E0L, + + pp[6] = { + 1.122751350964552113068262337278335028553E6L, + -2.808533301997696164408397079650699163276E6L, + -3.314325479115357458197119660818768924100E5L, + -6.848684465326256109712135497895525446398E4L, + -2.657817695110739185591505062971929859314E3L, + -1.655310302737837556654146291646499062882E2L, + }, + + qq[6] = { + 8.745588372054466262548908189000448124232E6L, + 3.746038264792471129367533128637019611485E6L, + 7.066358783162407559861156173539693900031E5L, + 7.448928604824620999413120955705448117056E4L, + 4.511583986730994111992253980546131408924E3L, + 1.368902937933296323345610240009071254014E2L, + /* 1.000000000000000000000000000000000000000E0 */ + }, + +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +/* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x) + -0.15625 <= x <= +.25 + Peak relative error 8.5e-22 */ + + pa[8] = { + -1.076952146179812072156734957705102256059E0L, + 1.884814957770385593365179835059971587220E2L, + -5.339153975012804282890066622962070115606E1L, + 4.435910679869176625928504532109635632618E1L, + 1.683219516032328828278557309642929135179E1L, + -2.360236618396952560064259585299045804293E0L, + 1.852230047861891953244413872297940938041E0L, + 9.394994446747752308256773044667843200719E-2L, + }, + + qa[7] = { + 4.559263722294508998149925774781887811255E2L, + 3.289248982200800575749795055149780689738E2L, + 2.846070965875643009598627918383314457912E2L, + 1.398715859064535039433275722017479994465E2L, + 6.060190733759793706299079050985358190726E1L, + 2.078695677795422351040502569964299664233E1L, + 4.641271134150895940966798357442234498546E0L, + /* 1.000000000000000000000000000000000000000E0 */ + }, + +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2)) + 1/2.85711669921875 < 1/x < 1/1.25 + Peak relative error 3.1e-21 */ + + ra[] = { + 1.363566591833846324191000679620738857234E-1L, + 1.018203167219873573808450274314658434507E1L, + 1.862359362334248675526472871224778045594E2L, + 1.411622588180721285284945138667933330348E3L, + 5.088538459741511988784440103218342840478E3L, + 8.928251553922176506858267311750789273656E3L, + 7.264436000148052545243018622742770549982E3L, + 2.387492459664548651671894725748959751119E3L, + 2.220916652813908085449221282808458466556E2L, + }, + + sa[] = { + -1.382234625202480685182526402169222331847E1L, + -3.315638835627950255832519203687435946482E2L, + -2.949124863912936259747237164260785326692E3L, + -1.246622099070875940506391433635999693661E4L, + -2.673079795851665428695842853070996219632E4L, + -2.880269786660559337358397106518918220991E4L, + -1.450600228493968044773354186390390823713E4L, + -2.874539731125893533960680525192064277816E3L, + -1.402241261419067750237395034116942296027E2L, + /* 1.000000000000000000000000000000000000000E0 */ + }, +/* + * Coefficients for approximation to erfc in [1/.35,107] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2)) + 1/6.6666259765625 < 1/x < 1/2.85711669921875 + Peak relative error 4.2e-22 */ + rb[] = { + -4.869587348270494309550558460786501252369E-5L, + -4.030199390527997378549161722412466959403E-3L, + -9.434425866377037610206443566288917589122E-2L, + -9.319032754357658601200655161585539404155E-1L, + -4.273788174307459947350256581445442062291E0L, + -8.842289940696150508373541814064198259278E0L, + -7.069215249419887403187988144752613025255E0L, + -1.401228723639514787920274427443330704764E0L, + }, + + sb[] = { + 4.936254964107175160157544545879293019085E-3L, + 1.583457624037795744377163924895349412015E-1L, + 1.850647991850328356622940552450636420484E0L, + 9.927611557279019463768050710008450625415E0L, + 2.531667257649436709617165336779212114570E1L, + 2.869752886406743386458304052862814690045E1L, + 1.182059497870819562441683560749192539345E1L, + /* 1.000000000000000000000000000000000000000E0 */ + }, +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2)) + 1/107 <= 1/x <= 1/6.6666259765625 + Peak relative error 1.1e-21 */ + rc[] = { + -8.299617545269701963973537248996670806850E-5L, + -6.243845685115818513578933902532056244108E-3L, + -1.141667210620380223113693474478394397230E-1L, + -7.521343797212024245375240432734425789409E-1L, + -1.765321928311155824664963633786967602934E0L, + -1.029403473103215800456761180695263439188E0L, + }, + + sc[] = { + 8.413244363014929493035952542677768808601E-3L, + 2.065114333816877479753334599639158060979E-1L, + 1.639064941530797583766364412782135680148E0L, + 4.936788463787115555582319302981666347450E0L, + 5.005177727208955487404729933261347679090E0L, + /* 1.000000000000000000000000000000000000000E0 */ + }; + +long double +erfl(long double x) +{ + long double R, S, P, Q, s, y, z, r; + int32_t ix, i; + u_int32_t se, i0, i1; + + GET_LDOUBLE_WORDS (se, i0, i1, x); + ix = se & 0x7fff; + + if (ix >= 0x7fff) + { /* erf(nan)=nan */ + i = ((se & 0xffff) >> 15) << 1; + return (long double) (1 - i) + one / x; /* erf(+-inf)=+-1 */ + } + + ix = (ix << 16) | (i0 >> 16); + if (ix < 0x3ffed800) /* |x|<0.84375 */ + { + if (ix < 0x3fde8000) /* |x|<2**-33 */ + { + if (ix < 0x00080000) + return 0.125 * (8.0 * x + efx8 * x); /*avoid underflow */ + return x + efx * x; + } + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + return x + x * y; + } + if (ix < 0x3fffa000) /* 1.25 */ + { /* 0.84375 <= |x| < 1.25 */ + s = fabsl (x) - one; + P = pa[0] + s * (pa[1] + s * (pa[2] + + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + s * (qa[1] + s * (qa[2] + + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + if ((se & 0x8000) == 0) + return erx + P / Q; + else + return -erx - P / Q; + } + if (ix >= 0x4001d555) /* 6.6666259765625 */ + { /* inf>|x|>=6.666 */ + if ((se & 0x8000) == 0) + return one - tiny; + else + return tiny - one; + } + x = fabsl (x); + s = one / (x * x); + if (ix < 0x4000b6db) /* 2.85711669921875 */ + { + R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] + + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } + else + { /* |x| >= 1/0.35 */ + R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] + + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + + s * (sb[5] + s * (sb[6] + s)))))); + } + z = x; + GET_LDOUBLE_WORDS (i, i0, i1, z); + i1 = 0; + SET_LDOUBLE_WORDS (z, i, i0, i1); + r = + expl (-z * z - 0.5625) * expl ((z - x) * (z + x) + R / S); + if ((se & 0x8000) == 0) + return one - r / x; + else + return r / x - one; +} + +long double +erfcl(long double x) +{ + int32_t hx, ix; + long double R, S, P, Q, s, y, z, r; + u_int32_t se, i0, i1; + + GET_LDOUBLE_WORDS (se, i0, i1, x); + ix = se & 0x7fff; + if (ix >= 0x7fff) + { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (long double) (((se & 0xffff) >> 15) << 1) + one / x; + } + + ix = (ix << 16) | (i0 >> 16); + if (ix < 0x3ffed800) /* |x|<0.84375 */ + { + if (ix < 0x3fbe0000) /* |x|<2**-65 */ + return one - x; + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + if (ix < 0x3ffd8000) /* x<1/4 */ + { + return one - (x + x * y); + } + else + { + r = x * y; + r += (x - half); + return half - r; + } + } + if (ix < 0x3fffa000) /* 1.25 */ + { /* 0.84375 <= |x| < 1.25 */ + s = fabsl (x) - one; + P = pa[0] + s * (pa[1] + s * (pa[2] + + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + s * (qa[1] + s * (qa[2] + + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + if ((se & 0x8000) == 0) + { + z = one - erx; + return z - P / Q; + } + else + { + z = erx + P / Q; + return one + z; + } + } + if (ix < 0x4005d600) /* 107 */ + { /* |x|<107 */ + x = fabsl (x); + s = one / (x * x); + if (ix < 0x4000b6db) /* 2.85711669921875 */ + { /* |x| < 1/.35 ~ 2.857143 */ + R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] + + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } + else if (ix < 0x4001d555) /* 6.6666259765625 */ + { /* 6.666 > |x| >= 1/.35 ~ 2.857143 */ + R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] + + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + + s * (sb[5] + s * (sb[6] + s)))))); + } + else + { /* |x| >= 6.666 */ + if (se & 0x8000) + return two - tiny; /* x < -6.666 */ + + R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] + + s * (rc[4] + s * rc[5])))); + S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] + + s * (sc[4] + s)))); + } + z = x; + GET_LDOUBLE_WORDS (hx, i0, i1, z); + i1 = 0; + i0 &= 0xffffff00; + SET_LDOUBLE_WORDS (z, hx, i0, i1); + r = expl (-z * z - 0.5625) * + expl ((z - x) * (z + x) + R / S); + if ((se & 0x8000) == 0) + return r / x; + else + return two - r / x; + } + else + { + if ((se & 0x8000) == 0) + return tiny * tiny; + else + return two - tiny; + } +} diff --git a/src/openlibm/ld80/s_exp2l.c b/src/openlibm/ld80/s_exp2l.c new file mode 100644 index 0000000..0cf5259 --- /dev/null +++ b/src/openlibm/ld80/s_exp2l.c @@ -0,0 +1,295 @@ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/ld80/s_exp2l.c,v 1.3 2008/02/13 10:44:44 bde Exp $"); + +#include +#include + +#include "bsd_cdefs.h" +#include "amd64/bsd_ieeefp.h" + +#include + +#include "math_private.h" + +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +#define BIAS (LDBL_MAX_EXP - 1) +#define EXPMASK (BIAS + LDBL_MAX_EXP) + +static const long double huge = 0x1p10000L; +#if 0 /* XXX Prevent gcc from erroneously constant folding this. */ +static const long double twom10000 = 0x1p-10000L; +#else +static volatile long double twom10000 = 0x1p-10000L; +#endif + +static const double + redux = 0x1.8p63 / TBLSIZE, + P1 = 0x1.62e42fefa39efp-1, + P2 = 0x1.ebfbdff82c58fp-3, + P3 = 0x1.c6b08d7049fap-5, + P4 = 0x1.3b2ab6fba4da5p-7, + P5 = 0x1.5d8804780a736p-10, + P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, 0x1.2eb74966578p-58, + 0x1p+0, 0x0p+0, + 0x1.0163da9fb3335p+0, 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +OLM_DLLEXPORT long double +exp2l(long double x) +{ + union IEEEl2bits u, v; + long double r, twopk, twopkp10000, z; + uint32_t hx, ix, i0; + int k; + + /* Filter out exceptional cases. */ + u.e = x; + hx = u.xbits.expsign; + ix = hx & EXPMASK; + if (ix >= BIAS + 14) { /* |x| >= 16384 or x is NaN */ + if (ix == BIAS + LDBL_MAX_EXP) { + if (u.xbits.man != 1ULL << 63 || (hx & 0x8000) == 0) + return (x + x); /* x is +Inf or NaN */ + else + return (0.0); /* x is -Inf */ + } + if (x >= 16384) + return (huge * huge); /* overflow */ + if (x <= -16446) + return (twom10000 * twom10000); /* underflow */ + } else if (ix <= BIAS - 66) { /* |x| < 0x1p-66 */ + return (1.0 + x); + } + +#ifdef __i386__ + /* + * The default precision on i386 is 53 bits, so long doubles are + * broken. Call exp2() to get an accurate (double precision) result. + */ + if (__fpgetprec() != FP_PE) + return (exp2(x)); +#endif + + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + * + * XXX If the exponent is negative, the computation of k depends on + * '>>' doing sign extension. + */ + u.e = x + redux; + i0 = u.bits.manl + TBLSIZE / 2; + k = (int)i0 >> TBLBITS; + i0 = (i0 & (TBLSIZE - 1)) << 1; + u.e -= redux; + z = x - u.e; + v.xbits.man = 1ULL << 63; + if (k >= LDBL_MIN_EXP) { + v.xbits.expsign = LDBL_MAX_EXP - 1 + k; + twopk = v.e; + } else { + v.xbits.expsign = LDBL_MAX_EXP - 1 + k + 10000; + twopkp10000 = v.e; + } + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[i0]; + long double t_lo = tbl[i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + + z * (P5 + z * P6))))) + t_hi; + + /* Scale by 2**k. */ + if (k >= LDBL_MIN_EXP) { + if (k == LDBL_MAX_EXP) + return (r * 2.0 * 0x1p16383L); + return (r * twopk); + } else { + return (r * twopkp10000 * twom10000); + } +} diff --git a/src/openlibm/ld80/s_expm1l.c b/src/openlibm/ld80/s_expm1l.c new file mode 100644 index 0000000..6ad23fa --- /dev/null +++ b/src/openlibm/ld80/s_expm1l.c @@ -0,0 +1,138 @@ +/* $OpenBSD: s_expm1l.c,v 1.2 2011/07/20 21:02:51 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* expm1l.c + * + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+MAXLOG 200,000 1.2e-19 2.5e-20 + * + * ERROR MESSAGES: + * + * message condition value returned + * expm1l overflow x > MAXLOG MAXNUM + * + */ + +#include + +static const long double MAXLOGL = 1.1356523406294143949492E4L; + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ + +static const long double + P0 = -1.586135578666346600772998894928250240826E4L, + P1 = 2.642771505685952966904660652518429479531E3L, + P2 = -3.423199068835684263987132888286791620673E2L, + P3 = 1.800826371455042224581246202420972737840E1L, + P4 = -5.238523121205561042771939008061958820811E-1L, + + Q0 = -9.516813471998079611319047060563358064497E4L, + Q1 = 3.964866271411091674556850458227710004570E4L, + Q2 = -7.207678383830091850230366618190187434796E3L, + Q3 = 7.206038318724600171970199625081491823079E2L, + Q4 = -4.002027679107076077238836622982900945173E1L, + /* Q5 = 1.000000000000000000000000000000000000000E0 */ + +/* C1 + C2 = ln 2 */ +C1 = 6.93145751953125E-1L, +C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln 2^-65 */ +minarg = -4.5054566736396445112120088E1L; +static const long double huge = 0x1p10000L; + +long double +expm1l(long double x) +{ +long double px, qx, xx; +int k; + +/* Overflow. */ +if (x > MAXLOGL) + return (huge*huge); /* overflow */ + +if (x == 0.0) + return x; + +/* Minimum value. */ +if (x < minarg) + return -1.0L; + +xx = C1 + C2; + +/* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ +px = floorl (0.5 + x / xx); +k = px; +/* remainder times ln 2 */ +x -= px * C1; +x -= px * C2; + +/* Approximate exp(remainder ln 2). */ +px = (((( P4 * x + + P3) * x + + P2) * x + + P1) * x + + P0) * x; + +qx = (((( x + + Q4) * x + + Q3) * x + + Q2) * x + + Q1) * x + + Q0; + +xx = x * x; +qx = x + (0.5 * xx + xx * px / qx); + +/* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ +px = ldexpl(1.0L, k); +x = px * qx + (px - 1.0); +return x; +} diff --git a/src/openlibm/ld80/s_floorl.c b/src/openlibm/ld80/s_floorl.c new file mode 100644 index 0000000..7d42bd6 --- /dev/null +++ b/src/openlibm/ld80/s_floorl.c @@ -0,0 +1,80 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * floorl(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include + +#include "math_private.h" + +static const long double huge = 1.0e4930L; + +long double +floorl(long double x) +{ + int32_t i1,jj0; + u_int32_t i,j,se,i0,sx; + GET_LDOUBLE_WORDS(se,i0,i1,x); + sx = (se>>15)&1; + jj0 = (se&0x7fff)-0x3fff; + if(jj0<31) { + if(jj0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) { + if(sx==0) + return 0.0L; + else if(((se&0x7fff)|i0|i1)!=0) + return -1.0L; + } + } else { + i = (0x7fffffff)>>jj0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(sx) { + if (jj0>0 && (i0+(0x80000000>>jj0))>i0) + i0 += (0x80000000)>>jj0; + else + { + i = 0x7fffffff; + ++se; + } + } + i0 &= (~i); i1=0; + } + } + } else if (jj0>62) { + if(jj0==0x4000) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(jj0-31); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(sx) { + if(jj0==31) i0+=1; + else { + j = i1+(1<<(63-jj0)); + if(j + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* log1pl.c + * + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + * + * ERROR MESSAGES: + * + * log singularity: x-1 = 0; returns -INFINITY + * log domain: x-1 < 0; returns NAN + */ + +#include + +#include "math_private.h" + +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ + +static long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ + +static long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double +log1pl(long double xm1) +{ +long double x, y, z; +int e; + +if( isnan(xm1) ) + return(xm1); +if( xm1 == INFINITY ) + return(xm1); +if(xm1 == 0.0) + return(xm1); + +x = xm1 + 1.0L; + +/* Test for domain errors. */ +if( x <= 0.0L ) + { + if( x == 0.0L ) + return( -INFINITY ); + else + return( NAN ); + } + +/* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ +x = frexpl( x, &e ); + +/* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5L; + y = 0.5L * z + 0.5L; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5L; + z -= 0.5L; + y = 0.5L * x + 0.5L; + } +x = z / y; +z = x*x; +z = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) ); +z = z + e * C2; +z = z + x; +z = z + e * C1; +return( z ); +} + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0L; + else + x = xm1; + } +else + { + if (e != 0) + x = x - 1.0L; + else + x = xm1; + } +z = x*x; +y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 6 ) ); +y = y + e * C2; +z = y - 0.5 * z; +z = z + x; +z = z + e * C1; +return( z ); +} diff --git a/src/openlibm/ld80/s_modfl.c b/src/openlibm/ld80/s_modfl.c new file mode 100644 index 0000000..f9884af --- /dev/null +++ b/src/openlibm/ld80/s_modfl.c @@ -0,0 +1,69 @@ +/* @(#)s_modf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modfl(long double x, long double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include + +#include "math_private.h" + +static const long double one = 1.0; + +long double +modfl(long double x, long double *iptr) +{ + int32_t i0,i1,jj0; + u_int32_t i,se; + GET_LDOUBLE_WORDS(se,i0,i1,x); + jj0 = (se&0x7fff)-0x3fff; /* exponent of x */ + if(jj0<32) { /* integer part in high x */ + if(jj0<0) { /* |x|<1 */ + SET_LDOUBLE_WORDS(*iptr,se&0x8000,0,0); /* *iptr = +-0 */ + return x; + } else { + i = (0x7fffffff)>>jj0; + if(((i0&i)|i1)==0) { /* x is integral */ + *iptr = x; + SET_LDOUBLE_WORDS(x,se&0x8000,0,0); /* return +-0 */ + return x; + } else { + SET_LDOUBLE_WORDS(*iptr,se,i0&(~i),0); + return x - *iptr; + } + } + } else if (jj0>63) { /* no fraction part */ + *iptr = x*one; + /* We must handle NaNs separately. */ + if (jj0 == 0x4000 && ((i0 & 0x7fffffff) | i1)) + return x*one; + SET_LDOUBLE_WORDS(x,se&0x8000,0,0); /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((u_int32_t)(0x7fffffff))>>(jj0-32); + if((i1&i)==0) { /* x is integral */ + *iptr = x; + SET_LDOUBLE_WORDS(x,se&0x8000,0,0); /* return +-0 */ + return x; + } else { + SET_LDOUBLE_WORDS(*iptr,se,i0,i1&(~i)); + return x - *iptr; + } + } +} diff --git a/src/openlibm/ld80/s_nanl.c b/src/openlibm/ld80/s_nanl.c new file mode 100644 index 0000000..ca77048 --- /dev/null +++ b/src/openlibm/ld80/s_nanl.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/ld80/s_nanl.c,v 1.2 2007/12/18 23:46:31 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +nanl(const char *s) +{ + union { + union IEEEl2bits ieee; + uint32_t bits[3]; + } u; + + __scan_nan(u.bits, 3, s); + u.ieee.bits.exp = 0x7fff; + u.ieee.bits.manh |= 0xc0000000; /* make it a quiet NaN */ + return (u.ieee.e); +} diff --git a/src/openlibm/ld80/s_nextafterl.c b/src/openlibm/ld80/s_nextafterl.c new file mode 100644 index 0000000..1e0764b --- /dev/null +++ b/src/openlibm/ld80/s_nextafterl.c @@ -0,0 +1,90 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + * nextafterl(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include + +#include "math_private.h" + +long double +nextafterl(long double x, long double y) +{ + int32_t hx,hy,ix,iy; + u_int32_t lx,ly,esx,esy; + + GET_LDOUBLE_WORDS(esx,hx,lx,x); + GET_LDOUBLE_WORDS(esy,hy,ly,y); + ix = esx&0x7fff; /* |x| */ + iy = esy&0x7fff; /* |y| */ + + if (((ix==0x7fff)&&((hx&0x7fffffff|lx)!=0)) || /* x is nan */ + ((iy==0x7fff)&&((hy&0x7fffffff|ly)!=0))) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if((ix|hx|lx)==0) { /* x == 0 */ + volatile long double u; + SET_LDOUBLE_WORDS(x,esy&0x8000,0,1);/* return +-minsubnormal */ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(esx<0x8000) { /* x > 0 */ + if(ix>iy||((ix==iy) && (hx>hy||((hx==hy)&&(lx>ly))))) { + /* x > y, x -= ulp */ + if(lx==0) { + if ((hx&0x7fffffff)==0) esx -= 1; + hx = (hx - 1) | (hx & 0x80000000); + } + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if(lx==0) { + hx = (hx + 1) | (hx & 0x80000000); + if ((hx&0x7fffffff)==0) esx += 1; + } + } + } else { /* x < 0 */ + if(esy>=0||(ix>iy||((ix==iy)&&(hx>hy||((hx==hy)&&(lx>ly)))))){ + /* x < y, x -= ulp */ + if(lx==0) { + if ((hx&0x7fffffff)==0) esx -= 1; + hx = (hx - 1) | (hx & 0x80000000); + } + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if(lx==0) { + hx = (hx + 1) | (hx & 0x80000000); + if ((hx&0x7fffffff)==0) esx += 1; + } + } + } + esy = esx&0x7fff; + if(esy==0x7fff) return x+x; /* overflow */ + if(esy==0) { + volatile long double u = x*x; /* underflow */ + if(u==x) { + SET_LDOUBLE_WORDS(x,esx,hx,lx); + return x; + } + } + SET_LDOUBLE_WORDS(x,esx,hx,lx); + return x; +} + +//__strong_alias(nexttowardl, nextafterl); diff --git a/src/openlibm/ld80/s_nexttoward.c b/src/openlibm/ld80/s_nexttoward.c new file mode 100644 index 0000000..b017668 --- /dev/null +++ b/src/openlibm/ld80/s_nexttoward.c @@ -0,0 +1,86 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + * nexttoward(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include +#include + +#include "math_private.h" + +double +nexttoward(double x, long double y) +{ + int32_t hx,ix,iy; + u_int32_t lx,hy,ly,esy; + + EXTRACT_WORDS(hx,lx,x); + GET_LDOUBLE_WORDS(esy,hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = esy&0x7fff; /* |y| */ + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ + ((iy>=0x7fff)&&(hy|ly)!=0)) /* y is nan */ + return x+y; + if((long double) x==y) return y; /* x=y, return y */ + if((ix|lx)==0) { /* x == 0 */ + volatile double u; + INSERT_WORDS(x,(esy&0x8000)<<16,1); /* return +-minsub */ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(hx>=0) { /* x > 0 */ + if (esy>=0x8000||((ix>>20)&0x7ff)>iy-0x3c00 + || (((ix>>20)&0x7ff)==iy-0x3c00 + && (((hx<<11)|(lx>>21))>(hy&0x7fffffff) + || (((hx<<11)|(lx>>21))==(hy&0x7fffffff) + && (lx<<11)>ly)))) { /* x > y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } else { /* x < 0 */ + if (esy<0x8000||((ix>>20)&0x7ff)>iy-0x3c00 + || (((ix>>20)&0x7ff)==iy-0x3c00 + && (((hx<<11)|(lx>>21))>(hy&0x7fffffff) + || (((hx<<11)|(lx>>21))==(hy&0x7fffffff) + && (lx<<11)>ly)))) {/* x < y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } + hy = hx&0x7ff00000; + if(hy>=0x7ff00000) { + x = x+x; /* overflow */ + return x; + } + if(hy<0x00100000) { + volatile double u = x*x; /* underflow */ + if(u==x) { + INSERT_WORDS(x,hx,lx); + return x; + } + } + INSERT_WORDS(x,hx,lx); + return x; +} diff --git a/src/openlibm/ld80/s_nexttowardf.c b/src/openlibm/ld80/s_nexttowardf.c new file mode 100644 index 0000000..f2ac10d --- /dev/null +++ b/src/openlibm/ld80/s_nexttowardf.c @@ -0,0 +1,67 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +#include "math_private.h" + +float +nexttowardf(float x, long double y) +{ + int32_t hx,ix,iy; + u_int32_t hy,ly,esy; + + GET_FLOAT_WORD(hx,x); + GET_LDOUBLE_WORDS(esy,hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = esy&0x7fff; /* |y| */ + + if((ix>0x7f800000) || /* x is nan */ + (iy>=0x7fff&&((hy|ly)!=0))) /* y is nan */ + return x+y; + if((long double) x==y) return y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + volatile float u; + SET_FLOAT_WORD(x,((esy&0x8000)<<16)|1);/* return +-minsub*/ + u = x; + u = u * u; /* raise underflow flag */ + return x; + } + if(hx>=0) { /* x > 0 */ + if(esy>=0x8000||((ix>>23)&0xff)>iy-0x3f80 + || (((ix>>23)&0xff)==iy-0x3f80 + && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x > y, x -= ulp */ + hx -= 1; + } else { /* x < y, x += ulp */ + hx += 1; + } + } else { /* x < 0 */ + if(esy<0x8000||((ix>>23)&0xff)>iy-0x3f80 + || (((ix>>23)&0xff)==iy-0x3f80 + && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x < y, x -= ulp */ + hx -= 1; + } else { /* x > y, x += ulp */ + hx += 1; + } + } + hy = hx&0x7f800000; + if(hy>=0x7f800000) { + x = x+x; /* overflow */ + return x; + } + if(hy<0x00800000) { + volatile float u = x*x; /* underflow */ + } + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/src/openlibm/ld80/s_remquol.c b/src/openlibm/ld80/s_remquol.c new file mode 100644 index 0000000..f649dca --- /dev/null +++ b/src/openlibm/ld80/s_remquol.c @@ -0,0 +1,166 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +#include +#include +#include + +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define LDBL_NBIT 0 +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS EXT_FRACHBITS +#else +#define LDBL_NBIT 0x80000000 +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (EXT_FRACHBITS - 1) +#endif + +#define MANL_SHIFT (EXT_FRACLBITS - 1) + +static const long double Zero[] = {0.0L, -0.0L}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +long double +remquol(long double x, long double y, int *quo) +{ + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + uint32_t hy; + uint32_t lx,ly,lz; + uint32_t esx, esy; + int ix,iy,n,q,sx,sxy; + + GET_LDOUBLE_WORDS(esx,hx,lx,x); + GET_LDOUBLE_WORDS(esy,hy,ly,y); + sx = esx & 0x8000; + sxy = sx ^ (esy & 0x8000); + esx &= 0x7fff; /* |x| */ + esy &= 0x7fff; /* |y| */ + SET_LDOUBLE_EXP(x,esx); + SET_LDOUBLE_EXP(y,esy); + + /* purge off exception values */ + if((esy|hy|ly)==0 || /* y=0 */ + (esx == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (esy == BIAS + LDBL_MAX_EXP && + ((hy&~LDBL_NBIT)|ly)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(esx<=esy) { + if((esx>MANL_SHIFT); lx = lx+lx;} + else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;} + q <<= 1; + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) { /* return sign(x)*0 */ + *quo = (sxy ? -q : q); + return Zero[sx!=0]; + } + while(hx<(1ULL<>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + if (iy < LDBL_MIN_EXP) { + esx = (iy + BIAS + 512) & 0x7fff; + SET_LDOUBLE_WORDS(x,esx,hx,lx); + x *= 0x1p-512; + GET_LDOUBLE_WORDS(esx,hx,lx,x); + } else { + esx = (iy + BIAS) & 0x7fff; + } + SET_LDOUBLE_WORDS(x,esx,hx,lx); +fixup: + y = fabsl(y); + if (y < LDBL_MIN * 2) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + + GET_LDOUBLE_EXP(esx,x); + esx ^= sx; + SET_LDOUBLE_EXP(x,esx); + + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/src/openlibm/ld80/s_tanhl.c b/src/openlibm/ld80/s_tanhl.c new file mode 100644 index 0000000..1a46583 --- /dev/null +++ b/src/openlibm/ld80/s_tanhl.c @@ -0,0 +1,79 @@ +/* @(#)s_tanh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* tanhl(x) + * Return the Hyperbolic Tangent of x + * + * Method : + * x -x + * e - e + * 0. tanhl(x) is defined to be ----------- + * x -x + * e + e + * 1. reduce x to non-negative by tanhl(-x) = -tanhl(x). + * 2. 0 <= x <= 2**-55 : tanhl(x) := x*(one+x) + * -t + * 2**-55 < x <= 1 : tanhl(x) := -----; t = expm1l(-2x) + * t + 2 + * 2 + * 1 <= x <= 23.0 : tanhl(x) := 1- ----- ; t=expm1l(2x) + * t + 2 + * 23.0 < x <= INF : tanhl(x) := 1. + * + * Special cases: + * tanhl(NaN) is NaN; + * only tanhl(0)=0 is exact for finite argument. + */ + +#include + +#include "math_private.h" + +static const long double one=1.0, two=2.0, tiny = 1.0e-4900L; + +long double +tanhl(long double x) +{ + long double t,z; + int32_t se; + u_int32_t jj0,jj1,ix; + + /* High word of |x|. */ + GET_LDOUBLE_WORDS(se,jj0,jj1,x); + ix = se&0x7fff; + + /* x is INF or NaN */ + if(ix==0x7fff) { + /* for NaN it's not important which branch: tanhl(NaN) = NaN */ + if (se&0x8000) return one/x-one; /* tanhl(-inf)= -1; */ + else return one/x+one; /* tanhl(+inf)=+1 */ + } + + /* |x| < 23 */ + if (ix < 0x4003 || (ix == 0x4003 && jj0 < 0xb8000000u)) {/* |x|<23 */ + if ((ix|jj0|jj1) == 0) + return x; /* x == +- 0 */ + if (ix<0x3fc8) /* |x|<2**-55 */ + return x*(one+tiny); /* tanh(small) = small */ + if (ix>=0x3fff) { /* |x|>=1 */ + t = expm1l(two*fabsl(x)); + z = one - two/(t+two); + } else { + t = expm1l(-two*fabsl(x)); + z= -t/(t+two); + } + /* |x| > 23, return +-1 */ + } else { + z = one - tiny; /* raised inexact flag */ + } + return (se&0x8000)? -z: z; +} diff --git a/src/openlibm/ld80/s_truncl.c b/src/openlibm/ld80/s_truncl.c new file mode 100644 index 0000000..8a261d8 --- /dev/null +++ b/src/openlibm/ld80/s_truncl.c @@ -0,0 +1,72 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +/* + * truncl(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncl(x). + */ + +#include +//#include + +#include +#include +#include + +#include "math_private.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (EXT_FRACHBITS + 1) +#else +#define MANH_SIZE EXT_FRACHBITS +#endif + +static const long double huge = 1.0e300; +static const float zero[] = { 0.0, -0.0 }; + +long double +truncl(long double x) +{ + int e, es; + uint32_t ix0, ix1; + + GET_LDOUBLE_WORDS(es,ix0,ix1,x); + e = (es&0x7fff) - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + return (zero[(es&0x8000)!=0]); + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((ix0 & m) | ix1) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) { /* raise inexact flag */ + ix0 &= ~m; + ix1 = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((ix1 & m) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) /* raise inexact flag */ + ix1 &= ~m; + } + SET_LDOUBLE_WORDS(x,es,ix0,ix1); + return (x); +} diff --git a/src/openlibm/loongarch64/Make.files b/src/openlibm/loongarch64/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/loongarch64/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/loongarch64/fenv.c b/src/openlibm/loongarch64/fenv.c new file mode 100644 index 0000000..9c95f2a --- /dev/null +++ b/src/openlibm/loongarch64/fenv.c @@ -0,0 +1,27 @@ +#define __fenv_static +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +/* + * Hopefully the system ID byte is immutable, so it's valid to use + * this as a default environment. + */ +const fenv_t __fe_dfl_env = 0; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); +extern inline int feenableexcept(int __mask); +extern inline int fedisableexcept(int __mask); +extern inline int fegetexcept(void); \ No newline at end of file diff --git a/src/openlibm/mips/Make.files b/src/openlibm/mips/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/mips/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/mips/fenv-softfloat.h b/src/openlibm/mips/fenv-softfloat.h new file mode 100644 index 0000000..0511335 --- /dev/null +++ b/src/openlibm/mips/fenv-softfloat.h @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2004-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FENV_H_ +#error "This file is meant to be included only by ." +#endif + +/* + * This file implements the functionality of on platforms that + * lack an FPU and use softfloat in libc for floating point. To use it, + * you must write an that provides the following: + * + * - a typedef for fenv_t, which may be an integer or struct type + * - a typedef for fexcept_t (XXX This file assumes fexcept_t is a + * simple integer type containing the exception mask.) + * - definitions of FE_* constants for the five exceptions and four + * rounding modes in IEEE 754, as described in fenv(3) + * - a definition, and the corresponding external symbol, for FE_DFL_ENV + * - a macro __set_env(env, flags, mask, rnd), which sets the given fenv_t + * from the exception flags, mask, and rounding mode + * - macros __env_flags(env), __env_mask(env), and __env_round(env), which + * extract fields from an fenv_t + * - a definition of __fenv_static + * + * If the architecture supports an optional FPU, it's recommended that you + * define fenv_t and fexcept_t to match the hardware ABI. Otherwise, it + * doesn't matter how you define them. + */ + +extern int __softfloat_float_exception_flags; +extern int __softfloat_float_exception_mask; +extern int __softfloat_float_rounding_mode; +void __softfloat_float_raise(int); + +__fenv_static inline int +feclearexcept(int __excepts) +{ + + __softfloat_float_exception_flags &= ~__excepts; + return (0); +} + +__fenv_static inline int +fegetexceptflag(fexcept_t *__flagp, int __excepts) +{ + + *__flagp = __softfloat_float_exception_flags & __excepts; + return (0); +} + +__fenv_static inline int +fesetexceptflag(const fexcept_t *__flagp, int __excepts) +{ + + __softfloat_float_exception_flags &= ~__excepts; + __softfloat_float_exception_flags |= *__flagp & __excepts; + return (0); +} + +__fenv_static inline int +feraiseexcept(int __excepts) +{ + + __softfloat_float_raise(__excepts); + return (0); +} + +__fenv_static inline int +fetestexcept(int __excepts) +{ + + return (__softfloat_float_exception_flags & __excepts); +} + +__fenv_static inline int +fegetround(void) +{ + + return (__softfloat_float_rounding_mode); +} + +__fenv_static inline int +fesetround(int __round) +{ + + __softfloat_float_rounding_mode = __round; + return (0); +} + +__fenv_static inline int +fegetenv(fenv_t *__envp) +{ + + __set_env(*__envp, __softfloat_float_exception_flags, + __softfloat_float_exception_mask, __softfloat_float_rounding_mode); + return (0); +} + +__fenv_static inline int +feholdexcept(fenv_t *__envp) +{ + fenv_t __env; + + fegetenv(__envp); + __softfloat_float_exception_flags = 0; + __softfloat_float_exception_mask = 0; + return (0); +} + +__fenv_static inline int +fesetenv(const fenv_t *__envp) +{ + + __softfloat_float_exception_flags = __env_flags(*__envp); + __softfloat_float_exception_mask = __env_mask(*__envp); + __softfloat_float_rounding_mode = __env_round(*__envp); + return (0); +} + +__fenv_static inline int +feupdateenv(const fenv_t *__envp) +{ + int __oflags = __softfloat_float_exception_flags; + + fesetenv(__envp); + feraiseexcept(__oflags); + return (0); +} + +#if __BSD_VISIBLE + +/* We currently provide no external definitions of the functions below. */ + +__fenv_static inline int +feenableexcept(int __mask) +{ + int __omask = __softfloat_float_exception_mask; + + __softfloat_float_exception_mask |= __mask; + return (__omask); +} + +__fenv_static inline int +fedisableexcept(int __mask) +{ + int __omask = __softfloat_float_exception_mask; + + __softfloat_float_exception_mask &= ~__mask; + return (__omask); +} + +__fenv_static inline int +fegetexcept(void) +{ + + return (__softfloat_float_exception_mask); +} + +#endif /* __BSD_VISIBLE */ \ No newline at end of file diff --git a/src/openlibm/mips/fenv.c b/src/openlibm/mips/fenv.c new file mode 100644 index 0000000..4a7ed80 --- /dev/null +++ b/src/openlibm/mips/fenv.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define __fenv_static +#include "openlibm_fenv.h" + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +/* + * Hopefully the system ID byte is immutable, so it's valid to use + * this as a default environment. + */ +const fenv_t __fe_dfl_env = 0; + +#ifdef __mips_soft_float +#define __set_env(env, flags, mask, rnd) env = ((flags) \ + | (mask)<<_FPUSW_SHIFT \ + | (rnd) << 24) +#define __env_flags(env) ((env) & FE_ALL_EXCEPT) +#define __env_mask(env) (((env) >> _FPUSW_SHIFT) \ + & FE_ALL_EXCEPT) +#define __env_round(env) (((env) >> 24) & _ROUND_MASK) +#include "fenv-softfloat.h" +#endif + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); +extern inline int feenableexcept(int __mask); +extern inline int fedisableexcept(int __mask); +extern inline int fegetexcept(void); + diff --git a/src/openlibm/openlibm.pc.in b/src/openlibm/openlibm.pc.in new file mode 100644 index 0000000..bfad876 --- /dev/null +++ b/src/openlibm/openlibm.pc.in @@ -0,0 +1,6 @@ +Name: openlibm +Version: ${version} +URL: https://github.com/JuliaMath/openlibm +Description: High quality system independent, open source libm. +Cflags: -I${includedir} +Libs: -L${libdir} -lopenlibm diff --git a/src/openlibm/powerpc/Make.files b/src/openlibm/powerpc/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/powerpc/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/powerpc/fenv.c b/src/openlibm/powerpc/fenv.c new file mode 100644 index 0000000..bf7d0cb --- /dev/null +++ b/src/openlibm/powerpc/fenv.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +const fenv_t __fe_dfl_env = 0x00000000; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); diff --git a/src/openlibm/riscv64/Make.files b/src/openlibm/riscv64/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/riscv64/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/riscv64/fenv.c b/src/openlibm/riscv64/fenv.c new file mode 100644 index 0000000..0905092 --- /dev/null +++ b/src/openlibm/riscv64/fenv.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/lib/msun/riscv/fenv.c 332792 2018-04-19 20:36:15Z brooks $ + */ + +#define __fenv_static +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +/* + * Hopefully the system ID byte is immutable, so it's valid to use + * this as a default environment. + */ +const fenv_t __fe_dfl_env = {0}; + +#ifdef __riscv_float_abi_soft +#define __set_env(env, flags, mask, rnd) env = ((flags) | (rnd) << 5) +#define __env_flags(env) ((env) & FE_ALL_EXCEPT) +#define __env_mask(env) (0) /* No exception traps. */ +#define __env_round(env) (((env) >> 5) & _ROUND_MASK) +#include "fenv-softfloat.h" +#endif + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); +extern inline int feenableexcept(int __mask); +extern inline int fedisableexcept(int __mask); +extern inline int fegetexcept(void); diff --git a/src/openlibm/s390/Make.files b/src/openlibm/s390/Make.files new file mode 100644 index 0000000..483a7cc --- /dev/null +++ b/src/openlibm/s390/Make.files @@ -0,0 +1 @@ +$(CUR_SRCS) = fenv.c diff --git a/src/openlibm/s390/fenv.c b/src/openlibm/s390/fenv.c new file mode 100644 index 0000000..2bcce76 --- /dev/null +++ b/src/openlibm/s390/fenv.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2016 Dan Horák + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * cloned from ppc/fenv.c + */ + +#define __fenv_static +#include + +#ifdef __GNUC_GNU_INLINE__ +#error "This file must be compiled with C99 'inline' semantics" +#endif + +const fenv_t __fe_dfl_env = 0x00000000; + +extern inline int feclearexcept(int __excepts); +extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); +extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts); +extern inline int feraiseexcept(int __excepts); +extern inline int fetestexcept(int __excepts); +extern inline int fegetround(void); +extern inline int fesetround(int __round); +extern inline int fegetenv(fenv_t *__envp); +extern inline int feholdexcept(fenv_t *__envp); +extern inline int fesetenv(const fenv_t *__envp); +extern inline int feupdateenv(const fenv_t *__envp); diff --git a/src/openlibm/src/Make.files b/src/openlibm/src/Make.files new file mode 100644 index 0000000..5170403 --- /dev/null +++ b/src/openlibm/src/Make.files @@ -0,0 +1,78 @@ +$(CUR_SRCS) = common.c \ + e_acos.c e_acosf.c e_acosh.c e_acoshf.c e_asin.c e_asinf.c \ + e_atan2.c e_atan2f.c e_atanh.c e_atanhf.c e_cosh.c e_coshf.c e_exp.c \ + e_expf.c e_fmod.c e_fmodf.c \ + e_hypot.c e_hypotf.c e_j0.c e_j0f.c e_j1.c e_j1f.c \ + e_jn.c e_jnf.c e_lgamma.c e_lgamma_r.c e_lgammaf.c e_lgammaf_r.c \ + e_log.c e_log10.c e_log10f.c e_log2.c e_log2f.c e_logf.c \ + e_pow.c e_powf.c e_remainder.c e_remainderf.c \ + e_rem_pio2.c e_rem_pio2f.c \ + e_sinh.c e_sinhf.c e_sqrt.c e_sqrtf.c \ + k_cos.c k_exp.c k_expf.c k_rem_pio2.c k_sin.c k_tan.c \ + k_cosf.c k_sinf.c k_tanf.c \ + s_asinh.c s_asinhf.c s_atan.c s_atanf.c s_carg.c s_cargf.c \ + s_cbrt.c s_cbrtf.c s_ceil.c s_ceilf.c \ + s_copysign.c s_copysignf.c s_cos.c s_cosf.c \ + s_csqrt.c s_csqrtf.c s_erf.c s_erff.c \ + s_exp2.c s_exp2f.c s_expm1.c s_expm1f.c s_fabs.c s_fabsf.c s_fdim.c \ + s_floor.c s_floorf.c \ + s_fmax.c s_fmaxf.c s_fmin.c \ + s_fminf.c s_fpclassify.c \ + s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \ + s_isinf.c s_isfinite.c s_isnormal.c s_isnan.c \ + s_log1p.c s_log1pf.c s_logb.c s_logbf.c \ + s_modf.c s_modff.c \ + s_nextafter.c s_nextafterf.c \ + s_nexttowardf.c s_remquo.c s_remquof.c \ + s_rint.c s_rintf.c s_round.c s_roundf.c \ + s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \ + s_signgam.c s_sin.c s_sincos.c \ + s_sinf.c s_sincosf.c s_tan.c s_tanf.c s_tanh.c s_tanhf.c s_tgammaf.c \ + s_trunc.c s_truncf.c s_cpow.c s_cpowf.c \ + w_cabs.c w_cabsf.c + +ifneq ($(ARCH), wasm32) + +$(CUR_SRCS) += \ + s_fma.c s_fmaf.c s_lrint.c s_lrintf.c s_lround.c s_lroundf.c \ + s_llrint.c s_llrintf.c s_llround.c s_llroundf.c s_nearbyint.c + +ifneq ($(OS), WINNT) +$(CUR_SRCS) += s_nan.c +endif + +endif + +# Add in long double functions for x86, x64 and aarch64 +ifeq ($(LONG_DOUBLE_NOT_DOUBLE),1) +# C99 long double functions +$(CUR_SRCS) += s_copysignl.c s_fabsl.c s_llrintl.c s_lrintl.c s_modfl.c + +# If long double != double use these; otherwise, we alias the double versions. +$(CUR_SRCS) += e_acosl.c e_asinl.c e_atan2l.c e_fmodl.c \ + s_fmaxl.c s_fminl.c s_ilogbl.c \ + e_hypotl.c e_lgammal.c e_remainderl.c e_sqrtl.c \ + s_atanl.c s_ceill.c s_cosl.c s_cprojl.c \ + s_csqrtl.c s_floorl.c s_fmal.c \ + s_frexpl.c s_logbl.c s_nexttoward.c \ + s_remquol.c s_roundl.c s_lroundl.c s_llroundl.c \ + s_cpowl.c s_cargl.c \ + s_sinl.c s_sincosl.c s_tanl.c s_truncl.c w_cabsl.c \ + s_nextafterl.c s_rintl.c s_scalbnl.c polevll.c \ + s_casinl.c s_ctanl.c \ + s_cimagl.c s_conjl.c s_creall.c s_cacoshl.c s_catanhl.c s_casinhl.c \ + s_catanl.c s_csinl.c s_cacosl.c s_cexpl.c s_csinhl.c s_ccoshl.c \ + s_clogl.c s_ctanhl.c s_ccosl.c s_cbrtl.c +endif + +# C99 complex functions +$(CUR_SRCS) += s_ccosh.c s_ccoshf.c s_cexp.c s_cexpf.c \ + s_cimag.c s_cimagf.c \ + s_conj.c s_conjf.c \ + s_cproj.c s_cprojf.c s_creal.c s_crealf.c \ + s_csinh.c s_csinhf.c s_ctanh.c s_ctanhf.c \ + s_cacos.c s_cacosf.c \ + s_cacosh.c s_cacoshf.c \ + s_casin.c s_casinf.c s_casinh.c s_casinhf.c \ + s_catan.c s_catanf.c s_catanh.c s_catanhf.c \ + s_clog.c s_clogf.c diff --git a/src/openlibm/src/aarch64_fpmath.h b/src/openlibm/src/aarch64_fpmath.h new file mode 100644 index 0000000..e1fdc63 --- /dev/null +++ b/src/openlibm/src/aarch64_fpmath.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2002, 2003 David Schultz + * Copyright (2) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/lib/libc/aarch64/_fpmath.h 281197 2015-04-07 09:52:14Z andrew $ + */ + +#include + +union IEEEl2bits { + long double e; + struct { + uint64_t manl :64; + uint64_t manh :48; + unsigned int exp :15; + unsigned int sign :1; + } bits; + /* TODO andrew: Check the packing here */ + struct { + uint64_t manl :64; + uint64_t manh :48; + unsigned int expsign :16; + } xbits; +}; + +#define LDBL_NBIT 0 +#define LDBL_IMPLICIT_NBIT +#define mask_nbit_l(u) ((void)0) + +#define LDBL_MANH_SIZE 48 +#define LDBL_MANL_SIZE 64 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)((u).bits.manl >> 32); \ + (a)[2] = (uint32_t)(u).bits.manh; \ + (a)[3] = (uint32_t)((u).bits.manh >> 32); \ +} while(0) diff --git a/src/openlibm/src/amd64_fpmath.h b/src/openlibm/src/amd64_fpmath.h new file mode 100644 index 0000000..41b01c3 --- /dev/null +++ b/src/openlibm/src/amd64_fpmath.h @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2002, 2003 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/amd64/_fpmath.h,v 1.7 2008/01/17 16:39:06 bde Exp $ + */ + +union IEEEl2bits { + long double e; + struct { + unsigned int manl :32; + unsigned int manh :32; + unsigned int exp :15; + unsigned int sign :1; + unsigned int junkl :16; + unsigned int junkh :32; + } bits; + struct { + unsigned long man :64; + unsigned int expsign :16; + unsigned long junk :48; + } xbits; +}; + +#define LDBL_NBIT 0x80000000 +#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT) + +#define LDBL_MANH_SIZE 32 +#define LDBL_MANL_SIZE 32 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)(u).bits.manh; \ +} while (0) diff --git a/src/openlibm/src/bsd_cdefs.h b/src/openlibm/src/bsd_cdefs.h new file mode 100644 index 0000000..5799193 --- /dev/null +++ b/src/openlibm/src/bsd_cdefs.h @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 + * $FreeBSD: src/sys/sys/cdefs.h,v 1.114 2011/02/18 21:44:53 nwhitehorn Exp $ + */ + +/* Do not redefine macros if the system provides them in sys/cdefs.h. + * The two macros correspond to different platforms. */ +#ifndef _BSD_CDEFS_H_ +#define _BSD_CDEFS_H_ + +/* + * This code has been put in place to help reduce the addition of + * compiler specific defines in FreeBSD code. It helps to aid in + * having a compiler-agnostic source tree. + */ + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +#if __GNUC__ >= 3 || defined(__INTEL_COMPILER) +#define __GNUCLIKE_ASM 3 +#else +#define __GNUCLIKE_ASM 2 +#endif + +#define __CC_SUPPORTS___INLINE__ 1 + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#if defined(__STDC__) || defined(__cplusplus) + +#define __volatile volatile +#if defined(__cplusplus) +#define __inline inline /* convert to C++ keyword */ +#else +#if !defined(__CC_SUPPORTS___INLINE) +#define __inline /* delete GCC keyword */ +#endif /* ! __CC_SUPPORTS___INLINE */ +#endif /* !__cplusplus */ + +#else /* !(__STDC__ || __cplusplus) */ + +#if !defined(__CC_SUPPORTS___INLINE) +#define __inline +#define __volatile +#endif /* !__CC_SUPPORTS___INLINE */ +#endif /* !(__STDC__ || __cplusplus) */ + +/* + * Macro to test if we're using a specific version of gcc or later. + */ +#ifndef __GNUC_PREREQ__ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define __GNUC_PREREQ__(ma, mi) \ + (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) +#else +#define __GNUC_PREREQ__(ma, mi) 0 +#endif +#endif /* __GNUC_PREREQ__ */ + +/* + * Compiler-dependent macro to help declare pure (no side effects) functions. + * It is null except for versions of gcc that are known to support the features + * properly (old versions of gcc-2 supported the dead and pure features + * in a different (wrong) way), and for icc. If we do not provide an implementation + * for a given compiler, let the compile fail if it is told to use + * a feature that we cannot live without. + */ +#if !defined(__pure2) && (__GNUC_PREREQ__(2, 7) || defined(__INTEL_COMPILER)) +#define __pure2 __attribute__((__const__)) +#endif + +#endif /* !_BSD_CDEFS_H_ */ diff --git a/src/openlibm/src/cdefs-compat.h b/src/openlibm/src/cdefs-compat.h new file mode 100644 index 0000000..834c547 --- /dev/null +++ b/src/openlibm/src/cdefs-compat.h @@ -0,0 +1,105 @@ +#ifndef _CDEFS_COMPAT_H_ +#define _CDEFS_COMPAT_H_ + +#if !defined(__BEGIN_DECLS) +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif +#endif /* !defined(__BEGIN_DECLS) */ + +#ifdef __GNUC__ +#if defined(__strong_alias) && defined(__NetBSD__) +#define openlibm_strong_reference(sym,alias) __strong_alias(alias,sym) +#elif defined(__strong_reference) +#define openlibm_strong_reference(sym,alias) __strong_reference(sym,alias) +#else +#ifdef __APPLE__ +#define openlibm_strong_reference(sym,aliassym) openlibm_weak_reference(sym,aliassym) +#else +#define openlibm_strong_reference(sym,aliassym) \ + OLM_DLLEXPORT extern __typeof (aliassym) aliassym __attribute__ ((__alias__ (#sym))); +#endif /* __APPLE__ */ +#endif /* __strong_reference */ + +#ifdef __wasm__ +#define openlibm_weak_reference(sym,alias) openlibm_strong_reference(sym,alias) +#elif defined(__weak_alias) && defined(__NetBSD__) +#define openlibm_weak_reference(sym,alias) __weak_alias(alias,sym) +#elif defined(__weak_reference) +#define openlibm_weak_reference(sym,alias) __weak_reference(sym,alias) +#else +#ifdef __ELF__ +#ifdef __STDC__ +#define openlibm_weak_reference(sym,alias) \ + __asm__(".weak " #alias); \ + __asm__(".equ " #alias ", " #sym) +#ifdef __warn_references +#define openlibm_warn_references(sym,msg) __warn_references(sym,msg) +#else +#define openlibm_warn_references(sym,msg) \ + __asm__(".section .gnu.warning." #sym); \ + __asm__(".asciz \"" msg "\""); \ + __asm__(".previous") +#endif /* __warn_references */ +#else +#define openlibm_weak_reference(sym,alias) \ + __asm__(".weak alias"); \ + __asm__(".equ alias, sym") +#ifdef __warn_references +#define openlibm_warn_references(sym,msg) __warn_references(sym,msg) +#else +#define openlibm_warn_references(sym,msg) \ + __asm__(".section .gnu.warning.sym"); \ + __asm__(".asciz \"msg\""); \ + __asm__(".previous") +#endif /* __warn_references */ +#endif /* __STDC__ */ +#elif defined(__clang__) /* CLANG */ +#if defined(_WIN32) && defined(_X86_) +#define openlibm_asm_symbol_prefix "_" +#else +#define openlibm_asm_symbol_prefix "" +#endif +#ifdef __STDC__ +#define openlibm_weak_reference(sym,alias) \ + __asm__(".weak_reference " openlibm_asm_symbol_prefix #alias); \ + __asm__(".set " openlibm_asm_symbol_prefix #alias ", " openlibm_asm_symbol_prefix #sym) +#else +#define openlibm_weak_reference(sym,alias) \ + __asm__(".weak_reference openlibm_asm_symbol_prefix/**/alias");\ + __asm__(".set openlibm_asm_symbol_prefix/**/alias, openlibm_asm_symbol_prefix/**/sym") +#endif +#else /* !__ELF__ */ +#ifdef __STDC__ +#define openlibm_weak_reference(sym,alias) \ + __asm__(".stabs \"_" #alias "\",11,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#ifdef __warn_references +#define openlibm_warn_references(sym,msg) __warn_references(sym,msg) +#else +#define openlibm_warn_references(sym,msg) \ + __asm__(".stabs \"" msg "\",30,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#endif /* __warn_references */ +#else +#define openlibm_weak_reference(sym,alias) \ + __asm__(".stabs \"_/**/alias\",11,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#ifdef __warn_references +#define openlibm_warn_references(sym,msg) __warn_references(sym,msg) +#else +#define openlibm_warn_references(sym,msg) \ + __asm__(".stabs msg,30,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#endif /* __warn_references */ +#endif /* __STDC__ */ +#endif /* __ELF__ */ +#endif /* __weak_reference */ +#endif /* __GNUC__ */ + + +#endif /* _CDEFS_COMPAT_H_ */ diff --git a/src/openlibm/src/common.c b/src/openlibm/src/common.c new file mode 100644 index 0000000..b02d697 --- /dev/null +++ b/src/openlibm/src/common.c @@ -0,0 +1,7 @@ +#include + +#include "math_private.h" + +OLM_DLLEXPORT int isopenlibm(void) { + return 1; +} diff --git a/src/openlibm/src/e_acos.c b/src/openlibm/src/e_acos.c new file mode 100644 index 0000000..7295ad6 --- /dev/null +++ b/src/openlibm/src/e_acos.c @@ -0,0 +1,111 @@ + +/* @(#)e_acos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_acos.c,v 1.13 2008/07/31 22:41:26 das Exp $"); + +/* __ieee754_acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include +#include + +#include "math_private.h" + +static const double +one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +pio2_hi = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +static volatile double +pio2_lo = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +static const double +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +OLM_DLLEXPORT double +__ieee754_acos(double x) +{ + double z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3ff00000) { /* |x| >= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) { /* |x|==1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3fe00000) { /* |x| < 0.5 */ + if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ + z = x*x; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*0.5; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + s = sqrt(z); + r = p/q; + w = r*s-pio2_lo; + return pi - 2.0*(s+w); + } else { /* x > 0.5 */ + z = (one-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + r = p/q; + w = r*s+c; + return 2.0*(df+w); + } +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(acos, acosl); +#endif diff --git a/src/openlibm/src/e_acosf.c b/src/openlibm/src/e_acosf.c new file mode 100644 index 0000000..2beab5c --- /dev/null +++ b/src/openlibm/src/e_acosf.c @@ -0,0 +1,78 @@ +/* e_acosf.c -- float version of e_acos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_acosf.c,v 1.11 2008/08/03 17:39:54 das Exp $"); + +#include + +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +pi = 3.1415925026e+00, /* 0x40490fda */ +pio2_hi = 1.5707962513e+00; /* 0x3fc90fda */ +static volatile float +pio2_lo = 7.5497894159e-08; /* 0x33a22168 */ +static const float +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +OLM_DLLEXPORT float +__ieee754_acosf(float x) +{ + float z,p,q,r,w,s,c,df; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3f800000) { /* |x| >= 1 */ + if(ix==0x3f800000) { /* |x| == 1 */ + if(hx>0) return 0.0; /* acos(1) = 0 */ + else return pi+(float)2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(ix<0x3f000000) { /* |x| < 0.5 */ + if(ix<=0x32800000) return pio2_hi+pio2_lo;/*if|x|<2**-26*/ + z = x*x; + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + r = p/q; + return pio2_hi - (x - (pio2_lo-x*r)); + } else if (hx<0) { /* x < -0.5 */ + z = (one+x)*(float)0.5; + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + s = sqrtf(z); + r = p/q; + w = r*s-pio2_lo; + return pi - (float)2.0*(s+w); + } else { /* x > 0.5 */ + int32_t idf; + z = (one-x)*(float)0.5; + s = sqrtf(z); + df = s; + GET_FLOAT_WORD(idf,df); + SET_FLOAT_WORD(df,idf&0xfffff000); + c = (z-df*df)/(s+df); + p = z*(pS0+z*(pS1+z*pS2)); + q = one+z*qS1; + r = p/q; + w = r*s+c; + return (float)2.0*(df+w); + } +} diff --git a/src/openlibm/src/e_acosh.c b/src/openlibm/src/e_acosh.c new file mode 100644 index 0000000..1e783a6 --- /dev/null +++ b/src/openlibm/src/e_acosh.c @@ -0,0 +1,68 @@ + +/* @(#)e_acosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_acosh.c,v 1.9 2008/02/22 02:30:34 das Exp $"); + +/* __ieee754_acosh(x) + * Method : + * Based on + * acosh(x) = log [ x + sqrt(x*x-1) ] + * we have + * acosh(x) := log(x)+ln2, if x is large; else + * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else + * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. + * + * Special cases: + * acosh(x) is NaN with signal if x<1. + * acosh(NaN) is NaN without signal. + */ + +#include +#include + +#include "math_private.h" + +static const double +one = 1.0, +ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */ + +OLM_DLLEXPORT double +__ieee754_acosh(double x) +{ + double t; + int32_t hx; + u_int32_t lx; + EXTRACT_WORDS(hx,lx,x); + if(hx<0x3ff00000) { /* x < 1 */ + return (x-x)/(x-x); + } else if(hx >=0x41b00000) { /* x > 2**28 */ + if(hx >=0x7ff00000) { /* x is inf of NaN */ + return x+x; + } else + return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */ + } else if(((hx-0x3ff00000)|lx)==0) { + return 0.0; /* acosh(1) = 0 */ + } else if (hx > 0x40000000) { /* 2**28 > x > 2 */ + t=x*x; + return __ieee754_log(2.0*x-one/(x+sqrt(t-one))); + } else { /* 1 + +#include "math_private.h" + +static const float +one = 1.0, +ln2 = 6.9314718246e-01; /* 0x3f317218 */ + +OLM_DLLEXPORT float +__ieee754_acoshf(float x) +{ + float t; + int32_t hx; + GET_FLOAT_WORD(hx,x); + if(hx<0x3f800000) { /* x < 1 */ + return (x-x)/(x-x); + } else if(hx >=0x4d800000) { /* x > 2**28 */ + if(hx >=0x7f800000) { /* x is inf of NaN */ + return x+x; + } else + return __ieee754_logf(x)+ln2; /* acosh(huge)=log(2x) */ + } else if (hx==0x3f800000) { + return 0.0; /* acosh(1) = 0 */ + } else if (hx > 0x40000000) { /* 2**28 > x > 2 */ + t=x*x; + return __ieee754_logf((float)2.0*x-one/(x+__ieee754_sqrtf(t-one))); + } else { /* 1. + */ + +#include +#include + +#include "invtrig.h" +#include "math_private.h" + +static const long double +one= 1.00000000000000000000e+00; + +#ifdef __i386__ +/* XXX Work around the fact that gcc truncates long double constants on i386 */ +static volatile double +pi1 = 3.14159265358979311600e+00, /* 0x1.921fb54442d18p+1 */ +pi2 = 1.22514845490862001043e-16; /* 0x1.1a80000000000p-53 */ +#define pi ((long double)pi1 + pi2) +#else +static const long double +pi = 3.14159265358979323846264338327950280e+00L; +#endif + +OLM_DLLEXPORT long double +acosl(long double x) +{ + union IEEEl2bits u; + long double z,p,q,r,w,s,c,df; + int16_t expsign, expt; + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= BIAS) { /* |x| >= 1 */ + if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) { + if (expsign>0) return 0.0; /* acos(1) = 0 */ + else return pi+2.0*pio2_lo; /* acos(-1)= pi */ + } + return (x-x)/(x-x); /* acos(|x|>1) is NaN */ + } + if(expt 0.5 */ + z = (one-x)*0.5; + s = sqrtl(z); + u.e = s; + u.bits.manl = 0; + df = u.e; + c = (z-df*df)/(s+df); + p = P(z); + q = Q(z); + r = p/q; + w = r*s+c; + return 2.0*(df+w); + } +} diff --git a/src/openlibm/src/e_asin.c b/src/openlibm/src/e_asin.c new file mode 100644 index 0000000..e287bf1 --- /dev/null +++ b/src/openlibm/src/e_asin.c @@ -0,0 +1,117 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_asin.c,v 1.15 2011/02/10 07:37:50 das Exp $"); + +/* __ieee754_asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include +#include + +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +huge = 1.000e+300, +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */ + /* coefficient for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +OLM_DLLEXPORT double +__ieee754_asin(double x) +{ + double t=0.0,w,p,q,c,r,s; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>= 0x3ff00000) { /* |x|>= 1 */ + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((ix-0x3ff00000)|lx)==0) + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3fe00000) { /* |x|<0.5 */ + if(ix<0x3e500000) { /* if |x| < 2**-26 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabs(x); + t = w*0.5; + p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); + q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); + s = sqrt(t); + if(ix>=0x3FEF3333) { /* if |x| > 0.975 */ + w = p/q; + t = pio2_hi-(2.0*(s+s*w)-pio2_lo); + } else { + w = s; + SET_LOW_WORD(w,0); + c = (t-w*w)/(s+w); + r = p/q; + p = 2.0*s*r-(pio2_lo-2.0*c); + q = pio4_hi-2.0*w; + t = pio4_hi-(p-q); + } + if(hx>0) return t; else return -t; +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(asin, asinl); +#endif diff --git a/src/openlibm/src/e_asinf.c b/src/openlibm/src/e_asinf.c new file mode 100644 index 0000000..1c1ab2c --- /dev/null +++ b/src/openlibm/src/e_asinf.c @@ -0,0 +1,66 @@ +/* e_asinf.c -- float version of e_asin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_asinf.c,v 1.13 2008/08/08 00:21:27 das Exp $"); + +#include + +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +huge = 1.000e+30, + /* coefficient for R(x^2) */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static const double +pio2 = 1.570796326794896558e+00; + +OLM_DLLEXPORT float +__ieee754_asinf(float x) +{ + double s; + float t,w,p,q; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x3f800000) { /* |x| >= 1 */ + if(ix==0x3f800000) /* |x| == 1 */ + return x*pio2; /* asin(+-1) = +-pi/2 with inexact */ + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (ix<0x3f000000) { /* |x|<0.5 */ + if(ix<0x39800000) { /* |x| < 2**-12 */ + if(huge+x>one) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = t*(pS0+t*(pS1+t*pS2)); + q = one+t*qS1; + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabsf(x); + t = w*(float)0.5; + p = t*(pS0+t*(pS1+t*pS2)); + q = one+t*qS1; + s = sqrt(t); + w = p/q; + t = pio2-2.0*(s+s*w); + if(hx>0) return t; else return -t; +} diff --git a/src/openlibm/src/e_asinl.c b/src/openlibm/src/e_asinl.c new file mode 100644 index 0000000..521913a --- /dev/null +++ b/src/openlibm/src/e_asinl.c @@ -0,0 +1,77 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* FreeBSD: head/lib/msun/src/e_asin.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_asinl.c,v 1.2 2008/08/03 17:49:05 das Exp $"); + +/* + * See comments in e_asin.c. + * Converted to long double by David Schultz . + */ + +#include +#include + +#include "invtrig.h" +#include "math_private.h" + +static const long double +one = 1.00000000000000000000e+00, +huge = 1.000e+300; + +OLM_DLLEXPORT long double +asinl(long double x) +{ + union IEEEl2bits u; + long double t=0.0,w,p,q,c,r,s; + int16_t expsign, expt; + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= BIAS) { /* |x|>= 1 */ + if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) + /* asin(1)=+-pi/2 with inexact */ + return x*pio2_hi+x*pio2_lo; + return (x-x)/(x-x); /* asin(|x|>1) is NaN */ + } else if (exptone) return x;/* return x with inexact if x!=0*/ + } + t = x*x; + p = P(t); + q = Q(t); + w = p/q; + return x+x*w; + } + /* 1> |x|>= 0.5 */ + w = one-fabsl(x); + t = w*0.5; + p = P(t); + q = Q(t); + s = sqrtl(t); + if(u.bits.manh>=THRESH) { /* if |x| is close to 1 */ + w = p/q; + t = pio2_hi-(2.0*(s+s*w)-pio2_lo); + } else { + u.e = s; + u.bits.manl = 0; + w = u.e; + c = (t-w*w)/(s+w); + r = p/q; + p = 2.0*s*r-(pio2_lo-2.0*c); + q = pio4_hi-2.0*w; + t = pio4_hi-(p-q); + } + if(expsign>0) return t; else return -t; +} diff --git a/src/openlibm/src/e_atan2.c b/src/openlibm/src/e_atan2.c new file mode 100644 index 0000000..9b021b9 --- /dev/null +++ b/src/openlibm/src/e_atan2.c @@ -0,0 +1,129 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2.c,v 1.14 2008/08/02 19:17:00 das Exp $"); + +/* __ieee754_atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static volatile double +tiny = 1.0e-300; +static const double +zero = 0.0, +pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */ +pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */ +pi = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +static volatile double +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +OLM_DLLEXPORT double +__ieee754_atan2(double y, double x) +{ + double z; + int32_t k,m,hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + EXTRACT_WORDS(hy,ly,y); + iy = hy&0x7fffffff; + if(((ix|((lx|-lx)>>31))>0x7ff00000)|| + ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */ + return x+y; + if(hx==0x3ff00000&&lx==0) return atan(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if((iy|ly)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7ff00000) { + if(iy==0x7ff00000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>20; + if(k > 60) { /* |y/x| > 2**60 */ + z=pi_o_2+0.5*pi_lo; + m&=1; + } + else if(hx<0&&k<-60) z=0.0; /* 0 > |y|/x > -2**-60 */ + else z=atan(fabs(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(atan2, atan2l); +#endif diff --git a/src/openlibm/src/e_atan2f.c b/src/openlibm/src/e_atan2f.c new file mode 100644 index 0000000..a52a581 --- /dev/null +++ b/src/openlibm/src/e_atan2f.c @@ -0,0 +1,97 @@ +/* e_atan2f.c -- float version of e_atan2.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2f.c,v 1.12 2008/08/03 17:39:54 das Exp $"); + +#include + +#include "math_private.h" + +static volatile float +tiny = 1.0e-30; +static const float +zero = 0.0, +pi_o_4 = 7.8539818525e-01, /* 0x3f490fdb */ +pi_o_2 = 1.5707963705e+00, /* 0x3fc90fdb */ +pi = 3.1415927410e+00; /* 0x40490fdb */ +static volatile float +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +OLM_DLLEXPORT float +__ieee754_atan2f(float y, float x) +{ + float z; + int32_t k,m,hx,hy,ix,iy; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + GET_FLOAT_WORD(hy,y); + iy = hy&0x7fffffff; + if((ix>0x7f800000)|| + (iy>0x7f800000)) /* x or y is NaN */ + return x+y; + if(hx==0x3f800000) return atanf(y); /* x=1.0 */ + m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if(iy==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if(ix==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* when x is INF */ + if(ix==0x7f800000) { + if(iy==0x7f800000) { + switch(m) { + case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */ + case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ + case 2: return (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ + case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + + /* compute y/x */ + k = (iy-ix)>>23; + if(k > 26) { /* |y/x| > 2**26 */ + z=pi_o_2+(float)0.5*pi_lo; + m&=1; + } + else if(k<-26&&hx<0) z=0.0; /* 0 > |y|/x > -2**-26 */ + else z=atanf(fabsf(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/src/openlibm/src/e_atan2l.c b/src/openlibm/src/e_atan2l.c new file mode 100644 index 0000000..1c0a796 --- /dev/null +++ b/src/openlibm/src/e_atan2l.c @@ -0,0 +1,120 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* FreeBSD: head/lib/msun/src/e_atan2.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_atan2l.c,v 1.3 2008/08/02 19:17:00 das Exp $"); + +/* + * See comments in e_atan2.c. + * Converted to long double by David Schultz . + */ + +#include +#include + +#include "invtrig.h" +#include "math_private.h" + +static volatile long double +tiny = 1.0e-300; +static const long double +zero = 0.0; + +#ifdef __i386__ +/* XXX Work around the fact that gcc truncates long double constants on i386 */ +static volatile double +pi1 = 3.14159265358979311600e+00, /* 0x1.921fb54442d18p+1 */ +pi2 = 1.22514845490862001043e-16; /* 0x1.1a80000000000p-53 */ +#define pi ((long double)pi1 + pi2) +#else +static const long double +pi = 3.14159265358979323846264338327950280e+00L; +#endif + +OLM_DLLEXPORT long double +atan2l(long double y, long double x) +{ + union IEEEl2bits ux, uy; + long double z; + int32_t k,m; + int16_t exptx, expsignx, expty, expsigny; + + uy.e = y; + expsigny = uy.xbits.expsign; + expty = expsigny & 0x7fff; + ux.e = x; + expsignx = ux.xbits.expsign; + exptx = expsignx & 0x7fff; + + if ((exptx==BIAS+LDBL_MAX_EXP && + ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)!=0) || /* x is NaN */ + (expty==BIAS+LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* y is NaN */ + return x+y; + if (expsignx==BIAS && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0) + return atanl(y); /* x=1.0 */ + m = ((expsigny>>15)&1)|((expsignx>>14)&2); /* 2*sign(x)+sign(y) */ + + /* when y = 0 */ + if(expty==0 && ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)==0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi+tiny;/* atan(+0,-anything) = pi */ + case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if(exptx==0 && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)==0) + return (expsigny<0)? -pio2_hi-tiny: pio2_hi+tiny; + + /* when x is INF */ + if(exptx==BIAS+LDBL_MAX_EXP) { + if(expty==BIAS+LDBL_MAX_EXP) { + switch(m) { + case 0: return pio2_hi*0.5+tiny;/* atan(+INF,+INF) */ + case 1: return -pio2_hi*0.5-tiny;/* atan(-INF,+INF) */ + case 2: return 1.5*pio2_hi+tiny;/*atan(+INF,-INF)*/ + case 3: return -1.5*pio2_hi-tiny;/*atan(-INF,-INF)*/ + } + } else { + switch(m) { + case 0: return zero ; /* atan(+...,+INF) */ + case 1: return -zero ; /* atan(-...,+INF) */ + case 2: return pi+tiny ; /* atan(+...,-INF) */ + case 3: return -pi-tiny ; /* atan(-...,-INF) */ + } + } + } + /* when y is INF */ + if(expty==BIAS+LDBL_MAX_EXP) + return (expsigny<0)? -pio2_hi-tiny: pio2_hi+tiny; + + /* compute y/x */ + k = expty-exptx; + if(k > LDBL_MANT_DIG+2) { /* |y/x| huge */ + z=pio2_hi+pio2_lo; + m&=1; + } + else if(expsignx<0&&k<-LDBL_MANT_DIG-2) z=0.0; /* |y/x| tiny, x<0 */ + else z=atanl(fabsl(y/x)); /* safe to do y/x */ + switch (m) { + case 0: return z ; /* atan(+,+) */ + case 1: return -z ; /* atan(-,+) */ + case 2: return pi-(z-pi_lo);/* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo)-pi;/* atan(-,-) */ + } +} diff --git a/src/openlibm/src/e_atanh.c b/src/openlibm/src/e_atanh.c new file mode 100644 index 0000000..5e1db91 --- /dev/null +++ b/src/openlibm/src/e_atanh.c @@ -0,0 +1,68 @@ + +/* @(#)e_atanh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_atanh.c,v 1.8 2008/02/22 02:30:34 das Exp $"); + +/* __ieee754_atanh(x) + * Method : + * 1.Reduced x to positive by atanh(-x) = -atanh(x) + * 2.For x>=0.5 + * 1 2x x + * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + * 2 1 - x 1 - x + * + * For x<0.5 + * atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) + * + * Special cases: + * atanh(x) is NaN if |x| > 1 with signal; + * atanh(NaN) is that NaN with no signal; + * atanh(+-1) is +-INF with signal. + * + */ + +#include +#include + +#include "math_private.h" + +static const double one = 1.0, huge = 1e300; +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_atanh(double x) +{ + double t; + int32_t hx,ix; + u_int32_t lx; + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; + if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */ + return (x-x)/(x-x); + if(ix==0x3ff00000) + return x/zero; + if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */ + SET_HIGH_WORD(x,ix); + if(ix<0x3fe00000) { /* x < 0.5 */ + t = x+x; + t = 0.5*log1p(t+t*x/(one-x)); + } else + t = 0.5*log1p((x+x)/(one-x)); + if(hx>=0) return t; else return -t; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(atanh, atanhl); +#endif diff --git a/src/openlibm/src/e_atanhf.c b/src/openlibm/src/e_atanhf.c new file mode 100644 index 0000000..1ce329c --- /dev/null +++ b/src/openlibm/src/e_atanhf.c @@ -0,0 +1,46 @@ +/* e_atanhf.c -- float version of e_atanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_atanhf.c,v 1.7 2008/02/22 02:30:34 das Exp $"); + +#include + +#include "math_private.h" + +static const float one = 1.0, huge = 1e30; + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_atanhf(float x) +{ + float t; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if (ix>0x3f800000) /* |x|>1 */ + return (x-x)/(x-x); + if(ix==0x3f800000) + return x/zero; + if(ix<0x31800000&&(huge+x)>zero) return x; /* x<2**-28 */ + SET_FLOAT_WORD(x,ix); + if(ix<0x3f000000) { /* x < 0.5 */ + t = x+x; + t = (float)0.5*log1pf(t+t*x/(one-x)); + } else + t = (float)0.5*log1pf((x+x)/(one-x)); + if(hx>=0) return t; else return -t; +} diff --git a/src/openlibm/src/e_cosh.c b/src/openlibm/src/e_cosh.c new file mode 100644 index 0000000..2e76570 --- /dev/null +++ b/src/openlibm/src/e_cosh.c @@ -0,0 +1,85 @@ + +/* @(#)e_cosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_cosh.c,v 1.10 2011/10/21 06:28:47 das Exp $"); + +/* __ieee754_cosh(x) + * Method : + * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 + * 1. Replace x by |x| (cosh(x) = cosh(-x)). + * 2. + * [ exp(x) - 1 ]^2 + * 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- + * 2*exp(x) + * + * exp(x) + 1/exp(x) + * ln2/2 <= x <= 22 : cosh(x) := ------------------- + * 2 + * 22 <= x <= lnovft : cosh(x) := exp(x)/2 + * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) + * ln2ovft < x : cosh(x) := huge*huge (overflow) + * + * Special cases: + * cosh(x) is |x| if x is +INF, -INF, or NaN. + * only cosh(0)=1 is exact for finite x. + */ + +#include +#include + +#include "math_private.h" + +static const double one = 1.0, half=0.5, huge = 1.0e300; + +OLM_DLLEXPORT double +__ieee754_cosh(double x) +{ + double t,w; + int32_t ix; + + /* High word of |x|. */ + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) return x*x; + + /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ + if(ix<0x3fd62e43) { + t = expm1(fabs(x)); + w = one+t; + if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */ + return one+(t*t)/(w+w); + } + + /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ + if (ix < 0x40360000) { + t = __ieee754_exp(fabs(x)); + return half*t+half/t; + } + + /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ + if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x408633CE) + return __ldexp_exp(fabs(x), -1); + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(cosh, coshl); +#endif diff --git a/src/openlibm/src/e_coshf.c b/src/openlibm/src/e_coshf.c new file mode 100644 index 0000000..e129659 --- /dev/null +++ b/src/openlibm/src/e_coshf.c @@ -0,0 +1,60 @@ +/* e_coshf.c -- float version of e_cosh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_coshf.c,v 1.9 2011/10/21 06:28:47 das Exp $"); + +#include + +#include "math_private.h" + +static const float one = 1.0, half=0.5, huge = 1.0e30; + +OLM_DLLEXPORT float +__ieee754_coshf(float x) +{ + float t,w; + int32_t ix; + + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) return x*x; + + /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ + if(ix<0x3eb17218) { + t = expm1f(fabsf(x)); + w = one+t; + if (ix<0x39800000) return one; /* cosh(tiny) = 1 */ + return one+(t*t)/(w+w); + } + + /* |x| in [0.5*ln2,9], return (exp(|x|)+1/exp(|x|))/2; */ + if (ix < 0x41100000) { + t = __ieee754_expf(fabsf(x)); + return half*t+half/t; + } + + /* |x| in [9, log(maxfloat)] return half*exp(|x|) */ + if (ix < 0x42b17217) return half*__ieee754_expf(fabsf(x)); + + /* |x| in [log(maxfloat), overflowthresold] */ + if (ix<=0x42b2d4fc) + return __ldexp_expf(fabsf(x), -1); + + /* |x| > overflowthresold, cosh(x) overflow */ + return huge*huge; +} diff --git a/src/openlibm/src/e_exp.c b/src/openlibm/src/e_exp.c new file mode 100644 index 0000000..639b9fe --- /dev/null +++ b/src/openlibm/src/e_exp.c @@ -0,0 +1,171 @@ + +/* @(#)e_exp.c 1.6 04/04/22 */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_exp.c,v 1.14 2011/10/21 06:26:38 das Exp $"); + +/* __ieee754_exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remes algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ------- + * R - r + * r*R1(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - R1(r) + * where + * 2 4 10 + * R1(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then exp(x) overflow + * if x < -7.45133219101941108420e+02 then exp(x) underflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const double +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+300, +o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */ +ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */ +ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +static volatile double +twom1000= 9.33263618503218878990e-302; /* 2**-1000=0x01700000,0*/ + +OLM_DLLEXPORT double +__ieee754_exp(double x) /* default IEEE double exp */ +{ + double y,hi=0.0,lo=0.0,c,t,twopk; + int32_t k=0,xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t lx; + GET_LOW_WORD(lx,x); + if(((hx&0xfffff)|lx)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom1000*twom1000; /* underflow */ + } + + /* this implementation gives 2.7182818284590455 for exp(1.0), + which is well within the allowable error. however, + 2.718281828459045 is closer to the true value so we prefer that + answer, given that 1.0 is such an important argument value. */ + if (x == 1.0) + return 2.718281828459045235360; + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = (int)(invln2*x+halF[xsb]); + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + STRICT_ASSIGN(double, x, hi - lo); + } + else if(hx < 0x3e300000) { /* when |x|<2**-28 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + if(k >= -1021) + INSERT_WORDS(twopk,0x3ff00000+(k<<20), 0); + else + INSERT_WORDS(twopk,0x3ff00000+((k+1000)<<20), 0); + c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + if(k==0) return one-((x*c)/(c-2.0)-x); + else y = one-((lo-(x*c)/(2.0-c))-hi); + if(k >= -1021) { + if (k==1024) return y*2.0*0x1p1023; + return y*twopk; + } else { + return y*twopk*twom1000; + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(exp, expl); +#endif diff --git a/src/openlibm/src/e_expf.c b/src/openlibm/src/e_expf.c new file mode 100644 index 0000000..a239413 --- /dev/null +++ b/src/openlibm/src/e_expf.c @@ -0,0 +1,97 @@ +/* e_expf.c -- float version of e_exp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_expf.c,v 1.16 2011/10/21 06:26:38 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const float +one = 1.0, +halF[2] = {0.5,-0.5,}, +huge = 1.0e+30, +o_threshold= 8.8721679688e+01, /* 0x42b17180 */ +u_threshold= -1.0397208405e+02, /* 0xc2cff1b5 */ +ln2HI[2] ={ 6.9314575195e-01, /* 0x3f317200 */ + -6.9314575195e-01,}, /* 0xbf317200 */ +ln2LO[2] ={ 1.4286067653e-06, /* 0x35bfbe8e */ + -1.4286067653e-06,}, /* 0xb5bfbe8e */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +P1 = 1.6666625440e-1, /* 0xaaaa8f.0p-26 */ +P2 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +static volatile float twom100 = 7.8886090522e-31; /* 2**-100=0x0d800000 */ + +OLM_DLLEXPORT float +__ieee754_expf(float x) +{ + float y,hi=0.0,lo=0.0,c,t,twopk; + int32_t k=0,xsb; + u_int32_t hx; + + GET_FLOAT_WORD(hx,x); + xsb = (hx>>31)&1; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out non-finite argument */ + if(hx >= 0x42b17218) { /* if |x|>=88.721... */ + if(hx>0x7f800000) + return x+x; /* NaN */ + if(hx==0x7f800000) + return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */ + if(x > o_threshold) return huge*huge; /* overflow */ + if(x < u_threshold) return twom100*twom100; /* underflow */ + } + + /* argument reduction */ + if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; + } else { + k = invln2*x+halF[xsb]; + t = k; + hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + lo = t*ln2LO[0]; + } + STRICT_ASSIGN(float, x, hi - lo); + } + else if(hx < 0x39000000) { /* when |x|<2**-14 */ + if(huge+x>one) return one+x;/* trigger inexact */ + } + else k = 0; + + /* x is now in primary range */ + t = x*x; + if(k >= -125) + SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); + else + SET_FLOAT_WORD(twopk,0x3f800000+((k+100)<<23)); + c = x - t*(P1+t*P2); + if(k==0) return one-((x*c)/(c-(float)2.0)-x); + else y = one-((lo-(x*c)/((float)2.0-c))-hi); + if(k >= -125) { + if(k==128) return y*2.0F*0x1p127F; + return y*twopk; + } else { + return y*twopk*twom100; + } +} diff --git a/src/openlibm/src/e_fmod.c b/src/openlibm/src/e_fmod.c new file mode 100644 index 0000000..285da8d --- /dev/null +++ b/src/openlibm/src/e_fmod.c @@ -0,0 +1,133 @@ + +/* @(#)e_fmod.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmod.c,v 1.10 2008/02/22 02:30:34 das Exp $"); + +/* + * __ieee754_fmod(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include + +#include "math_private.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +OLM_DLLEXPORT double +__ieee754_fmod(double x, double y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t lx,ly,lz; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx>31); lx = lx+lx;} + else { + if((hz|lz)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + hx = hz+hz+(lz>>31); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + INSERT_WORDS(x,hx|sx,lx); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((u_int32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = sx; + } else { + lx = hx>>(n-32); hx = sx; + } + INSERT_WORDS(x,hx|sx,lx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/src/openlibm/src/e_fmodf.c b/src/openlibm/src/e_fmodf.c new file mode 100644 index 0000000..88fd8ae --- /dev/null +++ b/src/openlibm/src/e_fmodf.c @@ -0,0 +1,105 @@ +/* e_fmodf.c -- float version of e_fmod.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmodf.c,v 1.7 2008/02/22 02:30:34 das Exp $"); + +/* + * __ieee754_fmodf(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include + +#include "math_private.h" + +static const float one = 1.0, Zero[] = {0.0, -0.0,}; + +OLM_DLLEXPORT float +__ieee754_fmodf(float x, float y) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if(hy==0||(hx>=0x7f800000)|| /* y=0,or x not finite */ + (hy>0x7f800000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx>31]; /* |x|=|y| return x*0*/ + + /* determine ix = ilogb(x) */ + if(hx<0x00800000) { /* subnormal x */ + for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; + } else ix = (hx>>23)-127; + + /* determine iy = ilogb(y) */ + if(hy<0x00800000) { /* subnormal y */ + for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1; + } else iy = (hy>>23)-127; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -126) + hx = 0x00800000|(0x007fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -126-ix; + hx = hx<= -126) + hy = 0x00800000|(0x007fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -126-iy; + hy = hy<>31]; + hx = hz+hz; + } + } + hz=hx-hy; + if(hz>=0) {hx=hz;} + + /* convert back to floating value and restore the sign */ + if(hx==0) /* return sign(x)*0 */ + return Zero[(u_int32_t)sx>>31]; + while(hx<0x00800000) { /* normalize x */ + hx = hx+hx; + iy -= 1; + } + if(iy>= -126) { /* normalize output */ + hx = ((hx-0x00800000)|((iy+127)<<23)); + SET_FLOAT_WORD(x,hx|sx); + } else { /* subnormal output */ + n = -126 - iy; + hx >>= n; + SET_FLOAT_WORD(x,hx|sx); + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} diff --git a/src/openlibm/src/e_fmodl.c b/src/openlibm/src/e_fmodl.c new file mode 100644 index 0000000..47d961b --- /dev/null +++ b/src/openlibm/src/e_fmodl.c @@ -0,0 +1,150 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_fmodl.c,v 1.2 2008/07/31 20:09:47 das Exp $"); + +#include +#include +#include + +#include "fpmath.h" + +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +#if LDBL_MANL_SIZE > 32 +typedef u_int64_t manl_t; +#else +typedef u_int32_t manl_t; +#endif + +#if LDBL_MANH_SIZE > 32 +typedef u_int64_t manh_t; +#else +typedef u_int32_t manh_t; +#endif + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS LDBL_MANH_SIZE +#else +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (LDBL_MANH_SIZE - 1) +#endif + +#define MANL_SHIFT (LDBL_MANL_SIZE - 1) + +static const long double one = 1.0, Zero[] = {0.0, -0.0,}; + +/* + * fmodl(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +OLM_DLLEXPORT long double +fmodl(long double x, long double y) +{ + union IEEEl2bits ux, uy; + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + manh_t hy; + manl_t lx,ly,lz; + int ix,iy,n,sx; + + ux.e = x; + uy.e = y; + sx = ux.bits.sign; + + /* purge off exception values */ + if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */ + (ux.bits.exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (uy.bits.exp == BIAS + LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(ux.bits.exp<=uy.bits.exp) { + if((ux.bits.exp>MANL_SHIFT); lx = lx+lx;} + else { + if ((hz|lz)==0) /* return sign(x)*0 */ + return Zero[sx]; + hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; + } + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) /* return sign(x)*0 */ + return Zero[sx]; + while(hx<(1ULL<>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + ux.bits.manh = hx; /* The mantissa is truncated here if needed. */ + ux.bits.manl = lx; + if (iy < LDBL_MIN_EXP) { + ux.bits.exp = iy + (BIAS + 512); + ux.e *= 0x1p-512; + } else { + ux.bits.exp = iy + BIAS; + } + x = ux.e * one; /* create necessary signal */ + return x; /* exact output */ +} diff --git a/src/openlibm/src/e_hypot.c b/src/openlibm/src/e_hypot.c new file mode 100644 index 0000000..3f4c1d1 --- /dev/null +++ b/src/openlibm/src/e_hypot.c @@ -0,0 +1,131 @@ + +/* @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypot.c,v 1.14 2011/10/15 07:00:28 das Exp $"); + +/* __ieee754_hypot(x,y) + * + * Method : + * If (assume round-to-nearest) z=x*x+y*y + * has error less than sqrt(2)/2 ulp, than + * sqrt(z) has error less than 1 ulp (exercise). + * + * So, compute sqrt(x*x+y*y) with some care as + * follows to get the error below 1 ulp: + * + * Assume x>y>0; + * (if possible, set rounding to round-to-nearest) + * 1. if x > 2y use + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + * where x1 = x with lower 32 bits cleared, x2 = x-x1; else + * 2. if x <= 2y use + * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y)) + * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, + * y1= y with lower 32 bits chopped, y2 = y-y1. + * + * NOTE: scaling may be necessary if some argument is too + * large or too tiny + * + * Special cases: + * hypot(x,y) is INF if x or y is +INF or -INF; else + * hypot(x,y) is NAN if x or y is NAN. + * + * Accuracy: + * hypot(x,y) returns sqrt(x^2+y^2) with error less + * than 1 ulps (units in the last place) + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +__ieee754_hypot(double x, double y) +{ + double a,b,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_HIGH_WORD(ha,x); + ha &= 0x7fffffff; + GET_HIGH_WORD(hb,y); + hb &= 0x7fffffff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabs(a); + b = fabs(b); + if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */ + k=0; + if(ha > 0x5f300000) { /* a>2**500 */ + if(ha >= 0x7ff00000) { /* Inf or NaN */ + u_int32_t low; + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabs(x+0.0)-fabs(y+0.0); + GET_LOW_WORD(low,a); + if(((ha&0xfffff)|low)==0) w = a; + GET_LOW_WORD(low,b); + if(((hb^0x7ff00000)|low)==0) w = b; + return w; + } + /* scale a and b by 2**-600 */ + ha -= 0x25800000; hb -= 0x25800000; k += 600; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + if(hb < 0x20b00000) { /* b < 2**-500 */ + if(hb <= 0x000fffff) { /* subnormal b or 0 */ + u_int32_t low; + GET_LOW_WORD(low,b); + if((hb|low)==0) return a; + t1=0; + SET_HIGH_WORD(t1,0x7fd00000); /* t1=2^1022 */ + b *= t1; + a *= t1; + k -= 1022; + } else { /* scale a and b by 2^600 */ + ha += 0x25800000; /* a *= 2^600 */ + hb += 0x25800000; /* b *= 2^600 */ + k -= 600; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = 0; + SET_HIGH_WORD(t1,ha); + t2 = a-t1; + w = sqrt(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + y1 = 0; + SET_HIGH_WORD(y1,hb); + y2 = b - y1; + t1 = 0; + SET_HIGH_WORD(t1,ha+0x00100000); + t2 = a - t1; + w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int32_t high; + t1 = 1.0; + GET_HIGH_WORD(high,t1); + SET_HIGH_WORD(t1,high+(k<<20)); + return t1*w; + } else return w; +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(hypot, hypotl); +#endif diff --git a/src/openlibm/src/e_hypotf.c b/src/openlibm/src/e_hypotf.c new file mode 100644 index 0000000..e90fb5d --- /dev/null +++ b/src/openlibm/src/e_hypotf.c @@ -0,0 +1,84 @@ +/* e_hypotf.c -- float version of e_hypot.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypotf.c,v 1.14 2011/10/15 07:00:28 das Exp $"); + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +__ieee754_hypotf(float x, float y) +{ + float a,b,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_FLOAT_WORD(ha,x); + ha &= 0x7fffffff; + GET_FLOAT_WORD(hb,y); + hb &= 0x7fffffff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabsf(a); + b = fabsf(b); + if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */ + k=0; + if(ha > 0x58800000) { /* a>2**50 */ + if(ha >= 0x7f800000) { /* Inf or NaN */ + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabsf(x+0.0F)-fabsf(y+0.0F); + if(ha == 0x7f800000) w = a; + if(hb == 0x7f800000) w = b; + return w; + } + /* scale a and b by 2**-68 */ + ha -= 0x22000000; hb -= 0x22000000; k += 68; + SET_FLOAT_WORD(a,ha); + SET_FLOAT_WORD(b,hb); + } + if(hb < 0x26800000) { /* b < 2**-50 */ + if(hb <= 0x007fffff) { /* subnormal b or 0 */ + if(hb==0) return a; + SET_FLOAT_WORD(t1,0x7e800000); /* t1=2^126 */ + b *= t1; + a *= t1; + k -= 126; + } else { /* scale a and b by 2^68 */ + ha += 0x22000000; /* a *= 2^68 */ + hb += 0x22000000; /* b *= 2^68 */ + k -= 68; + SET_FLOAT_WORD(a,ha); + SET_FLOAT_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + SET_FLOAT_WORD(t1,ha&0xfffff000); + t2 = a-t1; + w = __ieee754_sqrtf(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + SET_FLOAT_WORD(y1,hb&0xfffff000); + y2 = b - y1; + SET_FLOAT_WORD(t1,(ha+0x00800000)&0xfffff000); + t2 = a - t1; + w = __ieee754_sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + SET_FLOAT_WORD(t1,0x3f800000+(k<<23)); + return t1*w; + } else return w; +} diff --git a/src/openlibm/src/e_hypotl.c b/src/openlibm/src/e_hypotl.c new file mode 100644 index 0000000..2632774 --- /dev/null +++ b/src/openlibm/src/e_hypotl.c @@ -0,0 +1,124 @@ +/* From: @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_hypotl.c,v 1.3 2011/10/16 05:36:39 das Exp $"); + +/* long double version of hypot(). See e_hypot.c for most comments. */ + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#define GET_LDBL_MAN(h, l, v) do { \ + union IEEEl2bits uv; \ + \ + uv.e = v; \ + h = uv.bits.manh; \ + l = uv.bits.manl; \ +} while (0) + +#undef GET_HIGH_WORD +#define GET_HIGH_WORD(i, v) GET_LDBL_EXPSIGN(i, v) +#undef SET_HIGH_WORD +#define SET_HIGH_WORD(v, i) SET_LDBL_EXPSIGN(v, i) + +#define DESW(exp) (exp) /* delta expsign word */ +#define ESW(exp) (MAX_EXP - 1 + (exp)) /* expsign word */ +#define MANT_DIG LDBL_MANT_DIG +#define MAX_EXP LDBL_MAX_EXP + +#if LDBL_MANL_SIZE > 32 +typedef u_int64_t man_t; +#else +typedef u_int32_t man_t; +#endif + +OLM_DLLEXPORT long double +hypotl(long double x, long double y) +{ + long double a=x,b=y,t1,t2,y1,y2,w; + int32_t j,k,ha,hb; + + GET_HIGH_WORD(ha,x); + ha &= 0x7fff; + GET_HIGH_WORD(hb,y); + hb &= 0x7fff; + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + a = fabsl(a); + b = fabsl(b); + if((ha-hb)>DESW(MANT_DIG+7)) {return a+b;} /* x/y > 2**(MANT_DIG+7) */ + k=0; + if(ha > ESW(MAX_EXP/2-12)) { /* a>2**(MAX_EXP/2-12) */ + if(ha >= ESW(MAX_EXP)) { /* Inf or NaN */ + man_t manh, manl; + /* Use original arg order iff result is NaN; quieten sNaNs. */ + w = fabsl(x+0.0)-fabsl(y+0.0); + GET_LDBL_MAN(manh,manl,a); + if (manh == LDBL_NBIT && manl == 0) w = a; + GET_LDBL_MAN(manh,manl,b); + if (hb >= ESW(MAX_EXP) && manh == LDBL_NBIT && manl == 0) w = b; + return w; + } + /* scale a and b by 2**-(MAX_EXP/2+88) */ + ha -= DESW(MAX_EXP/2+88); hb -= DESW(MAX_EXP/2+88); + k += MAX_EXP/2+88; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + if(hb < ESW(-(MAX_EXP/2-12))) { /* b < 2**-(MAX_EXP/2-12) */ + if(hb <= 0) { /* subnormal b or 0 */ + man_t manh, manl; + GET_LDBL_MAN(manh,manl,b); + if((manh|manl)==0) return a; + t1=1; + SET_HIGH_WORD(t1,ESW(MAX_EXP-2)); /* t1=2^(MAX_EXP-2) */ + b *= t1; + a *= t1; + k -= MAX_EXP-2; + } else { /* scale a and b by 2^(MAX_EXP/2+88) */ + ha += DESW(MAX_EXP/2+88); + hb += DESW(MAX_EXP/2+88); + k -= MAX_EXP/2+88; + SET_HIGH_WORD(a,ha); + SET_HIGH_WORD(b,hb); + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = a; + union IEEEl2bits uv; + uv.e = t1; uv.bits.manl = 0; t1 = uv.e; + t2 = a-t1; + w = sqrtl(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + y1 = b; + union IEEEl2bits uv; + uv.e = y1; uv.bits.manl = 0; y1 = uv.e; + y2 = b - y1; + t1 = a; + uv.e = t1; uv.bits.manl = 0; t1 = uv.e; + t2 = a - t1; + w = sqrtl(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + u_int32_t high; + t1 = 1.0; + GET_HIGH_WORD(high,t1); + SET_HIGH_WORD(t1,high+DESW(k)); + return t1*w; + } else return w; +} diff --git a/src/openlibm/src/e_j0.c b/src/openlibm/src/e_j0.c new file mode 100644 index 0000000..a2419d3 --- /dev/null +++ b/src/openlibm/src/e_j0.c @@ -0,0 +1,388 @@ + +/* @(#)e_j0.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_j0.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +/* __ieee754_j0(x), __ieee754_y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include + +#include "math_private.h" + +static double pzero(double), qzero(double); + +static const double +huge = 1e300, +one = 1.0, +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + /* R0/S0 on [0, 2.00] */ +R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ +R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ +R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ +R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ +S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ +S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ +S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ +S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_j0(double x) +{ + double z, s,c,ss,cc,r,u,v; + int32_t hx,ix; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return one/(x*x); + x = fabs(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(x); + c = cos(x); + ss = s-c; + cc = s+c; + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = -cos(x+x); + if ((s*c)0x48000000) z = (invsqrtpi*cc)/sqrt(x); + else { + u = pzero(x); v = qzero(x); + z = invsqrtpi*(u*cc-v*ss)/sqrt(x); + } + return z; + } + if(ix<0x3f200000) { /* |x| < 2**-13 */ + if(huge+x>one) { /* raise inexact if x != 0 */ + if(ix<0x3e400000) return one; /* |x|<2**-27 */ + else return one - 0.25*x*x; + } + } + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = one+z*(S01+z*(S02+z*(S03+z*S04))); + if(ix < 0x3FF00000) { /* |x| < 1.00 */ + return one + z*(-0.25+(r/s)); + } else { + u = 0.5*x; + return((one+u)*(one-u)+z*(r/s)); + } +} + +static const double +u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ +u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ +u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ +u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ +u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ +u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ +u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ +v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ +v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ +v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ +v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +OLM_DLLEXPORT double +__ieee754_y0(double x) +{ + double z, s,c,ss,cc,u,v; + int32_t hx,ix,lx; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */ + if(ix>=0x7ff00000) return one/(x+x*x); + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) + * where x0 = x-pi/4 + * Better formula: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) + cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + s = sin(x); + c = cos(x); + ss = s-c; + cc = s+c; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = -cos(x+x); + if ((s*c)0x48000000) z = (invsqrtpi*ss)/sqrt(x); + else { + u = pzero(x); v = qzero(x); + z = invsqrtpi*(u*ss+v*cc)/sqrt(x); + } + return z; + } + if(ix<=0x3e400000) { /* x < 2**-27 */ + return(u00 + tpi*__ieee754_log(x)); + } + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = one+z*(v01+z*(v02+z*(v03+z*v04))); + return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x))); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + + /* Note: This function is only called for ix>=0x40000000 (see above) */ + static double pzero(double x) +{ + const double *p,*q; + double z,r,s; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + assert(ix>=0x40000000 && ix<=0x48000000); + if(ix>=0x40200000) {p = pR8; q= pS8;} + else if(ix>=0x40122E8B){p = pR5; q= pS5;} + else if(ix>=0x4006DB6D){p = pR3; q= pS3;} + else {p = pR2; q= pS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + + /* Note: This function is only called for ix>=0x40000000 (see above) */ + static double qzero(double x) +{ + const double *p,*q; + double s,r,z; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + assert(ix>=0x40000000 && ix<=0x48000000); + if(ix>=0x40200000) {p = qR8; q= qS8;} + else if(ix>=0x40122E8B){p = qR5; q= qS5;} + else if(ix>=0x4006DB6D){p = qR3; q= qS3;} + else {p = qR2; q= qS2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125 + r/s)/x; +} diff --git a/src/openlibm/src/e_j0f.c b/src/openlibm/src/e_j0f.c new file mode 100644 index 0000000..62258b1 --- /dev/null +++ b/src/openlibm/src/e_j0f.c @@ -0,0 +1,337 @@ +/* e_j0f.c -- float version of e_j0.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include "cdefs-compat.h" + +#include +#include "math_private.h" + +static float pzerof(float), qzerof(float); + +static const float +huge = 1e30, +one = 1.0, +invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01, /* 0x3f22f983 */ + /* R0/S0 on [0, 2.00] */ +R02 = 1.5625000000e-02, /* 0x3c800000 */ +R03 = -1.8997929874e-04, /* 0xb947352e */ +R04 = 1.8295404516e-06, /* 0x35f58e88 */ +R05 = -4.6183270541e-09, /* 0xb19eaf3c */ +S01 = 1.5619102865e-02, /* 0x3c7fe744 */ +S02 = 1.1692678527e-04, /* 0x38f53697 */ +S03 = 5.1354652442e-07, /* 0x3509daa6 */ +S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_j0f(float x) +{ + float z, s,c,ss,cc,r,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return one/(x*x); + x = fabsf(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(x); + c = cosf(x); + ss = s-c; + cc = s+c; + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = -cosf(x+x); + if ((s*c)0x58000000) z = (invsqrtpi*cc)/sqrtf(x); /* |x|>2**49 */ + else { + u = pzerof(x); v = qzerof(x); + z = invsqrtpi*(u*cc-v*ss)/sqrtf(x); + } + return z; + } + if(ix<0x3b000000) { /* |x| < 2**-9 */ + if(huge+x>one) { /* raise inexact if x != 0 */ + if(ix<0x39800000) return one; /* |x|<2**-12 */ + else return one - x*x/4; + } + } + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = one+z*(S01+z*(S02+z*(S03+z*S04))); + if(ix < 0x3F800000) { /* |x| < 1.00 */ + return one + z*((float)-0.25+(r/s)); + } else { + u = (float)0.5*x; + return((one+u)*(one-u)+z*(r/s)); + } +} + +static const float +u00 = -7.3804296553e-02, /* 0xbd9726b5 */ +u01 = 1.7666645348e-01, /* 0x3e34e80d */ +u02 = -1.3818567619e-02, /* 0xbc626746 */ +u03 = 3.4745343146e-04, /* 0x39b62a69 */ +u04 = -3.8140706238e-06, /* 0xb67ff53c */ +u05 = 1.9559013964e-08, /* 0x32a802ba */ +u06 = -3.9820518410e-11, /* 0xae2f21eb */ +v01 = 1.2730483897e-02, /* 0x3c509385 */ +v02 = 7.6006865129e-05, /* 0x389f65e0 */ +v03 = 2.5915085189e-07, /* 0x348b216c */ +v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +OLM_DLLEXPORT float +__ieee754_y0f(float x) +{ + float z, s,c,ss,cc,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */ + if(ix>=0x7f800000) return one/(x+x*x); + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0)) + * where x0 = x-pi/4 + * Better formula: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) + cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + s = sinf(x); + c = cosf(x); + ss = s-c; + cc = s+c; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = -cosf(x+x); + if ((s*c)0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */ + else { + u = pzerof(x); v = qzerof(x); + z = invsqrtpi*(u*ss+v*cc)/sqrtf(x); + } + return z; + } + if(ix<=0x39000000) { /* x < 2**-13 */ + return(u00 + tpi*__ieee754_logf(x)); + } + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = one+z*(v01+z*(v02+z*(v03+z*v04))); + return(u/v + tpi*(__ieee754_j0f(x)*__ieee754_logf(x))); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + + static float pzerof(float x) +{ + const float *p,*q; + float z,r,s; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = pR8; q= pS8;} + else if(ix>=0x409173eb){p = pR5; q= pS5;} + else if(ix>=0x4036d917){p = pR3; q= pS3;} + else {p = pR2; q= pS2;} /* ix>=0x40000000 */ + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + + static float qzerof(float x) +{ + const float *p,*q; + float s,r,z; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = qR8; q= qS8;} + else if(ix>=0x409173eb){p = qR5; q= qS5;} + else if(ix>=0x4036d917){p = qR3; q= qS3;} + else {p = qR2; q= qS2;} /* ix>=0x40000000 */ + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-(float).125 + r/s)/x; +} diff --git a/src/openlibm/src/e_j1.c b/src/openlibm/src/e_j1.c new file mode 100644 index 0000000..4be57cd --- /dev/null +++ b/src/openlibm/src/e_j1.c @@ -0,0 +1,383 @@ + +/* @(#)e_j1.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_j1.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +/* __ieee754_j1(x), __ieee754_y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include + +#include "math_private.h" + +static double pone(double), qone(double); + +static const double +huge = 1e300, +one = 1.0, +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + /* R0/S0 on [0,2] */ +r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ +r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ +r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ +r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ +s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ +s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ +s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ +s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ +s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_j1(double x) +{ + double z, s,c,ss,cc,r,u,v,y; + int32_t hx,ix; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return one/x; + y = fabs(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(y); + c = cos(y); + ss = -s-c; + cc = s-c; + if(ix<0x7fe00000) { /* make sure y+y not overflow */ + z = cos(y+y); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* + * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) + * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) + */ + if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y); + else { + u = pone(y); v = qone(y); + z = invsqrtpi*(u*cc-v*ss)/sqrt(y); + } + if(hx<0) return -z; + else return z; + } + if(ix<0x3e400000) { /* |x|<2**-27 */ + if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */ + } + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + r *= x; + return(x*0.5+r/s); +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +OLM_DLLEXPORT double +__ieee754_y1(double x) +{ + double z, s,c,ss,cc,u,v; + int32_t hx,ix,lx; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ + if(ix>=0x7ff00000) return one/(x+x*x); + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sin(x); + c = cos(x); + ss = -s-c; + cc = s-c; + if(ix<0x7fe00000) { /* make sure x+x not overflow */ + z = cos(x+x); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) + * where x0 = x-3pi/4 + * Better formula: + * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (cos(x) + sin(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x); + else { + u = pone(x); v = qone(x); + z = invsqrtpi*(u*ss+v*cc)/sqrt(x); + } + return z; + } + if(ix<=0x3c900000) { /* x < 2**-54 */ + return(-tpi/x); + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x)); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + + /* Note: This function is only called for ix>=0x40000000 (see above) */ + static double pone(double x) +{ + const double *p,*q; + double z,r,s; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + assert(ix>=0x40000000 && ix<=0x48000000); + if(ix>=0x40200000) {p = pr8; q= ps8;} + else if(ix>=0x40122E8B){p = pr5; q= ps5;} + else if(ix>=0x4006DB6D){p = pr3; q= ps3;} + else {p = pr2; q= ps2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + + /* Note: This function is only called for ix>=0x40000000 (see above) */ + static double qone(double x) +{ + const double *p,*q; + double s,r,z; + int32_t ix; + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + assert(ix>=0x40000000 && ix<=0x48000000); + if(ix>=0x40200000) {p = qr8; q= qs8;} + else if(ix>=0x40122E8B){p = qr5; q= qs5;} + else if(ix>=0x4006DB6D){p = qr3; q= qs3;} + else {p = qr2; q= qs2;} + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375 + r/s)/x; +} diff --git a/src/openlibm/src/e_j1f.c b/src/openlibm/src/e_j1f.c new file mode 100644 index 0000000..ac32c6f --- /dev/null +++ b/src/openlibm/src/e_j1f.c @@ -0,0 +1,332 @@ +/* e_j1f.c -- float version of e_j1.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include "cdefs-compat.h" +#include +#include "math_private.h" + +static float ponef(float), qonef(float); + +static const float +huge = 1e30, +one = 1.0, +invsqrtpi= 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01, /* 0x3f22f983 */ + /* R0/S0 on [0,2] */ +r00 = -6.2500000000e-02, /* 0xbd800000 */ +r01 = 1.4070566976e-03, /* 0x3ab86cfd */ +r02 = -1.5995563444e-05, /* 0xb7862e36 */ +r03 = 4.9672799207e-08, /* 0x335557d2 */ +s01 = 1.9153760746e-02, /* 0x3c9ce859 */ +s02 = 1.8594678841e-04, /* 0x3942fab6 */ +s03 = 1.1771846857e-06, /* 0x359dffc2 */ +s04 = 5.0463624390e-09, /* 0x31ad6446 */ +s05 = 1.2354227016e-11; /* 0x2d59567e */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_j1f(float x) +{ + float z, s,c,ss,cc,r,u,v,y; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return one/x; + y = fabsf(x); + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(y); + c = cosf(y); + ss = -s-c; + cc = s-c; + if(ix<0x7f000000) { /* make sure y+y not overflow */ + z = cosf(y+y); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* + * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x) + * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x) + */ + if(ix>0x58000000) z = (invsqrtpi*cc)/sqrtf(y); /* |x|>2**49 */ + else { + u = ponef(y); v = qonef(y); + z = invsqrtpi*(u*cc-v*ss)/sqrtf(y); + } + if(hx<0) return -z; + else return z; + } + if(ix<0x39000000) { /* |x|<2**-13 */ + if(huge+x>one) return (float)0.5*x;/* inexact if x!=0 necessary */ + } + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + r *= x; + return(x*(float)0.5+r/s); +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +OLM_DLLEXPORT float +__ieee754_y1f(float x) +{ + float z, s,c,ss,cc,u,v; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */ + if(ix>=0x7f800000) return one/(x+x*x); + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + if(ix >= 0x40000000) { /* |x| >= 2.0 */ + s = sinf(x); + c = cosf(x); + ss = -s-c; + cc = s-c; + if(ix<0x7f000000) { /* make sure x+x not overflow */ + z = cosf(x+x); + if ((s*c)>zero) cc = z/ss; + else ss = z/cc; + } + /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0)) + * where x0 = x-3pi/4 + * Better formula: + * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (cos(x) + sin(x)) + * To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one. + */ + if(ix>0x58000000) z = (invsqrtpi*ss)/sqrtf(x); /* |x|>2**49 */ + else { + u = ponef(x); v = qonef(x); + z = invsqrtpi*(u*ss+v*cc)/sqrtf(x); + } + return z; + } + if(ix<=0x33000000) { /* x < 2**-25 */ + return(-tpi/x); + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return(x*(u/v) + tpi*(__ieee754_j1f(x)*__ieee754_logf(x)-one/x)); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + + static float ponef(float x) +{ + const float *p,*q; + float z,r,s; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = pr8; q= ps8;} + else if(ix>=0x409173eb){p = pr5; q= ps5;} + else if(ix>=0x4036d917){p = pr3; q= ps3;} + else {p = pr2; q= ps2;} /* ix>=0x40000000 */ + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return one+ r/s; +} + + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + + static float qonef(float x) +{ + const float *p,*q; + float s,r,z; + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + if(ix>=0x41000000) {p = qr8; q= qs8;} + else if(ix>=0x409173eb){p = qr5; q= qs5;} + else if(ix>=0x4036d917){p = qr3; q= qs3;} + else {p = qr2; q= qs2;} /* ix>=0x40000000 */ + z = one/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return ((float).375 + r/s)/x; +} diff --git a/src/openlibm/src/e_jn.c b/src/openlibm/src/e_jn.c new file mode 100644 index 0000000..1a53965 --- /dev/null +++ b/src/openlibm/src/e_jn.c @@ -0,0 +1,271 @@ + +/* @(#)e_jn.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_jn.c,v 1.11 2010/11/13 10:54:10 uqs Exp $"); + +/* + * __ieee754_jn(n, x), __ieee754_yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for nx, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + * + */ + +#include + +#include "math_private.h" + +static const double +invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ +one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */ + +static const double zero = 0.00000000000000000000e+00; + +OLM_DLLEXPORT double +__ieee754_jn(int n, double x) +{ + int32_t i,hx,ix,lx, sgn; + double a, b, temp, di; + double z, w; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if J(n,NaN) is NaN */ + if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; + if(n<0){ + n = -n; + x = -x; + hx ^= 0x80000000; + } + if(n==0) return(__ieee754_j0(x)); + if(n==1) return(__ieee754_j1(x)); + sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */ + x = fabs(x); + if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */ + b = zero; + else if((double)n<=x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if(ix>=0x52D00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(n&3) { + case 0: temp = cos(x)+sin(x); break; + case 1: temp = -cos(x)+sin(x); break; + case 2: temp = -cos(x)-sin(x); break; + case 3: temp = cos(x)-sin(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = __ieee754_j0(x); + b = __ieee754_j1(x); + for(i=1;i33) /* underflow */ + b = zero; + else { + temp = x*0.5; b = temp; + for (a=one,i=2;i<=n;i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t,v; + double q0,q1,h,tmp; int32_t k,m; + w = (n+n)/(double)x; h = 2.0/(double)x; + q0 = w; z = w+h; q1 = w*z - 1.0; k=1; + while(q1<1.0e9) { + k += 1; z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + m = n+n; + for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t); + a = t; + b = one; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = n; + v = two/x; + tmp = tmp*__ieee754_log(fabs(v*tmp)); + if(tmp<7.09782712893383973096e+02) { + for(i=n-1,di=(double)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + } + } else { + for(i=n-1,di=(double)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + /* scale b to avoid spurious overflow */ + if(b>1e100) { + a /= b; + t /= b; + b = one; + } + } + } + z = __ieee754_j0(x); + w = __ieee754_j1(x); + if (fabs(z) >= fabs(w)) + b = (t*z/b); + else + b = (t*w/a); + } + } + if(sgn==1) return -b; else return b; +} + +OLM_DLLEXPORT double +__ieee754_yn(int n, double x) +{ + int32_t i,hx,ix,lx; + int32_t sign; + double a, b, temp; + + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + /* if Y(n,NaN) is NaN */ + if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; + if((ix|lx)==0) return -one/zero; + if(hx<0) return zero/zero; + sign = 1; + if(n<0){ + n = -n; + sign = 1 - ((n&1)<<1); + } + if(n==0) return(__ieee754_y0(x)); + if(n==1) return(sign*__ieee754_y1(x)); + if(ix==0x7ff00000) return zero; + if(ix>=0x52D00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(n&3) { + case 0: temp = sin(x)-cos(x); break; + case 1: temp = -sin(x)-cos(x); break; + case 2: temp = -sin(x)+cos(x); break; + case 3: temp = sin(x)+cos(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + u_int32_t high; + a = __ieee754_y0(x); + b = __ieee754_y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(high,b); + for(i=1;i0) return b; else return -b; +} diff --git a/src/openlibm/src/e_jnf.c b/src/openlibm/src/e_jnf.c new file mode 100644 index 0000000..cb73e86 --- /dev/null +++ b/src/openlibm/src/e_jnf.c @@ -0,0 +1,200 @@ +/* e_jnf.c -- float version of e_jn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_jnf.c,v 1.11 2010/11/13 10:54:10 uqs Exp $"); + +#include + +#include "math_private.h" + +static const float +two = 2.0000000000e+00, /* 0x40000000 */ +one = 1.0000000000e+00; /* 0x3F800000 */ + +static const float zero = 0.0000000000e+00; + +OLM_DLLEXPORT float +__ieee754_jnf(int n, float x) +{ + int32_t i,hx,ix, sgn; + float a, b, temp, di; + float z, w; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if J(n,NaN) is NaN */ + if(ix>0x7f800000) return x+x; + if(n<0){ + n = -n; + x = -x; + hx ^= 0x80000000; + } + if(n==0) return(__ieee754_j0f(x)); + if(n==1) return(__ieee754_j1f(x)); + sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */ + x = fabsf(x); + if(ix==0||ix>=0x7f800000) /* if x is 0 or inf */ + b = zero; + else if((float)n<=x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = __ieee754_j0f(x); + b = __ieee754_j1f(x); + for(i=1;i33) /* underflow */ + b = zero; + else { + temp = x*(float)0.5; b = temp; + for (a=one,i=2;i<=n;i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t,v; + float q0,q1,h,tmp; int32_t k,m; + w = (n+n)/(float)x; h = (float)2.0/(float)x; + q0 = w; z = w+h; q1 = w*z - (float)1.0; k=1; + while(q1<(float)1.0e9) { + k += 1; z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + m = n+n; + for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t); + a = t; + b = one; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = n; + v = two/x; + tmp = tmp*__ieee754_logf(fabsf(v*tmp)); + if(tmp<(float)8.8721679688e+01) { + for(i=n-1,di=(float)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + } + } else { + for(i=n-1,di=(float)(i+i);i>0;i--){ + temp = b; + b *= di; + b = b/x - a; + a = temp; + di -= two; + /* scale b to avoid spurious overflow */ + if(b>(float)1e10) { + a /= b; + t /= b; + b = one; + } + } + } + z = __ieee754_j0f(x); + w = __ieee754_j1f(x); + if (fabsf(z) >= fabsf(w)) + b = (t*z/b); + else + b = (t*w/a); + } + } + if(sgn==1) return -b; else return b; +} + +OLM_DLLEXPORT float +__ieee754_ynf(int n, float x) +{ + int32_t i,hx,ix,ib; + int32_t sign; + float a, b, temp; + + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + /* if Y(n,NaN) is NaN */ + if(ix>0x7f800000) return x+x; + if(ix==0) return -one/zero; + if(hx<0) return zero/zero; + sign = 1; + if(n<0){ + n = -n; + sign = 1 - ((n&1)<<1); + } + if(n==0) return(__ieee754_y0f(x)); + if(n==1) return(sign*__ieee754_y1f(x)); + if(ix==0x7f800000) return zero; + + a = __ieee754_y0f(x); + b = __ieee754_y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib,b); + for(i=1;i0) return b; else return -b; +} diff --git a/src/openlibm/src/e_lgamma.c b/src/openlibm/src/e_lgamma.c new file mode 100644 index 0000000..d316796 --- /dev/null +++ b/src/openlibm/src/e_lgamma.c @@ -0,0 +1,36 @@ + +/* @(#)e_lgamma.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgamma.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +/* __ieee754_lgamma(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_lgamma_r + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +__ieee754_lgamma(double x) +{ +#ifdef OPENLIBM_ONLY_THREAD_SAFE + int signgam; +#endif + + return __ieee754_lgamma_r(x,&signgam); +} diff --git a/src/openlibm/src/e_lgamma_r.c b/src/openlibm/src/e_lgamma_r.c new file mode 100644 index 0000000..df3ae23 --- /dev/null +++ b/src/openlibm/src/e_lgamma_r.c @@ -0,0 +1,298 @@ + +/* @(#)e_lgamma_r.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgamma_r.c,v 1.11 2011/10/15 07:00:28 das Exp $"); + +/* __ieee754_lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include + +#include "math_private.h" + +static const double +two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +static const double zero= 0.00000000000000000000e+00; + + static double sin_pi(double x) +{ + double y,z; + int n,ix; + + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + + if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floor(y); + if(z!=y) { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */ + n = (int) (y*4.0); + } else { + if(ix>=0x43400000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x43300000) z = y+two52; /* exact */ + GET_LOW_WORD(n,z); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = __kernel_sin(pi*y,zero,0); break; + case 1: + case 2: y = __kernel_cos(pi*(0.5-y),zero); break; + case 3: + case 4: y = __kernel_sin(pi*(one-y),zero,0); break; + case 5: + case 6: y = -__kernel_cos(pi*(y-1.5),zero); break; + default: y = __kernel_sin(pi*(y-2.0),zero,0); break; + } + return -y; +} + + +OLM_DLLEXPORT double +__ieee754_lgamma_r(double x, int *signgamp) +{ + double t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,lx,ix; + + EXTRACT_WORDS(hx,lx,x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return x*x; + if((ix|lx)==0) return one/zero; + if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -__ieee754_log(-x); + } else return -__ieee754_log(x); + } + if(hx<0) { + if(ix>=0x43300000) /* |x|>=2**52, must be -integer */ + return one/zero; + t = sin_pi(x); + if(t==zero) return one/zero; /* -integer */ + nadj = __ieee754_log(pi/fabs(t*x)); + if(t=0x3FE76944) {y = one-x; i= 0;} + else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-0.5*y + p1/p2); + } + } + else if(ix<0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x-(double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+6.0); /* FALLTHRU */ + case 6: z *= (y+5.0); /* FALLTHRU */ + case 5: z *= (y+4.0); /* FALLTHRU */ + case 4: z *= (y+3.0); /* FALLTHRU */ + case 3: z *= (y+2.0); /* FALLTHRU */ + r += __ieee754_log(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x43900000) { + t = __ieee754_log(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(__ieee754_log(x)-one); + if(hx<0) r = nadj - r; + return r; +} diff --git a/src/openlibm/src/e_lgammaf.c b/src/openlibm/src/e_lgammaf.c new file mode 100644 index 0000000..5b95f02 --- /dev/null +++ b/src/openlibm/src/e_lgammaf.c @@ -0,0 +1,37 @@ +/* e_lgammaf.c -- float version of e_lgamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgammaf.c,v 1.8 2008/02/22 02:30:35 das Exp $"); + +/* __ieee754_lgammaf(x) + * Return the logarithm of the Gamma function of x. + * + * Method: call __ieee754_lgammaf_r + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +__ieee754_lgammaf(float x) +{ +#ifdef OPENLIBM_ONLY_THREAD_SAFE + int signgam; +#endif + + return __ieee754_lgammaf_r(x,&signgam); +} diff --git a/src/openlibm/src/e_lgammaf_r.c b/src/openlibm/src/e_lgammaf_r.c new file mode 100644 index 0000000..7446dfc --- /dev/null +++ b/src/openlibm/src/e_lgammaf_r.c @@ -0,0 +1,231 @@ +/* e_lgammaf_r.c -- float version of e_lgamma_r.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_lgammaf_r.c,v 1.12 2011/10/15 07:00:28 das Exp $"); + +#include + +#include "math_private.h" + +static const float +two23= 8.3886080000e+06, /* 0x4b000000 */ +half= 5.0000000000e-01, /* 0x3f000000 */ +one = 1.0000000000e+00, /* 0x3f800000 */ +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +static const float zero= 0.0000000000e+00; + + static float sin_pif(float x) +{ + float y,z; + int n,ix; + + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + + if(ix<0x3e800000) return __kernel_sindf(pi*x); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorf(y); + if(z!=y) { /* inexact anyway */ + y *= (float)0.5; + y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */ + n = (int) (y*(float)4.0); + } else { + if(ix>=0x4b800000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x4b000000) z = y+two23; /* exact */ + GET_FLOAT_WORD(n,z); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = __kernel_sindf(pi*y); break; + case 1: + case 2: y = __kernel_cosdf(pi*((float)0.5-y)); break; + case 3: + case 4: y = __kernel_sindf(pi*(one-y)); break; + case 5: + case 6: y = -__kernel_cosdf(pi*(y-(float)1.5)); break; + default: y = __kernel_sindf(pi*(y-(float)2.0)); break; + } + return -y; +} + + +OLM_DLLEXPORT float +__ieee754_lgammaf_r(float x, int *signgamp) +{ + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,ix; + + GET_FLOAT_WORD(hx,x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return x*x; + if(ix==0) return one/zero; + if(ix<0x35000000) { /* |x|<2**-21, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -__ieee754_logf(-x); + } else return -__ieee754_logf(x); + } + if(hx<0) { + if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */ + return one/zero; + t = sin_pif(x); + if(t==zero) return one/zero; /* -integer */ + nadj = __ieee754_logf(pi/fabsf(t*x)); + if(t=0x3f3b4a20) {y = one-x; i= 0;} + else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-(float)0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-(float)0.5*y + p1/p2); + } + } + else if(ix<0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x-(float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+(float)6.0); /* FALLTHRU */ + case 6: z *= (y+(float)5.0); /* FALLTHRU */ + case 5: z *= (y+(float)4.0); /* FALLTHRU */ + case 4: z *= (y+(float)3.0); /* FALLTHRU */ + case 3: z *= (y+(float)2.0); /* FALLTHRU */ + r += __ieee754_logf(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x5c800000) { + t = __ieee754_logf(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(__ieee754_logf(x)-one); + if(hx<0) r = nadj - r; + return r; +} diff --git a/src/openlibm/src/e_lgammal.c b/src/openlibm/src/e_lgammal.c new file mode 100644 index 0000000..c1bfb25 --- /dev/null +++ b/src/openlibm/src/e_lgammal.c @@ -0,0 +1,15 @@ +#include "cdefs-compat.h" + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +lgammal(long double x) +{ +#ifdef OPENLIBM_ONLY_THREAD_SAFE + int signgam; +#endif + + return (lgammal_r(x, &signgam)); +} diff --git a/src/openlibm/src/e_log.c b/src/openlibm/src/e_log.c new file mode 100644 index 0000000..29584bb --- /dev/null +++ b/src/openlibm/src/e_log.c @@ -0,0 +1,146 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_log.c,v 1.15 2008/03/29 16:37:59 das Exp $"); + +/* __ieee754_log(x) + * Return the logrithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_log(double x) +{ + double hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,hx,i,j; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + f = x-1.0; + if((0x000fffff&(2+hx))<3) { /* -2**-20 <= f < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + dk=(double)k; + return dk*ln2_hi+dk*ln2_lo; + } + } + R = f*f*(0.5-0.33333333333333333*f); + if(k==0) return f-R; else {dk=(double)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/(2.0+f); + dk = (double)k; + z = s*s; + i = hx-0x6147a; + w = z*z; + j = 0x6b851-hx; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(log, logl); +#endif diff --git a/src/openlibm/src/e_log10.c b/src/openlibm/src/e_log10.c new file mode 100644 index 0000000..8e3c4e0 --- /dev/null +++ b/src/openlibm/src/e_log10.c @@ -0,0 +1,93 @@ + +/* @(#)e_log10.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_log10.c,v 1.15 2011/10/15 05:23:28 das Exp $"); + +/* + * Return the base 10 logarithm of x. See e_log.c and k_log.h for most + * comments. + * + * log10(x) = (f - 0.5*f*f + k_log1p(f)) / ln10 + k * log10(2) + * in not-quite-routine extra precision. + */ + +#include +#include + +#include "math_private.h" +#include "k_log.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_log10(double x) +{ + double f,hfsq,hi,lo,r,val_hi,val_lo,w,y,y2; + int32_t i,k,hx; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + if (hx == 0x3ff00000 && lx == 0) + return zero; /* log(1) = +0 */ + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + y = (double)k; + f = x - 1.0; + hfsq = 0.5*f*f; + r = k_log1p(f); + + /* See e_log2.c for most details. */ + hi = f - hfsq; + SET_LOW_WORD(hi,0); + lo = (f - hi) - hfsq + r; + val_hi = hi*ivln10hi; + y2 = y*log10_2hi; + val_lo = y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y*log10_2hi is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y2 + val_hi; + val_lo += (y2 - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(log10, log10l); +#endif diff --git a/src/openlibm/src/e_log10f.c b/src/openlibm/src/e_log10f.c new file mode 100644 index 0000000..1f6e31a --- /dev/null +++ b/src/openlibm/src/e_log10f.c @@ -0,0 +1,75 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_log10f.c,v 1.13 2011/10/16 05:36:23 das Exp $"); + +/* + * Float version of e_log10.c. See the latter for most comments. + */ + +#include + +#include "math_private.h" +#include "k_logf.h" + +// VBS +#define float_t float + +static const float +two25 = 3.3554432000e+07, /* 0x4c000000 */ +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07; /* 0x355427db */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_log10f(float x) +{ + float f,hfsq,hi,lo,r,y; + int32_t i,k,hx; + + GET_FLOAT_WORD(hx,x); + + k=0; + if (hx < 0x00800000) { /* x < 2**-126 */ + if ((hx&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(hx,x); + } + if (hx >= 0x7f800000) return x+x; + if (hx == 0x3f800000) + return zero; /* log(1) = +0 */ + k += (hx>>23)-127; + hx &= 0x007fffff; + i = (hx+(0x4afb0d))&0x800000; + SET_FLOAT_WORD(x,hx|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + y = (float)k; + f = x - (float)1.0; + hfsq = (float)0.5*f*f; + r = k_log1pf(f); + + /* See e_log2f.c and e_log2.c for details. */ + if (sizeof(float_t) > sizeof(float)) + return (r - hfsq + f) * ((float_t)ivln10lo + ivln10hi) + + y * ((float_t)log10_2lo + log10_2hi); + hi = f - hfsq; + GET_FLOAT_WORD(hx,hi); + SET_FLOAT_WORD(hi,hx&0xfffff000); + lo = (f - hi) - hfsq + r; + return y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + + y*log10_2hi; +} diff --git a/src/openlibm/src/e_log2.c b/src/openlibm/src/e_log2.c new file mode 100644 index 0000000..1570233 --- /dev/null +++ b/src/openlibm/src/e_log2.c @@ -0,0 +1,116 @@ + +/* @(#)e_log10.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_log2.c,v 1.4 2011/10/15 05:23:28 das Exp $"); + +/* + * Return the base 2 logarithm of x. See e_log.c and k_log.h for most + * comments. + * + * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel, + * then does the combining and scaling steps + * log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k + * in not-quite-routine extra precision. + */ + +#include +#include + +#include "math_private.h" +#include "k_log.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ +ivln2lo = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +__ieee754_log2(double x) +{ + double f,hfsq,hi,lo,r,val_hi,val_lo,w,y; + int32_t i,k,hx; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + + k=0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx&0x7fffffff)|lx)==0) + return -two54/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 54; x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx,x); + } + if (hx >= 0x7ff00000) return x+x; + if (hx == 0x3ff00000 && lx == 0) + return zero; /* log(1) = +0 */ + k += (hx>>20)-1023; + hx &= 0x000fffff; + i = (hx+0x95f64)&0x100000; + SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ + k += (i>>20); + y = (double)k; + f = x - 1.0; + hfsq = 0.5*f*f; + r = k_log1p(f); + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + hi = f - hfsq; + SET_LOW_WORD(hi,0); + lo = (f - hi) - hfsq + r; + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(log2, log2l); +#endif diff --git a/src/openlibm/src/e_log2f.c b/src/openlibm/src/e_log2f.c new file mode 100644 index 0000000..58977ac --- /dev/null +++ b/src/openlibm/src/e_log2f.c @@ -0,0 +1,85 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_log2f.c,v 1.5 2011/10/15 05:23:28 das Exp $"); + +/* + * Float version of e_log2.c. See the latter for most comments. + */ + +#include + +#include "math_private.h" +#include "k_logf.h" + +// VBS +#define float_t float + +static const float +two25 = 3.3554432000e+07, /* 0x4c000000 */ +ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ +ivln2lo = -1.7605285393e-04; /* 0xb9389ad4 */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_log2f(float x) +{ + float f,hfsq,hi,lo,r,y; + int32_t i,k,hx; + + GET_FLOAT_WORD(hx,x); + + k=0; + if (hx < 0x00800000) { /* x < 2**-126 */ + if ((hx&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(hx,x); + } + if (hx >= 0x7f800000) return x+x; + if (hx == 0x3f800000) + return zero; /* log(1) = +0 */ + k += (hx>>23)-127; + hx &= 0x007fffff; + i = (hx+(0x4afb0d))&0x800000; + SET_FLOAT_WORD(x,hx|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + y = (float)k; + f = x - (float)1.0; + hfsq = (float)0.5*f*f; + r = k_log1pf(f); + + /* + * We no longer need to avoid falling into the multi-precision + * calculations due to compiler bugs breaking Dekker's theorem. + * Keep avoiding this as an optimization. See e_log2.c for more + * details (some details are here only because the optimization + * is not yet available in double precision). + * + * Another compiler bug turned up. With gcc on i386, + * (ivln2lo + ivln2hi) would be evaluated in float precision + * despite runtime evaluations using double precision. So we + * must cast one of its terms to float_t. This makes the whole + * expression have type float_t, so return is forced to waste + * time clobbering its extra precision. + */ + if (sizeof(float_t) > sizeof(float)) + return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y; + + hi = f - hfsq; + GET_FLOAT_WORD(hx,hi); + SET_FLOAT_WORD(hi,hx&0xfffff000); + lo = (f - hi) - hfsq + r; + return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y; +} diff --git a/src/openlibm/src/e_logf.c b/src/openlibm/src/e_logf.c new file mode 100644 index 0000000..dc5e151 --- /dev/null +++ b/src/openlibm/src/e_logf.c @@ -0,0 +1,89 @@ +/* e_logf.c -- float version of e_log.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_logf.c,v 1.11 2008/03/29 16:37:59 das Exp $"); + +#include + +#include "math_private.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +two25 = 3.355443200e+07, /* 0x4c000000 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +__ieee754_logf(float x) +{ + float hfsq,f,s,z,R,w,t1,t2,dk; + int32_t k,ix,i,j; + + GET_FLOAT_WORD(ix,x); + + k=0; + if (ix < 0x00800000) { /* x < 2**-126 */ + if ((ix&0x7fffffff)==0) + return -two25/zero; /* log(+-0)=-inf */ + if (ix<0) return (x-x)/zero; /* log(-#) = NaN */ + k -= 25; x *= two25; /* subnormal number, scale up x */ + GET_FLOAT_WORD(ix,x); + } + if (ix >= 0x7f800000) return x+x; + k += (ix>>23)-127; + ix &= 0x007fffff; + i = (ix+(0x95f64<<3))&0x800000; + SET_FLOAT_WORD(x,ix|(i^0x3f800000)); /* normalize x or x/2 */ + k += (i>>23); + f = x-(float)1.0; + if((0x007fffff&(0x8000+ix))<0xc000) { /* -2**-9 <= f < 2**-9 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + dk=(float)k; + return dk*ln2_hi+dk*ln2_lo; + } + } + R = f*f*((float)0.5-(float)0.33333333333333333*f); + if(k==0) return f-R; else {dk=(float)k; + return dk*ln2_hi-((R-dk*ln2_lo)-f);} + } + s = f/((float)2.0+f); + dk = (float)k; + z = s*s; + i = ix-(0x6147a<<3); + w = z*z; + j = (0x6b851<<3)-ix; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + i |= j; + R = t2+t1; + if(i>0) { + hfsq=(float)0.5*f*f; + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); + } else { + if(k==0) return f-s*(f-R); else + return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); + } +} diff --git a/src/openlibm/src/e_pow.c b/src/openlibm/src/e_pow.c new file mode 100644 index 0000000..a891552 --- /dev/null +++ b/src/openlibm/src/e_pow.c @@ -0,0 +1,317 @@ +/* @(#)e_pow.c 1.5 04/04/22 SMI */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_pow.c,v 1.14 2011/10/21 06:26:07 das Exp $"); + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +OLM_DLLEXPORT double +__ieee754_pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx==0x3ff00000 && lx == 0) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return (x+0.0)+(y+0.0); + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if((j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return one; /* (-1)**+-inf is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x40080000) return x*x*x; /* y is 3 */ + if(hy==0x40100000) { /* y is 4 */ + u = x*x; + return u*u; + } + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be + n = (hx>>31)+1; + but ANSI C says a right shift of a signed negative quantity is + implementation defined. */ + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + SET_LOW_WORD(t1,0); + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + SET_LOW_WORD(t_h,0); + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + SET_LOW_WORD(p_h,0); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + SET_LOW_WORD(t1,0); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1,0); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + EXTRACT_WORDS(j,i,z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t,n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + SET_LOW_WORD(t,0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_HIGH_WORD(j,z); + j += (n<<20); + if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ + else SET_HIGH_WORD(z,j); + return s*z; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(pow, powl); +#endif diff --git a/src/openlibm/src/e_powf.c b/src/openlibm/src/e_powf.c new file mode 100644 index 0000000..9527ef0 --- /dev/null +++ b/src/openlibm/src/e_powf.c @@ -0,0 +1,253 @@ +/* e_powf.c -- float version of e_pow.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_powf.c,v 1.16 2011/10/21 06:26:07 das Exp $"); + +#include + +#include "math_private.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +zero = 0.0, +half = 0.5, +qrtr = 0.25, +thrd = 3.33333343e-01, /* 0x3eaaaaab */ +one = 1.0, +two = 2.0, +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +OLM_DLLEXPORT float +__ieee754_powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if(iy==0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx==0x3f800000) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if(ix > 0x7f800000 || + iy > 0x7f800000) + return 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>=0x4b800000) yisint = 2; /* even integer y */ + else if(iy>=0x3f800000) { + k = (iy>>23)-0x7f; /* exponent */ + j = iy>>(23-k); + if((j<<(23-k))==iy) yisint = 2-(j&1); + } + } + + /* special value of y */ + if (iy==0x7f800000) { /* y is +-inf */ + if (ix==0x3f800000) + return one; /* (-1)**+-inf is NaN */ + else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3f800000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3f000000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return __ieee754_sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if(ix==0x7f800000||ix==0||ix==0x3f800000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3f800000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + n = ((u_int32_t)hx>>31)-1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if(ix<0x3f7ffff6) return (hy<0)? sn*huge*huge:sn*tiny*tiny; + if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-1; /* t has 20 trailing zeros */ + w = (t*t)*(half-t*(thrd-t*qrtr)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = v-(t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00800000) + {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); } + n += ((ix)>>23)-0x7f; + j = ix&0x007fffff; + /* determine interval */ + ix = j|0x3f800000; /* normalize ix */ + if(j<=0x1cc471) k=0; /* |x|>1)&0xfffff000)|0x20000000; + SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3+s2+r; + GET_FLOAT_WORD(is,t_h); + SET_FLOAT_WORD(t_h,is&0xfffff000); + t_l = r-((t_h-3)-s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u+v; + GET_FLOAT_WORD(is,p_h); + SET_FLOAT_WORD(p_h,is&0xfffff000); + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n; + t1 = (((z_h+z_l)+dp_h[k])+t); + GET_FLOAT_WORD(is,t1); + SET_FLOAT_WORD(t1,is&0xfffff000); + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is,y); + SET_FLOAT_WORD(y1,is&0xfffff000); + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + GET_FLOAT_WORD(j,z); + if (j>0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j==0x43000000) { /* if z == 128 */ + if(p_l+ovt>z-p_h) return sn*huge*huge; /* overflow */ + } + else if ((j&0x7fffffff)>0x43160000) /* z <= -150 */ + return sn*tiny*tiny; /* underflow */ + else if (j==0xc3160000){ /* z == -150 */ + if(p_l<=z-p_h) return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>23)-0x7f; + n = 0; + if(i>0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23)-0x7f; /* new k for n */ + SET_FLOAT_WORD(t,n&~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + GET_FLOAT_WORD(is,t); + SET_FLOAT_WORD(t,is&0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + GET_FLOAT_WORD(j,z); + j += (n<<23); + if((j>>23)<=0) z = scalbnf(z,n); /* subnormal output */ + else SET_FLOAT_WORD(z,j); + return sn*z; +} diff --git a/src/openlibm/src/e_rem_pio2.c b/src/openlibm/src/e_rem_pio2.c new file mode 100644 index 0000000..c09e38a --- /dev/null +++ b/src/openlibm/src/e_rem_pio2.c @@ -0,0 +1,183 @@ + +/* @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_rem_pio2.c,v 1.22 2011/06/19 17:07:58 kargl Exp $"); + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include +#include + +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +__inline int +__ieee754_rem_pio2(double x, double *y) +{ + double z,w,t,r,fn; + double tx[3],ty[2]; + int32_t e0,i,j,nx,n,ix,hx; + u_int32_t low; + + GET_HIGH_WORD(hx,x); /* high word of x */ + ix = hx&0x7fffffff; +#if 0 /* Must be handled in caller. */ + if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} +#endif + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (hx > 0) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + return -1; + } + } else { + if (hx > 0) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0])-2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0])+2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (hx > 0) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0])-3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0])+3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (hx > 0) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0])-4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0])+4*pio2_1t; + return -4; + } + } + } + if(ix<0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + { + u_int32_t high; + j = ix>>20; + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>16) { /* 2nd iteration needed, good to 118 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_HIGH_WORD(high,y[0]); + i = j-((high>>20)&0x7ff); + if(i>49) { /* 3rd iteration need, 151 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7ff00000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + GET_LOW_WORD(low,x); + e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ + INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low); + for(i=0;i<2;i++) { + tx[i] = (double)((int32_t)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,ty,e0,nx,1); + if(hx<0) {y[0] = -ty[0]; y[1] = -ty[1]; return -n;} + y[0] = ty[0]; y[1] = ty[1]; return n; +} diff --git a/src/openlibm/src/e_rem_pio2f.c b/src/openlibm/src/e_rem_pio2f.c new file mode 100644 index 0000000..9861bb9 --- /dev/null +++ b/src/openlibm/src/e_rem_pio2f.c @@ -0,0 +1,81 @@ +/* e_rem_pio2f.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_rem_pio2f.c,v 1.32 2009/06/03 08:16:34 ed Exp $"); + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __kernel_rem_pio2() for large x + */ + +#include +#include + +#include "math_private.h" + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ + +static const double +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +__inline int +__ieee754_rem_pio2f(float x, double *y) +{ + double w,r,fn; + double tx[1],ty[1]; + float z; + int32_t e0,n,ix,hx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + /* 33+53 bit pi is good enough for medium size */ + if(ix<0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + STRICT_ASSIGN(double,fn,x*invpio2+0x1.8p52); + fn = fn-0x1.8p52; +#ifdef HAVE_EFFICIENT_IRINT + n = irint(fn); +#else + n = (int32_t)fn; +#endif + r = x-fn*pio2_1; + w = fn*pio2_1t; + *y = r-w; + return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(|x|)-23) */ + e0 = (ix>>23)-150; /* e0 = ilogb(|x|)-23; */ + SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23))); + tx[0] = z; + n = __kernel_rem_pio2(tx,ty,e0,1,0); + if(hx<0) {*y = -ty[0]; return -n;} + *y = ty[0]; return n; +} diff --git a/src/openlibm/src/e_remainder.c b/src/openlibm/src/e_remainder.c new file mode 100644 index 0000000..a72631c --- /dev/null +++ b/src/openlibm/src/e_remainder.c @@ -0,0 +1,79 @@ + +/* @(#)e_remainder.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainder.c,v 1.12 2008/03/30 20:47:42 das Exp $"); + +/* __ieee754_remainder(x,p) + * Return : + * returns x REM p = x - [x/p]*p as if in infinite + * precise arithmetic, where [x/p] is the (infinite bit) + * integer nearest x/p (in half way case choose the even one). + * Method : + * Based on fmod() return x-[x/p]chopped*p exactlp. + */ + +#include +#include + +#include "math_private.h" + +static const double zero = 0.0; + + +OLM_DLLEXPORT double +__ieee754_remainder(double x, double p) +{ + int32_t hx,hp; + u_int32_t sx,lx,lp; + double p_half; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hp,lp,p); + sx = hx&0x80000000; + hp &= 0x7fffffff; + hx &= 0x7fffffff; + + /* purge off exception values */ + if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */ + if((hx>=0x7ff00000)|| /* x not finite */ + ((hp>=0x7ff00000)&& /* p is NaN */ + (((hp-0x7ff00000)|lp)!=0))) + return ((long double)x*p)/((long double)x*p); + + + if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */ + if (((hx-hp)|(lx-lp))==0) return zero*x; + x = fabs(x); + p = fabs(p); + if (hp<0x00200000) { + if(x+x>p) { + x-=p; + if(x+x>=p) x -= p; + } + } else { + p_half = 0.5*p; + if(x>p_half) { + x-=p; + if(x>=p_half) x -= p; + } + } + GET_HIGH_WORD(hx,x); + if ((hx&0x7fffffff)==0) hx = 0; + SET_HIGH_WORD(x,hx^sx); + return x; +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(remainder, remainderl); +#endif diff --git a/src/openlibm/src/e_remainderf.c b/src/openlibm/src/e_remainderf.c new file mode 100644 index 0000000..ac0d153 --- /dev/null +++ b/src/openlibm/src/e_remainderf.c @@ -0,0 +1,66 @@ +/* e_remainderf.c -- float version of e_remainder.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainderf.c,v 1.8 2008/02/12 17:11:36 bde Exp $"); + +#include + +#include "math_private.h" + +static const float zero = 0.0; + + +OLM_DLLEXPORT float +__ieee754_remainderf(float x, float p) +{ + int32_t hx,hp; + u_int32_t sx; + float p_half; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hp,p); + sx = hx&0x80000000; + hp &= 0x7fffffff; + hx &= 0x7fffffff; + + /* purge off exception values */ + if(hp==0) return (x*p)/(x*p); /* p = 0 */ + if((hx>=0x7f800000)|| /* x not finite */ + ((hp>0x7f800000))) /* p is NaN */ + return ((long double)x*p)/((long double)x*p); + + + if (hp<=0x7effffff) x = __ieee754_fmodf(x,p+p); /* now x < 2p */ + if ((hx-hp)==0) return zero*x; + x = fabsf(x); + p = fabsf(p); + if (hp<0x01000000) { + if(x+x>p) { + x-=p; + if(x+x>=p) x -= p; + } + } else { + p_half = (float)0.5*p; + if(x>p_half) { + x-=p; + if(x>=p_half) x -= p; + } + } + GET_FLOAT_WORD(hx,x); + if ((hx&0x7fffffff)==0) hx = 0; + SET_FLOAT_WORD(x,hx^sx); + return x; +} diff --git a/src/openlibm/src/e_remainderl.c b/src/openlibm/src/e_remainderl.c new file mode 100644 index 0000000..5f1ee61 --- /dev/null +++ b/src/openlibm/src/e_remainderl.c @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_remainderl.c,v 1.1 2008/03/30 20:47:42 das Exp $"); + +#include +#include "math_private.h" + +OLM_DLLEXPORT long double +remainderl(long double x, long double y) +{ + int quo; + + return (remquol(x, y, &quo)); +} diff --git a/src/openlibm/src/e_sinh.c b/src/openlibm/src/e_sinh.c new file mode 100644 index 0000000..7f3a2bf --- /dev/null +++ b/src/openlibm/src/e_sinh.c @@ -0,0 +1,79 @@ + +/* @(#)e_sinh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_sinh.c,v 1.11 2011/10/21 06:28:47 das Exp $"); + +/* __ieee754_sinh(x) + * Method : + * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + * 1. Replace x by |x| (sinh(-x) = -sinh(x)). + * 2. + * E + E/(E+1) + * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + * 2 + * + * 22 <= x <= lnovft : sinh(x) := exp(x)/2 + * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + * ln2ovft < x : sinh(x) := x*shuge (overflow) + * + * Special cases: + * sinh(x) is |x| if x is +INF, -INF, or NaN. + * only sinh(0)=0 is exact for finite x. + */ + +#include +#include + +#include "math_private.h" + +static const double one = 1.0, shuge = 1.0e307; + +OLM_DLLEXPORT double +__ieee754_sinh(double x) +{ + double t,h; + int32_t ix,jx; + + /* High word of |x|. */ + GET_HIGH_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) return x+x; + + h = 0.5; + if (jx<0) h = -h; + /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x40360000) { /* |x|<22 */ + if (ix<0x3e300000) /* |x|<2**-28 */ + if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ + t = expm1(fabs(x)); + if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one)); + return h*(t+t/(t+one)); + } + + /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ + if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x)); + + /* |x| in [log(maxdouble), overflowthresold] */ + if (ix<=0x408633CE) + return h*2.0*__ldexp_exp(fabs(x), -1); + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(sinh, sinhl); +#endif diff --git a/src/openlibm/src/e_sinhf.c b/src/openlibm/src/e_sinhf.c new file mode 100644 index 0000000..6e5e06d --- /dev/null +++ b/src/openlibm/src/e_sinhf.c @@ -0,0 +1,57 @@ +/* e_sinhf.c -- float version of e_sinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_sinhf.c,v 1.10 2011/10/21 06:28:47 das Exp $"); + +#include + +#include "math_private.h" + +static const float one = 1.0, shuge = 1.0e37; + +OLM_DLLEXPORT float +__ieee754_sinhf(float x) +{ + float t,h; + int32_t ix,jx; + + GET_FLOAT_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) return x+x; + + h = 0.5; + if (jx<0) h = -h; + /* |x| in [0,9], return sign(x)*0.5*(E+E/(E+1))) */ + if (ix < 0x41100000) { /* |x|<9 */ + if (ix<0x39800000) /* |x|<2**-12 */ + if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ + t = expm1f(fabsf(x)); + if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one)); + return h*(t+t/(t+one)); + } + + /* |x| in [9, logf(maxfloat)] return 0.5*exp(|x|) */ + if (ix < 0x42b17217) return h*__ieee754_expf(fabsf(x)); + + /* |x| in [logf(maxfloat), overflowthresold] */ + if (ix<=0x42b2d4fc) + return h*2.0F*__ldexp_expf(fabsf(x), -1); + + /* |x| > overflowthresold, sinh(x) overflow */ + return x*shuge; +} diff --git a/src/openlibm/src/e_sqrt.c b/src/openlibm/src/e_sqrt.c new file mode 100644 index 0000000..2eb4a1a --- /dev/null +++ b/src/openlibm/src/e_sqrt.c @@ -0,0 +1,451 @@ + +/* @(#)e_sqrt.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_sqrt.c,v 1.11 2008/03/02 01:47:58 das Exp $"); + +/* __ieee754_sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + +#include +#include + +#include "math_private.h" + +static const double one = 1.0, tiny=1.0e-300; + +OLM_DLLEXPORT double +__ieee754_sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + u_int32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0,ix1,x); + + /* take care of Inf and NaN */ + if((ix0&0x7ff00000)==0x7ff00000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix0<=0) { + if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix0<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix0>>20); + if(m==0) { /* subnormal x */ + while(ix0==0) { + m -= 21; + ix0 |= (ix1>>11); ix1 <<= 21; + } + for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; + m -= i-1; + ix0 |= (ix1>>(32-i)); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if(m&1){ /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s0+r; + if(t<=ix0) { + s0 = t+r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r>>=1; + } + + r = sign; + while(r!=0) { + t1 = s1+r; + t = s0; + if((t>31); + ix1 += ix1; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if((ix0|ix1)!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (q1==(u_int32_t)0xffffffff) { q1=0; q += 1;} + else if (z>one) { + if (q1==(u_int32_t)0xfffffffe) q+=1; + q1+=2; + } else + q1 += (q1&1); + } + } + ix0 = (q>>1)+0x3fe00000; + ix1 = q1>>1; + if ((q&1)==1) ix1 |= sign; + ix0 += (m <<20); + INSERT_WORDS(z,ix0,ix1); + return z; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(sqrt, sqrtl); +#endif + +/* +Other methods (use floating-point arithmetic) +------------- +(This is a copy of a drafted paper by Prof W. Kahan +and K.C. Ng, written in May, 1986) + + Two algorithms are given here to implement sqrt(x) + (IEEE double precision arithmetic) in software. + Both supply sqrt(x) correctly rounded. The first algorithm (in + Section A) uses newton iterations and involves four divisions. + The second one uses reciproot iterations to avoid division, but + requires more multiplications. Both algorithms need the ability + to chop results of arithmetic operations instead of round them, + and the INEXACT flag to indicate when an arithmetic operation + is executed exactly with no roundoff error, all part of the + standard (IEEE 754-1985). The ability to perform shift, add, + subtract and logical AND operations upon 32-bit words is needed + too, though not part of the standard. + +A. sqrt(x) by Newton Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + + 1 11 52 ...widths + ------------------------------------------------------ + x: |s| e | f | + ------------------------------------------------------ + msb lsb msb lsb ...order + + + ------------------------ ------------------------ + x0: |s| e | f1 | x1: | f2 | + ------------------------ ------------------------ + + By performing shifts and subtracts on x0 and x1 (both regarded + as integers), we obtain an 8-bit approximation of sqrt(x) as + follows. + + k := (x0>>1) + 0x1ff80000; + y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits + Here k is a 32-bit integer and T1[] is an integer array containing + correction terms. Now magically the floating value of y (y's + leading 32-bit word is y0, the value of its trailing word is 0) + approximates sqrt(x) to almost 8-bit. + + Value of T1: + static int T1[32]= { + 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215, + 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581, + 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,}; + + (2) Iterative refinement + + Apply Heron's rule three times to y, we have y approximates + sqrt(x) to within 1 ulp (Unit in the Last Place): + + y := (y+x/y)/2 ... almost 17 sig. bits + y := (y+x/y)/2 ... almost 35 sig. bits + y := y-(y-x/y)/2 ... within 1 ulp + + + Remark 1. + Another way to improve y to within 1 ulp is: + + y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x) + y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x) + + 2 + (x-y )*y + y := y + 2* ---------- ...within 1 ulp + 2 + 3y + x + + + This formula has one division fewer than the one above; however, + it requires more multiplications and additions. Also x must be + scaled in advance to avoid spurious overflow in evaluating the + expression 3y*y+x. Hence it is not recommended uless division + is slow. If division is very slow, then one should use the + reciproot algorithm given in section B. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + I := FALSE; ... reset INEXACT flag I + R := RZ; ... set rounding mode to round-toward-zero + z := x/y; ... chopped quotient, possibly inexact + If(not I) then { ... if the quotient is exact + if(z=y) { + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + } else { + z := z - ulp; ... special rounding + } + } + i := TRUE; ... sqrt(x) is inexact + If (r=RN) then z=z+ulp ... rounded-to-nearest + If (r=RP) then { ... round-toward-+inf + y = y+ulp; z=z+ulp; + } + y := y+z; ... chopped sum + y0:=y0-0x00100000; ... y := y/2 is correctly rounded. + I := i; ... restore inexact flag + R := r; ... restore rounded mode + return sqrt(x):=y. + + (4) Special cases + + Square root of +inf, +-0, or NaN is itself; + Square root of a negative number is NaN with invalid signal. + + +B. sqrt(x) by Reciproot Iteration + + (1) Initial approximation + + Let x0 and x1 be the leading and the trailing 32-bit words of + a floating point number x (in IEEE double format) respectively + (see section A). By performing shifs and subtracts on x0 and y0, + we obtain a 7.8-bit approximation of 1/sqrt(x) as follows. + + k := 0x5fe80000 - (x0>>1); + y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits + + Here k is a 32-bit integer and T2[] is an integer array + containing correction terms. Now magically the floating + value of y (y's leading 32-bit word is y0, the value of + its trailing word y1 is set to zero) approximates 1/sqrt(x) + to almost 7.8-bit. + + Value of T2: + static int T2[64]= { + 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866, + 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f, + 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d, + 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0, + 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989, + 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd, + 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e, + 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,}; + + (2) Iterative refinement + + Apply Reciproot iteration three times to y and multiply the + result by x to get an approximation z that matches sqrt(x) + to about 1 ulp. To be exact, we will have + -1ulp < sqrt(x)-z<1.0625ulp. + + ... set rounding mode to Round-to-nearest + y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x) + y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x) + ... special arrangement for better accuracy + z := x*y ... 29 bits to sqrt(x), with z*y<1 + z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x) + + Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that + (a) the term z*y in the final iteration is always less than 1; + (b) the error in the final result is biased upward so that + -1 ulp < sqrt(x) - z < 1.0625 ulp + instead of |sqrt(x)-z|<1.03125ulp. + + (3) Final adjustment + + By twiddling y's last bit it is possible to force y to be + correctly rounded according to the prevailing rounding mode + as follows. Let r and i be copies of the rounding mode and + inexact flag before entering the square root program. Also we + use the expression y+-ulp for the next representable floating + numbers (up and down) of y. Note that y+-ulp = either fixed + point y+-1, or multiply y by nextafter(1,+-inf) in chopped + mode. + + R := RZ; ... set rounding mode to round-toward-zero + switch(r) { + case RN: ... round-to-nearest + if(x<= z*(z-ulp)...chopped) z = z - ulp; else + if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp; + break; + case RZ:case RM: ... round-to-zero or round-to--inf + R:=RP; ... reset rounding mod to round-to-+inf + if(x=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp; + break; + case RP: ... round-to-+inf + if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else + if(x>z*z ...chopped) z = z+ulp; + break; + } + + Remark 3. The above comparisons can be done in fixed point. For + example, to compare x and w=z*z chopped, it suffices to compare + x1 and w1 (the trailing parts of x and w), regarding them as + two's complement integers. + + ...Is z an exact square root? + To determine whether z is an exact square root of x, let z1 be the + trailing part of z, and also let x0 and x1 be the leading and + trailing parts of x. + + If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0 + I := 1; ... Raise Inexact flag: z is not exact + else { + j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2 + k := z1 >> 26; ... get z's 25-th and 26-th + fraction bits + I := i or (k&j) or ((k&(j+j+1))!=(x1&3)); + } + R:= r ... restore rounded mode + return sqrt(x):=z. + + If multiplication is cheaper then the foregoing red tape, the + Inexact flag can be evaluated by + + I := i; + I := (z*z!=x) or I. + + Note that z*z can overwrite I; this value must be sensed if it is + True. + + Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be + zero. + + -------------------- + z1: | f2 | + -------------------- + bit 31 bit 0 + + Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd + or even of logb(x) have the following relations: + + ------------------------------------------------- + bit 27,26 of z1 bit 1,0 of x1 logb(x) + ------------------------------------------------- + 00 00 odd and even + 01 01 even + 10 10 odd + 10 00 even + 11 01 even + ------------------------------------------------- + + (4) Special cases (see (4) of Section A). + + */ + diff --git a/src/openlibm/src/e_sqrtf.c b/src/openlibm/src/e_sqrtf.c new file mode 100644 index 0000000..2aeaa9f --- /dev/null +++ b/src/openlibm/src/e_sqrtf.c @@ -0,0 +1,86 @@ +/* e_sqrtf.c -- float version of e_sqrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +#include "math_private.h" + +static const float one = 1.0, tiny=1.0e-30; + +OLM_DLLEXPORT float +__ieee754_sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + u_int32_t r; + + GET_FLOAT_WORD(ix,x); + + /* take care of Inf and NaN */ + if((ix&0x7f800000)==0x7f800000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix<=0) { + if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix>>23); + if(m==0) { /* subnormal x */ + for(i=0;(ix&0x00800000)==0;i++) ix<<=1; + m -= i-1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if(m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s+r; + if(t<=ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if(ix!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (z>one) + q += 2; + else + q += (q&1); + } + } + ix = (q>>1)+0x3f000000; + ix += (m <<23); + SET_FLOAT_WORD(z,ix); + return z; +} diff --git a/src/openlibm/src/e_sqrtl.c b/src/openlibm/src/e_sqrtl.c new file mode 100644 index 0000000..a073bf9 --- /dev/null +++ b/src/openlibm/src/e_sqrtl.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/e_sqrtl.c,v 1.1 2008/03/02 01:47:58 das Exp $"); + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +/* Return (x + ulp) for normal positive x. Assumes no overflow. */ +static inline long double +inc(long double x) +{ + union IEEEl2bits u; + + u.e = x; + if (++u.bits.manl == 0) { + if (++u.bits.manh == 0) { + u.bits.exp++; + u.bits.manh |= LDBL_NBIT; + } + } + return (u.e); +} + +/* Return (x - ulp) for normal positive x. Assumes no underflow. */ +static inline long double +dec(long double x) +{ + union IEEEl2bits u; + + u.e = x; + if (u.bits.manl-- == 0) { + if (u.bits.manh-- == LDBL_NBIT) { + u.bits.exp--; + u.bits.manh |= LDBL_NBIT; + } + } + return (u.e); +} + +#ifndef __GNUC__ +#pragma STDC FENV_ACCESS ON +#endif + +/* + * This is slow, but simple and portable. You should use hardware sqrt + * if possible. + */ + +OLM_DLLEXPORT long double +sqrtl(long double x) +{ + union IEEEl2bits u; + int k, r; + long double lo, xn; + fenv_t env; + + u.e = x; + + /* If x = NaN, then sqrt(x) = NaN. */ + /* If x = Inf, then sqrt(x) = Inf. */ + /* If x = -Inf, then sqrt(x) = NaN. */ + if (u.bits.exp == LDBL_MAX_EXP * 2 - 1) + return (x * x + x); + + /* If x = +-0, then sqrt(x) = +-0. */ + if ((u.bits.manh | u.bits.manl | u.bits.exp) == 0) + return (x); + + /* If x < 0, then raise invalid and return NaN */ + if (u.bits.sign) + return ((x - x) / (x - x)); + + feholdexcept(&env); + + if (u.bits.exp == 0) { + /* Adjust subnormal numbers. */ + u.e *= 0x1.0p514; + k = -514; + } else { + k = 0; + } + /* + * u.e is a normal number, so break it into u.e = e*2^n where + * u.e = (2*e)*2^2k for odd n and u.e = (4*e)*2^2k for even n. + */ + if ((u.bits.exp - 0x3ffe) & 1) { /* n is odd. */ + k += u.bits.exp - 0x3fff; /* 2k = n - 1. */ + u.bits.exp = 0x3fff; /* u.e in [1,2). */ + } else { + k += u.bits.exp - 0x4000; /* 2k = n - 2. */ + u.bits.exp = 0x4000; /* u.e in [2,4). */ + } + + /* + * Newton's iteration. + * Split u.e into a high and low part to achieve additional precision. + */ + xn = sqrt(u.e); /* 53-bit estimate of sqrtl(x). */ +#if LDBL_MANT_DIG > 100 + xn = (xn + (u.e / xn)) * 0.5; /* 106-bit estimate. */ +#endif + lo = u.e; + u.bits.manl = 0; /* Zero out lower bits. */ + lo = (lo - u.e) / xn; /* Low bits divided by xn. */ + xn = xn + (u.e / xn); /* High portion of estimate. */ + u.e = xn + lo; /* Combine everything. */ + u.bits.exp += (k >> 1) - 1; + + feclearexcept(FE_INEXACT); + r = fegetround(); + fesetround(FE_TOWARDZERO); /* Set to round-toward-zero. */ + xn = x / u.e; /* Chopped quotient (inexact?). */ + + if (!fetestexcept(FE_INEXACT)) { /* Quotient is exact. */ + if (xn == u.e) { + fesetenv(&env); + return (u.e); + } + /* Round correctly for inputs like x = y**2 - ulp. */ + xn = dec(xn); /* xn = xn - ulp. */ + } + + if (r == FE_TONEAREST) { + xn = inc(xn); /* xn = xn + ulp. */ + } else if (r == FE_UPWARD) { + u.e = inc(u.e); /* u.e = u.e + ulp. */ + xn = inc(xn); /* xn = xn + ulp. */ + } + u.e = u.e + xn; /* Chopped sum. */ + feupdateenv(&env); /* Restore env and raise inexact */ + u.bits.exp--; + return (u.e); +} diff --git a/src/openlibm/src/fpmath.h b/src/openlibm/src/fpmath.h new file mode 100644 index 0000000..eb824d7 --- /dev/null +++ b/src/openlibm/src/fpmath.h @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2003 Mike Barcroft + * Copyright (c) 2002 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/fpmath.h,v 1.4 2008/12/23 22:20:59 marcel Exp $ + */ +#ifndef _FPMATH_H_ +#define _FPMATH_H_ + +#if defined(__aarch64__) +#include "aarch64_fpmath.h" +#elif defined(__i386__) || defined(__x86_64__) +#ifdef __LP64__ +#include "amd64_fpmath.h" +#else +#include "i386_fpmath.h" +#endif +#elif defined(__powerpc__) || defined(__POWERPC__) +#include "powerpc_fpmath.h" +#elif defined(__mips__) +#include "mips_fpmath.h" +#elif defined(__s390__) +#include "s390_fpmath.h" +#elif defined(__riscv) +#include "riscv_fpmath.h" +#elif defined(__loongarch64) +#include "loongarch64_fpmath.h" +#endif + +/* Definitions provided directly by GCC and Clang. */ +#if !(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)) + +#if defined(__GLIBC__) + +#include +#include +#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN +#define __BYTE_ORDER__ __BYTE_ORDER + +#elif defined(__APPLE__) + +#include +#define __ORDER_LITTLE_ENDIAN__ LITTLE_ENDIAN +#define __ORDER_BIG_ENDIAN__ BIG_ENDIAN +#define __BYTE_ORDER__ BYTE_ORDER + +#elif defined(_WIN32) + +#define __ORDER_LITTLE_ENDIAN__ 1234 +#define __ORDER_BIG_ENDIAN__ 4321 +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ + +#endif + +#endif /* __BYTE_ORDER__, __ORDER_LITTLE_ENDIAN__ and __ORDER_BIG_ENDIAN__ */ + +#ifndef __FLOAT_WORD_ORDER__ +#define __FLOAT_WORD_ORDER__ __BYTE_ORDER__ +#endif + +union IEEEf2bits { + float f; + struct { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + unsigned int man :23; + unsigned int exp :8; + unsigned int sign :1; +#else /* _BIG_ENDIAN */ + unsigned int sign :1; + unsigned int exp :8; + unsigned int man :23; +#endif + } bits; +}; + +#define DBL_MANH_SIZE 20 +#define DBL_MANL_SIZE 32 + +union IEEEd2bits { + double d; + struct { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ + unsigned int manl :32; +#endif + unsigned int manh :20; + unsigned int exp :11; + unsigned int sign :1; +#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ + unsigned int manl :32; +#endif +#else /* _BIG_ENDIAN */ + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; +#endif + } bits; +}; + +#endif diff --git a/src/openlibm/src/i386_fpmath.h b/src/openlibm/src/i386_fpmath.h new file mode 100644 index 0000000..455631c --- /dev/null +++ b/src/openlibm/src/i386_fpmath.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2002, 2003 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/i386/_fpmath.h,v 1.6 2008/01/17 16:39:06 bde Exp $ + */ + +union IEEEl2bits { + long double e; + struct { + unsigned int manl :32; + unsigned int manh :32; + unsigned int exp :15; + unsigned int sign :1; + unsigned int junk :16; + } bits; + struct { + unsigned long long man :64; + unsigned int expsign :16; + unsigned int junk :16; + } xbits; +}; + +#define LDBL_NBIT 0x80000000 +#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT) + +#define LDBL_MANH_SIZE 32 +#define LDBL_MANL_SIZE 32 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)(u).bits.manh; \ +} while (0) diff --git a/src/openlibm/src/k_cos.c b/src/openlibm/src/k_cos.c new file mode 100644 index 0000000..f3054ef --- /dev/null +++ b/src/openlibm/src/k_cos.c @@ -0,0 +1,80 @@ + +/* @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_cos.c,v 1.12 2008/02/19 12:54:14 bde Exp $"); + +/* + * __kernel_cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include + +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +OLM_DLLEXPORT double +__kernel_cos(double x, double y) +{ + double hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = one-hz; + return w + (((one-w)-hz) + (z*r-x*y)); +} diff --git a/src/openlibm/src/k_cosf.c b/src/openlibm/src/k_cosf.c new file mode 100644 index 0000000..6774db4 --- /dev/null +++ b/src/openlibm/src/k_cosf.c @@ -0,0 +1,48 @@ +/* k_cosf.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_COSDF +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_cosf.c,v 1.18 2009/06/03 08:16:34 ed Exp $"); +#endif + +#include + +#include "math_private.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +one = 1.0, +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +#ifndef INLINE_KERNEL_COSDF +extern +#endif +//__inline float +OLM_DLLEXPORT float +__kernel_cosdf(double x) +{ + double r, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((one+z*C0) + w*C1) + (w*z)*r; +} diff --git a/src/openlibm/src/k_exp.c b/src/openlibm/src/k_exp.c new file mode 100644 index 0000000..4739e20 --- /dev/null +++ b/src/openlibm/src/k_exp.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_exp.c,v 1.1 2011/10/21 06:27:56 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const u_int32_t k = 1799; /* constant for reduction */ +static const double kln2 = 1246.97177782734161156; /* k * ln2 */ + +/* + * Compute exp(x), scaled to avoid spurious overflow. An exponent is + * returned separately in 'expt'. + * + * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 + * Output: 2**1023 <= y < 2**1024 + */ +static double +__frexp_exp(double x, int *expt) +{ + double exp_x; + u_int32_t hx; + + /* + * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to + * minimize |exp(kln2) - 2**k|. We also scale the exponent of + * exp_x to MAX_EXP so that the result can be multiplied by + * a tiny number without losing accuracy due to denormalization. + */ + exp_x = exp(x - kln2); + GET_HIGH_WORD(hx, exp_x); + *expt = (hx >> 20) - (0x3ff + 1023) + k; + SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); + return (exp_x); +} + +/* + * __ldexp_exp(x, expt) and __ldexp_cexp(x, expt) compute exp(x) * 2**expt. + * They are intended for large arguments (real part >= ln(DBL_MAX)) + * where care is needed to avoid overflow. + * + * The present implementation is narrowly tailored for our hyperbolic and + * exponential functions. We assume expt is small (0 or -1), and the caller + * has filtered out very large x, for which overflow would be inevitable. + */ + +OLM_DLLEXPORT double +__ldexp_exp(double x, int expt) +{ + double exp_x, scale; + int ex_expt; + + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + INSERT_WORDS(scale, (0x3ff + expt) << 20, 0); + return (exp_x * scale); +} + +OLM_DLLEXPORT double complex +__ldexp_cexp(double complex z, int expt) +{ + double x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = creal(z); + y = cimag(z); + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + + /* + * Arrange so that scale1 * scale2 == 2**expt. We use this to + * compensate for scalbn being horrendously slow. + */ + half_expt = expt / 2; + INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); + half_expt = expt - half_expt; + INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); + + return (CMPLX(cos(y) * exp_x * scale1 * scale2, + sin(y) * exp_x * scale1 * scale2)); +} diff --git a/src/openlibm/src/k_expf.c b/src/openlibm/src/k_expf.c new file mode 100644 index 0000000..bbf094c --- /dev/null +++ b/src/openlibm/src/k_expf.c @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_expf.c,v 1.1 2011/10/21 06:27:56 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const u_int32_t k = 235; /* constant for reduction */ +static const float kln2 = 162.88958740F; /* k * ln2 */ + +/* + * See k_exp.c for details. + * + * Input: ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7 + * Output: 2**127 <= y < 2**128 + */ +static float +__frexp_expf(float x, int *expt) +{ + double exp_x; + u_int32_t hx; + + exp_x = expf(x - kln2); + GET_FLOAT_WORD(hx, exp_x); + *expt = (hx >> 23) - (0x7f + 127) + k; + SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23)); + return (exp_x); +} + +OLM_DLLEXPORT float +__ldexp_expf(float x, int expt) +{ + float exp_x, scale; + int ex_expt; + + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + SET_FLOAT_WORD(scale, (0x7f + expt) << 23); + return (exp_x * scale); +} + +OLM_DLLEXPORT float complex +__ldexp_cexpf(float complex z, int expt) +{ + float x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = crealf(z); + y = cimagf(z); + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + + half_expt = expt / 2; + SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23); + half_expt = expt - half_expt; + SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23); + + return (CMPLXF(cosf(y) * exp_x * scale1 * scale2, + sinf(y) * exp_x * scale1 * scale2)); +} diff --git a/src/openlibm/src/k_log.h b/src/openlibm/src/k_log.h new file mode 100644 index 0000000..a0943c4 --- /dev/null +++ b/src/openlibm/src/k_log.h @@ -0,0 +1,100 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_log.h,v 1.2 2011/10/15 05:23:28 das Exp $"); + +/* + * k_log1p(f): + * Return log(1+f) - f for 1+f in ~[sqrt(2)/2, sqrt(2)]. + * + * The following describes the overall strategy for computing + * logarithms in base e. The argument reduction and adding the final + * term of the polynomial are done by the caller for increased accuracy + * when different bases are used. + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +static const double +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +/* + * We always inline k_log1p(), since doing so produces a + * substantial performance improvement (~40% on amd64). + */ +static inline double +k_log1p(double f) +{ + double hfsq,s,z,R,w,t1,t2; + + s = f/(2.0+f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*(Lg4+w*Lg6)); + t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2+t1; + hfsq=0.5*f*f; + return s*(hfsq+R); +} diff --git a/src/openlibm/src/k_logf.h b/src/openlibm/src/k_logf.h new file mode 100644 index 0000000..1b665ae --- /dev/null +++ b/src/openlibm/src/k_logf.h @@ -0,0 +1,39 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_logf.h,v 1.3 2011/10/15 05:23:28 das Exp $"); + +/* + * Float version of k_log.h. See the latter for most comments. + */ + +static const float +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +static inline float +k_log1pf(float f) +{ + float hfsq,s,z,R,w,t1,t2; + + s = f/((float)2.0+f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2+t1; + hfsq=(float)0.5*f*f; + return s*(hfsq+R); +} diff --git a/src/openlibm/src/k_rem_pio2.c b/src/openlibm/src/k_rem_pio2.c new file mode 100644 index 0000000..9555d3a --- /dev/null +++ b/src/openlibm/src/k_rem_pio2.c @@ -0,0 +1,444 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_rem_pio2.c,v 1.11 2008/02/25 11:43:20 bde Exp $"); + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +#if LDBL_MAX_EXP > 16384 +#error "ipio2 table needs to be expanded" +#endif +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif + +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +static const double +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +OLM_DLLEXPORT int +__kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (double)((int32_t)(twon24* z)); + iq[i] = (int32_t)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t) z; + z -= (double)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if(q0==0) ih = iq[jz-1]>>23; + else if(z>=0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==0.0) { + jz -= 1; q0 -= 24; + while(iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if(z>=two24) { + fw = (double)((int32_t)(twon24*z)); + iq[jz] = (int32_t)(z-two24*fw); + jz += 1; q0 += 24; + iq[jz] = (int32_t) fw; + } else iq[jz] = (int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(double)iq[i]; fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + STRICT_ASSIGN(double,fw,fw); + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/src/openlibm/src/k_sin.c b/src/openlibm/src/k_sin.c new file mode 100644 index 0000000..0b3de39 --- /dev/null +++ b/src/openlibm/src/k_sin.c @@ -0,0 +1,71 @@ + +/* @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_sin.c,v 1.11 2008/02/19 12:54:14 bde Exp $"); + +/* __kernel_sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include + +#include "math_private.h" + +static const double +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +OLM_DLLEXPORT double +__kernel_sin(double x, double y, int iy) +{ + double z,r,v,w; + + z = x*x; + w = z*z; + r = S2+z*(S3+z*S4) + z*w*(S5+z*S6); + v = z*x; + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/openlibm/src/k_sinf.c b/src/openlibm/src/k_sinf.c new file mode 100644 index 0000000..15c8e03 --- /dev/null +++ b/src/openlibm/src/k_sinf.c @@ -0,0 +1,48 @@ +/* k_sinf.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_SINDF +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_sinf.c,v 1.16 2009/06/03 08:16:34 ed Exp $"); +#endif + +#include + +#include "math_private.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +#ifndef INLINE_KERNEL_SINDF +extern +#endif +//__inline float +OLM_DLLEXPORT float +__kernel_sindf(double x) +{ + double r, s, w, z; + + /* Try to optimize for parallel evaluation as in k_tanf.c. */ + z = x*x; + w = z*z; + r = S3+z*S4; + s = z*x; + return (x + s*(S1+z*S2)) + s*w*r; +} diff --git a/src/openlibm/src/k_tan.c b/src/openlibm/src/k_tan.c new file mode 100644 index 0000000..41f754b --- /dev/null +++ b/src/openlibm/src/k_tan.c @@ -0,0 +1,134 @@ +/* @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* INDENT OFF */ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_tan.c,v 1.13 2008/02/22 02:30:35 das Exp $"); + +/* __kernel_tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include + +#include "math_private.h" + +static const double xxx[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +/* one */ 1.00000000000000000000e+00, /* 3FF00000, 00000000 */ +/* pio4 */ 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ +/* pio4lo */ 3.06161699786838301793e-17 /* 3C81A626, 33145C07 */ +}; +#define one xxx[13] +#define pio4 xxx[14] +#define pio4lo xxx[15] +#define T xxx +/* INDENT ON */ + +double +__kernel_tan(double x, double y, int iy) { + double z, r, v, w, s; + int32_t ix, hx; + + GET_HIGH_WORD(hx,x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */ + if (hx < 0) { + x = -x; + y = -y; + } + z = pio4 - x; + w = pio4lo - y; + x = z + w; + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + + w * T[11])))); + v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + + w * T[12]))))); + s = z * x; + r = y + z * (s * (r + v) + y); + r += T[0] * s; + w = x + r; + if (ix >= 0x3FE59428) { + v = (double) iy; + return (double) (1 - ((hx >> 30) & 2)) * + (v - 2.0 * (x - (w * w / (w + v) - r))); + } + if (iy == 1) + return w; + else { + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + double a, t; + z = w; + SET_LOW_WORD(z,0); + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + SET_LOW_WORD(t,0); + s = 1.0 + t * z; + return t + a * (s + t * v); + } +} diff --git a/src/openlibm/src/k_tanf.c b/src/openlibm/src/k_tanf.c new file mode 100644 index 0000000..9c17d1b --- /dev/null +++ b/src/openlibm/src/k_tanf.c @@ -0,0 +1,68 @@ +/* k_tanf.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef INLINE_KERNEL_TANDF +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/k_tanf.c,v 1.23 2009/06/03 08:16:34 ed Exp $"); +#endif + +#include + +#include "math_private.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double +T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +#ifndef INLINE_KERNEL_TANDF +extern +#endif +//__inline float +OLM_DLLEXPORT float +__kernel_tandf(double x, int iy) +{ + double z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4]+z*T[5]; + t = T[2]+z*T[3]; + w = z*z; + s = z*x; + u = T[0]+z*T[1]; + r = (x+s*u)+(s*w)*(t+w*r); + if(iy==1) return r; + else return -1.0/r; +} diff --git a/src/openlibm/src/loongarch64_fpmath.h b/src/openlibm/src/loongarch64_fpmath.h new file mode 100644 index 0000000..31ea131 --- /dev/null +++ b/src/openlibm/src/loongarch64_fpmath.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2023 Yifan An + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +union IEEEl2bits { + long double e; + struct { + uint64_t manl :64; + uint64_t manh :48; + unsigned int exp :15; + unsigned int sign :1; + } bits; + struct { + uint64_t manl :64; + uint64_t manh :48; + unsigned int expsign :16; + } xbits; +}; + +#define LDBL_NBIT 0 +#define LDBL_IMPLICIT_NBIT +#define mask_nbit_l(u) ((void)0) + +#define LDBL_MANH_SIZE 48 +#define LDBL_MANL_SIZE 64 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)((u).bits.manl >> 32); \ + (a)[2] = (uint32_t)(u).bits.manh; \ + (a)[3] = (uint32_t)((u).bits.manh >> 32); \ +} while(0) diff --git a/src/openlibm/src/math_private.h b/src/openlibm/src/math_private.h new file mode 100644 index 0000000..15a27b2 --- /dev/null +++ b/src/openlibm/src/math_private.h @@ -0,0 +1,375 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD: src/lib/msun/src/math_private.h,v 1.34 2011/10/21 06:27:56 das Exp $ + */ + +#ifndef _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include +#include +#include "cdefs-compat.h" +#include "types-compat.h" +#include "fpmath.h" +#include +#include "math_private_openbsd.h" + +/* + * The original fdlibm code used statements like: + * n0 = ((*(int*)&one)>>29)^1; * index of high word * + * ix0 = *(n0+(int*)&x); * high word of x * + * ix1 = *((1-n0)+(int*)&x); * low word of x * + * to dig two 32 bit words out of the 64 bit IEEE floating point + * value. That is non-ANSI, and, moreover, the gcc instruction + * scheduler gets it wrong. We instead use the following macros. + * Unlike the original code, we determine the endianness at compile + * time, not at run time; I don't see much benefit to selecting + * endianness at run time. + */ + +/* + * A union which permits us to convert between a double and two 32 bit + * ints. + */ + +#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ + +typedef union +{ + double value; + struct + { + u_int32_t msw; + u_int32_t lsw; + } parts; + struct + { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +typedef union +{ + double value; + struct + { + u_int32_t lsw; + u_int32_t msw; + } parts; + struct + { + u_int64_t w; + } xparts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get a 64-bit int from a double. */ +#define EXTRACT_WORD64(ix,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix) = ew_u.xparts.w; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i,d) \ +do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* Set a double from a 64-bit int. */ +#define INSERT_WORD64(d,ix) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.xparts.w = (ix); \ + (d) = iw_u.value; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d,v) \ +do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d,v) \ +do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ +} while (0) + +/* + * A union which permits us to convert between a float and a 32 bit + * int. + */ + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +/* Get expsign as a 16 bit int from a long double. */ + +#define GET_LDBL_EXPSIGN(i,d) \ +do { \ + union IEEEl2bits ge_u; \ + ge_u.e = (d); \ + (i) = ge_u.xbits.expsign; \ +} while (0) + +/* Set expsign of a long double from a 16 bit int. */ + +#define SET_LDBL_EXPSIGN(d,v) \ +do { \ + union IEEEl2bits se_u; \ + se_u.e = (d); \ + se_u.xbits.expsign = (v); \ + (d) = se_u.e; \ +} while (0) + + +#ifndef __FreeBSD__ +#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) +#else +#ifdef FLT_EVAL_METHOD +// Attempt to get strict C99 semantics for assignment with non-C99 compilers. +#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0 +#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval)) +#else +#define STRICT_ASSIGN(type, lval, rval) do { \ + volatile type __lval; \ + \ + if (sizeof(type) >= sizeof(long double)) \ + (lval) = (rval); \ + else { \ + __lval = (rval); \ + (lval) = __lval; \ + } \ +} while (0) +#endif +#endif +#endif + +/* + * Common routine to process the arguments to nan(), nanf(), and nanl(). + */ +void __scan_nan(u_int32_t *__words, int __num_words, const char *__s); + +/* + * Mix 1 or 2 NaNs. First add 0 to each arg. This normally just turns + * signaling NaNs into quiet NaNs by setting a quiet bit. We do this + * because we want to never return a signaling NaN, and also because we + * don't want the quiet bit to affect the result. Then mix the converted + * args using addition. The result is typically the arg whose mantissa + * bits (considered as in integer) are largest. + * + * Technical complications: the result in bits might depend on the precision + * and/or on compiler optimizations, especially when different register sets + * are used for different precisions. Try to make the result not depend on + * at least the precision by always doing the main mixing step in long double + * precision. Try to reduce dependencies on optimizations by adding the + * the 0's in different precisions (unless everything is in long double + * precision). + */ +#define nan_mix(x, y) (((x) + 0.0L) + ((y) + 0)) + +#ifdef __GNUCLIKE_ASM + +/* Asm versions of some functions. */ + +#ifdef __amd64__ +static __inline int +irint(double x) +{ + int n; + + __asm__("cvtsd2si %1,%0" : "=r" (n) : "x" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#ifdef __i386__ +static __inline int +irint(double x) +{ + int n; + + __asm__("fistl %0" : "=m" (n) : "t" (x)); + return (n); +} +#define HAVE_EFFICIENT_IRINT +#endif + +#endif /* __GNUCLIKE_ASM */ + +/* + * ieee style elementary functions + * + * We rename functions here to improve other sources' diffability + * against fdlibm. + */ +#define __ieee754_sqrt sqrt +#define __ieee754_acos acos +#define __ieee754_acosh acosh +#define __ieee754_log log +#define __ieee754_log2 log2 +#define __ieee754_atanh atanh +#define __ieee754_asin asin +#define __ieee754_atan2 atan2 +#define __ieee754_exp exp +#define __ieee754_cosh cosh +#define __ieee754_fmod fmod +#define __ieee754_pow pow +#define __ieee754_lgamma lgamma +#define __ieee754_lgamma_r lgamma_r +#define __ieee754_log10 log10 +#define __ieee754_sinh sinh +#define __ieee754_hypot hypot +#define __ieee754_j0 j0 +#define __ieee754_j1 j1 +#define __ieee754_y0 y0 +#define __ieee754_y1 y1 +#define __ieee754_jn jn +#define __ieee754_yn yn +#define __ieee754_remainder remainder +#define __ieee754_sqrtf sqrtf +#define __ieee754_acosf acosf +#define __ieee754_acoshf acoshf +#define __ieee754_logf logf +#define __ieee754_atanhf atanhf +#define __ieee754_asinf asinf +#define __ieee754_atan2f atan2f +#define __ieee754_expf expf +#define __ieee754_coshf coshf +#define __ieee754_fmodf fmodf +#define __ieee754_powf powf +#define __ieee754_lgammaf lgammaf +#define __ieee754_lgammaf_r lgammaf_r +#define __ieee754_log10f log10f +#define __ieee754_log2f log2f +#define __ieee754_sinhf sinhf +#define __ieee754_hypotf hypotf +#define __ieee754_j0f j0f +#define __ieee754_j1f j1f +#define __ieee754_y0f y0f +#define __ieee754_y1f y1f +#define __ieee754_jnf jnf +#define __ieee754_ynf ynf +#define __ieee754_remainderf remainderf + +/* fdlibm kernel function */ +int __kernel_rem_pio2(double*,double*,int,int,int); + +/* double precision kernel functions */ +#ifdef INLINE_REM_PIO2 +__inline +#endif +int __ieee754_rem_pio2(double,double*); +double __kernel_sin(double,double,int); +double __kernel_cos(double,double); +double __kernel_tan(double,double,int); +double __ldexp_exp(double,int); +double complex __ldexp_cexp(double complex,int); + +/* float precision kernel functions */ +#ifdef INLINE_REM_PIO2F +__inline +#endif +int __ieee754_rem_pio2f(float,double*); +#ifdef INLINE_KERNEL_SINDF +__inline +#endif +float __kernel_sindf(double); +#ifdef INLINE_KERNEL_COSDF +__inline +#endif +float __kernel_cosdf(double); +#ifdef INLINE_KERNEL_TANDF +__inline +#endif +float __kernel_tandf(double,int); +float __ldexp_expf(float,int); +float complex __ldexp_cexpf(float complex,int); + +/* long double precision kernel functions */ +long double __kernel_sinl(long double, long double, int); +long double __kernel_cosl(long double, long double); +long double __kernel_tanl(long double, long double, int); + +#endif /* !_MATH_PRIVATE_H_ */ diff --git a/src/openlibm/src/math_private_openbsd.h b/src/openlibm/src/math_private_openbsd.h new file mode 100644 index 0000000..021670f --- /dev/null +++ b/src/openlibm/src/math_private_openbsd.h @@ -0,0 +1,218 @@ +/* $OpenBSD: math_private.h,v 1.17 2014/06/02 19:31:17 kettenis Exp $ */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + */ + +#ifndef _MATH_PRIVATE_OPENBSD_H_ +#define _MATH_PRIVATE_OPENBSD_H_ + +#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ + +typedef union +{ + long double value; + struct { + u_int32_t mswhi; + u_int32_t mswlo; + u_int32_t lswhi; + u_int32_t lswlo; + } parts32; + struct { + u_int64_t msw; + u_int64_t lsw; + } parts64; +} ieee_quad_shape_type; + +#endif + +#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +typedef union +{ + long double value; + struct { + u_int32_t lswlo; + u_int32_t lswhi; + u_int32_t mswlo; + u_int32_t mswhi; + } parts32; + struct { + u_int64_t lsw; + u_int64_t msw; + } parts64; +} ieee_quad_shape_type; + +#endif + +/* Get two 64 bit ints from a long double. */ + +#define GET_LDOUBLE_WORDS64(ix0,ix1,d) \ +do { \ + ieee_quad_shape_type qw_u; \ + qw_u.value = (d); \ + (ix0) = qw_u.parts64.msw; \ + (ix1) = qw_u.parts64.lsw; \ +} while (0) + +/* Set a long double from two 64 bit ints. */ + +#define SET_LDOUBLE_WORDS64(d,ix0,ix1) \ +do { \ + ieee_quad_shape_type qw_u; \ + qw_u.parts64.msw = (ix0); \ + qw_u.parts64.lsw = (ix1); \ + (d) = qw_u.value; \ +} while (0) + +/* Get the more significant 64 bits of a long double mantissa. */ + +#define GET_LDOUBLE_MSW64(v,d) \ +do { \ + ieee_quad_shape_type sh_u; \ + sh_u.value = (d); \ + (v) = sh_u.parts64.msw; \ +} while (0) + +/* Set the more significant 64 bits of a long double mantissa from an int. */ + +#define SET_LDOUBLE_MSW64(d,v) \ +do { \ + ieee_quad_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts64.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Get the least significant 64 bits of a long double mantissa. */ + +#define GET_LDOUBLE_LSW64(v,d) \ +do { \ + ieee_quad_shape_type sh_u; \ + sh_u.value = (d); \ + (v) = sh_u.parts64.lsw; \ +} while (0) + +/* A union which permits us to convert between a long double and + three 32 bit ints. */ + +#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ + +typedef union +{ + long double value; + struct { +#ifdef __LP64__ + int padh:32; +#endif + int exp:16; + int padl:16; + u_int32_t msw; + u_int32_t lsw; + } parts; +} ieee_extended_shape_type; + +#endif + +#if __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ + +typedef union +{ + long double value; + struct { + u_int32_t lsw; + u_int32_t msw; + int exp:16; + int padl:16; +#ifdef __LP64__ + int padh:32; +#endif + } parts; +} ieee_extended_shape_type; + +#endif + +/* Get three 32 bit ints from a double. */ + +#define GET_LDOUBLE_WORDS(se,ix0,ix1,d) \ +do { \ + ieee_extended_shape_type ew_u; \ + ew_u.value = (d); \ + (se) = ew_u.parts.exp; \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define SET_LDOUBLE_WORDS(d,se,ix0,ix1) \ +do { \ + ieee_extended_shape_type iw_u; \ + iw_u.parts.exp = (se); \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +/* Get the more significant 32 bits of a long double mantissa. */ + +#define GET_LDOUBLE_MSW(v,d) \ +do { \ + ieee_extended_shape_type sh_u; \ + sh_u.value = (d); \ + (v) = sh_u.parts.msw; \ +} while (0) + +/* Set the more significant 32 bits of a long double mantissa from an int. */ + +#define SET_LDOUBLE_MSW(d,v) \ +do { \ + ieee_extended_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ +} while (0) + +/* Get int from the exponent of a long double. */ + +#define GET_LDOUBLE_EXP(se,d) \ +do { \ + ieee_extended_shape_type ge_u; \ + ge_u.value = (d); \ + (se) = ge_u.parts.exp; \ +} while (0) + +/* Set exponent of a long double from an int. */ + +#define SET_LDOUBLE_EXP(d,se) \ +do { \ + ieee_extended_shape_type se_u; \ + se_u.value = (d); \ + se_u.parts.exp = (se); \ + (d) = se_u.value; \ +} while (0) + +/* + * Common routine to process the arguments to nan(), nanf(), and nanl(). + */ +void __scan_nan(uint32_t *__words, int __num_words, const char *__s); + +/* + * Functions internal to the math package, yet not static. + */ +double __exp__D(double, double); +struct Double __log__D(double); +long double __p1evll(long double, void *, int); +long double __polevll(long double, void *, int); + +#endif /* _MATH_PRIVATE_OPENBSD_H_ */ diff --git a/src/openlibm/src/mips_fpmath.h b/src/openlibm/src/mips_fpmath.h new file mode 100644 index 0000000..50f119f --- /dev/null +++ b/src/openlibm/src/mips_fpmath.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2002, 2003 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +union IEEEl2bits { + long double e; + struct { +#ifndef __MIPSEB__ + unsigned int manl :32; + unsigned int manh :20; + unsigned int exp :11; + unsigned int sign :1; +#else + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; +#endif + } bits; +}; + +#define LDBL_NBIT 0 +#define mask_nbit_l(u) ((void)0) +#define LDBL_IMPLICIT_NBIT + +#define LDBL_MANH_SIZE 20 +#define LDBL_MANL_SIZE 32 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)(u).bits.manh; \ +} while(0) + diff --git a/src/openlibm/src/polevll.c b/src/openlibm/src/polevll.c new file mode 100644 index 0000000..1c785d8 --- /dev/null +++ b/src/openlibm/src/polevll.c @@ -0,0 +1,104 @@ +/* $OpenBSD: polevll.c,v 1.2 2013/11/12 20:35:09 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* polevll.c + * p1evll.c + * + * Evaluate polynomial + * + * + * + * SYNOPSIS: + * + * int N; + * long double x, y, coef[N+1], polevl[]; + * + * y = polevll( x, coef, N ); + * + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evll() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevll(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + +#include + +#include "math_private.h" + +/* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] + */ +long double +__polevll(long double x, void *PP, int n) +{ + long double y; + long double *P; + + P = (long double *)PP; + y = *P++; + do { + y = y * x + *P++; + } while (--n); + + return (y); +} + +/* + * Polynomial evaluator: + * x^n + P[0] x^(n-1) + P[1] x^(n-2) + ... + P[n] + */ +long double +__p1evll(long double x, void *PP, int n) +{ + long double y; + long double *P; + + P = (long double *)PP; + n -= 1; + y = x + *P++; + do { + y = y * x + *P++; + } while (--n); + + return (y); +} diff --git a/src/openlibm/src/powerpc_fpmath.h b/src/openlibm/src/powerpc_fpmath.h new file mode 100644 index 0000000..6d80eb4 --- /dev/null +++ b/src/openlibm/src/powerpc_fpmath.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2003 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +union IEEEl2bits { + long double e; + struct { + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; + } bits; +}; + +#define mask_nbit_l(u) ((void)0) +#define LDBL_IMPLICIT_NBIT +#define LDBL_NBIT 0 + +#define LDBL_MANH_SIZE 20 +#define LDBL_MANL_SIZE 32 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)(u).bits.manh; \ +} while(0) diff --git a/src/openlibm/src/riscv_fpmath.h b/src/openlibm/src/riscv_fpmath.h new file mode 100644 index 0000000..cfa85ff --- /dev/null +++ b/src/openlibm/src/riscv_fpmath.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2002, 2003 David Schultz + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/lib/libc/riscv/_fpmath.h 362788 2020-06-29 19:30:35Z mhorne $ + */ + +union IEEEl2bits { + long double e; + struct { + unsigned long manl :64; + unsigned long manh :48; + unsigned int exp :15; + unsigned int sign :1; + } bits; + struct { + unsigned long manl :64; + unsigned long manh :48; + unsigned int expsign :16; + } xbits; +}; + +#define LDBL_NBIT 0 +#define LDBL_IMPLICIT_NBIT +#define mask_nbit_l(u) ((void)0) + +#define LDBL_MANH_SIZE 48 +#define LDBL_MANL_SIZE 64 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)((u).bits.manl >> 32); \ + (a)[2] = (uint32_t)(u).bits.manh; \ + (a)[3] = (uint32_t)((u).bits.manh >> 32); \ +} while(0) + diff --git a/src/openlibm/src/s390_fpmath.h b/src/openlibm/src/s390_fpmath.h new file mode 100644 index 0000000..1e7787c --- /dev/null +++ b/src/openlibm/src/s390_fpmath.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2016 Dan Horák + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * cloned from powerpc_fpmath.h + */ + +union IEEEl2bits { + long double e; + struct { + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; + } bits; +}; + +#define mask_nbit_l(u) ((void)0) +#define LDBL_IMPLICIT_NBIT +#define LDBL_NBIT 0 + +#define LDBL_MANH_SIZE 20 +#define LDBL_MANL_SIZE 32 + +#define LDBL_TO_ARRAY32(u, a) do { \ + (a)[0] = (uint32_t)(u).bits.manl; \ + (a)[1] = (uint32_t)(u).bits.manh; \ +} while(0) diff --git a/src/openlibm/src/s_asinh.c b/src/openlibm/src/s_asinh.c new file mode 100644 index 0000000..ca7937c --- /dev/null +++ b/src/openlibm/src/s_asinh.c @@ -0,0 +1,62 @@ +/* @(#)s_asinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_asinh.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +/* asinh(x) + * Method : + * Based on + * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] + * we have + * asinh(x) := x if 1+x*x=1, + * := sign(x)*(log(x)+ln2)) for large |x|, else + * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else + * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2))) + */ + +#include +#include + +#include "math_private.h" + +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +huge= 1.00000000000000000000e+300; + +OLM_DLLEXPORT double +asinh(double x) +{ + double t,w; + int32_t hx,ix; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */ + if(ix< 0x3e300000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* return x inexact except 0 */ + } + if(ix>0x41b00000) { /* |x| > 2**28 */ + w = __ieee754_log(fabs(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabs(x); + w = __ieee754_log(2.0*t+one/(__ieee754_sqrt(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1p(fabs(x)+t/(one+__ieee754_sqrt(one+t))); + } + if(hx>0) return w; else return -w; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(asinh, asinhl); +#endif diff --git a/src/openlibm/src/s_asinhf.c b/src/openlibm/src/s_asinhf.c new file mode 100644 index 0000000..c9d3694 --- /dev/null +++ b/src/openlibm/src/s_asinhf.c @@ -0,0 +1,49 @@ +/* s_asinhf.c -- float version of s_asinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_asinhf.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +static const float +one = 1.0000000000e+00, /* 0x3F800000 */ +ln2 = 6.9314718246e-01, /* 0x3f317218 */ +huge= 1.0000000000e+30; + +OLM_DLLEXPORT float +asinhf(float x) +{ + float t,w; + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return x+x; /* x is inf or NaN */ + if(ix< 0x31800000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* return x inexact except 0 */ + } + if(ix>0x4d800000) { /* |x| > 2**28 */ + w = __ieee754_logf(fabsf(x))+ln2; + } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */ + t = fabsf(x); + w = __ieee754_logf((float)2.0*t+one/(__ieee754_sqrtf(x*x+one)+t)); + } else { /* 2.0 > |x| > 2**-28 */ + t = x*x; + w =log1pf(fabsf(x)+t/(one+__ieee754_sqrtf(one+t))); + } + if(hx>0) return w; else return -w; +} diff --git a/src/openlibm/src/s_atan.c b/src/openlibm/src/s_atan.c new file mode 100644 index 0000000..23a2949 --- /dev/null +++ b/src/openlibm/src/s_atan.c @@ -0,0 +1,124 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_atan.c,v 1.13 2011/02/10 07:37:50 das Exp $"); + +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + + static const double +one = 1.0, +huge = 1.0e300; + +OLM_DLLEXPORT double +atan(double x) +{ + double w,s1,s2,z; + int32_t ix,hx,id; + + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x44100000) { /* if |x| >= 2^66 */ + u_int32_t low; + GET_LOW_WORD(low,x); + if(ix>0x7ff00000|| + (ix==0x7ff00000&&(low!=0))) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile double *)&atanlo[3]; + else return -atanhi[3]-*(volatile double *)&atanlo[3]; + } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(atan, atanl); +#endif diff --git a/src/openlibm/src/s_atanf.c b/src/openlibm/src/s_atanf.c new file mode 100644 index 0000000..cdba6a3 --- /dev/null +++ b/src/openlibm/src/s_atanf.c @@ -0,0 +1,93 @@ +/* s_atanf.c -- float version of s_atan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_atanf.c,v 1.10 2008/08/01 01:24:25 das Exp $"); + +#include + +#include "math_private.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +}; + +static const float +one = 1.0, +huge = 1.0e30; + +OLM_DLLEXPORT float +atanf(float x) +{ + float w,s1,s2,z; + int32_t ix,hx,id; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x4c800000) { /* if |x| >= 2**26 */ + if(ix>0x7f800000) + return x+x; /* NaN */ + if(hx>0) return atanhi[3]+*(volatile float *)&atanlo[3]; + else return -atanhi[3]-*(volatile float *)&atanlo[3]; + } if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <=|x|<11/16 */ + id = 0; x = ((float)2.0*x-one)/((float)2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; x = (x-(float)1.5)/(one+(float)1.5*x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; x = -(float)1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); + s2 = w*(aT[1]+w*aT[3]); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (hx<0)? -z:z; + } +} diff --git a/src/openlibm/src/s_atanl.c b/src/openlibm/src/s_atanl.c new file mode 100644 index 0000000..4edfa5a --- /dev/null +++ b/src/openlibm/src/s_atanl.c @@ -0,0 +1,85 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* FreeBSD: head/lib/msun/src/s_atan.c 176451 2008-02-22 02:30:36Z das */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_atanl.c,v 1.1 2008/07/31 22:41:26 das Exp $"); + +/* + * See comments in s_atan.c. + * Converted to long double by David Schultz . + */ + +#include +#include + +#include "invtrig.h" +#include "math_private.h" + +static const long double +one = 1.0, +huge = 1.0e300; + +OLM_DLLEXPORT long double +atanl(long double x) +{ + union IEEEl2bits u; + long double w,s1,s2,z; + int id; + int16_t expsign, expt; + int32_t expman; + + u.e = x; + expsign = u.xbits.expsign; + expt = expsign & 0x7fff; + if(expt >= ATAN_CONST) { /* if |x| is large, atan(x)~=pi/2 */ + if(expt == BIAS + LDBL_MAX_EXP && + ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)!=0) + return x+x; /* NaN */ + if(expsign>0) return atanhi[3]+atanlo[3]; + else return -atanhi[3]-atanlo[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + /* XXX There should be a more convenient way to do this. */ + expman = (expt << 8) | ((u.bits.manh >> (MANH_SIZE - 9)) & 0xff); + if (expman < ((BIAS - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (expt < ATAN_LINEAR) { /* if |x| is small, atanl(x)~=x */ + if(huge+x>one) return x; /* raise inexact */ + } + id = -1; + } else { + x = fabsl(x); + if (expman < (BIAS << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((BIAS - 1) << 8) + 0x60) { /* 7/16 <=|x|<11/16 */ + id = 0; x = (2.0*x-one)/(2.0+x); + } else { /* 11/16<=|x|< 19/16 */ + id = 1; x = (x-one)/(x+one); + } + } else { + if (expman < ((BIAS + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; x = (x-1.5)/(one+1.5*x); + } else { /* 2.4375 <= |x| < 2^ATAN_CONST */ + id = 3; x = -1.0/x; + } + }} + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z*T_even(w); + s2 = w*T_odd(w); + if (id<0) return x - x*(s1+s2); + else { + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return (expsign<0)? -z:z; + } +} diff --git a/src/openlibm/src/s_cabs.c b/src/openlibm/src/s_cabs.c new file mode 100644 index 0000000..481632a --- /dev/null +++ b/src/openlibm/src/s_cabs.c @@ -0,0 +1,32 @@ +/* $OpenBSD: s_cabs.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "math_private.h" + +double +cabs(double complex z) +{ + return hypot(__real__ z, __imag__ z); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(cabs, cabsl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_cabsf.c b/src/openlibm/src/s_cabsf.c new file mode 100644 index 0000000..8d9bd96 --- /dev/null +++ b/src/openlibm/src/s_cabsf.c @@ -0,0 +1,25 @@ +/* $OpenBSD: s_cabsf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +float +cabsf(float complex z) +{ + return hypotf(__real__ z, __imag__ z); +} diff --git a/src/openlibm/src/s_cabsl.c b/src/openlibm/src/s_cabsl.c new file mode 100644 index 0000000..847ded7 --- /dev/null +++ b/src/openlibm/src/s_cabsl.c @@ -0,0 +1,26 @@ +/* $OpenBSD: s_cabsl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $ */ + +/* + * Copyright (c) 2011 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +long double +cabsl(long double complex z) +{ + return hypotl(__real__ z, __imag__ z); +} diff --git a/src/openlibm/src/s_cacos.c b/src/openlibm/src/s_cacos.c new file mode 100644 index 0000000..e29717b --- /dev/null +++ b/src/openlibm/src/s_cacos.c @@ -0,0 +1,67 @@ +/* $OpenBSD: s_cacos.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacos() + * + * Complex circular arc cosine + * + * + * + * SYNOPSIS: + * + * double complex cacos(); + * double complex z, w; + * + * w = cacos (z); + * + * + * + * DESCRIPTION: + * + * + * w = arccos z = PI/2 - arcsin z. + * + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 1.6e-15 2.8e-16 + * IEEE -10,+10 30000 1.8e-14 2.2e-15 + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +cacos(double complex z) +{ + double complex w; + + w = casin (z); + w = (M_PI_2 - creal (w)) - cimag (w) * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(cacos, cacosl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_cacosf.c b/src/openlibm/src/s_cacosf.c new file mode 100644 index 0000000..f3c0eb9 --- /dev/null +++ b/src/openlibm/src/s_cacosf.c @@ -0,0 +1,60 @@ +/* $OpenBSD: s_cacosf.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacosf() + * + * Complex circular arc cosine + * + * + * + * SYNOPSIS: + * + * void cacosf(); + * cmplxf z, w; + * + * cacosf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * + * w = arccos z = PI/2 - arcsin z. + * + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 9.2e-6 1.2e-6 + * + */ + +#include +#include + +float complex +cacosf(float complex z) +{ + float complex w; + + w = casinf( z ); + w = ((float)M_PI_2 - crealf (w)) - cimagf (w) * I; + return (w); +} diff --git a/src/openlibm/src/s_cacosh.c b/src/openlibm/src/s_cacosh.c new file mode 100644 index 0000000..f16c14c --- /dev/null +++ b/src/openlibm/src/s_cacosh.c @@ -0,0 +1,62 @@ +/* $OpenBSD: s_cacosh.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacosh + * + * Complex inverse hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * double complex cacosh(); + * double complex z, w; + * + * w = cacosh (z); + * + * + * + * DESCRIPTION: + * + * acosh z = i acos z . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.6e-14 2.1e-15 + * + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +cacosh(double complex z) +{ + double complex w; + + w = I * cacos (z); + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(cacosh, cacoshl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_cacoshf.c b/src/openlibm/src/s_cacoshf.c new file mode 100644 index 0000000..f3c40ae --- /dev/null +++ b/src/openlibm/src/s_cacoshf.c @@ -0,0 +1,55 @@ +/* $OpenBSD: s_cacoshf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacoshf + * + * Complex inverse hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * float complex cacoshf(); + * float complex z, w; + * + * w = cacoshf (z); + * + * + * + * DESCRIPTION: + * + * acosh z = i acos z . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.6e-14 2.1e-15 + * + */ + +#include +#include + +float complex +cacoshf(float complex z) +{ + float complex w; + + w = I * cacosf (z); + return (w); +} diff --git a/src/openlibm/src/s_cacoshl.c b/src/openlibm/src/s_cacoshl.c new file mode 100644 index 0000000..5e5ae31 --- /dev/null +++ b/src/openlibm/src/s_cacoshl.c @@ -0,0 +1,56 @@ +/* $OpenBSD: s_cacoshl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacoshl + * + * Complex inverse hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * long double complex cacoshl(); + * long double complex z, w; + * + * w = cacoshl (z); + * + * + * + * DESCRIPTION: + * + * acosh z = i acos z . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.6e-14 2.1e-15 + * + */ + +#include +#include + +long double complex +cacoshl(long double complex z) +{ + long double complex w; + + w = I * cacosl(z); + return (w); +} diff --git a/src/openlibm/src/s_cacosl.c b/src/openlibm/src/s_cacosl.c new file mode 100644 index 0000000..8a7b8a1 --- /dev/null +++ b/src/openlibm/src/s_cacosl.c @@ -0,0 +1,63 @@ +/* $OpenBSD: s_cacosl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cacosl() + * + * Complex circular arc cosine + * + * + * + * SYNOPSIS: + * + * long double complex cacosl(); + * long double complex z, w; + * + * w = cacosl( z ); + * + * + * + * DESCRIPTION: + * + * + * w = arccos z = PI/2 - arcsin z. + * + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 1.6e-15 2.8e-16 + * IEEE -10,+10 30000 1.8e-14 2.2e-15 + */ + +#include +#include + +static const long double PIO2L = 1.570796326794896619231321691639751442098585L; + +long double complex +cacosl(long double complex z) +{ + long double complex w; + + w = casinl(z); + w = (PIO2L - creall(w)) - cimagl(w) * I; + return (w); +} diff --git a/src/openlibm/src/s_carg.c b/src/openlibm/src/s_carg.c new file mode 100644 index 0000000..2ebfe17 --- /dev/null +++ b/src/openlibm/src/s_carg.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_carg.c,v 1.1 2007/12/12 23:43:51 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +carg(double complex z) +{ + + return (atan2(cimag(z), creal(z))); +} diff --git a/src/openlibm/src/s_cargf.c b/src/openlibm/src/s_cargf.c new file mode 100644 index 0000000..41e320b --- /dev/null +++ b/src/openlibm/src/s_cargf.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cargf.c,v 1.1 2007/12/12 23:43:51 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +cargf(float complex z) +{ + + return (atan2f(cimagf(z), crealf(z))); +} diff --git a/src/openlibm/src/s_cargl.c b/src/openlibm/src/s_cargl.c new file mode 100644 index 0000000..5052133 --- /dev/null +++ b/src/openlibm/src/s_cargl.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cargl.c,v 1.1 2008/07/31 22:41:26 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +cargl(long double complex z) +{ + + return (atan2l(cimagl(z), creall(z))); +} diff --git a/src/openlibm/src/s_casin.c b/src/openlibm/src/s_casin.c new file mode 100644 index 0000000..4e5daaa --- /dev/null +++ b/src/openlibm/src/s_casin.c @@ -0,0 +1,136 @@ +/* $OpenBSD: s_casin.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casin() + * + * Complex circular arc sine + * + * + * + * SYNOPSIS: + * + * double complex casin(); + * double complex z, w; + * + * w = casin (z); + * + * + * + * DESCRIPTION: + * + * Inverse complex sine: + * + * 2 + * w = -i clog( iz + csqrt( 1 - z ) ). + * + * casin(z) = -i casinh(iz) + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 10100 2.1e-15 3.4e-16 + * IEEE -10,+10 30000 2.2e-14 2.7e-15 + * Larger relative error can be observed for z near zero. + * Also tested by csin(casin(z)) = z. + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +casin(double complex z) +{ + double complex w; + static double complex ca, ct, zz, z2; + double x, y; + + x = creal (z); + y = cimag (z); + + if (y == 0.0) { + if (fabs(x) > 1.0) { + w = M_PI_2 + 0.0 * I; + /*mtherr ("casin", DOMAIN);*/ + } + else { + w = asin (x) + 0.0 * I; + } + return (w); + } + + /* Power series expansion */ + /* + b = cabs(z); + if( b < 0.125 ) { + z2.r = (x - y) * (x + y); + z2.i = 2.0 * x * y; + + cn = 1.0; + n = 1.0; + ca.r = x; + ca.i = y; + sum.r = x; + sum.i = y; + do { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabs(ct.r) + fabs(ct.i); + } + while( b > MACHEP ); + w->r = sum.r; + w->i = sum.i; + return; + } + */ + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0 * x * y) * I; + + zz = 1.0 - creal(zz) - cimag(zz) * I; + z2 = csqrt (zz); + + zz = ct + z2; + zz = clog (zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0 * I); + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(casin, casinl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_casinf.c b/src/openlibm/src/s_casinf.c new file mode 100644 index 0000000..1573264 --- /dev/null +++ b/src/openlibm/src/s_casinf.c @@ -0,0 +1,132 @@ +/* $OpenBSD: s_casinf.c,v 1.3 2011/07/20 19:28:33 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casinf() + * + * Complex circular arc sine + * + * + * + * SYNOPSIS: + * + * void casinf(); + * cmplxf z, w; + * + * casinf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * Inverse complex sine: + * + * 2 + * w = -i clog( iz + csqrt( 1 - z ) ). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.1e-5 1.5e-6 + * Larger relative error can be observed for z near zero. + * + */ + +#include +#include + +float complex +casinf(float complex z) +{ + float complex w; + float x, y; + static float complex ca, ct, zz, z2; + /* + float cn, n; + static float a, b, s, t, u, v, y2; + static cmplxf sum; + */ + + x = crealf(z); + y = cimagf(z); + + if(y == 0.0f) { + if(fabsf(x) > 1.0f) { + w = (float)M_PI_2 + 0.0f * I; + /*mtherr( "casinf", DOMAIN );*/ + } + else { + w = asinf (x) + 0.0f * I; + } + return (w); + } + + /* Power series expansion */ + /* + b = cabsf(z); + if(b < 0.125) { + z2.r = (x - y) * (x + y); + z2.i = 2.0 * x * y; + + cn = 1.0; + n = 1.0; + ca.r = x; + ca.i = y; + sum.r = x; + sum.i = y; + do { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabsf(ct.r) + fabsf(ct.i); + } + while(b > MACHEPF); + w->r = sum.r; + w->i = sum.i; + return; + } + */ + + + ca = x + y * I; + ct = ca * I; /* iz */ + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0f * x * y) * I; + zz = 1.0f - crealf(zz) - cimagf(zz) * I; + z2 = csqrtf (zz); + + zz = ct + z2; + zz = clogf (zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0f * I); + return (w); +} diff --git a/src/openlibm/src/s_casinh.c b/src/openlibm/src/s_casinh.c new file mode 100644 index 0000000..4b1154d --- /dev/null +++ b/src/openlibm/src/s_casinh.c @@ -0,0 +1,62 @@ +/* $OpenBSD: s_casinh.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casinh + * + * Complex inverse hyperbolic sine + * + * + * + * SYNOPSIS: + * + * double complex casinh(); + * double complex z, w; + * + * w = casinh (z); + * + * + * + * DESCRIPTION: + * + * casinh z = -i casin iz . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.8e-14 2.6e-15 + * + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +casinh(double complex z) +{ + double complex w; + + w = -1.0 * I * casin (z * I); + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(casinh, casinhl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_casinhf.c b/src/openlibm/src/s_casinhf.c new file mode 100644 index 0000000..8894624 --- /dev/null +++ b/src/openlibm/src/s_casinhf.c @@ -0,0 +1,55 @@ +/* $OpenBSD: s_casinhf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casinhf + * + * Complex inverse hyperbolic sine + * + * + * + * SYNOPSIS: + * + * float complex casinhf(); + * float complex z, w; + * + * w = casinhf (z); + * + * + * + * DESCRIPTION: + * + * casinh z = -i casin iz . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.8e-14 2.6e-15 + * + */ + +#include +#include + +float complex +casinhf(float complex z) +{ + float complex w; + + w = -1.0f * I * casinf (z * I); + return (w); +} diff --git a/src/openlibm/src/s_casinhl.c b/src/openlibm/src/s_casinhl.c new file mode 100644 index 0000000..33ae217 --- /dev/null +++ b/src/openlibm/src/s_casinhl.c @@ -0,0 +1,56 @@ +/* $OpenBSD: s_casinhl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casinhl + * + * Complex inverse hyperbolic sine + * + * + * + * SYNOPSIS: + * + * long double complex casinhf(); + * long double complex z, w; + * + * w = casinhl (z); + * + * + * + * DESCRIPTION: + * + * casinh z = -i casin iz . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.8e-14 2.6e-15 + * + */ + +#include +#include + +long double complex +casinhl(long double complex z) +{ + long double complex w; + + w = -1.0L * I * casinl(z * I); + return (w); +} diff --git a/src/openlibm/src/s_casinl.c b/src/openlibm/src/s_casinl.c new file mode 100644 index 0000000..b346272 --- /dev/null +++ b/src/openlibm/src/s_casinl.c @@ -0,0 +1,130 @@ +/* $OpenBSD: s_casinl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* casinl() + * + * Complex circular arc sine + * + * + * + * SYNOPSIS: + * + * long double complex casinl(); + * long double complex z, w; + * + * w = casinl( z ); + * + * + * + * DESCRIPTION: + * + * Inverse complex sine: + * + * 2 + * w = -i clog( iz + csqrt( 1 - z ) ). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 10100 2.1e-15 3.4e-16 + * IEEE -10,+10 30000 2.2e-14 2.7e-15 + * Larger relative error can be observed for z near zero. + * Also tested by csin(casin(z)) = z. + */ + +#include +#include +#include + +#if LDBL_MANT_DIG == 64 +static const long double MACHEPL= 5.42101086242752217003726400434970855712890625E-20L; +#elif LDBL_MANT_DIG == 113 +static const long double MACHEPL = 9.629649721936179265279889712924636592690508e-35L; +#endif + +static const long double PIO2L = 1.570796326794896619231321691639751442098585L; + +long double complex +casinl(long double complex z) +{ + long double complex w; + long double x, y, b; + static long double complex ca, ct, zz, z2; + + x = creall(z); + y = cimagl(z); + + if (y == 0.0L) { + if (fabsl(x) > 1.0L) { + w = PIO2L + 0.0L * I; + /*mtherr( "casinl", DOMAIN );*/ + } + else { + w = asinl(x) + 0.0L * I; + } + return (w); + } + + /* Power series expansion */ + b = cabsl(z); + if (b < 0.125L) { + long double complex sum; + long double n, cn; + + z2 = (x - y) * (x + y) + (2.0L * x * y) * I; + cn = 1.0L; + n = 1.0L; + ca = x + y * I; + sum = x + y * I; + do { + ct = z2 * ca; + ca = ct; + + cn *= n; + n += 1.0L; + cn /= n; + n += 1.0L; + b = cn/n; + + ct *= b; + sum += ct; + b = cabsl(ct); + } + + while (b > MACHEPL); + w = sum; + return w; + } + + ca = x + y * I; + ct = ca * I; /* iz */ + /* sqrt(1 - z*z) */ + /* cmul(&ca, &ca, &zz) */ + /* x * x - y * y */ + zz = (x - y) * (x + y) + (2.0L * x * y) * I; + zz = 1.0L - creall(zz) - cimagl(zz) * I; + z2 = csqrtl(zz); + + zz = ct + z2; + zz = clogl(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0L * I); + return (w); +} diff --git a/src/openlibm/src/s_catan.c b/src/openlibm/src/s_catan.c new file mode 100644 index 0000000..9ee3dbb --- /dev/null +++ b/src/openlibm/src/s_catan.c @@ -0,0 +1,133 @@ +/* $OpenBSD: s_catan.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catan() + * + * Complex circular arc tangent + * + * + * + * SYNOPSIS: + * + * double complex catan(); + * double complex z, w; + * + * w = catan (z); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * catan(z) = -i catanh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include +#include +#include + +#include "math_private.h" + +#define MAXNUM 1.0e308 + +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; + +static double +_redupi(double x) +{ + double t; + long i; + + t = x/M_PI; + if(t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return (t); +} + +double complex +catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal (z); + y = cimag (z); + + if ((x == 0.0) && (y > 1.0)) + goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + if (a == 0.0) + goto ovrf; + + t = 0.5 * atan2 (2.0 * x, a); + w = _redupi (t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) + goto ovrf; + + t = y + 1.0; + a = (x2 + (t * t))/a; + w = w + (0.25 * log (a)) * I; + return (w); + +ovrf: + /*mtherr ("catan", OVERFLOW);*/ + w = MAXNUM + MAXNUM * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(catan, catanl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_catanf.c b/src/openlibm/src/s_catanf.c new file mode 100644 index 0000000..d40cb56 --- /dev/null +++ b/src/openlibm/src/s_catanf.c @@ -0,0 +1,124 @@ +/* $OpenBSD: s_catanf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catanf() + * + * Complex circular arc tangent + * + * + * + * SYNOPSIS: + * + * float complex catanf(); + * float complex z, w; + * + * w = catanf( z ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-6 5.2e-8 + * + */ + +#include +#include + +#define MAXNUMF 1.0e38F + +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; + +static float +_redupif(float xx) +{ + float x, t; + long i; + + x = xx; + t = x/(float)M_PI; + if(t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return(t); +} + +float complex +catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if((x == 0.0f) && (y > 1.0f)) + goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + if (a == 0.0f) + goto ovrf; + + t = 0.5f * atan2f(2.0f * x, a); + w = _redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if(a == 0.0f) + goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = w + (0.25f * logf (a)) * I; + return (w); + +ovrf: + /*mtherr( "catanf", OVERFLOW );*/ + w = MAXNUMF + MAXNUMF * I; + return (w); +} diff --git a/src/openlibm/src/s_catanh.c b/src/openlibm/src/s_catanh.c new file mode 100644 index 0000000..3e3eeaf --- /dev/null +++ b/src/openlibm/src/s_catanh.c @@ -0,0 +1,62 @@ +/* $OpenBSD: s_catanh.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catanh + * + * Complex inverse hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * double complex catanh(); + * double complex z, w; + * + * w = catanh (z); + * + * + * + * DESCRIPTION: + * + * Inverse tanh, equal to -i catan (iz); + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-16 6.2e-17 + * + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +catanh(double complex z) +{ + double complex w; + + w = -1.0 * I * catan (z * I); + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(catanh, catanhl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_catanhf.c b/src/openlibm/src/s_catanhf.c new file mode 100644 index 0000000..7d43825 --- /dev/null +++ b/src/openlibm/src/s_catanhf.c @@ -0,0 +1,55 @@ +/* $OpenBSD: s_catanhf.c,v 1.1 2008/09/07 20:36:09 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catanhf + * + * Complex inverse hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * float complex catanhf(); + * float complex z, w; + * + * w = catanhf (z); + * + * + * + * DESCRIPTION: + * + * Inverse tanh, equal to -i catan (iz); + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-16 6.2e-17 + * + */ + +#include +#include + +float complex +catanhf(float complex z) +{ + float complex w; + + w = -1.0f * I * catanf (z * I); + return (w); +} diff --git a/src/openlibm/src/s_catanhl.c b/src/openlibm/src/s_catanhl.c new file mode 100644 index 0000000..711a268 --- /dev/null +++ b/src/openlibm/src/s_catanhl.c @@ -0,0 +1,56 @@ +/* $OpenBSD: s_catanhl.c,v 1.1 2011/07/08 19:25:31 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catanhl + * + * Complex inverse hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * long double complex catanhl(); + * long double complex z, w; + * + * w = catanhl (z); + * + * + * + * DESCRIPTION: + * + * Inverse tanh, equal to -i catan (iz); + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-16 6.2e-17 + * + */ + +#include +#include + +long double complex +catanhl(long double complex z) +{ + long double complex w; + + w = -1.0L * I * catanl(z * I); + return (w); +} diff --git a/src/openlibm/src/s_catanl.c b/src/openlibm/src/s_catanl.c new file mode 100644 index 0000000..acd51b0 --- /dev/null +++ b/src/openlibm/src/s_catanl.c @@ -0,0 +1,127 @@ +/* $OpenBSD: s_catanl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* catanl() + * + * Complex circular arc tangent + * + * + * + * SYNOPSIS: + * + * long double complex catanl(); + * long double complex z, w; + * + * w = catanl( z ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include +#include +#include + +static const long double PIL = 3.141592653589793238462643383279502884197169L; +static const long double DP1 = 3.14159265358979323829596852490908531763125L; +static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; +static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; + +static long double +redupil(long double x) +{ + long double t; + long i; + + t = x / PIL; + if (t >= 0.0L) + t += 0.5L; + else + t -= 0.5L; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return (t); +} + +long double complex +catanl(long double complex z) +{ + long double complex w; + long double a, t, x, x2, y; + + x = creall(z); + y = cimagl(z); + + if ((x == 0.0L) && (y > 1.0L)) + goto ovrf; + + x2 = x * x; + a = 1.0L - x2 - (y * y); + if (a == 0.0L) + goto ovrf; + + t = atan2l(2.0L * x, a) * 0.5L; + w = redupil(t); + + t = y - 1.0L; + a = x2 + (t * t); + if (a == 0.0L) + goto ovrf; + + t = y + 1.0L; + a = (x2 + (t * t)) / a; + w = w + (0.25L * logl(a)) * I; + return (w); + +ovrf: + /*mtherr( "catanl", OVERFLOW );*/ + w = LDBL_MAX + LDBL_MAX * I; + return (w); +} diff --git a/src/openlibm/src/s_cbrt.c b/src/openlibm/src/s_cbrt.c new file mode 100644 index 0000000..b6316ad --- /dev/null +++ b/src/openlibm/src/s_cbrt.c @@ -0,0 +1,118 @@ +/* @(#)s_cbrt.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrt.c,v 1.17 2011/03/12 16:50:39 kargl Exp $"); + +#include + +#include "math_private.h" + +/* cbrt(x) + * Return cube root of x + */ +static const u_int32_t + B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ + B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double +P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ +P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ +P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ +P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ +P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +OLM_DLLEXPORT double +cbrt(double x) +{ + int32_t hx; + union { + double value; + u_int64_t bits; + } u; + double r,s,t=0.0,w; + u_int32_t sign; + u_int32_t high,low; + + EXTRACT_WORDS(hx,low,x); + sign=hx&0x80000000; /* sign= sign(x) */ + hx ^=sign; + if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */ + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if(hx<0x00100000) { /* zero or subnormal? */ + if((hx|low)==0) + return(x); /* cbrt(0) is itself */ + SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */ + t*=x; + GET_HIGH_WORD(high,t); + INSERT_WORDS(t,sign|((high&0x7fffffff)/3+B2),0); + } else + INSERT_WORDS(t,sign|(hx/3+B1),0); + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in k_tanf.c. + */ + r=(t*t)*(t/x); + t=t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.value=t; + u.bits=(u.bits+0x80000000)&0xffffffffc0000000ULL; + t=u.value; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s=t*t; /* t*t is exact */ + r=x/s; /* error <= 0.5 ulps; |r| < |t| */ + w=t+t; /* t+t is exact */ + r=(r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t=t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + return(t); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(cbrt, cbrtl); +#endif diff --git a/src/openlibm/src/s_cbrtf.c b/src/openlibm/src/s_cbrtf.c new file mode 100644 index 0000000..6a3a762 --- /dev/null +++ b/src/openlibm/src/s_cbrtf.c @@ -0,0 +1,74 @@ +/* s_cbrtf.c -- float version of s_cbrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrtf.c,v 1.18 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +/* cbrtf(x) + * Return cube root of x + */ +static const unsigned + B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +OLM_DLLEXPORT float +cbrtf(float x) +{ + double r,T; + float t; + int32_t hx; + u_int32_t sign; + u_int32_t high; + + GET_FLOAT_WORD(hx,x); + sign=hx&0x80000000; /* sign= sign(x) */ + hx ^=sign; + if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */ + + /* rough cbrt to 5 bits */ + if(hx<0x00800000) { /* zero or subnormal? */ + if(hx==0) + return(x); /* cbrt(+-0) is itself */ + SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */ + t*=x; + GET_FLOAT_WORD(high,t); + SET_FLOAT_WORD(t,sign|((high&0x7fffffff)/3+B2)); + } else + SET_FLOAT_WORD(t,sign|(hx/3+B1)); + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T=t; + r=T*T*T; + T=T*((double)x+x+r)/(x+r+r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r=T*T*T; + T=T*((double)x+x+r)/(x+r+r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return(T); +} diff --git a/src/openlibm/src/s_cbrtl.c b/src/openlibm/src/s_cbrtl.c new file mode 100644 index 0000000..2fe0360 --- /dev/null +++ b/src/openlibm/src/s_cbrtl.c @@ -0,0 +1,161 @@ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cbrtl.c,v 1.1 2011/03/12 19:37:35 kargl Exp $"); + +#include +#include +// VBS +//#include + +#include "fpmath.h" +#include "math_private.h" +#if defined(__i386__) +#include "i387/bsd_ieeefp.h" +#endif + +#define BIAS (LDBL_MAX_EXP - 1) + +static const unsigned + B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +OLM_DLLEXPORT long double +cbrtl(long double x) +{ + union IEEEl2bits u, v; + long double r, s, t, w; + double dr, dt, dx; + float ft, fx; + u_int32_t hx; + u_int16_t expsign; + int k; + + u.e = x; + expsign = u.xbits.expsign; + k = expsign & 0x7fff; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (k == BIAS + LDBL_MAX_EXP) + return (x + x); + +#ifdef __i386__ + fp_prec_t oprec; + + oprec = fpgetprec(); + if (oprec != FP_PE) + fpsetprec(FP_PE); +#endif + + if (k == 0) { + /* If x = +-0, then cbrt(x) = +-0. */ + if ((u.bits.manh | u.bits.manl) == 0) { +#ifdef __i386__ + if (oprec != FP_PE) + fpsetprec(oprec); +#endif + return (x); + } + /* Adjust subnormal numbers. */ + u.e *= 0x1.0p514; + k = u.bits.exp; + k -= BIAS + 514; + } else + k -= BIAS; + u.xbits.expsign = BIAS; + v.e = 1; + + x = u.e; + switch (k % 3) { + case 1: + case -2: + x = 2*x; + k--; + break; + case 2: + case -1: + x = 4*x; + k -= 2; + break; + } + v.xbits.expsign = (expsign & 0x8000) | (BIAS + k / 3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + fx = x; + GET_FLOAT_WORD(hx, fx); + SET_FLOAT_WORD(ft, ((hx & 0x7fffffff) / 3 + B1)); + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + volatile double vd2 = 0x1.0p32; + volatile double vd1 = 0x1.0p-31; + #define vd ((long double)vd2 + vd1) + + t = dt + vd - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#else +#error "Unsupported long double format" +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s=t*t; /* t*t is exact */ + r=x/s; /* error <= 0.5 ulps; |r| < |t| */ + w=t+t; /* t+t is exact */ + r=(r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t=t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.e; +#ifdef __i386__ + if (oprec != FP_PE) + fpsetprec(oprec); +#endif + return (t); +} diff --git a/src/openlibm/src/s_ccos.c b/src/openlibm/src/s_ccos.c new file mode 100644 index 0000000..faafdb0 --- /dev/null +++ b/src/openlibm/src/s_ccos.c @@ -0,0 +1,91 @@ +/* $OpenBSD: s_ccos.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ccos() + * + * Complex circular cosine + * + * + * + * SYNOPSIS: + * + * double complex ccos(); + * double complex z, w; + * + * w = ccos (z); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = cos x cosh y - i sin x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 4.5e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + */ + +#include +#include +#include + +#include "math_private.h" + +/* calculate cosh and sinh */ + +static void +_cchsh(double x, double *c, double *s) +{ + double e, ei; + + if (fabs(x) <= 0.5) { + *c = cosh(x); + *s = sinh(x); + } + else { + e = exp(x); + ei = 0.5/e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + +double complex +ccos(double complex z) +{ + double complex w; + double ch, sh; + + _cchsh( cimag(z), &ch, &sh ); + w = cos(creal (z)) * ch - (sin (creal (z)) * sh) * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(ccos, ccosl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_ccosf.c b/src/openlibm/src/s_ccosf.c new file mode 100644 index 0000000..ce382f0 --- /dev/null +++ b/src/openlibm/src/s_ccosf.c @@ -0,0 +1,84 @@ +/* $OpenBSD: s_ccosf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ccosf() + * + * Complex circular cosine + * + * + * + * SYNOPSIS: + * + * void ccosf(); + * cmplxf z, w; + * + * ccosf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = cos x cosh y - i sin x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.8e-7 5.5e-8 + */ + +#include +#include + +/* calculate cosh and sinh */ + +static void +_cchshf(float xx, float *c, float *s) +{ + float x, e, ei; + + x = xx; + if(fabsf(x) <= 0.5f) { + *c = coshf(x); + *s = sinhf(x); + } + else { + e = expf(x); + ei = 0.5f/e; + e = 0.5f * e; + *s = e - ei; + *c = e + ei; + } +} + +float complex +ccosf(float complex z) +{ + float complex w; + float ch, sh; + + _cchshf( cimagf(z), &ch, &sh ); + w = cosf( crealf(z) ) * ch + ( -sinf( crealf(z) ) * sh) * I; + return (w); +} diff --git a/src/openlibm/src/s_ccosh.c b/src/openlibm/src/s_ccosh.c new file mode 100644 index 0000000..110494a --- /dev/null +++ b/src/openlibm/src/s_ccosh.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ccosh.c,v 1.2 2011/10/21 06:29:32 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const double huge = 0x1p1023; + +OLM_DLLEXPORT double complex +ccosh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return (CMPLX(cosh(x), x * y)); + if (ix < 0x40360000) /* small x: normal case */ + return (CMPLX(cosh(x) * cos(y), sinh(x) * sin(y))); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return (CMPLX(h * cos(y), copysign(h, x) * sin(y))); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return (CMPLX(creal(z), cimag(z) * copysign(1, x))); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return (CMPLX(h * h * cos(y), h * sin(y))); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return (CMPLX(y - y, copysign(0, x * (y - y)))); + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return (CMPLX(x * x, copysign(0, x) * y)); + return (CMPLX(x * x, copysign(0, (x + x) * y))); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return (CMPLX(y - y, x * (y - y))); + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return (CMPLX(x * x, x * (y - y))); + return (CMPLX((x * x) * cos(y), x * sin(y))); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return (CMPLX((x * x) * (y - y), (x + x) * (y - y))); +} + +OLM_DLLEXPORT double complex +ccos(double complex z) +{ + + /* ccos(z) = ccosh(I * z) */ + return (ccosh(CMPLX(-cimag(z), creal(z)))); +} diff --git a/src/openlibm/src/s_ccoshf.c b/src/openlibm/src/s_ccoshf.c new file mode 100644 index 0000000..53c8e7a --- /dev/null +++ b/src/openlibm/src/s_ccoshf.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic cosine of a complex argument. See s_ccosh.c for details. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ccoshf.c,v 1.2 2011/10/21 06:29:32 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const float huge = 0x1p127; + +OLM_DLLEXPORT float complex +ccoshf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return (CMPLXF(coshf(x), x * y)); + if (ix < 0x41100000) /* small x: normal case */ + return (CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y))); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return (CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y))); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return (CMPLXF(crealf(z), cimagf(z) * copysignf(1, x))); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return (CMPLXF(h * h * cosf(y), h * sinf(y))); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return (CMPLXF(y - y, copysignf(0, x * (y - y)))); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return (CMPLXF(x * x, copysignf(0, x) * y)); + return (CMPLXF(x * x, copysignf(0, (x + x) * y))); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return (CMPLXF(y - y, x * (y - y))); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return (CMPLXF(x * x, x * (y - y))); + return (CMPLXF((x * x) * cosf(y), x * sinf(y))); + } + + return (CMPLXF((x * x) * (y - y), (x + x) * (y - y))); +} + +OLM_DLLEXPORT float complex +ccosf(float complex z) +{ + + return (ccoshf(CMPLXF(-cimagf(z), crealf(z)))); +} diff --git a/src/openlibm/src/s_ccoshl.c b/src/openlibm/src/s_ccoshl.c new file mode 100644 index 0000000..0233d19 --- /dev/null +++ b/src/openlibm/src/s_ccoshl.c @@ -0,0 +1,59 @@ +/* $OpenBSD: s_ccoshl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ccoshl + * + * Complex hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * long double complex ccoshl(); + * long double complex z, w; + * + * w = ccoshl (z); + * + * + * + * DESCRIPTION: + * + * ccosh(z) = cosh x cos y + i sinh x sin y . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.9e-16 8.1e-17 + * + */ + +#include +#include + +long double complex +ccoshl(long double complex z) +{ + long double complex w; + long double x, y; + + x = creall(z); + y = cimagl(z); + w = coshl(x) * cosl(y) + (sinhl(x) * sinl(y)) * I; + return (w); +} diff --git a/src/openlibm/src/s_ccosl.c b/src/openlibm/src/s_ccosl.c new file mode 100644 index 0000000..0d50483 --- /dev/null +++ b/src/openlibm/src/s_ccosl.c @@ -0,0 +1,82 @@ +/* $OpenBSD: s_ccosl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ccosl() + * + * Complex circular cosine + * + * + * + * SYNOPSIS: + * + * long double complex ccosl(); + * long double complex z, w; + * + * w = ccosl( z ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = cos x cosh y - i sin x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 4.5e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + */ + +#include +#include + +static void +cchshl(long double x, long double *c, long double *s) +{ + long double e, ei; + + if(fabsl(x) <= 0.5L) { + *c = coshl(x); + *s = sinhl(x); + } else { + e = expl(x); + ei = 0.5L/e; + e = 0.5L * e; + *s = e - ei; + *c = e + ei; + } +} + +long double complex +ccosl(long double complex z) +{ + long double complex w; + long double ch, sh; + + cchshl(cimagl(z), &ch, &sh); + w = cosl(creall(z)) * ch + (-sinl(creall(z)) * sh) * I; + return (w); +} diff --git a/src/openlibm/src/s_ceil.c b/src/openlibm/src/s_ceil.c new file mode 100644 index 0000000..9c70a97 --- /dev/null +++ b/src/openlibm/src/s_ceil.c @@ -0,0 +1,77 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ceil.c,v 1.11 2008/02/15 07:01:40 bde Exp $"); + +/* + * ceil(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceil(x). + */ + +#include +#include + +#include "math_private.h" + +static const double huge = 1.0e300; + +OLM_DLLEXPORT double +ceil(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;i1=0;} + else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0>0) { + if(j0==20) i0+=1; + else { + j = i1 + (1<<(52-j0)); + if(j + +#include "math_private.h" + +static const float huge = 1.0e30; + +OLM_DLLEXPORT float +ceilf(float x) +{ + int32_t i0,j0; + u_int32_t i; + + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;} + else if(i0!=0) { i0=0x3f800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/src/openlibm/src/s_ceill.c b/src/openlibm/src/s_ceill.c new file mode 100644 index 0000000..f525411 --- /dev/null +++ b/src/openlibm/src/s_ceill.c @@ -0,0 +1,102 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_ceil.c 5.1 93/09/24 + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ceill.c,v 1.9 2008/02/14 15:10:33 bde Exp $"); + +/* + * ceill(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to ceill(x). + */ + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#define INC_MANH(u, c) do { \ + u_int64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) \ + u.bits.exp++; \ +} while (0) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#define INC_MANH(u, c) do { \ + u_int64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) { \ + u.bits.exp++; \ + u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \ + } \ +} while (0) +#endif + +static const long double huge = 1.0e300; + +OLM_DLLEXPORT long double +ceill(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + if (u.bits.exp > 0 || + (u.bits.manh | u.bits.manl) != 0) + u.e = u.bits.sign ? -0.0 : 1.0; + } else { + u_int64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (!u.bits.sign) { +#ifdef LDBL_IMPLICIT_NBIT + if (e == 0) + u.bits.exp++; + else +#endif + INC_MANH(u, 1llu << (MANH_SIZE - e - 1)); + } + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + u_int64_t m = (u_int64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (!u.bits.sign) { + if (e == MANH_SIZE - 1) + INC_MANH(u, 1); + else { + u_int64_t o = u.bits.manl; + u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1); + if (u.bits.manl < o) /* got a carry */ + INC_MANH(u, 1); + } + } + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/src/openlibm/src/s_cexp.c b/src/openlibm/src/s_cexp.c new file mode 100644 index 0000000..1510721 --- /dev/null +++ b/src/openlibm/src/s_cexp.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cexp.c,v 1.3 2011/10/21 06:27:56 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const u_int32_t +exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ +cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +OLM_DLLEXPORT double complex +cexp(double complex z) +{ + double x, y, exp_x; + u_int32_t hx, hy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hy, ly, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if ((hy | ly) == 0) + return (CMPLX(exp(x), y)); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) + return (CMPLX(cos(y), sin(y))); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return (CMPLX(y - y, y - y)); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return (CMPLX(0.0, 0.0)); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return (CMPLX(x, y - y)); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 709.7 and 1454.3, so we must scale to avoid + * overflow in exp(x). + */ + return (__ldexp_cexp(z, 0)); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = exp(x); + return (CMPLX(exp_x * cos(y), exp_x * sin(y))); + } +} diff --git a/src/openlibm/src/s_cexpf.c b/src/openlibm/src/s_cexpf.c new file mode 100644 index 0000000..05f4544 --- /dev/null +++ b/src/openlibm/src/s_cexpf.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cexpf.c,v 1.3 2011/10/21 06:27:56 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const u_int32_t +exp_ovfl = 0x42b17218, /* MAX_EXP * ln2 ~= 88.722839355 */ +cexp_ovfl = 0x43400074; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +OLM_DLLEXPORT float complex +cexpf(float complex z) +{ + float x, y, exp_x; + u_int32_t hx, hy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hy, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if (hy == 0) + return (CMPLXF(expf(x), y)); + GET_FLOAT_WORD(hx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if ((hx & 0x7fffffff) == 0) + return (CMPLXF(cosf(y), sinf(y))); + + if (hy >= 0x7f800000) { + if ((hx & 0x7fffffff) != 0x7f800000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return (CMPLXF(y - y, y - y)); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return (CMPLXF(0.0, 0.0)); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return (CMPLXF(x, y - y)); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 88.7 and 192, so we must scale to avoid + * overflow in expf(x). + */ + return (__ldexp_cexpf(z, 0)); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = expf(x); + return (CMPLXF(exp_x * cosf(y), exp_x * sinf(y))); + } +} diff --git a/src/openlibm/src/s_cexpl.c b/src/openlibm/src/s_cexpl.c new file mode 100644 index 0000000..f143d88 --- /dev/null +++ b/src/openlibm/src/s_cexpl.c @@ -0,0 +1,69 @@ +/* $OpenBSD: s_cexpl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cexpl() + * + * Complex exponential function + * + * + * + * SYNOPSIS: + * + * long double complex cexpl(); + * long double complex z, w; + * + * w = cexpl( z ); + * + * + * + * DESCRIPTION: + * + * Returns the exponential of the complex argument z + * into the complex result w. + * + * If + * z = x + iy, + * r = exp(x), + * + * then + * + * w = r cos y + i r sin y. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8700 3.7e-17 1.1e-17 + * IEEE -10,+10 30000 3.0e-16 8.7e-17 + * + */ + +#include +#include + +long double complex +cexpl(long double complex z) +{ + long double complex w; + long double r; + + r = expl(creall(z)); + w = r * cosl(cimagl(z)) + (r * sinl(cimagl(z))) * I; + return (w); +} diff --git a/src/openlibm/src/s_cimag.c b/src/openlibm/src/s_cimag.c new file mode 100644 index 0000000..456ae99 --- /dev/null +++ b/src/openlibm/src/s_cimag.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_cimag.c,v 1.3 2009/03/14 18:24:15 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +cimag(double complex z) +{ + return (__imag__ z); +} diff --git a/src/openlibm/src/s_cimagf.c b/src/openlibm/src/s_cimagf.c new file mode 100644 index 0000000..8287412 --- /dev/null +++ b/src/openlibm/src/s_cimagf.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_cimagf.c,v 1.3 2009/03/14 18:24:15 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +cimagf(float complex z) +{ + return (__imag__ z); +} diff --git a/src/openlibm/src/s_cimagl.c b/src/openlibm/src/s_cimagl.c new file mode 100644 index 0000000..588c6a3 --- /dev/null +++ b/src/openlibm/src/s_cimagl.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_cimagl.c,v 1.3 2009/03/14 18:24:15 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +cimagl(long double complex z) +{ + return (__imag__ z); +} diff --git a/src/openlibm/src/s_clog.c b/src/openlibm/src/s_clog.c new file mode 100644 index 0000000..6412df7 --- /dev/null +++ b/src/openlibm/src/s_clog.c @@ -0,0 +1,79 @@ +/* $OpenBSD: s_clog.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* clog.c + * + * Complex natural logarithm + * + * + * + * SYNOPSIS: + * + * double complex clog(); + * double complex z, w; + * + * w = clog (z); + * + * + * + * DESCRIPTION: + * + * Returns complex logarithm to the base e (2.718...) of + * the complex argument x. + * + * If z = x + iy, r = sqrt( x**2 + y**2 ), + * then + * w = log(r) + i arctan(y/x). + * + * The arctangent ranges from -PI to +PI. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 7000 8.5e-17 1.9e-17 + * IEEE -10,+10 30000 5.0e-15 1.1e-16 + * + * Larger relative error can be observed for z near 1 +i0. + * In IEEE arithmetic the peak absolute error is 5.2e-16, rms + * absolute error 1.0e-16. + */ + +#include +#include +#include + +#include "math_private.h" + +double complex +clog(double complex z) +{ + double complex w; + double p, rr; + + /*rr = sqrt( z->r * z->r + z->i * z->i );*/ + rr = cabs(z); + p = log(rr); + rr = atan2 (cimag (z), creal (z)); + w = p + rr * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(clog, clogl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_clogf.c b/src/openlibm/src/s_clogf.c new file mode 100644 index 0000000..e157aae --- /dev/null +++ b/src/openlibm/src/s_clogf.c @@ -0,0 +1,72 @@ +/* $OpenBSD: s_clogf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* clogf.c + * + * Complex natural logarithm + * + * + * + * SYNOPSIS: + * + * void clogf(); + * cmplxf z, w; + * + * clogf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * Returns complex logarithm to the base e (2.718...) of + * the complex argument x. + * + * If z = x + iy, r = sqrt( x**2 + y**2 ), + * then + * w = log(r) + i arctan(y/x). + * + * The arctangent ranges from -PI to +PI. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.9e-6 6.2e-8 + * + * Larger relative error can be observed for z near 1 +i0. + * In IEEE arithmetic the peak absolute error is 3.1e-7. + * + */ + +#include +#include + +float complex +clogf(float complex z) +{ + float complex w; + float p, rr, x, y; + + x = crealf(z); + y = cimagf(z); + rr = atan2f(y, x); + p = cabsf(z); + p = logf(p); + w = p + rr * I; + return (w); +} diff --git a/src/openlibm/src/s_clogl.c b/src/openlibm/src/s_clogl.c new file mode 100644 index 0000000..c337103 --- /dev/null +++ b/src/openlibm/src/s_clogl.c @@ -0,0 +1,73 @@ +/* $OpenBSD: s_clogl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* clogl.c + * + * Complex natural logarithm + * + * + * + * SYNOPSIS: + * + * long double complex clogl(); + * long double complex z, w; + * + * w = clogl( z ); + * + * + * + * DESCRIPTION: + * + * Returns complex logarithm to the base e (2.718...) of + * the complex argument x. + * + * If z = x + iy, r = sqrt( x**2 + y**2 ), + * then + * w = log(r) + i arctan(y/x). + * + * The arctangent ranges from -PI to +PI. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 7000 8.5e-17 1.9e-17 + * IEEE -10,+10 30000 5.0e-15 1.1e-16 + * + * Larger relative error can be observed for z near 1 +i0. + * In IEEE arithmetic the peak absolute error is 5.2e-16, rms + * absolute error 1.0e-16. + */ + +#include +#include + +long double complex +clogl(long double complex z) +{ + long double complex w; + long double p, rr; + + /*rr = sqrt(z->r * z->r + z->i * z->i);*/ + p = cabsl(z); + p = logl(p); + rr = atan2l(cimagl(z), creall(z)); + w = p + rr * I; + return (w); +} diff --git a/src/openlibm/src/s_conj.c b/src/openlibm/src/s_conj.c new file mode 100644 index 0000000..a7c0940 --- /dev/null +++ b/src/openlibm/src/s_conj.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_conj.c,v 1.2 2008/08/07 14:39:56 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double complex +conj(double complex z) +{ + + return (CMPLX(creal(z), -cimag(z))); +} diff --git a/src/openlibm/src/s_conjf.c b/src/openlibm/src/s_conjf.c new file mode 100644 index 0000000..d2ff743 --- /dev/null +++ b/src/openlibm/src/s_conjf.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_conjf.c,v 1.2 2008/08/07 14:39:56 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float complex +conjf(float complex z) +{ + + return (CMPLXF(crealf(z), -cimagf(z))); +} diff --git a/src/openlibm/src/s_conjl.c b/src/openlibm/src/s_conjl.c new file mode 100644 index 0000000..e4d7a01 --- /dev/null +++ b/src/openlibm/src/s_conjl.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_conjl.c,v 1.2 2008/08/07 14:39:56 das Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double complex +conjl(long double complex z) +{ + + return (CMPLXL(creall(z), -cimagl(z))); +} diff --git a/src/openlibm/src/s_copysign.c b/src/openlibm/src/s_copysign.c new file mode 100644 index 0000000..a52701f --- /dev/null +++ b/src/openlibm/src/s_copysign.c @@ -0,0 +1,34 @@ +/* @(#)s_copysign.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_copysign.c,v 1.10 2008/02/22 02:30:35 das Exp $"); + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +copysign(double x, double y) +{ + u_int32_t hx,hy; + GET_HIGH_WORD(hx,x); + GET_HIGH_WORD(hy,y); + SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); + return x; +} diff --git a/src/openlibm/src/s_copysignf.c b/src/openlibm/src/s_copysignf.c new file mode 100644 index 0000000..945b3fd --- /dev/null +++ b/src/openlibm/src/s_copysignf.c @@ -0,0 +1,37 @@ +/* s_copysignf.c -- float version of s_copysign.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_copysignf.c,v 1.10 2008/02/22 02:30:35 das Exp $"); + +/* + * copysignf(float x, float y) + * copysignf(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +copysignf(float x, float y) +{ + u_int32_t ix,iy; + GET_FLOAT_WORD(ix,x); + GET_FLOAT_WORD(iy,y); + SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000)); + return x; +} diff --git a/src/openlibm/src/s_copysignl.c b/src/openlibm/src/s_copysignl.c new file mode 100644 index 0000000..6cae5d3 --- /dev/null +++ b/src/openlibm/src/s_copysignl.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_copysignl.c,v 1.2 2007/01/07 07:54:21 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT long double +copysignl(long double x, long double y) +{ + union IEEEl2bits ux, uy; + + ux.e = x; + uy.e = y; + ux.bits.sign = uy.bits.sign; + return (ux.e); +} diff --git a/src/openlibm/src/s_cos.c b/src/openlibm/src/s_cos.c new file mode 100644 index 0000000..9896bd8 --- /dev/null +++ b/src/openlibm/src/s_cos.c @@ -0,0 +1,89 @@ +/* @(#)s_cos.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cos.c,v 1.13 2011/02/10 07:37:50 das Exp $"); + +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cosine function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include +#include + +//#define INLINE_REM_PIO2 +#include "math_private.h" +//#include "e_rem_pio2.c" + +OLM_DLLEXPORT double +cos(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e46a09e) /* if x < 2**-27 * sqrt(2) */ + if(((int)x)==0) return 1.0; /* generate inexact */ + return __kernel_cos(x,z); + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch(n&3) { + case 0: return __kernel_cos(y[0],y[1]); + case 1: return -__kernel_sin(y[0],y[1],1); + case 2: return -__kernel_cos(y[0],y[1]); + default: + return __kernel_sin(y[0],y[1],1); + } + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(cos, cosl); +#endif diff --git a/src/openlibm/src/s_cosf.c b/src/openlibm/src/s_cosf.c new file mode 100644 index 0000000..57ec7c7 --- /dev/null +++ b/src/openlibm/src/s_cosf.c @@ -0,0 +1,85 @@ +/* s_cosf.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cosf.c,v 1.18 2008/02/25 22:19:17 bde Exp $"); + +#include +#include + +//#define INLINE_KERNEL_COSDF +//#define INLINE_KERNEL_SINDF +//#define INLINE_REM_PIO2F +#include "math_private.h" +//#include "e_rem_pio2f.c" +//#include "k_cosf.c" +//#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +OLM_DLLEXPORT float +cosf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return 1.0; /* 1 with inexact if x != 0 */ + return __kernel_cosdf(x); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix<=0x4016cbe3) { /* |x| ~> 3*pi/4 */ + if(hx>0) + return __kernel_sindf(c1pio2 - x); + else + return __kernel_sindf(x + c1pio2); + } else + return -__kernel_cosdf(x + (hx > 0 ? -c2pio2 : c2pio2)); + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix<=0x40afeddf) { /* |x| ~> 7*pi/4 */ + if(hx>0) + return __kernel_sindf(x - c3pio2); + else + return __kernel_sindf(-c3pio2 - x); + } else + return __kernel_cosdf(x + (hx > 0 ? -c4pio2 : c4pio2)); + } + + /* cos(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch(n&3) { + case 0: return __kernel_cosdf(y); + case 1: return __kernel_sindf(-y); + case 2: return -__kernel_cosdf(y); + default: + return __kernel_sindf(y); + } + } +} diff --git a/src/openlibm/src/s_cosl.c b/src/openlibm/src/s_cosl.c new file mode 100644 index 0000000..886d3e3 --- /dev/null +++ b/src/openlibm/src/s_cosl.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cosl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $"); + +/* + * Limited testing on pseudorandom numbers drawn within [-2e8:4e8] shows + * an accuracy of <= 0.7412 ULP. + */ + +#include +#include + +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT long double +cosl(long double x) +{ + union IEEEl2bits z; + int e0; + long double y[2]; + long double hi, lo; + + z.e = x; + z.bits.sign = 0; + + /* If x = +-0 or x is a subnormal number, then cos(x) = 1 */ + if (z.bits.exp == 0) + return (1.0); + + /* If x = NaN or Inf, then cos(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) + return (__kernel_cosl(z.e, 0)); + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + hi = __kernel_cosl(hi, lo); + break; + case 1: + hi = - __kernel_sinl(hi, lo, 1); + break; + case 2: + hi = - __kernel_cosl(hi, lo); + break; + case 3: + hi = __kernel_sinl(hi, lo, 1); + break; + } + + return (hi); +} diff --git a/src/openlibm/src/s_cpow.c b/src/openlibm/src/s_cpow.c new file mode 100644 index 0000000..dae6251 --- /dev/null +++ b/src/openlibm/src/s_cpow.c @@ -0,0 +1,78 @@ +/* $OpenBSD: s_cpow.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cpow + * + * Complex power function + * + * + * + * SYNOPSIS: + * + * double complex cpow(); + * double complex a, z, w; + * + * w = cpow (a, z); + * + * + * + * DESCRIPTION: + * + * Raises complex A to the complex Zth power. + * Definition is per AMS55 # 4.2.8, + * analytically equivalent to cpow(a,z) = cexp(z clog(a)). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 9.4e-15 1.5e-15 + * + */ + +#include +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double complex +cpow(double complex a, double complex z) +{ + double complex w; + double x, y, r, theta, absa, arga; + + x = creal (z); + y = cimag (z); + absa = cabs (a); + if (absa == 0.0) { + return (0.0 + 0.0 * I); + } + arga = carg (a); + r = pow (absa, x); + theta = x * arga; + if (y != 0.0) { + r = r * exp (-y * arga); + theta = theta + y * log (absa); + } + w = r * cos (theta) + (r * sin (theta)) * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(cpow, cpowl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_cpowf.c b/src/openlibm/src/s_cpowf.c new file mode 100644 index 0000000..764053d --- /dev/null +++ b/src/openlibm/src/s_cpowf.c @@ -0,0 +1,73 @@ +/* $OpenBSD: s_cpowf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cpowf + * + * Complex power function + * + * + * + * SYNOPSIS: + * + * float complex cpowf(); + * float complex a, z, w; + * + * w = cpowf (a, z); + * + * + * + * DESCRIPTION: + * + * Raises complex A to the complex Zth power. + * Definition is per AMS55 # 4.2.8, + * analytically equivalent to cpow(a,z) = cexp(z clog(a)). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 9.4e-15 1.5e-15 + * + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT float complex +cpowf(float complex a, float complex z) +{ + float complex w; + float x, y, r, theta, absa, arga; + + x = crealf(z); + y = cimagf(z); + absa = cabsf (a); + if (absa == 0.0f) { + return (0.0f + 0.0f * I); + } + arga = cargf (a); + r = powf (absa, x); + theta = x * arga; + if (y != 0.0f) { + r = r * expf (-y * arga); + theta = theta + y * logf (absa); + } + w = r * cosf (theta) + (r * sinf (theta)) * I; + return (w); +} diff --git a/src/openlibm/src/s_cpowl.c b/src/openlibm/src/s_cpowl.c new file mode 100644 index 0000000..81c9afd --- /dev/null +++ b/src/openlibm/src/s_cpowl.c @@ -0,0 +1,74 @@ +/* $OpenBSD: s_cpowl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* cpowl + * + * Complex power function + * + * + * + * SYNOPSIS: + * + * long double complex cpowl(); + * long double complex a, z, w; + * + * w = cpowl (a, z); + * + * + * + * DESCRIPTION: + * + * Raises complex A to the complex Zth power. + * Definition is per AMS55 # 4.2.8, + * analytically equivalent to cpow(a,z) = cexp(z clog(a)). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 9.4e-15 1.5e-15 + * + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double complex +cpowl(long double complex a, long double complex z) +{ + long double complex w; + long double x, y, r, theta, absa, arga; + + x = creall(z); + y = cimagl(z); + absa = cabsl(a); + if (absa == 0.0L) { + return (0.0L + 0.0L * I); + } + arga = cargl(a); + r = powl(absa, x); + theta = x * arga; + if (y != 0.0L) { + r = r * expl(-y * arga); + theta = theta + y * logl(absa); + } + w = r * cosl(theta) + (r * sinl(theta)) * I; + return (w); +} diff --git a/src/openlibm/src/s_cproj.c b/src/openlibm/src/s_cproj.c new file mode 100644 index 0000000..b9faa24 --- /dev/null +++ b/src/openlibm/src/s_cproj.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cproj.c,v 1.1 2008/08/07 15:07:48 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double complex +cproj(double complex z) +{ + + if (!isinf(creal(z)) && !isinf(cimag(z))) + return (z); + else + return (CMPLX(INFINITY, copysign(0.0, cimag(z)))); +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(cproj, cprojl); +#endif diff --git a/src/openlibm/src/s_cprojf.c b/src/openlibm/src/s_cprojf.c new file mode 100644 index 0000000..717c165 --- /dev/null +++ b/src/openlibm/src/s_cprojf.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cprojf.c,v 1.1 2008/08/07 15:07:48 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT float complex +cprojf(float complex z) +{ + + if (!isinf(crealf(z)) && !isinf(cimagf(z))) + return (z); + else + return (CMPLXF(INFINITY, copysignf(0.0, cimagf(z)))); +} diff --git a/src/openlibm/src/s_cprojl.c b/src/openlibm/src/s_cprojl.c new file mode 100644 index 0000000..753ab4c --- /dev/null +++ b/src/openlibm/src/s_cprojl.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_cprojl.c,v 1.1 2008/08/07 15:07:48 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double complex +cprojl(long double complex z) +{ + + if (!isinf(creall(z)) && !isinf(cimagl(z))) + return (z); + else + return (CMPLXL(INFINITY, copysignl(0.0, cimagl(z)))); +} diff --git a/src/openlibm/src/s_creal.c b/src/openlibm/src/s_creal.c new file mode 100644 index 0000000..28a0fbf --- /dev/null +++ b/src/openlibm/src/s_creal.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_creal.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +creal(double complex z) +{ + return z; +} diff --git a/src/openlibm/src/s_crealf.c b/src/openlibm/src/s_crealf.c new file mode 100644 index 0000000..9aaed5f --- /dev/null +++ b/src/openlibm/src/s_crealf.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_crealf.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +crealf(float complex z) +{ + return z; +} diff --git a/src/openlibm/src/s_creall.c b/src/openlibm/src/s_creall.c new file mode 100644 index 0000000..576666e --- /dev/null +++ b/src/openlibm/src/s_creall.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Stefan Farfeleder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_creall.c,v 1.1 2004/05/30 09:21:56 stefanf Exp $ + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +creall(long double complex z) +{ + return z; +} diff --git a/src/openlibm/src/s_csin.c b/src/openlibm/src/s_csin.c new file mode 100644 index 0000000..a905991 --- /dev/null +++ b/src/openlibm/src/s_csin.c @@ -0,0 +1,93 @@ +/* $OpenBSD: s_csin.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* csin() + * + * Complex circular sine + * + * + * + * SYNOPSIS: + * + * double complex csin(); + * double complex z, w; + * + * w = csin (z); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = sin x cosh y + i cos x sinh y. + * + * csin(z) = -i csinh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 5.3e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + * Also tested by csin(casin(z)) = z. + * + */ + +#include +#include +#include + +#include "math_private.h" + +/* calculate cosh and sinh */ + +static void +cchsh(double x, double *c, double *s) +{ + double e, ei; + + if (fabs(x) <= 0.5) { + *c = cosh(x); + *s = sinh(x); + } + else { + e = exp(x); + ei = 0.5/e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + +double complex +csin(double complex z) +{ + double complex w; + double ch, sh; + + cchsh( cimag (z), &ch, &sh ); + w = sin (creal(z)) * ch + (cos (creal(z)) * sh) * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(csin, csinl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_csinf.c b/src/openlibm/src/s_csinf.c new file mode 100644 index 0000000..42aa981 --- /dev/null +++ b/src/openlibm/src/s_csinf.c @@ -0,0 +1,85 @@ +/* $OpenBSD: s_csinf.c,v 1.2 2010/07/18 18:42:26 guenther Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* csinf() + * + * Complex circular sine + * + * + * + * SYNOPSIS: + * + * void csinf(); + * cmplxf z, w; + * + * csinf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = sin x cosh y + i cos x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.9e-7 5.5e-8 + * + */ + +#include +#include + +/* calculate cosh and sinh */ + +static void +cchshf(float xx, float *c, float *s) +{ + float x, e, ei; + + x = xx; + if(fabsf(x) <= 0.5f) { + *c = coshf(x); + *s = sinhf(x); + } + else { + e = expf(x); + ei = 0.5f/e; + e = 0.5f * e; + *s = e - ei; + *c = e + ei; + } +} + +float complex +csinf(float complex z) +{ + float complex w; + float ch, sh; + + cchshf(cimagf(z), &ch, &sh); + w = sinf(crealf(z)) * ch + (cosf(crealf(z)) * sh) * I; + return (w); +} diff --git a/src/openlibm/src/s_csinh.c b/src/openlibm/src/s_csinh.c new file mode 100644 index 0000000..3838f25 --- /dev/null +++ b/src/openlibm/src/s_csinh.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_csinh.c,v 1.2 2011/10/21 06:29:32 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const double huge = 0x1p1023; + +OLM_DLLEXPORT double complex +csinh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return (CMPLX(sinh(x), y)); + if (ix < 0x40360000) /* small x: normal case */ + return (CMPLX(sinh(x) * cos(y), cosh(x) * sin(y))); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return (CMPLX(copysign(h, x) * cos(y), h * sin(y))); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return (CMPLX(creal(z) * copysign(1, x), cimag(z))); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return (CMPLX(h * cos(y), h * h * sin(y))); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return (CMPLX(copysign(0, x * (y - y)), y - y)); + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return (CMPLX(x, y)); + return (CMPLX(x, copysign(0, y))); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return (CMPLX(y - y, x * (y - y))); + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return (CMPLX(x * x, x * (y - y))); + return (CMPLX(x * cos(y), INFINITY * sin(y))); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return (CMPLX((x * x) * (y - y), (x + x) * (y - y))); +} + +OLM_DLLEXPORT double complex +csin(double complex z) +{ + + /* csin(z) = -I * csinh(I * z) */ + z = csinh(CMPLX(-cimag(z), creal(z))); + return (CMPLX(cimag(z), -creal(z))); +} diff --git a/src/openlibm/src/s_csinhf.c b/src/openlibm/src/s_csinhf.c new file mode 100644 index 0000000..94954b0 --- /dev/null +++ b/src/openlibm/src/s_csinhf.c @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic sine of a complex argument z. See s_csinh.c for details. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_csinhf.c,v 1.2 2011/10/21 06:29:32 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const float huge = 0x1p127; + +OLM_DLLEXPORT float complex +csinhf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return (CMPLXF(sinhf(x), y)); + if (ix < 0x41100000) /* small x: normal case */ + return (CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y))); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return (CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y))); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return (CMPLXF(crealf(z) * copysignf(1, x), cimagf(z))); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return (CMPLXF(h * cosf(y), h * h * sinf(y))); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return (CMPLXF(copysignf(0, x * (y - y)), y - y)); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return (CMPLXF(x, y)); + return (CMPLXF(x, copysignf(0, y))); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return (CMPLXF(y - y, x * (y - y))); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return (CMPLXF(x * x, x * (y - y))); + return (CMPLXF(x * cosf(y), INFINITY * sinf(y))); + } + + return (CMPLXF((x * x) * (y - y), (x + x) * (y - y))); +} + +OLM_DLLEXPORT float complex +csinf(float complex z) +{ + + z = csinhf(CMPLXF(-cimagf(z), crealf(z))); + return (CMPLXF(cimagf(z), -crealf(z))); +} diff --git a/src/openlibm/src/s_csinhl.c b/src/openlibm/src/s_csinhl.c new file mode 100644 index 0000000..57b577f --- /dev/null +++ b/src/openlibm/src/s_csinhl.c @@ -0,0 +1,58 @@ +/* $OpenBSD: s_csinhl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* csinhl + * + * Complex hyperbolic sine + * + * + * + * SYNOPSIS: + * + * long double complex csinhl(); + * long double complex z, w; + * + * w = csinhl (z); + * + * DESCRIPTION: + * + * csinh z = (cexp(z) - cexp(-z))/2 + * = sinh x * cos y + i cosh x * sin y . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 3.1e-16 8.2e-17 + * + */ + +#include +#include + +long double complex +csinhl(long double complex z) +{ + long double complex w; + long double x, y; + + x = creall(z); + y = cimagl(z); + w = sinhl(x) * cosl(y) + (coshl(x) * sinl(y)) * I; + return (w); +} diff --git a/src/openlibm/src/s_csinl.c b/src/openlibm/src/s_csinl.c new file mode 100644 index 0000000..3470ac5 --- /dev/null +++ b/src/openlibm/src/s_csinl.c @@ -0,0 +1,84 @@ +/* $OpenBSD: s_csinl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* csinl() + * + * Complex circular sine + * + * + * + * SYNOPSIS: + * + * long double complex csinl(); + * long double complex z, w; + * + * w = csinl( z ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = sin x cosh y + i cos x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 5.3e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + * Also tested by csin(casin(z)) = z. + * + */ + +#include +#include + +static void +cchshl(long double x, long double *c, long double *s) +{ + long double e, ei; + + if(fabsl(x) <= 0.5L) { + *c = coshl(x); + *s = sinhl(x); + } else { + e = expl(x); + ei = 0.5L/e; + e = 0.5L * e; + *s = e - ei; + *c = e + ei; + } +} + +long double complex +csinl(long double complex z) +{ + long double complex w; + long double ch, sh; + + cchshl(cimagl(z), &ch, &sh); + w = sinl(creall(z)) * ch + (cosl(creall(z)) * sh) * I; + return (w); +} diff --git a/src/openlibm/src/s_csqrt.c b/src/openlibm/src/s_csqrt.c new file mode 100644 index 0000000..9cf4255 --- /dev/null +++ b/src/openlibm/src/s_csqrt.c @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_csqrt.c,v 1.4 2008/08/08 00:15:16 das Exp $"); + +#include +#include +#include + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#ifndef __GNUC__ +#pragma STDC CX_LIMITED_RANGE ON +#endif + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH 0x1.a827999fcef32p+1022 + +OLM_DLLEXPORT double complex +csqrt(double complex z) +{ + double complex result; + double a, b; + double t; + int scale; + + a = creal(z); + b = cimag(z); + + /* Handle special cases. */ + if (z == 0) + return (CMPLX(0, b)); + if (isinf(b)) + return (CMPLX(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (CMPLX(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (CMPLX(fabs(b - b), copysign(a, b))); + else + return (CMPLX(a, copysign(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabs(a) >= THRESH || fabs(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + result = CMPLX(t, b / (2 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + result = CMPLX(fabs(b) / (2 * t), copysign(t, b)); + } + + /* Rescale. */ + if (scale) + return (result * 2); + else + return (result); +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(csqrt, csqrtl); +#endif diff --git a/src/openlibm/src/s_csqrtf.c b/src/openlibm/src/s_csqrtf.c new file mode 100644 index 0000000..a131829 --- /dev/null +++ b/src/openlibm/src/s_csqrtf.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_csqrtf.c,v 1.3 2008/08/08 00:15:16 das Exp $"); + +#include +#include + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#ifndef __GNUC__ +#pragma STDC CX_LIMITED_RANGE ON +#endif + +OLM_DLLEXPORT float complex +csqrtf(float complex z) +{ + float a = crealf(z), b = cimagf(z); + double t; + + /* Handle special cases. */ + if (z == 0) + return (CMPLXF(0, b)); + if (isinf(b)) + return (CMPLXF(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (CMPLXF(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrtf(inf + NaN i) = inf + NaN i + * csqrtf(inf + y i) = inf + 0 i + * csqrtf(-inf + NaN i) = NaN +- inf i + * csqrtf(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (CMPLXF(fabsf(b - b), copysignf(a, b))); + else + return (CMPLXF(a, copysignf(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* + * We compute t in double precision to avoid overflow and to + * provide correct rounding in nearly all cases. + * This is Algorithm 312, CACM vol 10, Oct 1967. + */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + return (CMPLXF(t, b / (2.0 * t))); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + return (CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b))); + } +} diff --git a/src/openlibm/src/s_csqrtl.c b/src/openlibm/src/s_csqrtl.c new file mode 100644 index 0000000..da97fb2 --- /dev/null +++ b/src/openlibm/src/s_csqrtl.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2007-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" + +#include +#include +#include + +#include "math_private.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#ifndef __GNUC__ +#pragma STDC CX_LIMITED_RANGE ON +#endif + +/* We risk spurious overflow for components >= LDBL_MAX / (1 + sqrt(2)). */ +#define THRESH (LDBL_MAX / 2.414213562373095048801688724209698L) + +OLM_DLLEXPORT long double complex +csqrtl(long double complex z) +{ + long double complex result; + long double a, b; + long double t; + int scale; + + a = creall(z); + b = cimagl(z); + + /* Handle special cases. */ + if (z == 0) + return (CMPLXL(0, b)); + if (isinf(b)) + return (CMPLXL(INFINITY, b)); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return (CMPLXL(a, t)); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return (CMPLXL(fabsl(b - b), copysignl(a, b))); + else + return (CMPLXL(a, copysignl(b - b, b))); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabsl(a) >= THRESH || fabsl(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrtl((a + hypotl(a, b)) * 0.5); + result = CMPLXL(t, b / (2 * t)); + } else { + t = sqrtl((-a + hypotl(a, b)) * 0.5); + result = CMPLXL(fabsl(b) / (2 * t), copysignl(t, b)); + } + + /* Rescale. */ + if (scale) + return (result * 2); + else + return (result); +} diff --git a/src/openlibm/src/s_ctan.c b/src/openlibm/src/s_ctan.c new file mode 100644 index 0000000..9420095 --- /dev/null +++ b/src/openlibm/src/s_ctan.c @@ -0,0 +1,159 @@ +/* $OpenBSD: s_ctan.c,v 1.6 2013/07/03 04:46:36 espie Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ctan() + * + * Complex circular tangent + * + * + * + * SYNOPSIS: + * + * double complex ctan(); + * double complex z, w; + * + * w = ctan (z); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * sin 2x + i sinh 2y + * w = --------------------. + * cos 2x + cosh 2y + * + * On the real axis the denominator is zero at odd multiples + * of PI/2. The denominator is evaluated by its Taylor + * series near these points. + * + * ctan(z) = -i ctanh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 7.1e-17 1.6e-17 + * IEEE -10,+10 30000 7.2e-16 1.2e-16 + * Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. + */ + +#include +#include +#include + +#include "math_private.h" + +#define MACHEP 1.1e-16 +#define MAXNUM 1.0e308 + +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; + +static double +_redupi(double x) +{ + double t; + long i; + + t = x/M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return (t); +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +static double +_ctans(double complex z) +{ + double f, x, x2, y, y2, rn, t; + double d; + + x = fabs (2.0 * creal (z)); + y = fabs (2.0 * cimag(z)); + + x = _redupi(x); + + x = x * x; + y = y * y; + x2 = 1.0; + y2 = 1.0; + f = 1.0; + rn = 0.0; + d = 0.0; + do { + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } + while (fabs(t/d) > MACHEP) + ; + return (d); +} + +double complex +ctan(double complex z) +{ + double complex w; + double d; + + d = cos (2.0 * creal (z)) + cosh (2.0 * cimag (z)); + + if (fabs(d) < 0.25) + d = _ctans (z); + + if (d == 0.0) { + /*mtherr ("ctan", OVERFLOW);*/ + w = MAXNUM + MAXNUM * I; + return (w); + } + + w = sin (2.0 * creal(z)) / d + (sinh (2.0 * cimag(z)) / d) * I; + return (w); +} + +#if LDBL_MANT_DIG == DBL_MANT_DIG +openlibm_strong_reference(ctan, ctanl); +#endif /* LDBL_MANT_DIG == DBL_MANT_DIG */ diff --git a/src/openlibm/src/s_ctanf.c b/src/openlibm/src/s_ctanf.c new file mode 100644 index 0000000..3bb3742 --- /dev/null +++ b/src/openlibm/src/s_ctanf.c @@ -0,0 +1,148 @@ +/* $OpenBSD: s_ctanf.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ctanf() + * + * Complex circular tangent + * + * + * + * SYNOPSIS: + * + * void ctanf(); + * cmplxf z, w; + * + * ctanf( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * sin 2x + i sinh 2y + * w = --------------------. + * cos 2x + cosh 2y + * + * On the real axis the denominator is zero at odd multiples + * of PI/2. The denominator is evaluated by its Taylor + * series near these points. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 3.3e-7 5.1e-8 + */ + +#include +#include + +#define MACHEPF 3.0e-8 +#define MAXNUMF 1.0e38f + +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; + +static float +_redupif(float xx) +{ + float x, t; + long i; + + x = xx; + t = x/(float)M_PI; + if(t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return(t); +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +static float +_ctansf(float complex z) +{ + float f, x, x2, y, y2, rn, t, d; + + x = fabsf(2.0f * crealf(z)); + y = fabsf(2.0f * cimagf(z)); + + x = _redupif(x); + + x = x * x; + y = y * y; + x2 = 1.0f; + y2 = 1.0f; + f = 1.0f; + rn = 0.0f; + d = 0.0f; + do { + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } + while (fabsf(t/d) > MACHEPF) + ; + return(d); +} + +float complex +ctanf(float complex z) +{ + float complex w; + float d; + + d = cosf( 2.0f * crealf(z) ) + coshf( 2.0f * cimagf(z) ); + + if(fabsf(d) < 0.25f) + d = _ctansf(z); + + if (d == 0.0f) { + /*mtherr( "ctanf", OVERFLOW );*/ + w = MAXNUMF + MAXNUMF * I; + return (w); + } + w = sinf (2.0f * crealf(z)) / d + (sinhf (2.0f * cimagf(z)) / d) * I; + return (w); +} diff --git a/src/openlibm/src/s_ctanh.c b/src/openlibm/src/s_ctanh.c new file mode 100644 index 0000000..8d452ee --- /dev/null +++ b/src/openlibm/src/s_ctanh.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ctanh.c,v 1.2 2011/10/21 06:30:16 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double complex +ctanh(double complex z) +{ + double x, y; + double t, beta, s, rho, denom; + u_int32_t hx, ix, lx; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (ix >= 0x7ff00000) { + if ((ix & 0xfffff) | lx) /* x is NaN */ + return (CMPLX(x, (y == 0 ? y : x * y))); + SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ + return (CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y)))); + } + + /* + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!isfinite(y)) + return (CMPLX(y - y, y - y)); + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (ix >= 0x40360000) { /* x >= 22 */ + double exp_mx = exp(-fabs(x)); + return (CMPLX(copysign(1, x), + 4 * sin(y) * cos(y) * exp_mx * exp_mx)); + } + + /* Kahan's algorithm */ + t = tan(y); + beta = 1.0 + t * t; /* = 1 / cos^2(y) */ + s = sinh(x); + rho = sqrt(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return (CMPLX((beta * rho * s) / denom, t / denom)); +} + +OLM_DLLEXPORT double complex +ctan(double complex z) +{ + + /* ctan(z) = -I * ctanh(I * z) */ + z = ctanh(CMPLX(-cimag(z), creal(z))); + return (CMPLX(cimag(z), -creal(z))); +} diff --git a/src/openlibm/src/s_ctanhf.c b/src/openlibm/src/s_ctanhf.c new file mode 100644 index 0000000..b2f8f19 --- /dev/null +++ b/src/openlibm/src/s_ctanhf.c @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Hyperbolic tangent of a complex argument z. See s_ctanh.c for details. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ctanhf.c,v 1.2 2011/10/21 06:30:16 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT float complex +ctanhf(float complex z) +{ + float x, y; + float t, beta, s, rho, denom; + u_int32_t hx, ix; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + + if (ix >= 0x7f800000) { + if (ix & 0x7fffff) + return (CMPLXF(x, (y == 0 ? y : x * y))); + SET_FLOAT_WORD(x, hx - 0x40000000); + return (CMPLXF(x, + copysignf(0, isinf(y) ? y : sinf(y) * cosf(y)))); + } + + if (!isfinite(y)) + return (CMPLXF(y - y, y - y)); + + if (ix >= 0x41300000) { /* x >= 11 */ + float exp_mx = expf(-fabsf(x)); + return (CMPLXF(copysignf(1, x), + 4 * sinf(y) * cosf(y) * exp_mx * exp_mx)); + } + + t = tanf(y); + beta = 1.0 + t * t; + s = sinhf(x); + rho = sqrtf(1 + s * s); + denom = 1 + beta * s * s; + return (CMPLXF((beta * rho * s) / denom, t / denom)); +} + +OLM_DLLEXPORT float complex +ctanf(float complex z) +{ + + z = ctanhf(CMPLXF(-cimagf(z), crealf(z))); + return (CMPLXF(cimagf(z), -crealf(z))); +} + diff --git a/src/openlibm/src/s_ctanhl.c b/src/openlibm/src/s_ctanhl.c new file mode 100644 index 0000000..6d996d4 --- /dev/null +++ b/src/openlibm/src/s_ctanhl.c @@ -0,0 +1,60 @@ +/* $OpenBSD: s_ctanhl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ctanhl + * + * Complex hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * long double complex ctanhl(); + * long double complex z, w; + * + * w = ctanhl (z); + * + * + * + * DESCRIPTION: + * + * tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.7e-14 2.4e-16 + * + */ + +#include +#include + +long double complex +ctanhl(long double complex z) +{ + long double complex w; + long double x, y, d; + + x = creall(z); + y = cimagl(z); + d = coshl(2.0L * x) + cosl(2.0L * y); + w = sinhl(2.0L * x) / d + (sinl(2.0L * y) / d) * I; + return (w); +} diff --git a/src/openlibm/src/s_ctanl.c b/src/openlibm/src/s_ctanl.c new file mode 100644 index 0000000..cf33ced --- /dev/null +++ b/src/openlibm/src/s_ctanl.c @@ -0,0 +1,157 @@ +/* $OpenBSD: s_ctanl.c,v 1.3 2011/07/20 21:02:51 martynas Exp $ */ + +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ctanl() + * + * Complex circular tangent + * + * + * + * SYNOPSIS: + * + * long double complex ctanl(); + * long double complex z, w; + * + * w = ctanl( z ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * sin 2x + i sinh 2y + * w = --------------------. + * cos 2x + cosh 2y + * + * On the real axis the denominator is zero at odd multiples + * of PI/2. The denominator is evaluated by its Taylor + * series near these points. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 7.1e-17 1.6e-17 + * IEEE -10,+10 30000 7.2e-16 1.2e-16 + * Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. + */ + +#include +#include +#include + +#if LDBL_MANT_DIG == 64 +static const long double MACHEPL= 5.42101086242752217003726400434970855712890625E-20L; +#elif LDBL_MANT_DIG == 113 +static const long double MACHEPL = 9.629649721936179265279889712924636592690508e-35L; +#endif + +static const long double PIL = 3.141592653589793238462643383279502884197169L; +static const long double DP1 = 3.14159265358979323829596852490908531763125L; +static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; +static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; + +static long double +redupil(long double x) +{ + long double t; + long i; + + t = x / PIL; + if (t >= 0.0L) + t += 0.5L; + else + t -= 0.5L; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return (t); +} + +static long double +ctansl(long double complex z) +{ + long double f, x, x2, y, y2, rn, t; + long double d; + + x = fabsl(2.0L * creall(z)); + y = fabsl(2.0L * cimagl(z)); + + x = redupil(x); + + x = x * x; + y = y * y; + x2 = 1.0L; + y2 = 1.0L; + f = 1.0L; + rn = 0.0L; + d = 0.0L; + do { + rn += 1.0L; + f *= rn; + rn += 1.0L; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0L; + f *= rn; + rn += 1.0L; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } + while (fabsl(t/d) > MACHEPL); + return(d); +} + +long double complex +ctanl(long double complex z) +{ + long double complex w; + long double d, x, y; + + x = creall(z); + y = cimagl(z); + d = cosl(2.0L * x) + coshl(2.0L * y); + + if (fabsl(d) < 0.25L) { + d = fabsl(d); + d = ctansl(z); + } + if (d == 0.0L) { + /*mtherr( "ctan", OVERFLOW );*/ + w = LDBL_MAX + LDBL_MAX * I; + return (w); + } + + w = sinl(2.0L * x) / d + (sinhl(2.0L * y) / d) * I; + return (w); +} diff --git a/src/openlibm/src/s_erf.c b/src/openlibm/src/s_erf.c new file mode 100644 index 0000000..67068c4 --- /dev/null +++ b/src/openlibm/src/s_erf.c @@ -0,0 +1,307 @@ +/* @(#)s_erf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_erf.c,v 1.8 2008/02/22 02:30:35 das Exp $"); + +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include +#include + +#include "math_private.h" + +static const double +tiny = 1e-300, +half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ + /* c = (float)0.84506291151 */ +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */ +efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +OLM_DLLEXPORT double +erf(double x) +{ + int32_t hx,ix,i; + double R,S,P,Q,s,y,z,r; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) { /* erf(nan)=nan */ + i = ((u_int32_t)hx>>31)<<1; + return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */ + } + + if(ix < 0x3feb0000) { /* |x|<0.84375 */ + if(ix < 0x3e300000) { /* |x|<2**-28 */ + if (ix < 0x00800000) + return 0.125*(8.0*x+efx8*x); /*avoid underflow */ + return x + efx*x; + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */ + s = fabs(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) return erx + P/Q; else return -erx - P/Q; + } + if (ix >= 0x40180000) { /* inf>|x|>=6 */ + if(hx>=0) return one-tiny; else return tiny-one; + } + x = fabs(x); + s = one/(x*x); + if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +OLM_DLLEXPORT double +erfc(double x) +{ + int32_t hx,ix; + double R,S,P,Q,s,y,z,r; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7ff00000) { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (double)(((u_int32_t)hx>>31)<<1)+one/x; + } + + if(ix < 0x3feb0000) { /* |x|<0.84375 */ + if(ix < 0x3c700000) /* |x|<2**-56 */ + return one-x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if(hx < 0x3fd00000) { /* x<1/4 */ + return one-(x+x*y); + } else { + r = x*y; + r += (x-half); + return half - r ; + } + } + if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */ + s = fabs(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) { + z = one-erx; return z - P/Q; + } else { + z = erx+P/Q; return one+z; + } + } + if (ix < 0x403c0000) { /* |x|<28 */ + x = fabs(x); + s = one/(x*x); + if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/.35 ~ 2.857143 */ + if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + r = __ieee754_exp(-z*z-0.5625)* + __ieee754_exp((z-x)*(z+x)+R/S); + if(hx>0) return r/x; else return two-r/x; + } else { + if(hx>0) return tiny*tiny; else return two-tiny; + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(erf, erfl); +openlibm_weak_reference(erfc, erfcl); +#endif diff --git a/src/openlibm/src/s_erff.c b/src/openlibm/src/s_erff.c new file mode 100644 index 0000000..ed6030f --- /dev/null +++ b/src/openlibm/src/s_erff.c @@ -0,0 +1,184 @@ +/* s_erff.c -- float version of s_erf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_erff.c,v 1.8 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +static const float +tiny = 1e-30, +half= 5.0000000000e-01, /* 0x3F000000 */ +one = 1.0000000000e+00, /* 0x3F800000 */ +two = 2.0000000000e+00, /* 0x40000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx = 1.2837916613e-01, /* 0x3e0375d4 */ +efx8= 1.0270333290e+00, /* 0x3f8375d4 */ +/* + * Domain [0, 0.84375], range ~[-5.4446e-10,5.5197e-10]: + * |(erf(x) - x)/x - p(x)/q(x)| < 2**-31. + */ +pp0 = 1.28379166e-01F, /* 0x1.06eba8p-3 */ +pp1 = -3.36030394e-01F, /* -0x1.58185ap-2 */ +pp2 = -1.86260219e-03F, /* -0x1.e8451ep-10 */ +qq1 = 3.12324286e-01F, /* 0x1.3fd1f0p-2 */ +qq2 = 2.16070302e-02F, /* 0x1.620274p-6 */ +qq3 = -1.98859419e-03F, /* -0x1.04a626p-9 */ +/* + * Domain [0.84375, 1.25], range ~[-1.953e-11,1.940e-11]: + * |(erf(x) - erx) - p(x)/q(x)| < 2**-36. + */ +erx = 8.42697144e-01F, /* 0x1.af7600p-1. erf(1) rounded to 16 bits. */ +pa0 = 3.64939137e-06F, /* 0x1.e9d022p-19 */ +pa1 = 4.15109694e-01F, /* 0x1.a91284p-2 */ +pa2 = -1.65179938e-01F, /* -0x1.5249dcp-3 */ +pa3 = 1.10914491e-01F, /* 0x1.c64e46p-4 */ +qa1 = 6.02074385e-01F, /* 0x1.344318p-1 */ +qa2 = 5.35934687e-01F, /* 0x1.126608p-1 */ +qa3 = 1.68576106e-01F, /* 0x1.593e6ep-3 */ +qa4 = 5.62181212e-02F, /* 0x1.cc89f2p-5 */ +/* + * Domain [1.25,1/0.35], range ~[-7.043e-10,7.457e-10]: + * |log(x*erfc(x)) + x**2 + 0.5625 - r(x)/s(x)| < 2**-30 + */ +ra0 = -9.87132732e-03F, /* -0x1.4376b2p-7 */ +ra1 = -5.53605914e-01F, /* -0x1.1b723cp-1 */ +ra2 = -2.17589188e+00F, /* -0x1.1683a0p+1 */ +ra3 = -1.43268085e+00F, /* -0x1.6ec42cp+0 */ +sa1 = 5.45995426e+00F, /* 0x1.5d6fe4p+2 */ +sa2 = 6.69798088e+00F, /* 0x1.acabb8p+2 */ +sa3 = 1.43113089e+00F, /* 0x1.6e5e98p+0 */ +sa4 = -5.77397496e-02F, /* -0x1.d90108p-5 */ +/* + * Domain [1/0.35, 11], range ~[-2.264e-13,2.336e-13]: + * |log(x*erfc(x)) + x**2 + 0.5625 - r(x)/s(x)| < 2**-42 + */ +rb0 = -9.86494310e-03F, /* -0x1.434124p-7 */ +rb1 = -6.25171244e-01F, /* -0x1.401672p-1 */ +rb2 = -6.16498327e+00F, /* -0x1.8a8f16p+2 */ +rb3 = -1.66696873e+01F, /* -0x1.0ab70ap+4 */ +rb4 = -9.53764343e+00F, /* -0x1.313460p+3 */ +sb1 = 1.26884899e+01F, /* 0x1.96081cp+3 */ +sb2 = 4.51839523e+01F, /* 0x1.6978bcp+5 */ +sb3 = 4.72810211e+01F, /* 0x1.7a3f88p+5 */ +sb4 = 8.93033314e+00F; /* 0x1.1dc54ap+3 */ + + +OLM_DLLEXPORT float +erff(float x) +{ + int32_t hx,ix,i; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) { /* erf(nan)=nan */ + i = ((u_int32_t)hx>>31)<<1; + return (float)(1-i)+one/x; /* erf(+-inf)=+-1 */ + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x38800000) { /* |x|<2**-14 */ + if (ix < 0x04000000) /* |x|<0x1p-119 */ + return (8*x+efx8*x)/8; /* avoid spurious underflow */ + return x + efx*x; + } + z = x*x; + r = pp0+z*(pp1+z*pp2); + s = one+z*(qq1+z*(qq2+z*qq3)); + y = r/s; + return x + x*y; + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*pa3)); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*qa4))); + if(hx>=0) return erx + P/Q; else return -erx - P/Q; + } + if (ix >= 0x40800000) { /* inf>|x|>=4 */ + if(hx>=0) return one-tiny; else return tiny-one; + } + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6E) { /* |x| < 1/0.35 */ + R=ra0+s*(ra1+s*(ra2+s*ra3)); + S=one+s*(sa1+s*(sa2+s*(sa3+s*sa4))); + } else { /* |x| >= 1/0.35 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*rb4))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*sb4))); + } + SET_FLOAT_WORD(z,hx&0xffffe000); + r = expf(-z*z-0.5625F)*expf((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +OLM_DLLEXPORT float +erfcf(float x) +{ + int32_t hx,ix; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix>=0x7f800000) { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (float)(((u_int32_t)hx>>31)<<1)+one/x; + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x33800000) /* |x|<2**-56 */ + return one-x; + z = x*x; + r = pp0+z*(pp1+z*pp2); + s = one+z*(qq1+z*(qq2+z*qq3)); + y = r/s; + if(hx < 0x3e800000) { /* x<1/4 */ + return one-(x+x*y); + } else { + r = x*y; + r += (x-half); + return half - r ; + } + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*pa3)); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*qa4))); + if(hx>=0) { + z = one-erx; return z - P/Q; + } else { + z = erx+P/Q; return one+z; + } + } + if (ix < 0x41300000) { /* |x|<28 */ + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6D) { /* |x| < 1/.35 ~ 2.857143*/ + R=ra0+s*(ra1+s*(ra2+s*ra3)); + S=one+s*(sa1+s*(sa2+s*(sa3+s*sa4))); + } else { /* |x| >= 1/.35 ~ 2.857143 */ + if(hx<0&&ix>=0x40a00000) return two-tiny;/* x < -5 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*rb4))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*sb4))); + } + SET_FLOAT_WORD(z,hx&0xffffe000); + r = expf(-z*z-0.5625F)*expf((z-x)*(z+x)+R/S); + if(hx>0) return r/x; else return two-r/x; + } else { + if(hx>0) return tiny*tiny; else return two-tiny; + } +} diff --git a/src/openlibm/src/s_exp2.c b/src/openlibm/src/s_exp2.c new file mode 100644 index 0000000..d643dbb --- /dev/null +++ b/src/openlibm/src/s_exp2.c @@ -0,0 +1,396 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_exp2.c,v 1.7 2008/02/22 02:27:34 das Exp $"); + +#include +#include + +#include "math_private.h" + +#define TBLBITS 8 +#define TBLSIZE (1 << TBLBITS) + +static const double + huge = 0x1p1000, + redux = 0x1.8p52 / TBLSIZE, + P1 = 0x1.62e42fefa39efp-1, + P2 = 0x1.ebfbdff82c575p-3, + P3 = 0x1.c6b08d704a0a6p-5, + P4 = 0x1.3b2ab88f70400p-7, + P5 = 0x1.5d88003875c74p-10; + +static volatile double twom1000 = 0x1p-1000; + +static const double tbl[TBLSIZE * 2] = { +/* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, + 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, + 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, + 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, + 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, + 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, + 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, + 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, + 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, + 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, + 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, + 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, + 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, + 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, + 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, + 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, + 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, + 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, + 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, + 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, + 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, + 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, + 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, + 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, + 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, + 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, + 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, + 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, + 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, + 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, + 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, + 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, + 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, + 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, + 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, + 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, + 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, + 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, + 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, + 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, + 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, + 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, + 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, + 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, + 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, + 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, + 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, + 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, + 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, + 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, + 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, + 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, + 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, + 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, + 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, + 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, + 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, + 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, + 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, + 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, + 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, + 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, + 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, + 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, + 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, + 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, + 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, + 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, + 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, + 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, + 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, + 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, + 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, + 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, + 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, + 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, + 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, + 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, + 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, + 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, + 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, + 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, + 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, + 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, + 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, + 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, + 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, + 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, + 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, + 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, + 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, + 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, + 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, + 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, + 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, + 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, + 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, + 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, + 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, + 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, + 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, + 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, + 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, + 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, + 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, + 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, + 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, + 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, + 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, + 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, + 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, + 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, + 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, + 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, + 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, + 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, + 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, + 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, + 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, + 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, + 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, + 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, + 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, + 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, + 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, + 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, + 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, + 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, + 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +OLM_DLLEXPORT double +exp2(double x) +{ + double r, t, twopk, twopkp1000, z; + u_int32_t hx, ix, lx, i0; + int k; + + /* Filter out exceptional cases. */ + GET_HIGH_WORD(hx,x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if(ix >= 0x40900000) { /* |x| >= 1024 */ + if(ix >= 0x7ff00000) { + GET_LOW_WORD(lx,x); + if(((ix & 0xfffff) | lx) != 0 || (hx & 0x80000000) == 0) + return (x + x); /* x is NaN or +Inf */ + else + return (0.0); /* x is -Inf */ + } + if(x >= 0x1.0p10) + return (huge * huge); /* overflow */ + if(x <= -0x1.0ccp10) + return (twom1000 * twom1000); /* underflow */ + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return (1.0 + x); + } + + /* Reduce x, computing z, i0, and k. */ + STRICT_ASSIGN(double, t, x + redux); + GET_LOW_WORD(i0, t); + i0 += TBLSIZE / 2; + k = (i0 >> TBLBITS) << 20; + i0 = (i0 & (TBLSIZE - 1)) << 1; + t -= redux; + z = x - t; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; /* exp2t[i0] */ + z -= tbl[i0 + 1]; /* eps[i0] */ + if (k >= -(1021 << 20)) + INSERT_WORDS(twopk, 0x3ff00000 + k, 0); + else + INSERT_WORDS(twopkp1000, 0x3ff00000 + k + (1000 << 20), 0); + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + /* Scale by 2**(k>>20). */ + if(k >= -(1021 << 20)) { + if (k == 1024 << 20) + return (r * 2.0 * 0x1p1023); + return (r * twopk); + } else { + return (r * twopkp1000 * twom1000); + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(exp2, exp2l); +#endif diff --git a/src/openlibm/src/s_exp2f.c b/src/openlibm/src/s_exp2f.c new file mode 100644 index 0000000..74bc9f3 --- /dev/null +++ b/src/openlibm/src/s_exp2f.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_exp2f.c,v 1.9 2008/02/22 02:27:34 das Exp $"); + +#include +#include + +#include "math_private.h" + +#define TBLBITS 4 +#define TBLSIZE (1 << TBLBITS) + +static const float + huge = 0x1p100f, + redux = 0x1.8p23f / TBLSIZE, + P1 = 0x1.62e430p-1f, + P2 = 0x1.ebfbe0p-3f, + P3 = 0x1.c6b348p-5f, + P4 = 0x1.3b2c9cp-7f; + +static volatile float twom100 = 0x1p-100f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +OLM_DLLEXPORT float +exp2f(float x) +{ + double tv, twopk, u, z; + float t; + u_int32_t hx, ix, i0; + int32_t k; + + /* Filter out exceptional cases. */ + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; /* high word of |x| */ + if(ix >= 0x43000000) { /* |x| >= 128 */ + if(ix >= 0x7f800000) { + if ((ix & 0x7fffff) != 0 || (hx & 0x80000000) == 0) + return (x + x); /* x is NaN or +Inf */ + else + return (0.0); /* x is -Inf */ + } + if(x >= 0x1.0p7f) + return (huge * huge); /* overflow */ + if(x <= -0x1.2cp7f) + return (twom100 * twom100); /* underflow */ + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return (1.0f + x); + } + + /* Reduce x, computing z, i0, and k. */ + STRICT_ASSIGN(float, t, x + redux); + GET_FLOAT_WORD(i0, t); + i0 += TBLSIZE / 2; + k = (i0 >> TBLBITS) << 20; + i0 &= TBLSIZE - 1; + t -= redux; + z = x - t; + INSERT_WORDS(twopk, 0x3ff00000 + k, 0); + + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + tv = exp2ft[i0]; + u = tv * z; + tv = tv + u * (P1 + z * P2) + u * (z * z) * (P3 + z * P4); + + /* Scale by 2**(k>>20). */ + return (tv * twopk); +} diff --git a/src/openlibm/src/s_expm1.c b/src/openlibm/src/s_expm1.c new file mode 100644 index 0000000..5798714 --- /dev/null +++ b/src/openlibm/src/s_expm1.c @@ -0,0 +1,221 @@ +/* @(#)s_expm1.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_expm1.c,v 1.12 2011/10/21 06:26:38 das Exp $"); + +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Reme algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +#include "math_private.h" + +static const double +one = 1.0, +huge = 1.0e+300, +tiny = 1.0e-300, +o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +OLM_DLLEXPORT double +expm1(double x) +{ + double y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + int32_t k,xsb; + u_int32_t hx; + + GET_HIGH_WORD(hx,x); + xsb = hx&0x80000000; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out huge and non-finite argument */ + if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if(hx >= 0x40862E42) { /* if |x|>=709.78... */ + if(hx>=0x7ff00000) { + u_int32_t low; + GET_LOW_WORD(low,x); + if(((hx&0xfffff)|low)!=0) + return x+x; /* NaN */ + else return (xsb==0)? x:-1.0;/* exp(+-inf)-1={inf,-1} */ + } + if(x > o_threshold) return huge*huge; /* overflow */ + } + if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */ + if(x+tiny<0.0) /* raise inexact */ + return tiny-one; /* return -1 */ + } + } + + /* argument reduction */ + if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if(xsb==0) + {hi = x - ln2_hi; lo = ln2_lo; k = 1;} + else + {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} + } else { + k = invln2*x+((xsb==0)?0.5:-0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + STRICT_ASSIGN(double, x, hi - lo); + c = (hi-x)-lo; + } + else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */ + t = huge+x; /* return x with inexact flags when x!=0 */ + return x - (t-(huge+x)); + } + else k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if(k==0) return x - (x*e-hxs); /* c is 0 */ + else { + INSERT_WORDS(twopk,0x3ff00000+(k<<20),0); /* 2^k */ + e = (x*(e-c)-c); + e -= hxs; + if(k== -1) return 0.5*(x-e)-0.5; + if(k==1) { + if(x < -0.25) return -2.0*(e-(x+0.5)); + else return one+2.0*(x-e); + } + if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ + y = one-(e-x); + if (k == 1024) y = y*2.0*0x1p1023; + else y = y*twopk; + return y-one; + } + t = one; + if(k<20) { + SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k)); /* t=1-2^-k */ + y = t-(e-x); + y = y*twopk; + } else { + SET_HIGH_WORD(t,((0x3ff-k)<<20)); /* 2^-k */ + y = x-(e+t); + y += one; + y = y*twopk; + } + } + return y; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(expm1, expm1l); +#endif diff --git a/src/openlibm/src/s_expm1f.c b/src/openlibm/src/s_expm1f.c new file mode 100644 index 0000000..cb7ceec --- /dev/null +++ b/src/openlibm/src/s_expm1f.c @@ -0,0 +1,123 @@ +/* s_expm1f.c -- float version of s_expm1.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_expm1f.c,v 1.12 2011/10/21 06:26:38 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const float +one = 1.0, +huge = 1.0e+30, +tiny = 1.0e-30, +o_threshold = 8.8721679688e+01,/* 0x42b17180 */ +ln2_hi = 6.9313812256e-01,/* 0x3f317180 */ +ln2_lo = 9.0580006145e-06,/* 0x3717f7d1 */ +invln2 = 1.4426950216e+00,/* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +OLM_DLLEXPORT float +expm1f(float x) +{ + float y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + int32_t k,xsb; + u_int32_t hx; + + GET_FLOAT_WORD(hx,x); + xsb = hx&0x80000000; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* filter out huge and non-finite argument */ + if(hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if(hx >= 0x42b17218) { /* if |x|>=88.721... */ + if(hx>0x7f800000) + return x+x; /* NaN */ + if(hx==0x7f800000) + return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ + if(x > o_threshold) return huge*huge; /* overflow */ + } + if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */ + if(x+tiny<(float)0.0) /* raise inexact */ + return tiny-one; /* return -1 */ + } + } + + /* argument reduction */ + if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if(xsb==0) + {hi = x - ln2_hi; lo = ln2_lo; k = 1;} + else + {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} + } else { + k = invln2*x+((xsb==0)?(float)0.5:(float)-0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + STRICT_ASSIGN(float, x, hi - lo); + c = (hi-x)-lo; + } + else if(hx < 0x33000000) { /* when |x|<2**-25, return x */ + t = huge+x; /* return x with inexact flags when x!=0 */ + return x - (t-(huge+x)); + } + else k = 0; + + /* x is now in primary range */ + hfx = (float)0.5*x; + hxs = x*hfx; + r1 = one+hxs*(Q1+hxs*Q2); + t = (float)3.0-r1*hfx; + e = hxs*((r1-t)/((float)6.0 - x*t)); + if(k==0) return x - (x*e-hxs); /* c is 0 */ + else { + SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); /* 2^k */ + e = (x*(e-c)-c); + e -= hxs; + if(k== -1) return (float)0.5*(x-e)-(float)0.5; + if(k==1) { + if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5)); + else return one+(float)2.0*(x-e); + } + if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ + y = one-(e-x); + if (k == 128) y = y*2.0F*0x1p127F; + else y = y*twopk; + return y-one; + } + t = one; + if(k<23) { + SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */ + y = t-(e-x); + y = y*twopk; + } else { + SET_FLOAT_WORD(t,((0x7f-k)<<23)); /* 2^-k */ + y = x-(e+t); + y += one; + y = y*twopk; + } + } + return y; +} diff --git a/src/openlibm/src/s_fabs.c b/src/openlibm/src/s_fabs.c new file mode 100644 index 0000000..43ffc1a --- /dev/null +++ b/src/openlibm/src/s_fabs.c @@ -0,0 +1,28 @@ +/* @(#)s_fabs.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * fabs(x) returns the absolute value of x. + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +fabs(double x) +{ + u_int32_t high; + GET_HIGH_WORD(high,x); + SET_HIGH_WORD(x,high&0x7fffffff); + return x; +} diff --git a/src/openlibm/src/s_fabsf.c b/src/openlibm/src/s_fabsf.c new file mode 100644 index 0000000..eeceee4 --- /dev/null +++ b/src/openlibm/src/s_fabsf.c @@ -0,0 +1,34 @@ +/* s_fabsf.c -- float version of s_fabs.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fabsf.c,v 1.8 2008/02/22 02:30:35 das Exp $"); + +/* + * fabsf(x) returns the absolute value of x. + */ + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +fabsf(float x) +{ + u_int32_t ix; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x7fffffff); + return x; +} diff --git a/src/openlibm/src/s_fabsl.c b/src/openlibm/src/s_fabsl.c new file mode 100644 index 0000000..6bc1971 --- /dev/null +++ b/src/openlibm/src/s_fabsl.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_fabsl.c,v 1.2 2003/10/25 19:53:28 des Exp $ + */ + +#include +#include "math_private.h" +#include "fpmath.h" + +OLM_DLLEXPORT long double +fabsl(long double x) +{ + union IEEEl2bits u; + + u.e = x; + u.bits.sign = 0; + return (u.e); +} diff --git a/src/openlibm/src/s_fdim.c b/src/openlibm/src/s_fdim.c new file mode 100644 index 0000000..2f05347 --- /dev/null +++ b/src/openlibm/src/s_fdim.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fdim.c,v 1.1 2004/06/30 07:04:01 das Exp $"); +#include +#include "math_private.h" + +#define DECL(type, fn) \ +OLM_DLLEXPORT type \ +fn(type x, type y) \ +{ \ + \ + if (isnan(x)) \ + return (x); \ + if (isnan(y)) \ + return (y); \ + return (x > y ? x - y : 0.0); \ +} + +DECL(double, fdim) +DECL(float, fdimf) +#ifdef OLM_LONG_DOUBLE +DECL(long double, fdiml) +#endif diff --git a/src/openlibm/src/s_floor.c b/src/openlibm/src/s_floor.c new file mode 100644 index 0000000..4a44bd5 --- /dev/null +++ b/src/openlibm/src/s_floor.c @@ -0,0 +1,78 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_floor.c,v 1.11 2008/02/15 07:01:40 bde Exp $"); + +/* + * floor(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floor(x). + */ + +#include +#include + +#include "math_private.h" + +static const double huge = 1.0e300; + +OLM_DLLEXPORT double +floor(double x) +{ + int32_t i0,i1,j0; + u_int32_t i,j; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=i1=0;} + else if(((i0&0x7fffffff)|i1)!=0) + { i0=0xbff00000;i1=0;} + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00100000)>>j0; + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + if(i0<0) { + if(j0==20) i0+=1; + else { + j = i1+(1<<(52-j0)); + if(j + +#include "math_private.h" + +static const float huge = 1.0e30; + +OLM_DLLEXPORT float +floorf(float x) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=0;} + else if((i0&0x7fffffff)!=0) + { i0=0xbf800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/src/openlibm/src/s_floorl.c b/src/openlibm/src/s_floorl.c new file mode 100644 index 0000000..8427edb --- /dev/null +++ b/src/openlibm/src/s_floorl.c @@ -0,0 +1,102 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_floorl.c,v 1.8 2008/02/14 15:10:34 bde Exp $"); + +/* + * floorl(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to floorl(x). + */ + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) \ + u.bits.exp++; \ +} while (0) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#define INC_MANH(u, c) do { \ + uint64_t o = u.bits.manh; \ + u.bits.manh += (c); \ + if (u.bits.manh < o) { \ + u.bits.exp++; \ + u.bits.manh |= 1llu << (LDBL_MANH_SIZE - 1); \ + } \ +} while (0) +#endif + +static const long double huge = 1.0e300; + +OLM_DLLEXPORT long double +floorl(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + if (u.bits.exp > 0 || + (u.bits.manh | u.bits.manl) != 0) + u.e = u.bits.sign ? -1.0 : 0.0; + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (u.bits.sign) { +#ifdef LDBL_IMPLICIT_NBIT + if (e == 0) + u.bits.exp++; + else +#endif + INC_MANH(u, 1llu << (MANH_SIZE - e - 1)); + } + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (u.bits.sign) { + if (e == MANH_SIZE - 1) + INC_MANH(u, 1); + else { + uint64_t o = u.bits.manl; + u.bits.manl += 1llu << (LDBL_MANT_DIG - e - 1); + if (u.bits.manl < o) /* got a carry */ + INC_MANH(u, 1); + } + } + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/src/openlibm/src/s_fma.c b/src/openlibm/src/s_fma.c new file mode 100644 index 0000000..63e529e --- /dev/null +++ b/src/openlibm/src/s_fma.c @@ -0,0 +1,284 @@ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fma.c,v 1.8 2011/10/21 06:30:43 das Exp $"); + +#include +#include +#include + +#include "math_private.h" + +/* + * A struct dd represents a floating-point number with twice the precision + * of a double. We maintain the invariant that "hi" stores the 53 high-order + * bits of the result. + */ +struct dd { + double hi; + double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd +dd_add(double a, double b) +{ + struct dd ret; + double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline double +add_adjusted(double a, double b) +{ + struct dd sum; + u_int64_t hibits, lobits; + + sum = dd_add(a, b); + if (sum.lo != 0) { + EXTRACT_WORD64(hibits, sum.hi); + if ((hibits & 1) == 0) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + EXTRACT_WORD64(lobits, sum.lo); + hibits += 1 - ((hibits ^ lobits) >> 62); + INSERT_WORD64(sum.hi, hibits); + } + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline double +add_and_denormalize(double a, double b, int scale) +{ + struct dd sum; + u_int64_t hibits, lobits; + int bits_lost; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + EXTRACT_WORD64(hibits, sum.hi); + bits_lost = -((int)(hibits >> 52) & 0x7ff) - scale + 1; + if ((bits_lost != 1) ^ (int)(hibits & 1)) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + EXTRACT_WORD64(lobits, sum.lo); + hibits += 1 - (((hibits ^ lobits) >> 62) & 2); + INSERT_WORD64(sum.hi, hibits); + } + } + return (ldexp(sum.hi, scale)); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd +dd_mul(double a, double b) +{ + static const double split = 0x1p27 + 1.0; + struct dd ret; + double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + * + * This algorithm is sensitive to the rounding precision. FPUs such + * as the i387 must be set in double-precision mode if variables are + * to be stored in FP registers in order to avoid incorrect results. + * This is the default on FreeBSD, but not on many other systems. + * + * Hardware instructions should be used on architectures that support it, + * since this implementation will likely be several times slower. + */ +OLM_DLLEXPORT double +fma(double x, double y, double z) +{ + double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + + xs = frexp(x, &ex); + ys = frexp(y, &ey); + zs = frexp(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -DBL_MANT_DIG) { + feraiseexcept(FE_INEXACT); + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); + switch (oround) { + case FE_TONEAREST: + return (z); + case FE_TOWARDZERO: + if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0)) + return (z); + else + return (nextafter(z, 0)); + case FE_DOWNWARD: + if ((x > 0.0) ^ (y < 0.0)) + return (z); + else + return (nextafter(z, -INFINITY)); + default: /* FE_UPWARD */ + if ((x > 0.0) ^ (y < 0.0)) + return (nextafter(z, INFINITY)); + else + return (z); + } + } + if (spread <= DBL_MANT_DIG * 2) + zs = ldexp(zs, -spread); + else + zs = copysign(DBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile double vzs = zs; /* XXX gcc CSE bug workaround */ + return (xy.hi + vzs + ldexp(xy.lo, spread)); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + */ + fesetround(oround); + adj = r.lo + xy.lo; + return (ldexp(r.hi + adj, spread)); + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogb(r.hi) > -1023) + return (ldexp(r.hi + adj, spread)); + else + return (add_and_denormalize(r.hi, adj, spread)); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(fma, fmal); +#endif diff --git a/src/openlibm/src/s_fmaf.c b/src/openlibm/src/s_fmaf.c new file mode 100644 index 0000000..b3c8efb --- /dev/null +++ b/src/openlibm/src/s_fmaf.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaf.c,v 1.3 2011/10/15 04:16:58 das Exp $"); + +#include +#include + +#include "math_private.h" + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +OLM_DLLEXPORT float +fmaf(float x, float y, float z) +{ + double xy, result; + u_int32_t hr, lr; + + xy = (double)x * y; + result = xy + z; + EXTRACT_WORDS(hr, lr, result); + /* Common case: The double precision result is fine. */ + if ((lr & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + (hr & 0x7ff00000) == 0x7ff00000 || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + return (result); + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + fesetround(FE_TOWARDZERO); + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) + SET_LOW_WORD(adjusted_result, lr + 1); + return (adjusted_result); +} diff --git a/src/openlibm/src/s_fmal.c b/src/openlibm/src/s_fmal.c new file mode 100644 index 0000000..2fe30c6 --- /dev/null +++ b/src/openlibm/src/s_fmal.c @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmal.c,v 1.7 2011/10/21 06:30:43 das Exp $"); + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd +dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double +add_adjusted(long double a, long double b) +{ + struct dd sum; + union IEEEl2bits u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.e = sum.hi; + if ((u.bits.manl & 1) == 0) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double +add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union IEEEl2bits u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.e = sum.hi; + bits_lost = -u.bits.exp - scale + 1; + if ((bits_lost != 1) ^ (int)(u.bits.manl & 1)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (ldexp(sum.hi, scale)); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd +dd_mul(long double a, long double b) +{ +#if LDBL_MANT_DIG == 64 + static const long double split = 0x1p32L + 1.0; +#elif LDBL_MANT_DIG == 113 + static const long double split = 0x1p57L + 1.0; +#endif + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +OLM_DLLEXPORT long double +fmal(long double x, long double y, long double z) +{ + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { + feraiseexcept(FE_INEXACT); + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); + switch (oround) { + case FE_TONEAREST: + return (z); + case FE_TOWARDZERO: + if ((x > 0.0) ^ (y < 0.0) ^ (z < 0.0)) + return (z); + else + return (nextafterl(z, 0)); + case FE_DOWNWARD: + if ((x > 0.0) ^ (y < 0.0)) + return (z); + else + return (nextafterl(z, -INFINITY)); + default: /* FE_UPWARD */ + if ((x > 0.0) ^ (y < 0.0)) + return (nextafterl(z, INFINITY)); + else + return (z); + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = ldexpl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return (xy.hi + vzs + ldexpl(xy.lo, spread)); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + */ + fesetround(oround); + adj = r.lo + xy.lo; + return (ldexpl(r.hi + adj, spread)); + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return (ldexpl(r.hi + adj, spread)); + else + return (add_and_denormalize(r.hi, adj, spread)); +} diff --git a/src/openlibm/src/s_fmax.c b/src/openlibm/src/s_fmax.c new file mode 100644 index 0000000..73919c6 --- /dev/null +++ b/src/openlibm/src/s_fmax.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmax.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT double +fmax(double x, double y) +{ + union IEEEd2bits u[2]; + + u[0].d = x; + u[1].d = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[0].bits.sign].d); + + return (x > y ? x : y); +} diff --git a/src/openlibm/src/s_fmaxf.c b/src/openlibm/src/s_fmaxf.c new file mode 100644 index 0000000..a803461 --- /dev/null +++ b/src/openlibm/src/s_fmaxf.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaxf.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT float +fmaxf(float x, float y) +{ + union IEEEf2bits u[2]; + + u[0].f = x; + u[1].f = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 255 && u[0].bits.man != 0) + return (y); + if (u[1].bits.exp == 255 && u[1].bits.man != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[0].bits.sign].f); + + return (x > y ? x : y); +} diff --git a/src/openlibm/src/s_fmaxl.c b/src/openlibm/src/s_fmaxl.c new file mode 100644 index 0000000..48de991 --- /dev/null +++ b/src/openlibm/src/s_fmaxl.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmaxl.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT long double +fmaxl(long double x, long double y) +{ + union IEEEl2bits u[2]; + + u[0].e = x; + mask_nbit_l(u[0]); + u[1].e = y; + mask_nbit_l(u[1]); + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[0].bits.sign ? y : x); + + return (x > y ? x : y); +} diff --git a/src/openlibm/src/s_fmin.c b/src/openlibm/src/s_fmin.c new file mode 100644 index 0000000..9c52739 --- /dev/null +++ b/src/openlibm/src/s_fmin.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fmin.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT double +fmin(double x, double y) +{ + union IEEEd2bits u[2]; + + u[0].d = x; + u[1].d = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[1].bits.sign].d); + + return (x < y ? x : y); +} diff --git a/src/openlibm/src/s_fminf.c b/src/openlibm/src/s_fminf.c new file mode 100644 index 0000000..cc4017f --- /dev/null +++ b/src/openlibm/src/s_fminf.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fminf.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT float +fminf(float x, float y) +{ + union IEEEf2bits u[2]; + + u[0].f = x; + u[1].f = y; + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 255 && u[0].bits.man != 0) + return (y); + if (u[1].bits.exp == 255 && u[1].bits.man != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[u[1].bits.sign].f); + + return (x < y ? x : y); +} diff --git a/src/openlibm/src/s_fminl.c b/src/openlibm/src/s_fminl.c new file mode 100644 index 0000000..043886d --- /dev/null +++ b/src/openlibm/src/s_fminl.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_fminl.c,v 1.1 2004/06/30 07:04:01 das Exp $"); + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT long double +fminl(long double x, long double y) +{ + union IEEEl2bits u[2]; + + u[0].e = x; + mask_nbit_l(u[0]); + u[1].e = y; + mask_nbit_l(u[1]); + + /* Check for NaNs to avoid raising spurious exceptions. */ + if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) + return (y); + if (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0) + return (x); + + /* Handle comparisons of signed zeroes. */ + if (u[0].bits.sign != u[1].bits.sign) + return (u[1].bits.sign ? y : x); + + return (x < y ? x : y); +} diff --git a/src/openlibm/src/s_fpclassify.c b/src/openlibm/src/s_fpclassify.c new file mode 100644 index 0000000..2b552e1 --- /dev/null +++ b/src/openlibm/src/s_fpclassify.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "math_private.h" +#include "fpmath.h" + +OLM_DLLEXPORT int +__fpclassifyd(double d) +{ + union IEEEd2bits u; + + u.d = d; + if (u.bits.exp == 2047) { + if (u.bits.manl == 0 && u.bits.manh == 0) { + return FP_INFINITE; + } else { + return FP_NAN; + } + } else if (u.bits.exp != 0) { + return FP_NORMAL; + } else if (u.bits.manl == 0 && u.bits.manh == 0) { + return FP_ZERO; + } else { + return FP_SUBNORMAL; + } +} + + +OLM_DLLEXPORT int +__fpclassifyf(float f) +{ + union IEEEf2bits u; + + u.f = f; + if (u.bits.exp == 255) { + if (u.bits.man == 0) { + return FP_INFINITE; + } else { + return FP_NAN; + } + } else if (u.bits.exp != 0) { + return FP_NORMAL; + } else if (u.bits.man == 0) { + return FP_ZERO; + } else { + return FP_SUBNORMAL; + } +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__fpclassifyl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + mask_nbit_l(u); + if (u.bits.exp == 32767) { + if (u.bits.manl == 0 && u.bits.manh == 0) { + return FP_INFINITE; + } else { + return FP_NAN; + } + } else if (u.bits.exp != 0) { + return FP_NORMAL; + } else if (u.bits.manl == 0 && u.bits.manh == 0) { + return FP_ZERO; + } else { + return FP_SUBNORMAL; + } +} +#endif + diff --git a/src/openlibm/src/s_frexp.c b/src/openlibm/src/s_frexp.c new file mode 100644 index 0000000..0385acf --- /dev/null +++ b/src/openlibm/src/s_frexp.c @@ -0,0 +1,56 @@ +/* @(#)s_frexp.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_frexp.c,v 1.11 2008/02/22 02:30:35 das Exp $"); + +/* + * for non-zero x + * x = frexp(arg,&exp); + * return a double fp quantity x such that 0.5 <= |x| <1.0 + * and the corresponding binary exponent "exp". That is + * arg = x*2^exp. + * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg + * with *exp=0. + */ + +#include +#include + +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */ + +OLM_DLLEXPORT double +frexp(double x, int *eptr) +{ + int32_t hx, ix, lx; + EXTRACT_WORDS(hx,lx,x); + ix = 0x7fffffff&hx; + *eptr = 0; + if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */ + if (ix<0x00100000) { /* subnormal */ + x *= two54; + GET_HIGH_WORD(hx,x); + ix = hx&0x7fffffff; + *eptr = -54; + } + *eptr += (ix>>20)-1022; + hx = (hx&0x800fffff)|0x3fe00000; + SET_HIGH_WORD(x,hx); + return x; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(frexp, frexpl); +#endif diff --git a/src/openlibm/src/s_frexpf.c b/src/openlibm/src/s_frexpf.c new file mode 100644 index 0000000..fe63046 --- /dev/null +++ b/src/openlibm/src/s_frexpf.c @@ -0,0 +1,44 @@ +/* s_frexpf.c -- float version of s_frexp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_frexpf.c,v 1.10 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +static const float +two25 = 3.3554432000e+07; /* 0x4c000000 */ + +OLM_DLLEXPORT float +frexpf(float x, int *eptr) +{ + int32_t hx,ix; + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + *eptr = 0; + if(ix>=0x7f800000||(ix==0)) return x; /* 0,inf,nan */ + if (ix<0x00800000) { /* subnormal */ + x *= two25; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + *eptr = -25; + } + *eptr += (ix>>23)-126; + hx = (hx&0x807fffff)|0x3f000000; + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/src/openlibm/src/s_frexpl.c b/src/openlibm/src/s_frexpl.c new file mode 100644 index 0000000..ed2d28b --- /dev/null +++ b/src/openlibm/src/s_frexpl.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_frexpl.c,v 1.1 2005/03/07 04:54:51 das Exp $ + */ + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT long double +frexpl(long double x, int *ex) +{ + union IEEEl2bits u; + + u.e = x; + switch (u.bits.exp) { + case 0: /* 0 or subnormal */ + if ((u.bits.manl | u.bits.manh) == 0) { + *ex = 0; + } else { + u.e *= 0x1.0p514; + *ex = u.bits.exp - 0x4200; + u.bits.exp = 0x3ffe; + } + break; + case 0x7fff: /* infinity or NaN; value of *ex is unspecified */ + break; + default: /* normal */ + *ex = u.bits.exp - 0x3ffe; + u.bits.exp = 0x3ffe; + break; + } + return (u.e); +} diff --git a/src/openlibm/src/s_ilogb.c b/src/openlibm/src/s_ilogb.c new file mode 100644 index 0000000..897e6d6 --- /dev/null +++ b/src/openlibm/src/s_ilogb.c @@ -0,0 +1,49 @@ +/* @(#)s_ilogb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogb.c,v 1.10 2008/02/22 02:30:35 das Exp $"); + +/* ilogb(double x) + * return the binary exponent of non-zero x + * ilogb(0) = FP_ILOGB0 + * ilogb(NaN) = FP_ILOGBNAN (no signal is raised) + * ilogb(inf) = INT_MAX (no signal is raised) + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT int +ilogb(double x) +{ + int32_t hx,lx,ix; + + EXTRACT_WORDS(hx,lx,x); + hx &= 0x7fffffff; + if(hx<0x00100000) { + if((hx|lx)==0) + return FP_ILOGB0; + else /* subnormal x */ + if(hx==0) { + for (ix = -1043; lx>0; lx<<=1) ix -=1; + } else { + for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1; + } + return ix; + } + else if (hx<0x7ff00000) return (hx>>20)-1023; + else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN; + else return INT_MAX; +} diff --git a/src/openlibm/src/s_ilogbf.c b/src/openlibm/src/s_ilogbf.c new file mode 100644 index 0000000..79e359d --- /dev/null +++ b/src/openlibm/src/s_ilogbf.c @@ -0,0 +1,41 @@ +/* s_ilogbf.c -- float version of s_ilogb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogbf.c,v 1.8 2008/02/22 02:30:35 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT int +ilogbf(float x) +{ + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + hx &= 0x7fffffff; + if(hx<0x00800000) { + if(hx==0) + return FP_ILOGB0; + else /* subnormal x */ + for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1; + return ix; + } + else if (hx<0x7f800000) return (hx>>23)-127; + else if (hx>0x7f800000) return FP_ILOGBNAN; + else return INT_MAX; +} diff --git a/src/openlibm/src/s_ilogbl.c b/src/openlibm/src/s_ilogbl.c new file mode 100644 index 0000000..d67eea8 --- /dev/null +++ b/src/openlibm/src/s_ilogbl.c @@ -0,0 +1,54 @@ +/* + * From: @(#)s_ilogb.c 5.1 93/09/24 + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_ilogbl.c,v 1.2 2008/02/22 02:30:35 das Exp $"); + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT int +ilogbl(long double x) +{ + union IEEEl2bits u; + unsigned long m; + int b; + + u.e = x; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_ILOGB0); + /* denormalized */ + if (u.bits.manh == 0) { + m = 1lu << (LDBL_MANL_SIZE - 1); + for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1) + b++; + } else { + m = 1lu << (LDBL_MANH_SIZE - 1); + for (b = 0; !(u.bits.manh & m); m >>= 1) + b++; + } +#ifdef LDBL_IMPLICIT_NBIT + b++; +#endif + return (LDBL_MIN_EXP - b - 1); + } else if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1) + return (u.bits.exp - LDBL_MAX_EXP + 1); + else if (u.bits.manl != 0 || u.bits.manh != 0) + return (FP_ILOGBNAN); + else + return (INT_MAX); +} diff --git a/src/openlibm/src/s_isfinite.c b/src/openlibm/src/s_isfinite.c new file mode 100644 index 0000000..7c11876 --- /dev/null +++ b/src/openlibm/src/s_isfinite.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_isfinite.c,v 1.1 2004/07/09 03:32:39 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT int +__isfinite(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp != 2047); +} + +OLM_DLLEXPORT int +__isfinitef(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp != 255); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__isfinitel(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.exp != 32767); +} +#endif diff --git a/src/openlibm/src/s_isinf.c b/src/openlibm/src/s_isinf.c new file mode 100644 index 0000000..02eaff3 --- /dev/null +++ b/src/openlibm/src/s_isinf.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +/* Provided by libc */ +#if 1 +OLM_DLLEXPORT int +(isinf) (double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0); +} +#endif + +OLM_DLLEXPORT int +__isinff(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp == 255 && u.bits.man == 0); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__isinfl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + mask_nbit_l(u); + return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0); +} +#endif + +openlibm_weak_reference(__isinff, isinff); diff --git a/src/openlibm/src/s_isnan.c b/src/openlibm/src/s_isnan.c new file mode 100644 index 0000000..b9066aa --- /dev/null +++ b/src/openlibm/src/s_isnan.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_isnan.c,v 1.9 2010/06/12 17:32:05 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +/* Provided by libc */ +#if 1 +OLM_DLLEXPORT int +(isnan) (double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); +} +#endif + +OLM_DLLEXPORT int +__isnanf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp == 255 && u.bits.man != 0); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__isnanl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + mask_nbit_l(u); + return (u.bits.exp == 32767 && (u.bits.manl != 0 || u.bits.manh != 0)); +} +#endif + +openlibm_weak_reference(__isnanf, isnanf); diff --git a/src/openlibm/src/s_isnormal.c b/src/openlibm/src/s_isnormal.c new file mode 100644 index 0000000..3c721d7 --- /dev/null +++ b/src/openlibm/src/s_isnormal.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_isnormal.c,v 1.1 2004/07/09 03:32:39 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT int +__isnormal(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp != 0 && u.bits.exp != 2047); +} + +OLM_DLLEXPORT int +__isnormalf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp != 0 && u.bits.exp != 255); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__isnormall(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.exp != 0 && u.bits.exp != 32767); +} +#endif diff --git a/src/openlibm/src/s_llrint.c b/src/openlibm/src/s_llrint.c new file mode 100644 index 0000000..dcd6aed --- /dev/null +++ b/src/openlibm/src/s_llrint.c @@ -0,0 +1,9 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrint.c,v 1.1 2005/01/11 23:12:55 das Exp $"); + +#define type double +#define roundit rint +#define dtype long long +#define fn llrint + +#include "s_lrint.c" diff --git a/src/openlibm/src/s_llrintf.c b/src/openlibm/src/s_llrintf.c new file mode 100644 index 0000000..81ae8f0 --- /dev/null +++ b/src/openlibm/src/s_llrintf.c @@ -0,0 +1,9 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrintf.c,v 1.1 2005/01/11 23:12:55 das Exp $"); + +#define type float +#define roundit rintf +#define dtype long long +#define fn llrintf + +#include "s_lrint.c" diff --git a/src/openlibm/src/s_llrintl.c b/src/openlibm/src/s_llrintl.c new file mode 100644 index 0000000..3b23238 --- /dev/null +++ b/src/openlibm/src/s_llrintl.c @@ -0,0 +1,9 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llrintl.c,v 1.1 2008/01/14 02:12:06 das Exp $"); + +#define type long double +#define roundit rintl +#define dtype long long +#define fn llrintl + +#include "s_lrint.c" diff --git a/src/openlibm/src/s_llround.c b/src/openlibm/src/s_llround.c new file mode 100644 index 0000000..717ea96 --- /dev/null +++ b/src/openlibm/src/s_llround.c @@ -0,0 +1,11 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llround.c,v 1.2 2005/04/08 00:52:27 das Exp $"); + +#define type double +#define roundit round +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llround + +#include "s_lround.c" diff --git a/src/openlibm/src/s_llroundf.c b/src/openlibm/src/s_llroundf.c new file mode 100644 index 0000000..9b8b8b8 --- /dev/null +++ b/src/openlibm/src/s_llroundf.c @@ -0,0 +1,11 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llroundf.c,v 1.2 2005/04/08 00:52:27 das Exp $"); + +#define type float +#define roundit roundf +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llroundf + +#include "s_lround.c" diff --git a/src/openlibm/src/s_llroundl.c b/src/openlibm/src/s_llroundl.c new file mode 100644 index 0000000..7a00657 --- /dev/null +++ b/src/openlibm/src/s_llroundl.c @@ -0,0 +1,11 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_llroundl.c,v 1.1 2005/04/08 01:24:08 das Exp $"); + +#define type long double +#define roundit roundl +#define dtype long long +#define DTYPE_MIN LLONG_MIN +#define DTYPE_MAX LLONG_MAX +#define fn llroundl + +#include "s_lround.c" diff --git a/src/openlibm/src/s_log1p.c b/src/openlibm/src/s_log1p.c new file mode 100644 index 0000000..1921b6a --- /dev/null +++ b/src/openlibm/src/s_log1p.c @@ -0,0 +1,179 @@ +/* @(#)s_log1p.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_log1p.c,v 1.10 2008/03/29 16:37:59 das Exp $"); + +/* double log1p(double x) + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log1p(f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Reme algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s + * (the values of Lp1 to Lp7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lp1*s +...+Lp7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log1p(f) = f - (hfsq - s*(hfsq+R)). + * + * 3. Finally, log1p(x) = k*ln2 + log1p(f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include +#include + +#include "math_private.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ +Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +OLM_DLLEXPORT double +log1p(double x) +{ + double hfsq,f,c,s,z,R,u; + int32_t k,hx,hu,ax; + + GET_HIGH_WORD(hx,x); + ax = hx&0x7fffffff; + + k = 1; + if (hx < 0x3FDA827A) { /* 1+x < sqrt(2)+ */ + if(ax>=0x3ff00000) { /* x <= -1.0 */ + if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */ + else return (x-x)/(x-x); /* log1p(x<-1)=NaN */ + } + if(ax<0x3e200000) { /* |x| < 2**-29 */ + if(two54+x>zero /* raise inexact */ + &&ax<0x3c900000) /* |x| < 2**-54 */ + return x; + else + return x - x*x*0.5; + } + if(hx>0||hx<=((int32_t)0xbfd2bec4)) { + k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + } + if (hx >= 0x7ff00000) return x+x; + if(k!=0) { + if(hx<0x43400000) { + STRICT_ASSIGN(double,u,1.0+x); + GET_HIGH_WORD(hu,u); + k = (hu>>20)-1023; + c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */ + c /= u; + } else { + u = x; + GET_HIGH_WORD(hu,u); + k = (hu>>20)-1023; + c = 0; + } + hu &= 0x000fffff; + /* + * The approximation to sqrt(2) used in thresholds is not + * critical. However, the ones used above must give less + * strict bounds than the one here so that the k==0 case is + * never reached from here, since here we have committed to + * using the correction term but don't use it if k==0. + */ + if(hu<0x6a09e) { /* u ~< sqrt(2) */ + SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */ + } else { + k += 1; + SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */ + hu = (0x00100000-hu)>>2; + } + f = u-1.0; + } + hfsq=0.5*f*f; + if(hu==0) { /* |f| < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + c += k*ln2_lo; + return k*ln2_hi+c; + } + } + R = hfsq*(1.0-0.66666666666666666*f); + if(k==0) return f-R; else + return k*ln2_hi-((R-(k*ln2_lo+c))-f); + } + s = f/(2.0+f); + z = s*s; + R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(log1p, log1pl); +#endif diff --git a/src/openlibm/src/s_log1pf.c b/src/openlibm/src/s_log1pf.c new file mode 100644 index 0000000..53c8f49 --- /dev/null +++ b/src/openlibm/src/s_log1pf.c @@ -0,0 +1,114 @@ +/* s_log1pf.c -- float version of s_log1p.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_log1pf.c,v 1.12 2008/03/29 16:37:59 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +two25 = 3.355443200e+07, /* 0x4c000000 */ +Lp1 = 6.6666668653e-01, /* 3F2AAAAB */ +Lp2 = 4.0000000596e-01, /* 3ECCCCCD */ +Lp3 = 2.8571429849e-01, /* 3E924925 */ +Lp4 = 2.2222198546e-01, /* 3E638E29 */ +Lp5 = 1.8183572590e-01, /* 3E3A3325 */ +Lp6 = 1.5313838422e-01, /* 3E1CD04F */ +Lp7 = 1.4798198640e-01; /* 3E178897 */ + +static const float zero = 0.0; + +OLM_DLLEXPORT float +log1pf(float x) +{ + float hfsq,f,c,s,z,R,u; + int32_t k,hx,hu,ax; + + GET_FLOAT_WORD(hx,x); + ax = hx&0x7fffffff; + + k = 1; + if (hx < 0x3ed413d0) { /* 1+x < sqrt(2)+ */ + if(ax>=0x3f800000) { /* x <= -1.0 */ + if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */ + else return (x-x)/(x-x); /* log1p(x<-1)=NaN */ + } + if(ax<0x38000000) { /* |x| < 2**-15 */ + if(two25+x>zero /* raise inexact */ + &&ax<0x33800000) /* |x| < 2**-24 */ + return x; + else + return x - x*x*(float)0.5; + } + if(hx>0||hx<=((int32_t)0xbe95f619)) { + k=0;f=x;hu=1;} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + } + if (hx >= 0x7f800000) return x+x; + if(k!=0) { + if(hx<0x5a000000) { + STRICT_ASSIGN(float,u,(float)1.0+x); + GET_FLOAT_WORD(hu,u); + k = (hu>>23)-127; + /* correction term */ + c = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0); + c /= u; + } else { + u = x; + GET_FLOAT_WORD(hu,u); + k = (hu>>23)-127; + c = 0; + } + hu &= 0x007fffff; + /* + * The approximation to sqrt(2) used in thresholds is not + * critical. However, the ones used above must give less + * strict bounds than the one here so that the k==0 case is + * never reached from here, since here we have committed to + * using the correction term but don't use it if k==0. + */ + if(hu<0x3504f4) { /* u < sqrt(2) */ + SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */ + } else { + k += 1; + SET_FLOAT_WORD(u,hu|0x3f000000); /* normalize u/2 */ + hu = (0x00800000-hu)>>2; + } + f = u-(float)1.0; + } + hfsq=(float)0.5*f*f; + if(hu==0) { /* |f| < 2**-20 */ + if(f==zero) { + if(k==0) { + return zero; + } else { + c += k*ln2_lo; + return k*ln2_hi+c; + } + } + R = hfsq*((float)1.0-(float)0.66666666666666666*f); + if(k==0) return f-R; else + return k*ln2_hi-((R-(k*ln2_lo+c))-f); + } + s = f/((float)2.0+f); + z = s*s; + R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); + if(k==0) return f-(hfsq-s*(hfsq+R)); else + return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} diff --git a/src/openlibm/src/s_logb.c b/src/openlibm/src/s_logb.c new file mode 100644 index 0000000..116b696 --- /dev/null +++ b/src/openlibm/src/s_logb.c @@ -0,0 +1,49 @@ +/* @(#)s_logb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_logb.c,v 1.12 2008/02/08 01:22:13 bde Exp $"); + +/* + * double logb(x) + * IEEE 754 logb. Included to pass IEEE test suite. Not recommend. + * Use ilogb instead. + */ + +#include +#include + +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16; /* 43500000 00000000 */ + +OLM_DLLEXPORT double +logb(double x) +{ + int32_t lx,ix; + EXTRACT_WORDS(ix,lx,x); + ix &= 0x7fffffff; /* high |x| */ + if((ix|lx)==0) return -1.0/fabs(x); + if(ix>=0x7ff00000) return x*x; + if(ix<0x00100000) { + x *= two54; /* convert subnormal x to normal */ + GET_HIGH_WORD(ix,x); + ix &= 0x7fffffff; + return (double) ((ix>>20)-1023-54); + } else + return (double) ((ix>>20)-1023); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(logb, logbl); +#endif diff --git a/src/openlibm/src/s_logbf.c b/src/openlibm/src/s_logbf.c new file mode 100644 index 0000000..8b1d117 --- /dev/null +++ b/src/openlibm/src/s_logbf.c @@ -0,0 +1,41 @@ +/* s_logbf.c -- float version of s_logb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_logbf.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +static const float +two25 = 3.355443200e+07; /* 0x4c000000 */ + +OLM_DLLEXPORT float +logbf(float x) +{ + int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* high |x| */ + if(ix==0) return (float)-1.0/fabsf(x); + if(ix>=0x7f800000) return x*x; + if(ix<0x00800000) { + x *= two25; /* convert subnormal x to normal */ + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + return (float) ((ix>>23)-127-25); + } else + return (float) ((ix>>23)-127); +} diff --git a/src/openlibm/src/s_logbl.c b/src/openlibm/src/s_logbl.c new file mode 100644 index 0000000..3c1336b --- /dev/null +++ b/src/openlibm/src/s_logbl.c @@ -0,0 +1,52 @@ +/* + * From: @(#)s_ilogb.c 5.1 93/09/24 + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT long double +logbl(long double x) +{ + union IEEEl2bits u; + unsigned long m; + int b; + + u.e = x; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) { /* x == 0 */ + u.bits.sign = 1; + return (1.0L / u.e); + } + /* denormalized */ + if (u.bits.manh == 0) { + m = 1lu << (LDBL_MANL_SIZE - 1); + for (b = LDBL_MANH_SIZE; !(u.bits.manl & m); m >>= 1) + b++; + } else { + m = 1lu << (LDBL_MANH_SIZE - 1); + for (b = 0; !(u.bits.manh & m); m >>= 1) + b++; + } +#ifdef LDBL_IMPLICIT_NBIT + b++; +#endif + return ((long double)(LDBL_MIN_EXP - b - 1)); + } + if (u.bits.exp < (LDBL_MAX_EXP << 1) - 1) /* normal */ + return ((long double)(u.bits.exp - LDBL_MAX_EXP + 1)); + else /* +/- inf or nan */ + return (x * x); +} diff --git a/src/openlibm/src/s_lrint.c b/src/openlibm/src/s_lrint.c new file mode 100644 index 0000000..e1c5546 --- /dev/null +++ b/src/openlibm/src/s_lrint.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" + +#include +#include + +#include "math_private.h" + +#ifndef type +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrint.c,v 1.1 2005/01/11 23:12:55 das Exp $"); +#define type double +#define roundit rint +#define dtype long +#define fn lrint +#endif + +/* + * C99 says we should not raise a spurious inexact exception when an + * invalid exception is raised. Unfortunately, the set of inputs + * that overflows depends on the rounding mode when 'dtype' has more + * significant bits than 'type'. Hence, we bend over backwards for the + * sake of correctness; an MD implementation could be more efficient. + */ +OLM_DLLEXPORT dtype +fn(type x) +{ + fenv_t env; + dtype d; + + feholdexcept(&env); + d = (dtype)roundit(x); + if (fetestexcept(FE_INVALID)) + feclearexcept(FE_INEXACT); + feupdateenv(&env); + return (d); +} diff --git a/src/openlibm/src/s_lrintf.c b/src/openlibm/src/s_lrintf.c new file mode 100644 index 0000000..f29ad52 --- /dev/null +++ b/src/openlibm/src/s_lrintf.c @@ -0,0 +1,9 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrintf.c,v 1.1 2005/01/11 23:12:55 das Exp $"); + +#define type float +#define roundit rintf +#define dtype long +#define fn lrintf + +#include "s_lrint.c" diff --git a/src/openlibm/src/s_lrintl.c b/src/openlibm/src/s_lrintl.c new file mode 100644 index 0000000..b57c27d --- /dev/null +++ b/src/openlibm/src/s_lrintl.c @@ -0,0 +1,9 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lrintl.c,v 1.1 2008/01/14 02:12:06 das Exp $"); + +#define type long double +#define roundit rintl +#define dtype long +#define fn lrintl + +#include "s_lrint.c" diff --git a/src/openlibm/src/s_lround.c b/src/openlibm/src/s_lround.c new file mode 100644 index 0000000..76fa732 --- /dev/null +++ b/src/openlibm/src/s_lround.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" + +#include +#include +#include + +#include "math_private.h" + +#ifndef type +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lround.c,v 1.2 2005/04/08 00:52:16 das Exp $"); +#define type double +#define roundit round +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lround +#endif + +/* + * If type has more precision than dtype, the endpoints dtype_(min|max) are + * of the form xxx.5; they are "out of range" because lround() rounds away + * from 0. On the other hand, if type has less precision than dtype, then + * all values that are out of range are integral, so we might as well assume + * that everything is in range. At compile time, INRANGE(x) should reduce to + * two floating-point comparisons in the former case, or TRUE otherwise. + */ +static const type dtype_min = DTYPE_MIN - 0.5; +static const type dtype_max = DTYPE_MAX + 0.5; +#define INRANGE(x) (dtype_max - DTYPE_MAX != 0.5 || \ + ((x) > dtype_min && (x) < dtype_max)) + +OLM_DLLEXPORT dtype +fn(type x) +{ + + if (INRANGE(x)) { + x = roundit(x); + return ((dtype)x); + } else { + feraiseexcept(FE_INVALID); + return (DTYPE_MAX); + } +} diff --git a/src/openlibm/src/s_lroundf.c b/src/openlibm/src/s_lroundf.c new file mode 100644 index 0000000..f526eef --- /dev/null +++ b/src/openlibm/src/s_lroundf.c @@ -0,0 +1,11 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lroundf.c,v 1.2 2005/04/08 00:52:27 das Exp $"); + +#define type float +#define roundit roundf +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lroundf + +#include "s_lround.c" diff --git a/src/openlibm/src/s_lroundl.c b/src/openlibm/src/s_lroundl.c new file mode 100644 index 0000000..eb8997c --- /dev/null +++ b/src/openlibm/src/s_lroundl.c @@ -0,0 +1,11 @@ +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_lroundl.c,v 1.1 2005/04/08 01:24:08 das Exp $"); + +#define type long double +#define roundit roundl +#define dtype long +#define DTYPE_MIN LONG_MIN +#define DTYPE_MAX LONG_MAX +#define fn lroundl + +#include "s_lround.c" diff --git a/src/openlibm/src/s_modf.c b/src/openlibm/src/s_modf.c new file mode 100644 index 0000000..e3b517b --- /dev/null +++ b/src/openlibm/src/s_modf.c @@ -0,0 +1,76 @@ +/* @(#)s_modf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include + +#include "math_private.h" + +static const double one = 1.0; + +OLM_DLLEXPORT double +modf(double x, double *iptr) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */ + if(j0<20) { /* integer part in high x */ + if(j0<0) { /* |x|<1 */ + INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */ + return x; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0&(~i),0); + return x - *iptr; + } + } + } else if (j0>51) { /* no fraction part */ + u_int32_t high; + if (j0 == 0x400) { /* inf/NaN */ + *iptr = x; + return 0.0 / x; + } + *iptr = x*one; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0,i1&(~i)); + return x - *iptr; + } + } +} diff --git a/src/openlibm/src/s_modff.c b/src/openlibm/src/s_modff.c new file mode 100644 index 0000000..0a0c840 --- /dev/null +++ b/src/openlibm/src/s_modff.c @@ -0,0 +1,58 @@ +/* s_modff.c -- float version of s_modf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_modff.c,v 1.9 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +static const float one = 1.0; + +OLM_DLLEXPORT float +modff(float x, float *iptr) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */ + if(j0<23) { /* integer part in x */ + if(j0<0) { /* |x|<1 */ + SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */ + return x; + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) { /* x is integral */ + u_int32_t ix; + *iptr = x; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } else { + SET_FLOAT_WORD(*iptr,i0&(~i)); + return x - *iptr; + } + } + } else { /* no fraction part */ + u_int32_t ix; + *iptr = x*one; + if (x != x) /* NaN */ + return x; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } +} diff --git a/src/openlibm/src/s_modfl.c b/src/openlibm/src/s_modfl.c new file mode 100644 index 0000000..44a9363 --- /dev/null +++ b/src/openlibm/src/s_modfl.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Derived from s_modf.c, which has the following Copyright: + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * $FreeBSD: src/lib/msun/src/s_modfl.c,v 1.1 2007/01/07 07:54:21 das Exp $ + */ + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#if LDBL_MANL_SIZE > 32 +#define MASK ((u_int64_t)-1) +#else +#define MASK ((u_int32_t)-1) +#endif +/* Return the last n bits of a word, representing the fractional part. */ +#define GETFRAC(bits, n) ((bits) & ~(MASK << (n))) +/* The number of fraction bits in manh, not counting the integer bit */ +#define HIBITS (LDBL_MANT_DIG - LDBL_MANL_SIZE) + +static const long double zero[] = { 0.0L, -0.0L }; + +OLM_DLLEXPORT long double +modfl(long double x, long double *iptr) +{ + union IEEEl2bits ux; + int e; + + ux.e = x; + e = ux.bits.exp - LDBL_MAX_EXP + 1; + if (e < HIBITS) { /* Integer part is in manh. */ + if (e < 0) { /* |x|<1 */ + *iptr = zero[ux.bits.sign]; + return (x); + } else { + if ((GETFRAC(ux.bits.manh, HIBITS - 1 - e) | + ux.bits.manl) == 0) { /* X is an integer. */ + *iptr = x; + return (zero[ux.bits.sign]); + } else { + /* Clear all but the top e+1 bits. */ + ux.bits.manh >>= HIBITS - 1 - e; + ux.bits.manh <<= HIBITS - 1 - e; + ux.bits.manl = 0; + *iptr = ux.e; + return (x - ux.e); + } + } + } else if (e >= LDBL_MANT_DIG - 1) { /* x has no fraction part. */ + *iptr = x; + if (x != x) /* Handle NaNs. */ + return (x); + return (zero[ux.bits.sign]); + } else { /* Fraction part is in manl. */ + if (GETFRAC(ux.bits.manl, LDBL_MANT_DIG - 1 - e) == 0) { + /* x is integral. */ + *iptr = x; + return (zero[ux.bits.sign]); + } else { + /* Clear all but the top e+1 bits. */ + ux.bits.manl >>= LDBL_MANT_DIG - 1 - e; + ux.bits.manl <<= LDBL_MANT_DIG - 1 - e; + *iptr = ux.e; + return (x - ux.e); + } + } +} diff --git a/src/openlibm/src/s_nan.c b/src/openlibm/src/s_nan.c new file mode 100644 index 0000000..dd1c5af --- /dev/null +++ b/src/openlibm/src/s_nan.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_nan.c,v 1.2 2007/12/18 23:46:32 das Exp $ + */ + +//VBS +//#include +#include +#include +#include +#include +#include //for memset + +#include "math_private.h" + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__DragonFly__) +static __inline int digittoint(int c) { + if ('0' <= c && c <= '9') + return (c - '0'); + else if ('A' <= c && c <= 'F') + return (c - 'A' + 10); + else if ('a' <= c && c <= 'f') + return (c - 'a' + 10); + return 0; +} +#endif + + +/* + * Scan a string of hexadecimal digits (the format nan(3) expects) and + * make a bit array (using the local endianness). We stop when we + * encounter an invalid character, NUL, etc. If we overflow, we do + * the same as gcc's __builtin_nan(), namely, discard the high order bits. + * + * The format this routine accepts needs to be compatible with what is used + * in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in + * __builtin_nan(). In fact, we're only 100% compatible for strings we + * consider valid, so we might be violating the C standard. But it's + * impossible to use nan(3) portably anyway, so this seems good enough. + */ +OLM_DLLEXPORT void +__scan_nan(u_int32_t *words, int num_words, const char *s) +{ + int si; /* index into s */ + int bitpos; /* index into words (in bits) */ + + memset(words, 0, num_words * sizeof(u_int32_t)); + + /* Allow a leading '0x'. (It's expected, but redundant.) */ + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + s += 2; + + /* Scan forwards in the string, looking for the end of the sequence. */ + for (si = 0; isxdigit(s[si]); si++) + ; + + /* Scan backwards, filling in the bits in words[] as we go. */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) { +#else + for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) { +#endif + if (--si < 0) + break; + words[bitpos / 32] |= digittoint(s[si]) << (bitpos % 32); + } +} + +OLM_DLLEXPORT double +nan(const char *s) +{ + union { + double d; + u_int32_t bits[2]; + } u; + + __scan_nan(u.bits, 2, s); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + u.bits[1] |= 0x7ff80000; +#else + u.bits[0] |= 0x7ff80000; +#endif + return (u.d); +} + +OLM_DLLEXPORT float +nanf(const char *s) +{ + union { + float f; + u_int32_t bits[1]; + } u; + + __scan_nan(u.bits, 1, s); + u.bits[0] |= 0x7fc00000; + return (u.f); +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(nan, nanl); +#endif diff --git a/src/openlibm/src/s_nearbyint.c b/src/openlibm/src/s_nearbyint.c new file mode 100644 index 0000000..95162a5 --- /dev/null +++ b/src/openlibm/src/s_nearbyint.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_nearbyint.c,v 1.2 2008/01/14 02:12:06 das Exp $"); + +#include +#include + +#include "math_private.h" + +/* + * We save and restore the floating-point environment to avoid raising + * an inexact exception. We can get away with using fesetenv() + * instead of feclearexcept()/feupdateenv() to restore the environment + * because the only exception defined for rint() is overflow, and + * rounding can't overflow as long as emax >= p. + */ +#define DECL(type, fn, rint) \ +OLM_DLLEXPORT type \ +fn(type x) \ +{ \ + type ret; \ + fenv_t env; \ + \ + fegetenv(&env); \ + ret = rint(x); \ + fesetenv(&env); \ + return (ret); \ +} + +DECL(double, nearbyint, rint) +DECL(float, nearbyintf, rintf) diff --git a/src/openlibm/src/s_nextafter.c b/src/openlibm/src/s_nextafter.c new file mode 100644 index 0000000..8b2ea05 --- /dev/null +++ b/src/openlibm/src/s_nextafter.c @@ -0,0 +1,83 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafter.c,v 1.12 2008/02/22 02:30:35 das Exp $"); + +/* IEEE functions + * nextafter(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +nextafter(double x, double y) +{ + volatile double t; + int32_t hx,hy,ix,iy; + u_int32_t lx,ly; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffff; /* |y| */ + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ + ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if((ix|lx)==0) { /* x == 0 */ + INSERT_WORDS(x,hy&0x80000000,1); /* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>=0) { /* x > 0 */ + if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x < y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } else { /* x < 0 */ + if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x > y, x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + } + hy = hx&0x7ff00000; + if(hy>=0x7ff00000) return x+x; /* overflow */ + if(hy<0x00100000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + INSERT_WORDS(y,hx,lx); + return y; + } + } + INSERT_WORDS(x,hx,lx); + return x; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(nextafter, nexttoward); +openlibm_weak_reference(nextafter, nexttowardl); +openlibm_weak_reference(nextafter, nextafterl); +#endif diff --git a/src/openlibm/src/s_nextafterf.c b/src/openlibm/src/s_nextafterf.c new file mode 100644 index 0000000..d4cd630 --- /dev/null +++ b/src/openlibm/src/s_nextafterf.c @@ -0,0 +1,67 @@ +/* s_nextafterf.c -- float version of s_nextafter.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafterf.c,v 1.11 2008/02/22 02:30:35 das Exp $"); + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +nextafterf(float x, float y) +{ + volatile float t; + int32_t hx,hy,ix,iy; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + ix = hx&0x7fffffff; /* |x| */ + iy = hy&0x7fffffff; /* |y| */ + + if((ix>0x7f800000) || /* x is nan */ + (iy>0x7f800000)) /* y is nan */ + return x+y; + if(x==y) return y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if(hx>=0) { /* x > 0 */ + if(hx>hy) { /* x > y, x -= ulp */ + hx -= 1; + } else { /* x < y, x += ulp */ + hx += 1; + } + } else { /* x < 0 */ + if(hy>=0||hx>hy){ /* x < y, x -= ulp */ + hx -= 1; + } else { /* x > y, x += ulp */ + hx += 1; + } + } + hy = hx&0x7f800000; + if(hy>=0x7f800000) return x+x; /* overflow */ + if(hy<0x00800000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + SET_FLOAT_WORD(y,hx); + return y; + } + } + SET_FLOAT_WORD(x,hx); + return x; +} diff --git a/src/openlibm/src/s_nextafterl.c b/src/openlibm/src/s_nextafterl.c new file mode 100644 index 0000000..bb73141 --- /dev/null +++ b/src/openlibm/src/s_nextafterl.c @@ -0,0 +1,80 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_nextafterl.c,v 1.2 2008/02/22 02:30:36 das Exp $"); + +/* IEEE functions + * nextafter(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT long double +nextafterl(long double x, long double y) +{ + volatile long double t; + union IEEEl2bits ux, uy; + + ux.e = x; + uy.e = y; + + if ((ux.bits.exp == 0x7fff && + ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl) != 0) || + (uy.bits.exp == 0x7fff && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return y; /* x=y, return y */ + if(x==0.0) { + ux.bits.manh = 0; /* return +-minsubnormal */ + ux.bits.manl = 1; + ux.bits.sign = uy.bits.sign; + t = ux.e*ux.e; + if(t==ux.e) return t; else return ux.e; /* raise underflow flag */ + } + if((x>0.0) ^ (x +#include + +#include "fpmath.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT double +nexttoward(double x, long double y) +{ + union IEEEl2bits uy; + volatile double t; + int32_t hx,ix; + u_int32_t lx; + + EXTRACT_WORDS(hx,lx,x); + ix = hx&0x7fffffff; /* |x| */ + uy.e = y; + + if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || + (uy.bits.exp == 0x7fff && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return (double)y; /* x=y, return y */ + if(x==0.0) { + INSERT_WORDS(x,uy.bits.sign<<31,1); /* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if((hx>0.0) ^ (x < y)) { /* x -= ulp */ + if(lx==0) hx -= 1; + lx -= 1; + } else { /* x += ulp */ + lx += 1; + if(lx==0) hx += 1; + } + ix = hx&0x7ff00000; + if(ix>=0x7ff00000) return x+x; /* overflow */ + if(ix<0x00100000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + INSERT_WORDS(x,hx,lx); + return x; + } + } + INSERT_WORDS(x,hx,lx); + return x; +} diff --git a/src/openlibm/src/s_nexttowardf.c b/src/openlibm/src/s_nexttowardf.c new file mode 100644 index 0000000..bf50862 --- /dev/null +++ b/src/openlibm/src/s_nexttowardf.c @@ -0,0 +1,61 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_nexttowardf.c,v 1.3 2011/02/10 07:38:38 das Exp $"); + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#define LDBL_INFNAN_EXP (LDBL_MAX_EXP * 2 - 1) + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT float +nexttowardf(float x, long double y) +{ + union IEEEl2bits uy; + volatile float t; + int32_t hx,ix; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; /* |x| */ + uy.e = y; + + if((ix>0x7f800000) || + (uy.bits.exp == LDBL_INFNAN_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) + return x+y; /* x or y is nan */ + if(x==y) return (float)y; /* x=y, return y */ + if(ix==0) { /* x == 0 */ + SET_FLOAT_WORD(x,(uy.bits.sign<<31)|1);/* return +-minsubnormal */ + t = x*x; + if(t==x) return t; else return x; /* raise underflow flag */ + } + if((hx>=0) ^ (x < y)) /* x -= ulp */ + hx -= 1; + else /* x += ulp */ + hx += 1; + ix = hx&0x7f800000; + if(ix>=0x7f800000) return x+x; /* overflow */ + if(ix<0x00800000) { /* underflow */ + t = x*x; + if(t!=x) { /* raise underflow flag */ + SET_FLOAT_WORD(x,hx); + return x; + } + } + SET_FLOAT_WORD(x,hx); + return x; +} +#endif diff --git a/src/openlibm/src/s_remquo.c b/src/openlibm/src/s_remquo.c new file mode 100644 index 0000000..afc325d --- /dev/null +++ b/src/openlibm/src/s_remquo.c @@ -0,0 +1,159 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquo.c,v 1.2 2008/03/30 20:47:26 das Exp $"); + +#include +#include + +#include "math_private.h" + +static const double Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +OLM_DLLEXPORT double +remquo(double x, double y, int *quo) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t lx,ly,lz,q,sxy; + + EXTRACT_WORDS(hx,lx,x); + EXTRACT_WORDS(hy,ly,y); + sxy = (hx ^ hy) & 0x80000000; + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ + ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ + return (x*y)/(x*y); + if(hx<=hy) { + if((hx>31]; /* |x|=|y| return x*0*/ + } + } + + /* determine ix = ilogb(x) */ + if(hx<0x00100000) { /* subnormal x */ + if(hx==0) { + for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; + } else { + for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; + } + } else ix = (hx>>20)-1023; + + /* determine iy = ilogb(y) */ + if(hy<0x00100000) { /* subnormal y */ + if(hy==0) { + for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; + } else { + for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; + } + } else iy = (hy>>20)-1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -1022) + hx = 0x00100000|(0x000fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -1022-ix; + if(n<=31) { + hx = (hx<>(32-n)); + lx <<= n; + } else { + hx = lx<<(n-32); + lx = 0; + } + } + if(iy >= -1022) + hy = 0x00100000|(0x000fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -1022-iy; + if(n<=31) { + hy = (hy<>(32-n)); + ly <<= n; + } else { + hy = ly<<(n-32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + q = 0; + while(n--) { + hz=hx-hy;lz=lx-ly; if(lx>31); lx = lx+lx;} + else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;} + q <<= 1; + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[(u_int32_t)sx>>31]; + } + while(hx<0x00100000) { /* normalize x */ + hx = hx+hx+(lx>>31); lx = lx+lx; + iy -= 1; + } + if(iy>= -1022) { /* normalize output */ + hx = ((hx-0x00100000)|((iy+1023)<<20)); + } else { /* subnormal output */ + n = -1022 - iy; + if(n<=20) { + lx = (lx>>n)|((u_int32_t)hx<<(32-n)); + hx >>= n; + } else if (n<=31) { + lx = (hx<<(32-n))|(lx>>n); hx = 0; + } else { + lx = hx>>(n-32); hx = 0; + } + } +fixup: + INSERT_WORDS(x,hx,lx); + y = fabs(y); + if (y < 0x1p-1021) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + GET_HIGH_WORD(hx,x); + SET_HIGH_WORD(x,hx^sx); + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(remquo, remquol); +#endif diff --git a/src/openlibm/src/s_remquof.c b/src/openlibm/src/s_remquof.c new file mode 100644 index 0000000..1983ed5 --- /dev/null +++ b/src/openlibm/src/s_remquof.c @@ -0,0 +1,123 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquof.c,v 1.1 2005/03/25 04:40:44 das Exp $"); + +#include + +#include "math_private.h" + +static const float Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +OLM_DLLEXPORT float +remquof(float x, float y, int *quo) +{ + int32_t n,hx,hy,hz,ix,iy,sx,i; + u_int32_t q,sxy; + + GET_FLOAT_WORD(hx,x); + GET_FLOAT_WORD(hy,y); + sxy = (hx ^ hy) & 0x80000000; + sx = hx&0x80000000; /* sign of x */ + hx ^=sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + + /* purge off exception values */ + if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */ + return (x*y)/(x*y); + if(hx>31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if(hx<0x00800000) { /* subnormal x */ + for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; + } else ix = (hx>>23)-127; + + /* determine iy = ilogb(y) */ + if(hy<0x00800000) { /* subnormal y */ + for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1; + } else iy = (hy>>23)-127; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if(ix >= -126) + hx = 0x00800000|(0x007fffff&hx); + else { /* subnormal x, shift x to normal */ + n = -126-ix; + hx <<= n; + } + if(iy >= -126) + hy = 0x00800000|(0x007fffff&hy); + else { /* subnormal y, shift y to normal */ + n = -126-iy; + hy <<= n; + } + + /* fix point fmod */ + n = ix - iy; + q = 0; + while(n--) { + hz=hx-hy; + if(hz<0) hx = hx << 1; + else {hx = hz << 1; q++;} + q <<= 1; + } + hz=hx-hy; + if(hz>=0) {hx=hz;q++;} + + /* convert back to floating value and restore the sign */ + if(hx==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[(u_int32_t)sx>>31]; + } + while(hx<0x00800000) { /* normalize x */ + hx <<= 1; + iy -= 1; + } + if(iy>= -126) { /* normalize output */ + hx = ((hx-0x00800000)|((iy+127)<<23)); + } else { /* subnormal output */ + n = -126 - iy; + hx >>= n; + } +fixup: + SET_FLOAT_WORD(x,hx); + y = fabsf(y); + if (y < 0x1p-125f) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) { + q++; + x-=y; + } + GET_FLOAT_WORD(hx,x); + SET_FLOAT_WORD(x,hx^sx); + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/src/openlibm/src/s_remquol.c b/src/openlibm/src/s_remquol.c new file mode 100644 index 0000000..b610b67 --- /dev/null +++ b/src/openlibm/src/s_remquol.c @@ -0,0 +1,178 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_remquol.c,v 1.2 2008/07/31 20:09:47 das Exp $"); + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#define BIAS (LDBL_MAX_EXP - 1) + +#if LDBL_MANL_SIZE > 32 +typedef u_int64_t manl_t; +#else +typedef u_int32_t manl_t; +#endif + +#if LDBL_MANH_SIZE > 32 +typedef u_int64_t manh_t; +#else +typedef u_int32_t manh_t; +#endif + +/* + * These macros add and remove an explicit integer bit in front of the + * fractional mantissa, if the architecture doesn't have such a bit by + * default already. + */ +#ifdef LDBL_IMPLICIT_NBIT +#define SET_NBIT(hx) ((hx) | (1ULL << LDBL_MANH_SIZE)) +#define HFRAC_BITS LDBL_MANH_SIZE +#else +#define SET_NBIT(hx) (hx) +#define HFRAC_BITS (LDBL_MANH_SIZE - 1) +#endif + +#define MANL_SHIFT (LDBL_MANL_SIZE - 1) + +static const long double Zero[] = {0.0L, -0.0L}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer. We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method. In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + * + * Assumptions: + * - The low part of the mantissa fits in a manl_t exactly. + * - The high part of the mantissa fits in an int64_t with enough room + * for an explicit integer bit in front of the fractional bits. + */ +OLM_DLLEXPORT long double +remquol(long double x, long double y, int *quo) +{ + union IEEEl2bits ux, uy; + int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */ + manh_t hy; + manl_t lx,ly,lz; + int ix,iy,n,q,sx,sxy; + + ux.e = x; + uy.e = y; + sx = ux.bits.sign; + sxy = sx ^ uy.bits.sign; + ux.bits.sign = 0; /* |x| */ + uy.bits.sign = 0; /* |y| */ + x = ux.e; + + /* purge off exception values */ + if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */ + (ux.bits.exp == BIAS + LDBL_MAX_EXP) || /* or x not finite */ + (uy.bits.exp == BIAS + LDBL_MAX_EXP && + ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */ + return (x*y)/(x*y); + if(ux.bits.exp<=uy.bits.exp) { + if((ux.bits.exp>MANL_SHIFT); lx = lx+lx;} + else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;} + q <<= 1; + } + hz=hx-hy;lz=lx-ly; if(lx=0) {hx=hz;lx=lz;q++;} + + /* convert back to floating value and restore the sign */ + if((hx|lx)==0) { /* return sign(x)*0 */ + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return Zero[sx]; + } + while(hx<(1ULL<>MANL_SHIFT); lx = lx+lx; + iy -= 1; + } + ux.bits.manh = hx; /* The integer bit is truncated here if needed. */ + ux.bits.manl = lx; + if (iy < LDBL_MIN_EXP) { + ux.bits.exp = iy + (BIAS + 512); + ux.e *= 0x1p-512; + } else { + ux.bits.exp = iy + BIAS; + } + ux.bits.sign = 0; + x = ux.e; +fixup: + y = fabsl(y); + if (y < LDBL_MIN * 2) { + if (x+x>y || (x+x==y && (q & 1))) { + q++; + x-=y; + } + } else if (x>0.5*y || (x==0.5*y && (q & 1))) { + q++; + x-=y; + } + + ux.e = x; + ux.bits.sign ^= sx; + x = ux.e; + + q &= 0x7fffffff; + *quo = (sxy ? -q : q); + return x; +} diff --git a/src/openlibm/src/s_rint.c b/src/openlibm/src/s_rint.c new file mode 100644 index 0000000..f81e692 --- /dev/null +++ b/src/openlibm/src/s_rint.c @@ -0,0 +1,92 @@ +/* @(#)s_rint.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_rint.c,v 1.16 2008/02/22 02:30:35 das Exp $"); + +/* + * rint(x) + * Return x rounded to integral value according to the prevailing + * rounding mode. + * Method: + * Using floating addition. + * Exception: + * Inexact flag raised if x not equal to rint(x). + */ + +#include +#include + +#include "math_private.h" + +static const double +TWO52[2]={ + 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ + -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +}; + +OLM_DLLEXPORT double +rint(double x) +{ + int32_t i0,j0,sx; + u_int32_t i,i1; + double w,t; + EXTRACT_WORDS(i0,i1,x); + sx = (i0>>31)&1; + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { + if(((i0&0x7fffffff)|i1)==0) return x; + i1 |= (i0&0x0fffff); + i0 &= 0xfffe0000; + i0 |= ((i1|-i1)>>12)&0x80000; + SET_HIGH_WORD(x,i0); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + t = w-TWO52[sx]; + GET_HIGH_WORD(i0,t); + SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); + return t; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + i>>=1; + if(((i0&i)|i1)!=0) { + /* + * Some bit is set after the 0.5 bit. To avoid the + * possibility of errors from double rounding in + * w = TWO52[sx]+x, adjust the 0.25 bit to a lower + * guard bit. We do this for all j0<=51. The + * adjustment is trickiest for j0==18 and j0==19 + * since then it spans the word boundary. + */ + if(j0==19) i1 = 0x40000000; else + if(j0==18) i1 = 0x80000000; else + i0 = (i0&(~i))|((0x20000)>>j0); + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + i>>=1; + if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); + } + INSERT_WORDS(x,i0,i1); + STRICT_ASSIGN(double,w,TWO52[sx]+x); + return w-TWO52[sx]; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(rint, rintl); +#endif diff --git a/src/openlibm/src/s_rintf.c b/src/openlibm/src/s_rintf.c new file mode 100644 index 0000000..60cdb46 --- /dev/null +++ b/src/openlibm/src/s_rintf.c @@ -0,0 +1,53 @@ +/* s_rintf.c -- float version of s_rint.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_rintf.c,v 1.12 2008/02/22 02:30:35 das Exp $"); + +#include +#include +#include + +#include "math_private.h" + +static const float +TWO23[2]={ + 8.3886080000e+06, /* 0x4b000000 */ + -8.3886080000e+06, /* 0xcb000000 */ +}; + +OLM_DLLEXPORT float +rintf(float x) +{ + int32_t i0,j0,sx; + float w,t; + GET_FLOAT_WORD(i0,x); + sx = (i0>>31)&1; + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { + if((i0&0x7fffffff)==0) return x; + STRICT_ASSIGN(float,w,TWO23[sx]+x); + t = w-TWO23[sx]; + GET_FLOAT_WORD(i0,t); + SET_FLOAT_WORD(t,(i0&0x7fffffff)|(sx<<31)); + return t; + } + STRICT_ASSIGN(float,w,TWO23[sx]+x); + return w-TWO23[sx]; + } + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ +} diff --git a/src/openlibm/src/s_rintl.c b/src/openlibm/src/s_rintl.c new file mode 100644 index 0000000..d20768e --- /dev/null +++ b/src/openlibm/src/s_rintl.c @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_rintl.c,v 1.5 2008/02/22 11:59:05 bde Exp $"); + +#include +#include +#include + +#include "fpmath.h" + +//VBS +#include "math_private.h" + + +#if LDBL_MAX_EXP != 0x4000 +/* We also require the usual bias, min exp and expsign packing. */ +#error "Unsupported long double format" +#endif + +#define BIAS (LDBL_MAX_EXP - 1) + +static const float +shift[2] = { +#if LDBL_MANT_DIG == 64 + 0x1.0p63, -0x1.0p63 +#elif LDBL_MANT_DIG == 113 + 0x1.0p112, -0x1.0p112 +#else +#error "Unsupported long double format" +#endif +}; +static const float zero[2] = { 0.0, -0.0 }; + +OLM_DLLEXPORT long double +rintl(long double x) +{ + union IEEEl2bits u; + u_int32_t expsign; + int ex, sign; + + u.e = x; + expsign = u.xbits.expsign; + ex = expsign & 0x7fff; + + if (ex >= BIAS + LDBL_MANT_DIG - 1) { + if (ex == BIAS + LDBL_MAX_EXP) + return (x + x); /* Inf, NaN, or unsupported format */ + return (x); /* finite and already an integer */ + } + sign = expsign >> 15; + + /* + * The following code assumes that intermediate results are + * evaluated in long double precision. If they are evaluated in + * greater precision, double rounding may occur, and if they are + * evaluated in less precision (as on i386), results will be + * wildly incorrect. + */ + x += shift[sign]; + x -= shift[sign]; + + /* + * If the result is +-0, then it must have the same sign as x, but + * the above calculation doesn't always give this. Fix up the sign. + */ + if (ex < BIAS && x == 0.0L) + return (zero[sign]); + + return (x); +} + +/* + * We save and restore the floating-point environment to avoid raising + * an inexact exception. We can get away with using fesetenv() + * instead of feclearexcept()/feupdateenv() to restore the environment + * because the only exception defined for rint() is overflow, and + * rounding can't overflow as long as emax >= p. + */ +#define DECL(type, fn, rint) \ +OLM_DLLEXPORT type \ +fn(type x) \ +{ \ + type ret; \ + fenv_t env; \ + \ + fegetenv(&env); \ + ret = rint(x); \ + fesetenv(&env); \ + return (ret); \ +} +DECL(long double, nearbyintl, rintl) diff --git a/src/openlibm/src/s_round.c b/src/openlibm/src/s_round.c new file mode 100644 index 0000000..a982ec3 --- /dev/null +++ b/src/openlibm/src/s_round.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_round.c,v 1.4 2005/12/02 13:45:06 bde Exp $"); + +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +round(double x) +{ + double t; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + if ((hx & 0x7fffffff) == 0x7ff00000) + return (x + x); + + if (!(hx & 0x80000000)) { + t = floor(x); + if (t - x <= -0.5) + t += 1; + return (t); + } else { + t = floor(-x); + if (t + x <= -0.5) + t += 1; + return (-t); + } +} diff --git a/src/openlibm/src/s_roundf.c b/src/openlibm/src/s_roundf.c new file mode 100644 index 0000000..784a8a5 --- /dev/null +++ b/src/openlibm/src/s_roundf.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_roundf.c,v 1.4 2005/12/02 13:45:06 bde Exp $"); + +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +roundf(float x) +{ + float t; + + if (!isfinite(x)) + return (x); + + if (x >= 0.0) { + t = floorf(x); + if (t - x <= -0.5) + t += 1.0; + return (t); + } else { + t = floorf(-x); + if (t + x <= -0.5) + t += 1.0; + return (-t); + } +} diff --git a/src/openlibm/src/s_roundl.c b/src/openlibm/src/s_roundl.c new file mode 100644 index 0000000..dbcd651 --- /dev/null +++ b/src/openlibm/src/s_roundl.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_roundl.c,v 1.2 2005/12/02 13:45:06 bde Exp $"); + +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +roundl(long double x) +{ + long double t; + + if (!isfinite(x)) + return (x); + + if (x >= 0.0) { + t = floorl(x); + if (t - x <= -0.5) + t += 1.0; + return (t); + } else { + t = floorl(-x); + if (t + x <= -0.5) + t += 1.0; + return (-t); + } +} diff --git a/src/openlibm/src/s_scalbln.c b/src/openlibm/src/s_scalbln.c new file mode 100644 index 0000000..8239db5 --- /dev/null +++ b/src/openlibm/src/s_scalbln.c @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2004 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_scalbln.c,v 1.2 2005/03/07 04:57:50 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +scalbln (double x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbn(x, in)); +} + +OLM_DLLEXPORT float +scalblnf (float x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbnf(x, in)); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT long double +scalblnl (long double x, long n) +{ + int in; + + in = (int)n; + if (in != n) { + if (n > 0) + in = INT_MAX; + else + in = INT_MIN; + } + return (scalbnl(x, (int)n)); +} +#endif diff --git a/src/openlibm/src/s_scalbn.c b/src/openlibm/src/s_scalbn.c new file mode 100644 index 0000000..dc3a0cf --- /dev/null +++ b/src/openlibm/src/s_scalbn.c @@ -0,0 +1,66 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * scalbn (double x, int n) + * scalbn(x,n) returns x* 2**n computed by exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +#include "cdefs-compat.h" + +#include +#include + +#include "math_private.h" + +static const double +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ +huge = 1.0e+300, +tiny = 1.0e-300; + +OLM_DLLEXPORT double +scalbn (double x, int n) +{ + int32_t k,hx,lx; + EXTRACT_WORDS(hx,lx,x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx,x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); + return x*twom54; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(scalbn, ldexpl); +openlibm_weak_reference(scalbn, scalbnl); +#endif + +openlibm_strong_reference(scalbn, ldexp); diff --git a/src/openlibm/src/s_scalbnf.c b/src/openlibm/src/s_scalbnf.c new file mode 100644 index 0000000..930ab8f --- /dev/null +++ b/src/openlibm/src/s_scalbnf.c @@ -0,0 +1,57 @@ +/* s_scalbnf.c -- float version of s_scalbn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "cdefs-compat.h" + +#include + +#include "math_private.h" + +static const float +two25 = 3.355443200e+07, /* 0x4c000000 */ +twom25 = 2.9802322388e-08, /* 0x33000000 */ +huge = 1.0e+30, +tiny = 1.0e-30; + +OLM_DLLEXPORT float +scalbnf (float x, int n) +{ + int32_t k,ix; + GET_FLOAT_WORD(ix,x); + k = (ix&0x7f800000)>>23; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((ix&0x7fffffff)==0) return x; /* +-0 */ + x *= two25; + GET_FLOAT_WORD(ix,x); + k = ((ix&0x7f800000)>>23) - 25; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0xff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0xfe) return huge*copysignf(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;} + if (k <= -25) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysignf(huge,x); /*overflow*/ + else return tiny*copysignf(tiny,x); /*underflow*/ + } + k += 25; /* subnormal result */ + SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); + return x*twom25; +} + +openlibm_strong_reference(scalbnf, ldexpf); diff --git a/src/openlibm/src/s_scalbnl.c b/src/openlibm/src/s_scalbnl.c new file mode 100644 index 0000000..7732944 --- /dev/null +++ b/src/openlibm/src/s_scalbnl.c @@ -0,0 +1,70 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * scalbnl (long double x, int n) + * scalbnl(x,n) returns x* 2**n computed by exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +/* + * We assume that a long double has a 15-bit exponent. On systems + * where long double is the same as double, scalbnl() is an alias + * for scalbn(), so we don't use this routine. + */ + +#include "cdefs-compat.h" + +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#if LDBL_MAX_EXP != 0x4000 +#error "Unsupported long double format" +#endif + +static const long double +huge = 0x1p16000L, +tiny = 0x1p-16000L; + +OLM_DLLEXPORT long double +scalbnl (long double x, int n) +{ + union IEEEl2bits u; + int k; + u.e = x; + k = u.bits.exp; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((u.bits.manh|u.bits.manl)==0) return x; /* +-0 */ + u.e *= 0x1p+128; + k = u.bits.exp - 128; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7fff) return x+x; /* NaN or Inf */ + k = k+n; + if (k >= 0x7fff) return huge*copysignl(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {u.bits.exp = k; return u.e;} + if (k <= -128) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 128; /* subnormal result */ + u.bits.exp = k; + return u.e*0x1p-128; +} + +openlibm_strong_reference(scalbnl, ldexpl); diff --git a/src/openlibm/src/s_signbit.c b/src/openlibm/src/s_signbit.c new file mode 100644 index 0000000..87f40f2 --- /dev/null +++ b/src/openlibm/src/s_signbit.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2003 Mike Barcroft + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/msun/src/s_signbit.c,v 1.1 2004/07/19 08:16:10 das Exp $ + */ + +#include + +#include "fpmath.h" +#include "math_private.h" + +OLM_DLLEXPORT int +__signbit(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.sign); +} + +OLM_DLLEXPORT int +__signbitf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.sign); +} + +#ifdef OLM_LONG_DOUBLE +OLM_DLLEXPORT int +__signbitl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + return (u.bits.sign); +} +#endif diff --git a/src/openlibm/src/s_signgam.c b/src/openlibm/src/s_signgam.c new file mode 100644 index 0000000..ad72a73 --- /dev/null +++ b/src/openlibm/src/s_signgam.c @@ -0,0 +1,7 @@ +#include + +#include "math_private.h" + +#ifndef OPENLIBM_ONLY_THREAD_SAFE +int signgam = 0; +#endif diff --git a/src/openlibm/src/s_sin.c b/src/openlibm/src/s_sin.c new file mode 100644 index 0000000..cc0a5c6 --- /dev/null +++ b/src/openlibm/src/s_sin.c @@ -0,0 +1,89 @@ +/* @(#)s_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_sin.c,v 1.13 2011/02/10 07:37:50 das Exp $"); + +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cose function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include +#include + +//#define INLINE_REM_PIO2 +#include "math_private.h" +//#include "e_rem_pio2.c" + +OLM_DLLEXPORT double +sin(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e500000) /* |x| < 2**-26 */ + {if((int)x==0) return x;} /* generate inexact */ + return __kernel_sin(x,z,0); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + switch(n&3) { + case 0: return __kernel_sin(y[0],y[1],1); + case 1: return __kernel_cos(y[0],y[1]); + case 2: return -__kernel_sin(y[0],y[1],1); + default: + return -__kernel_cos(y[0],y[1]); + } + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(sin, sinl); +#endif diff --git a/src/openlibm/src/s_sincos.c b/src/openlibm/src/s_sincos.c new file mode 100644 index 0000000..8628235 --- /dev/null +++ b/src/openlibm/src/s_sincos.c @@ -0,0 +1,159 @@ +/* @(#)s_sincos.c 5.1 13/07/15 */ +/* See openlibm LICENSE.md for full license details. + * + * ==================================================== + * This file is derived from fdlibm: + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * ==================================================== + * Copyright (C) 2013 Elliot Saba. All rights reserved. + * + * Developed at the University of Washington. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + #include "cdefs-compat.h" + +/* sincos(x, s, c) + * Several applications need sine and cosine of the same + * angle x. This function computes both at the same time, + * and stores the results in *sin and *cos. + * + * kernel function: + * __kernel_sin ... sine function on [-pi/4,pi/4] + * __kernel_cos ... cose function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Borrow liberally from s_sin.c and s_cos.c, merging + * efforts where applicable and returning their values in + * appropriate variables, thereby slightly reducing the + * amount of work relative to just calling sin/cos(x) + * separately + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * sincos(+-INF, s, c) is NaN, with signals; + * sincos(NaN, s, c) is that NaN; + */ + +#include +#include + +//#define INLINE_REM_PIO2 +#include "math_private.h" +//#include "e_rem_pio2.c" + +/* Constants used in polynomial approximation of sin/cos */ +static const double +one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10, /* 0x3DE5D93A, 0x5ACFD57C */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +static void +__kernel_sincos( double x, double y, int iy, double * k_s, double * k_c ) +{ + /* Inline calculation of sin/cos, as we can save + some work, and we will always need to calculate + both values, no matter the result of switch */ + double z, w, r, v, hz; + z = x*x; + w = z*z; + + /* cos-specific computation; equivalent to calling + __kernel_cos(x,y) and storing in k_c*/ + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + v = one-hz; + + *k_c = v + (((one-v)-hz) + (z*r-x*y)); + + /* sin-specific computation; equivalent to calling + __kernel_sin(x,y,1) and storing in k_s*/ + r = S2+z*(S3+z*S4) + z*w*(S5+z*S6); + v = z*x; + if(iy == 0) + *k_s = x+v*(S1+z*r); + else + *k_s = x-((z*(half*y-v*r)-y)-v*S1); +} + +OLM_DLLEXPORT void +sincos(double x, double * s, double * c) +{ + double y[2]; + int32_t ix; + + /* Store high word of x in ix */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + /* Check for small x for sin and cos */ + if(ix<0x3e46a09e) { + /* Check for exact zero */ + if( (int)x==0 ) { + *s = x; + *c = 1.0; + return; + } + } + /* Call kernel function with 0 extra */ + __kernel_sincos(x,0.0,0, s, c); + } else if( ix >= 0x7ff00000 ) { + /* sincos(Inf or NaN) is NaN */ + *s = x-x; + *c = x-x; + } + + /*argument reduction needed*/ + else { + double k_c, k_s; + + /* Calculate remainer, then sub out to kernel */ + int32_t n = __ieee754_rem_pio2(x,y); + __kernel_sincos( y[0], y[1], 1, &k_s, &k_c ); + + /* Figure out permutation of sin/cos outputs to true outputs */ + switch(n&3) { + case 0: + *c = k_c; + *s = k_s; + break; + case 1: + *c = -k_s; + *s = k_c; + break; + case 2: + *c = -k_c; + *s = -k_s; + break; + default: + *c = k_s; + *s = -k_c; + break; + } + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(sincos, sincosl); +#endif diff --git a/src/openlibm/src/s_sincosf.c b/src/openlibm/src/s_sincosf.c new file mode 100644 index 0000000..62caaac --- /dev/null +++ b/src/openlibm/src/s_sincosf.c @@ -0,0 +1,172 @@ +/* s_sincosf.c -- float version of s_sincos.c + * + * ==================================================== + * This file is derived from fdlibm: + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * ==================================================== + * Copyright (C) 2013 Elliot Saba + * Developed at the University of Washington + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== +*/ + +#include "cdefs-compat.h" + +#include +#include + +//#define INLINE_KERNEL_COSDF +//#define INLINE_KERNEL_SINDF +//#define INLINE_REM_PIO2F +#include "math_private.h" +//#include "e_rem_pio2f.c" +//#include "k_cosf.c" +//#include "k_sinf.c" + + +/* Constants used in shortcircuits in sincosf */ +static const double +sc1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +sc2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +sc3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +sc4pio2 = 4*M_PI_2, /* 0x401921FB, 0x54442D18 */ + +/* Constants used in polynomial approximation of sin/cos */ +one = 1.0, +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71, /* 0.0000027183114939898219064 */ +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +static void +__kernel_sincosdf( double x, float * s, float * c ) +{ + double r, w, z, v; + z = x*x; + w = z*z; + + /* cos-specific computation; equivalent to calling + __kernel_cos(x,y) and storing in k_c*/ + r = C2+z*C3; + double k_c = ((one+z*C0) + w*C1) + (w*z)*r; + + /* sin-specific computation; equivalent to calling + __kernel_sin(x,y,1) and storing in k_s*/ + r = S3+z*S4; + v = z*x; + double k_s = (x + v*(S1+z*S2)) + v*w*r; + + *c = k_c; + *s = k_s; +} + +OLM_DLLEXPORT void +sincosf(float x, float * s, float * c) { + // Worst approximation of sin and cos NA + *s = x; + *c = x; + + double y; + float k_c, k_s; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) { /* |x| < 2**-12 */ + /* Check if x is exactly zero */ + if(((int)x)==0) { + *s = x; + *c = 1.0f; + return; + } + } + __kernel_sincosdf(x, s, c); + return; + } + /* |x| ~<= 5*pi/4 */ + if (ix<=0x407b53d1) { + /* |x| ~<= 3pi/4 */ + if(ix<=0x4016cbe3) { + if(hx>0) { + __kernel_sincosdf( sc1pio2 - x, c, s ); + } + else { + __kernel_sincosdf( sc1pio2 + x, c, &k_s ); + *s = -k_s; + } + } else { + + if(hx>0) { + __kernel_sincosdf( sc2pio2 - x, s, &k_c ); + *c = -k_c; + } else { + __kernel_sincosdf( -sc2pio2 - x, s, &k_c ); + *c = -k_c; + } + } + return; + } + + /* |x| ~<= 9*pi/4 */ + if(ix<=0x40e231d5) { + /* |x| ~> 7*pi/4 */ + if(ix<=0x40afeddf) { + if(hx>0) { + __kernel_sincosdf( x - sc3pio2, c, &k_s ); + *s = -k_s; + } else { + __kernel_sincosdf( x + sc3pio2, &k_c, s ); + *c = -k_c; + } + } + else { + if( hx > 0 ) { + __kernel_sincosdf( x - sc4pio2, s, c ); + } else { + __kernel_sincosdf( x + sc4pio2, s, c ); + } + } + return; + } + + /* cos(Inf or NaN) is NaN */ + else if(ix>=0x7f800000) { + *c = *s = x-x; + } else { + /* general argument reduction needed */ + n = __ieee754_rem_pio2f(x,&y); + + switch(n&3) { + case 0: + __kernel_sincosdf( y, s, c ); + break; + case 1: + __kernel_sincosdf( -y, c, s ); + break; + case 2: + __kernel_sincosdf( -y, s, &k_c); + *c = -k_c; + break; + default: + __kernel_sincosdf( -y, &k_c, &k_s ); + *c = -k_c; + *s = -k_s; + break; + } + } + +} diff --git a/src/openlibm/src/s_sincosl.c b/src/openlibm/src/s_sincosl.c new file mode 100644 index 0000000..e2d3a34 --- /dev/null +++ b/src/openlibm/src/s_sincosl.c @@ -0,0 +1,31 @@ +/* s_sincosl.c -- long double version of s_sincos.c + * + * Copyright (C) 2013 Elliot Saba + * Developed at the University of Washington + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== +*/ + +#include "cdefs-compat.h" + +#include +#include + +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT void +sincosl( long double x, long double * s, long double * c ) +{ + *s = sinl( x ); + *c = cosl( x ); +} diff --git a/src/openlibm/src/s_sinf.c b/src/openlibm/src/s_sinf.c new file mode 100644 index 0000000..d987369 --- /dev/null +++ b/src/openlibm/src/s_sinf.c @@ -0,0 +1,85 @@ +/* s_sinf.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_sinf.c,v 1.17 2008/02/25 22:19:17 bde Exp $"); + +#include +#include + +//#define INLINE_KERNEL_COSDF +//#define INLINE_KERNEL_SINDF +//#define INLINE_REM_PIO2F +#include "math_private.h" +//#include "e_rem_pio2f.c" +//#include "k_cosf.c" +//#include "k_sinf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +OLM_DLLEXPORT float +sinf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_sindf(x); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix<=0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if(hx>0) + return __kernel_cosdf(x - s1pio2); + else + return -__kernel_cosdf(x + s1pio2); + } else + return __kernel_sindf((hx > 0 ? s2pio2 : -s2pio2) - x); + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix<=0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if(hx>0) + return -__kernel_cosdf(x - s3pio2); + else + return __kernel_cosdf(x + s3pio2); + } else + return __kernel_sindf(x + (hx > 0 ? -s4pio2 : s4pio2)); + } + + /* sin(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + switch(n&3) { + case 0: return __kernel_sindf(y); + case 1: return __kernel_cosdf(y); + case 2: return __kernel_sindf(-y); + default: + return -__kernel_cosdf(y); + } + } +} diff --git a/src/openlibm/src/s_sinl.c b/src/openlibm/src/s_sinl.c new file mode 100644 index 0000000..7304fc7 --- /dev/null +++ b/src/openlibm/src/s_sinl.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_sinl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $"); + +#include +#include + +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT long double +sinl(long double x) +{ + union IEEEl2bits z; + int e0, s; + long double y[2]; + long double hi, lo; + + z.e = x; + s = z.bits.sign; + z.bits.sign = 0; + + /* If x = +-0 or x is a subnormal number, then sin(x) = x */ + if (z.bits.exp == 0) + return (x); + + /* If x = NaN or Inf, then sin(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) { + hi = __kernel_sinl(z.e, 0, 0); + return (s ? -hi : hi); + } + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + hi = __kernel_sinl(hi, lo, 1); + break; + case 1: + hi = __kernel_cosl(hi, lo); + break; + case 2: + hi = - __kernel_sinl(hi, lo, 1); + break; + case 3: + hi = - __kernel_cosl(hi, lo); + break; + } + + return (hi); +} diff --git a/src/openlibm/src/s_tan.c b/src/openlibm/src/s_tan.c new file mode 100644 index 0000000..2b234a2 --- /dev/null +++ b/src/openlibm/src/s_tan.c @@ -0,0 +1,83 @@ +/* @(#)s_tan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tan.c,v 1.13 2011/02/10 07:37:50 das Exp $"); + +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __kernel_tan ... tangent function on [-pi/4,pi/4] + * __ieee754_rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include +#include + +//#define INLINE_REM_PIO2 +#include "math_private.h" +//#include "e_rem_pio2.c" + +OLM_DLLEXPORT double +tan(double x) +{ + double y[2],z=0.0; + int32_t n, ix; + + /* High word of x. */ + GET_HIGH_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3fe921fb) { + if(ix<0x3e400000) /* x < 2**-27 */ + if((int)x==0) return x; /* generate inexact */ + return __kernel_tan(x,z,1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7ff00000) return x-x; /* NaN */ + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2(x,y); + return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even + -1 -- n odd */ + } +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(tan, tanl); +#endif diff --git a/src/openlibm/src/s_tanf.c b/src/openlibm/src/s_tanf.c new file mode 100644 index 0000000..7ffe193 --- /dev/null +++ b/src/openlibm/src/s_tanf.c @@ -0,0 +1,72 @@ +/* s_tanf.c -- float version of s_tan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanf.c,v 1.17 2008/02/25 22:19:17 bde Exp $"); + +#include +#include + +//#define INLINE_KERNEL_TANDF +//#define INLINE_REM_PIO2F +#include "math_private.h" +//#include "e_rem_pio2f.c" +//#include "k_tanf.c" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +OLM_DLLEXPORT float +tanf(float x) +{ + double y; + int32_t n, hx, ix; + + GET_FLOAT_WORD(hx,x); + ix = hx & 0x7fffffff; + + if(ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if(ix<0x39800000) /* |x| < 2**-12 */ + if(((int)x)==0) return x; /* x with inexact if x != 0 */ + return __kernel_tandf(x,1); + } + if(ix<=0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if(ix<=0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t1pio2 : t1pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t2pio2 : t2pio2), 1); + } + if(ix<=0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if(ix<=0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __kernel_tandf(x + (hx>0 ? -t3pio2 : t3pio2), -1); + else + return __kernel_tandf(x + (hx>0 ? -t4pio2 : t4pio2), 1); + } + + /* tan(Inf or NaN) is NaN */ + else if (ix>=0x7f800000) return x-x; + + /* general argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,&y); + /* integer parameter: 1 -- n even; -1 -- n odd */ + return __kernel_tandf(y,1-((n&1)<<1)); + } +} diff --git a/src/openlibm/src/s_tanh.c b/src/openlibm/src/s_tanh.c new file mode 100644 index 0000000..1fa734d --- /dev/null +++ b/src/openlibm/src/s_tanh.c @@ -0,0 +1,83 @@ +/* @(#)s_tanh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanh.c,v 1.9 2008/02/22 02:30:36 das Exp $"); + +/* Tanh(x) + * Return the Hyperbolic Tangent of x + * + * Method : + * x -x + * e - e + * 0. tanh(x) is defined to be ----------- + * x -x + * e + e + * 1. reduce x to non-negative by tanh(-x) = -tanh(x). + * 2. 0 <= x < 2**-28 : tanh(x) := x with inexact if x != 0 + * -t + * 2**-28 <= x < 1 : tanh(x) := -----; t = expm1(-2x) + * t + 2 + * 2 + * 1 <= x < 22 : tanh(x) := 1 - -----; t = expm1(2x) + * t + 2 + * 22 <= x <= INF : tanh(x) := 1. + * + * Special cases: + * tanh(NaN) is NaN; + * only tanh(0)=0 is exact for finite argument. + */ + +#include +#include + +#include "math_private.h" + +static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300; + +OLM_DLLEXPORT double +tanh(double x) +{ + double t,z; + int32_t jx,ix; + + GET_HIGH_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7ff00000) { + if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ + else return one/x-one; /* tanh(NaN) = NaN */ + } + + /* |x| < 22 */ + if (ix < 0x40360000) { /* |x|<22 */ + if (ix<0x3e300000) { /* |x|<2**-28 */ + if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ + } + if (ix>=0x3ff00000) { /* |x|>=1 */ + t = expm1(two*fabs(x)); + z = one - two/(t+two); + } else { + t = expm1(-two*fabs(x)); + z= -t/(t+two); + } + /* |x| >= 22, return +-1 */ + } else { + z = one - tiny; /* raise inexact flag */ + } + return (jx>=0)? z: -z; +} + +#if (LDBL_MANT_DIG == 53) +openlibm_weak_reference(tanh, tanhl); +#endif diff --git a/src/openlibm/src/s_tanhf.c b/src/openlibm/src/s_tanhf.c new file mode 100644 index 0000000..cd77e4e --- /dev/null +++ b/src/openlibm/src/s_tanhf.c @@ -0,0 +1,56 @@ +/* s_tanhf.c -- float version of s_tanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanhf.c,v 1.9 2008/02/22 02:30:36 das Exp $"); + +#include + +#include "math_private.h" + +static const float one=1.0, two=2.0, tiny = 1.0e-30, huge = 1.0e30; +OLM_DLLEXPORT float +tanhf(float x) +{ + float t,z; + int32_t jx,ix; + + GET_FLOAT_WORD(jx,x); + ix = jx&0x7fffffff; + + /* x is INF or NaN */ + if(ix>=0x7f800000) { + if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */ + else return one/x-one; /* tanh(NaN) = NaN */ + } + + /* |x| < 9 */ + if (ix < 0x41100000) { /* |x|<9 */ + if (ix<0x39800000) { /* |x|<2**-12 */ + if(huge+x>one) return x; /* tanh(tiny) = tiny with inexact */ + } + if (ix>=0x3f800000) { /* |x|>=1 */ + t = expm1f(two*fabsf(x)); + z = one - two/(t+two); + } else { + t = expm1f(-two*fabsf(x)); + z= -t/(t+two); + } + /* |x| >= 9, return +-1 */ + } else { + z = one - tiny; /* raise inexact flag */ + } + return (jx>=0)? z: -z; +} diff --git a/src/openlibm/src/s_tanl.c b/src/openlibm/src/s_tanl.c new file mode 100644 index 0000000..0370e6b --- /dev/null +++ b/src/openlibm/src/s_tanl.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2007 Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tanl.c,v 1.3 2011/05/30 19:41:28 kargl Exp $"); + +/* + * Limited testing on pseudorandom numbers drawn within [0:4e8] shows + * an accuracy of <= 1.5 ULP where 247024 values of x out of 40 million + * possibles resulted in tan(x) that exceeded 0.5 ULP (ie., 0.6%). + */ + +#include +#include + +#include "math_private.h" +#if LDBL_MANT_DIG == 64 +#include "../ld80/e_rem_pio2l.h" +#elif LDBL_MANT_DIG == 113 +#include "../ld128/e_rem_pio2l.h" +#else +#error "Unsupported long double format" +#endif + +OLM_DLLEXPORT long double +tanl(long double x) +{ + union IEEEl2bits z; + int e0, s; + long double y[2]; + long double hi, lo; + + z.e = x; + s = z.bits.sign; + z.bits.sign = 0; + + /* If x = +-0 or x is subnormal, then tan(x) = x. */ + if (z.bits.exp == 0) + return (x); + + /* If x = NaN or Inf, then tan(x) = NaN. */ + if (z.bits.exp == 32767) + return ((x - x) / (x - x)); + + /* Optimize the case where x is already within range. */ + if (z.e < M_PI_4) { + hi = __kernel_tanl(z.e, 0, 0); + return (s ? -hi : hi); + } + + e0 = __ieee754_rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + + switch (e0 & 3) { + case 0: + case 2: + hi = __kernel_tanl(hi, lo, 0); + break; + case 1: + case 3: + hi = __kernel_tanl(hi, lo, 1); + break; + } + + return (hi); +} diff --git a/src/openlibm/src/s_tgammaf.c b/src/openlibm/src/s_tgammaf.c new file mode 100644 index 0000000..fbfa3fe --- /dev/null +++ b/src/openlibm/src/s_tgammaf.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_tgammaf.c,v 1.1 2008/02/18 17:27:10 das Exp $"); + +#include + +#include "math_private.h" + +/* + * We simply call tgamma() rather than bloating the math library with + * a float-optimized version of it. The reason is that tgammaf() is + * essentially useless, since the function is superexponential and + * floats have very limited range. + */ +OLM_DLLEXPORT float +tgammaf(float x) +{ + + return (tgamma(x)); +} diff --git a/src/openlibm/src/s_trunc.c b/src/openlibm/src/s_trunc.c new file mode 100644 index 0000000..c460cc9 --- /dev/null +++ b/src/openlibm/src/s_trunc.c @@ -0,0 +1,67 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_trunc.c,v 1.4 2008/02/22 02:27:34 das Exp $"); + +/* + * trunc(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to trunc(x). + */ + +#include +#include + +#include "math_private.h" + +static const double huge = 1.0e300; + +OLM_DLLEXPORT double +trunc(double x) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; + if(j0<20) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */ + i0 &= 0x80000000U; + i1 = 0; + } + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) return x; /* x is integral */ + if(huge+x>0.0) { /* raise inexact flag */ + i0 &= (~i); i1=0; + } + } + } else if (j0>51) { + if(j0==0x400) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } else { + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) return x; /* x is integral */ + if(huge+x>0.0) /* raise inexact flag */ + i1 &= (~i); + } + INSERT_WORDS(x,i0,i1); + return x; +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(trunc, truncl); +#endif diff --git a/src/openlibm/src/s_truncf.c b/src/openlibm/src/s_truncf.c new file mode 100644 index 0000000..d9fc62e --- /dev/null +++ b/src/openlibm/src/s_truncf.c @@ -0,0 +1,54 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_truncf.c,v 1.1 2004/06/20 09:25:43 das Exp $"); + +/* + * truncf(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncf(x). + */ + +#include + +#include "math_private.h" + +static const float huge = 1.0e30F; + +OLM_DLLEXPORT float +truncf(float x) +{ + int32_t i0,j0; + u_int32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>0.0F) /* |x|<1, so return 0*sign(x) */ + i0 &= 0x80000000; + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>0.0F) /* raise inexact flag */ + i0 &= (~i); + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} diff --git a/src/openlibm/src/s_truncl.c b/src/openlibm/src/s_truncl.c new file mode 100644 index 0000000..34d7b65 --- /dev/null +++ b/src/openlibm/src/s_truncl.c @@ -0,0 +1,69 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * From: @(#)s_floor.c 5.1 93/09/24 + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/s_truncl.c,v 1.9 2008/02/14 15:10:34 bde Exp $"); + +/* + * truncl(x) + * Return x rounded toward 0 to integral value + * Method: + * Bit twiddling. + * Exception: + * Inexact flag raised if x not equal to truncl(x). + */ + +#include +#include +#include + +#include "fpmath.h" +#include "math_private.h" + +#ifdef LDBL_IMPLICIT_NBIT +#define MANH_SIZE (LDBL_MANH_SIZE + 1) +#else +#define MANH_SIZE LDBL_MANH_SIZE +#endif + +static const long double huge = 1.0e300; +static const float zero[] = { 0.0, -0.0 }; + +OLM_DLLEXPORT long double +truncl(long double x) +{ + union IEEEl2bits u = { .e = x }; + int e = u.bits.exp - LDBL_MAX_EXP + 1; + + if (e < MANH_SIZE - 1) { + if (e < 0) { /* raise inexact if x != 0 */ + if (huge + x > 0.0) + u.e = zero[u.bits.sign]; + } else { + uint64_t m = ((1llu << MANH_SIZE) - 1) >> (e + 1); + if (((u.bits.manh & m) | u.bits.manl) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) { /* raise inexact flag */ + u.bits.manh &= ~m; + u.bits.manl = 0; + } + } + } else if (e < LDBL_MANT_DIG - 1) { + uint64_t m = (uint64_t)-1 >> (64 - LDBL_MANT_DIG + e + 1); + if ((u.bits.manl & m) == 0) + return (x); /* x is integral */ + if (huge + x > 0.0) /* raise inexact flag */ + u.bits.manl &= ~m; + } + return (u.e); +} diff --git a/src/openlibm/src/types-compat.h b/src/openlibm/src/types-compat.h new file mode 100644 index 0000000..b20b5ae --- /dev/null +++ b/src/openlibm/src/types-compat.h @@ -0,0 +1,13 @@ +#ifndef _TYPES_COMPAT_H_ +#define _TYPES_COMPAT_H_ + +#include +#include + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + + +#endif diff --git a/src/openlibm/src/w_cabs.c b/src/openlibm/src/w_cabs.c new file mode 100644 index 0000000..6dc9bde --- /dev/null +++ b/src/openlibm/src/w_cabs.c @@ -0,0 +1,25 @@ +/* + * cabs() wrapper for hypot(). + * + * Written by J.T. Conklin, + * Placed into the Public Domain, 1994. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/w_cabs.c,v 1.7 2008/03/30 20:03:06 das Exp $"); + +#include +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT double +cabs(double complex z) +{ + return hypot(creal(z), cimag(z)); +} + +#if LDBL_MANT_DIG == 53 +openlibm_weak_reference(cabs, cabsl); +#endif diff --git a/src/openlibm/src/w_cabsf.c b/src/openlibm/src/w_cabsf.c new file mode 100644 index 0000000..f14c71a --- /dev/null +++ b/src/openlibm/src/w_cabsf.c @@ -0,0 +1,19 @@ +/* + * cabsf() wrapper for hypotf(). + * + * Written by J.T. Conklin, + * Placed into the Public Domain, 1994. + */ + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT float +cabsf(z) + float complex z; +{ + + return hypotf(crealf(z), cimagf(z)); +} diff --git a/src/openlibm/src/w_cabsl.c b/src/openlibm/src/w_cabsl.c new file mode 100644 index 0000000..c10f1d4 --- /dev/null +++ b/src/openlibm/src/w_cabsl.c @@ -0,0 +1,22 @@ +/* + * cabs() wrapper for hypot(). + * + * Written by J.T. Conklin, + * Placed into the Public Domain, 1994. + * + * Modified by Steven G. Kargl for the long double type. + */ + +#include "cdefs-compat.h" +//__FBSDID("$FreeBSD: src/lib/msun/src/w_cabsl.c,v 1.1 2008/03/30 20:02:03 das Exp $"); + +#include +#include + +#include "math_private.h" + +OLM_DLLEXPORT long double +cabsl(long double complex z) +{ + return hypotl(creall(z), cimagl(z)); +} diff --git a/src/openlibm/test/.gitignore b/src/openlibm/test/.gitignore new file mode 100644 index 0000000..2d85b23 --- /dev/null +++ b/src/openlibm/test/.gitignore @@ -0,0 +1,9 @@ +/test-float +/test-float-system +/test-float.dSYM +/test-double +/test-double-system +/test-double.dSYM +/bench-openlibm +/bench-syslibm +/*.exe diff --git a/src/openlibm/test/Makefile b/src/openlibm/test/Makefile new file mode 100644 index 0000000..a61ce5a --- /dev/null +++ b/src/openlibm/test/Makefile @@ -0,0 +1,37 @@ +OPENLIBM_HOME=$(abspath ..) +include ../Make.inc + +# Set rpath of tests to builddir for loading shared library +OPENLIBM_LIB = -L.. -lopenlibm +ifneq ($(OS),WINNT) +ifneq ($(OS),Darwin) +OPENLIBM_LIB += -Wl,-rpath=$(OPENLIBM_HOME) +endif +else # WINNT +CFLAGS_add += -DIMPORT_EXPORTS +endif + +all: test-double test-float # test-double-system test-float-system + +bench: bench-syslibm bench-openlibm + +test-double: test-double.c libm-test.c libm-test-ulps.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $@.c -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -o $@ + +test-float: test-float.c libm-test.c libm-test-ulps.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $@.c -D__BSD_VISIBLE -I ../include -I../src $(OPENLIBM_LIB) -o $@ + +test-double-system: test-double.c libm-test.c libm-test-ulps.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -DSYS_MATH_H -lm -o $@ + +test-float-system: test-float.c libm-test.c libm-test-ulps.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -DSYS_MATH_H -lm -o $@ + +bench-openlibm: libm-bench.cpp + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< $(OPENLIBM_LIB) -o $@ + +bench-syslibm: libm-bench.cpp + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_add) $(LDFLAGS) $(LDFLAGS_arch) $< -lm -o $@ + +clean: + rm -fr test-double test-float test-double-system test-float-system bench-openlibm bench-syslibm *.dSYM diff --git a/src/openlibm/test/inf_torture.c b/src/openlibm/test/inf_torture.c new file mode 100644 index 0000000..f2b0124 --- /dev/null +++ b/src/openlibm/test/inf_torture.c @@ -0,0 +1,76 @@ +#include +#include + +int main(); +int main2(); +int main3(); +int main4(); + +int main() { + printf("+inf:\n"); + float fx = (float)INFINITY; unsigned int *fxi = (unsigned int*)&fx; + double dx = (double)INFINITY; long unsigned long int *dxi = (long unsigned long int*)&dx; + long double ldx = (long double)INFINITY; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]); + printf("\t\tf d ld\n"); + printf("correct:\t%x %x %x\n", isinf(fx), isinf(dx), isinf(ldx)); + printf("as floats:\t%x %x %x\n", isinf(*(float*)fxi), isinf(*(float*)dxi), isinf(*(float*)ldxi1)); + printf("as double:\t%x %x %x\n", isinf(*(double*)fxi), isinf(*(double*)dxi), isinf(*(double*)ldxi1)); + printf("as long double:\t%x %x %x\n", isinf(*(long double*)fxi), isinf(*(long double*)dxi), isinf(*(long double*)ldxi1)); + printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx)); + printf("sizes:\t%d %d %d\n", (int)sizeof(*fxi), (int)sizeof(*dxi), (int)sizeof(*ldxi1)*2); + printf("bit repr:\n f: %x\n d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1); + printf("\n"); + main2(); + return 0; +} + +int main2() { + printf("-inf:\n"); + float fx = (float)-INFINITY; unsigned int *fxi = (unsigned int*)&fx; + double dx = (double)-INFINITY; long unsigned long int *dxi = (long unsigned long int*)&dx; + long double ldx = (long double)-INFINITY; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]); + printf("\t\tf d ld\n"); + printf("correct:\t%x %x %x\n", isinf(fx), isinf(dx), isinf(ldx)); + printf("as floats:\t%x %x %x\n", isinf(*(float*)fxi), isinf(*(float*)dxi), isinf(*(float*)ldxi1)); + printf("as double:\t%x %x %x\n", isinf(*(double*)fxi), isinf(*(double*)dxi), isinf(*(double*)ldxi1)); + printf("as long double:\t%x %x %x\n", isinf(*(long double*)fxi), isinf(*(long double*)dxi), isinf(*(long double*)ldxi1)); + printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx)); + printf("bit repr:\n f: %x\n d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1); + printf("\n"); + main3(); + return 0; +} + +int main3() { + printf("+NaN:\n"); + float fx = (float)NAN; unsigned int *fxi = (unsigned int*)&fx; + double dx = (double)NAN; long unsigned long int *dxi = (long unsigned long int*)&dx; + long double ldx = (long double)NAN; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]); + printf("\t\tf d ld\n"); + printf("correct:\t%x %x %x\n", isnan(fx), isnan(dx), isnan(ldx)); + printf("as floats:\t%x %x %x\n", isnan(*(float*)fxi), isnan(*(float*)dxi), isnan(*(float*)ldxi1)); + printf("as double:\t%x %x %x\n", isnan(*(double*)fxi), isnan(*(double*)dxi), isnan(*(double*)ldxi1)); + printf("as long double:\t%x %x %x\n", isnan(*(long double*)fxi), isnan(*(long double*)dxi), isnan(*(long double*)ldxi1)); + printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx)); + printf("sizes:\t%d %d %d\n", (int)sizeof(*fxi), (int)sizeof(*dxi), (int)sizeof(*ldxi1)*2); + printf("bit repr:\n f: %x\n d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1); + printf("\n"); + main4(); + return 0; +} + +int main4() { + printf("-NaN:\n"); + float fx = (float)-NAN; unsigned int *fxi = (unsigned int*)&fx; + double dx = (double)-NAN; long unsigned long int *dxi = (long unsigned long int*)&dx; + long double ldx = (long double)-NAN; long unsigned long int *ldxi1 = (long unsigned long int*)&ldx; long unsigned long int *ldxi2 = &(ldxi1[1]); + printf("\t\tf d ld\n"); + printf("correct:\t%x %x %x\n", isnan(fx), isnan(dx), isnan(ldx)); + printf("as floats:\t%x %x %x\n", isnan(*(float*)fxi), isnan(*(float*)dxi), isnan(*(float*)ldxi1)); + printf("as double:\t%x %x %x\n", isnan(*(double*)fxi), isnan(*(double*)dxi), isnan(*(double*)ldxi1)); + printf("as long double:\t%x %x %x\n", isnan(*(long double*)fxi), isnan(*(long double*)dxi), isnan(*(long double*)ldxi1)); + printf("sizes ?4 8 12?:\t%d %d %d\n", (int)sizeof(fx), (int)sizeof(dx), (int)sizeof(ldx)); + printf("bit repr:\n f: %x\n d: %llx\n ld: %llx%llx\n", *fxi, *dxi, (0xFFFF)&*ldxi2, *ldxi1); + printf("\n"); + return 0; +} diff --git a/src/openlibm/test/libm-bench.cpp b/src/openlibm/test/libm-bench.cpp new file mode 100644 index 0000000..04876de --- /dev/null +++ b/src/openlibm/test/libm-bench.cpp @@ -0,0 +1,144 @@ +// Copyright (C) Dahua Lin, 2014. Provided under the MIT license. + +// Benchmark on libm functions + +#include +#include +#include +#include + + +// Timing facilities + +#ifdef __MACH__ + +#include + +class stimer +{ +public: + typedef uint64_t time_type; + + stimer() + { + ::mach_timebase_info(&m_baseinfo); + } + + time_type current() const + { + return ::mach_absolute_time(); + } + + double span(const time_type& t0, const time_type& t1) const + { + uint64_t d = (m_baseinfo.numer * (t1 - t0)) / m_baseinfo.denom; + return static_cast(d) / 1.0e9; + } + +private: + mach_timebase_info_data_t m_baseinfo; +}; + +#else + +class stimer +{ +public: + typedef timespec time_type; + + time_type current() const + { + time_type t; + ::clock_gettime(CLOCK_REALTIME, &t); + return t; + } + + double span(const time_type& t0, const time_type& t1) const + { + return double(t1.tv_sec - t0.tv_sec) + + double(t1.tv_nsec - t0.tv_nsec) * 1.0e-9; + } +}; + +#endif + + +inline double sec2mps(double s, long n) +{ + return n / (s * 1e6); +} + + +const long ARR_LEN = 1024; + +double a[ARR_LEN]; +double b[ARR_LEN]; +double r[ARR_LEN]; + +#define TFUN1(FNAME) \ + void test_##FNAME(long n) { \ + for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j]); \ + stimer tm; \ + stimer::time_type t0 = tm.current(); \ + for(int i = 0; i < n; ++i) { \ + for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j]); \ + } \ + double s = tm.span(t0, tm.current()); \ + double mps = sec2mps(s, n * ARR_LEN); \ + printf(" %-8s: %7.4f MPS\n", #FNAME, mps); } + +#define TFUN2(FNAME) \ + void test_##FNAME(long n) { \ + for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j], b[j]); \ + stimer tm; \ + stimer::time_type t0 = tm.current(); \ + for(int i = 0; i < n; ++i) { \ + for (int j = 0; j < ARR_LEN; ++j) r[j] = FNAME(a[j], b[j]); \ + } \ + double s = tm.span(t0, tm.current()); \ + double mps = sec2mps(s, n * ARR_LEN); \ + printf(" %-8s: %7.4f MPS\n", #FNAME, mps); } + + +#define TCALL(FNAME) test_##FNAME(20000) + +// define benchmark functions + +TFUN2(pow) +TFUN2(hypot) + +TFUN1(exp) +TFUN1(log) +TFUN1(log10) +TFUN1(sin) +TFUN1(cos) +TFUN1(tan) +TFUN1(asin) +TFUN1(acos) +TFUN1(atan) +TFUN2(atan2) + +int main(int argc, char *argv[]) +{ + // initialize array contents + for (int i = 0; i < ARR_LEN; ++i) + { + a[i] = rand() / (double) RAND_MAX; + b[i] = rand() / (double) RAND_MAX; + } + + TCALL(pow); + TCALL(hypot); + TCALL(exp); + TCALL(log); + TCALL(log10); + TCALL(sin); + TCALL(cos); + TCALL(tan); + TCALL(asin); + TCALL(acos); + TCALL(atan); + TCALL(atan2); + + return 0; +} diff --git a/src/openlibm/test/libm-test-ulps.h b/src/openlibm/test/libm-test-ulps.h new file mode 100644 index 0000000..67a415c --- /dev/null +++ b/src/openlibm/test/libm-test-ulps.h @@ -0,0 +1,254 @@ +/* This file is automatically generated + from libm-test-ulps with gen-libm-test.pl. + Don't change it - change instead the master files. */ + + +/* Maximal error of functions. */ +#define DELTAacos CHOOSE(1150, 1, 1, 1150, 0, 0) /* acos */ +#define DELTAacosh CHOOSE(1, 0, 0, 1, 0, 0) /* acosh */ +#define DELTAasin CHOOSE(1, 1, 0, 1, 0, 0) /* asin */ +#define DELTAasinh CHOOSE(656, 0, 0, 656, 0, 0) /* asinh */ +#define DELTAatan CHOOSE(549, 0, 0, 549, 0, 0) /* atan */ +#define DELTAatanh CHOOSE(1605, 1, 0, 1605, 1, 0) /* atanh */ +#define DELTAatan2 CHOOSE(549, 0, 0, 549, 0, 0) /* atan2 */ +#define DELTAcabs CHOOSE(560, 1, 1, 560, 1, 1) /* cabs */ +#define DELTAcacos CHOOSE(BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2), BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2)) /* cacos */ +#define DELTAcacosh CHOOSE(BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4), BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4)) /* cacosh */ +#define DELTAcasin CHOOSE(BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2), BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2)) /* casin */ +#define DELTAcasinh CHOOSE(BUILD_COMPLEX (892, 12), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6), BUILD_COMPLEX (892, 12), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6)) /* casinh */ +#define DELTAcatan CHOOSE(BUILD_COMPLEX (251, 474), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (251, 474), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* catan */ +#define DELTAcatanh CHOOSE(BUILD_COMPLEX (66, 447), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (66, 447), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0)) /* catanh */ +#define DELTAcbrt CHOOSE(716, 1, 0, 716, 1, 0) /* cbrt */ +#define DELTAccos CHOOSE(BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1)) /* ccos */ +#define DELTAccosh CHOOSE(BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1)) /* ccosh */ +#define DELTAcexp CHOOSE(BUILD_COMPLEX (940, 1067), 0, BUILD_COMPLEX (1, 0), BUILD_COMPLEX (940, 1067), 0, BUILD_COMPLEX (1, 0)) /* cexp */ +#define DELTAclog CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0) /* clog */ +#define DELTAclog10 CHOOSE(BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 1)) /* clog10 */ +#define DELTAcos CHOOSE(529, 2, 1, 529, 2, 1) /* cos */ +#define DELTAcosh CHOOSE(309, 0, 0, 309, 0, 0) /* cosh */ +#define DELTAcpow CHOOSE(BUILD_COMPLEX (2, 9), BUILD_COMPLEX (1, 1.104), BUILD_COMPLEX (4, 2.5333), BUILD_COMPLEX (2, 9), BUILD_COMPLEX (1, 1.104), BUILD_COMPLEX (4, 2.5333)) /* cpow */ +#define DELTAcsin CHOOSE(BUILD_COMPLEX (966, 168), 0, 0, BUILD_COMPLEX (966, 168), 0, 0) /* csin */ +#define DELTAcsinh CHOOSE(BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1)) /* csinh */ +#define DELTAcsqrt CHOOSE(BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0) /* csqrt */ +#define DELTActan CHOOSE(BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 1)) /* ctan */ +#define DELTActanh CHOOSE(BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 1)) /* ctanh */ +#define DELTAerfc CHOOSE(36, 24, 12, 36, 24, 12) /* erfc */ +#define DELTAexp CHOOSE(754, 0, 0, 754, 0, 0) /* exp */ +#define DELTAexp10 CHOOSE(1182, 1, 0, 1182, 1, 0) /* exp10 */ +#define DELTAexp2 CHOOSE(462, 0, 0, 462, 0, 0) /* exp2 */ +#define DELTAexpm1 CHOOSE(825, 1, 1, 825, 0, 0) /* expm1 */ +#define DELTAfmod CHOOSE(4096, 2, 1, 4096, 2, 1) /* fmod */ +#define DELTAgamma CHOOSE(1, 1, 0, 1, 1, 0) /* gamma */ +#define DELTAhypot CHOOSE(560, 1, 1, 560, 0, 0) /* hypot */ +#define DELTAj0 CHOOSE(0, 2, 2, 0, 2, 1) /* j0 */ +#define DELTAj1 CHOOSE(2, 2, 2, 2, 2, 1) /* j1 */ +#define DELTAjn CHOOSE(2, 6, 4, 2, 5, 2) /* jn */ +#define DELTAlgamma CHOOSE(1, 1, 2, 1, 1, 2) /* lgamma */ +#define DELTAlog CHOOSE(2341, 1, 1, 2341, 1, 1) /* log */ +#define DELTAlog10 CHOOSE(2033, 1, 1, 2033, 1, 1) /* log10 */ +#define DELTAlog1p CHOOSE(585, 1, 1, 585, 1, 1) /* log1p */ +#define DELTAlog2 CHOOSE(1688, 1, 1, 1688, 1, 1) /* log2 */ +#define DELTApow CHOOSE(725, 0, 0, 725, 0, 0) /* pow */ +#define DELTAsin CHOOSE(627, 0, 0, 627, 0, 0) /* sin */ +#define DELTAsincos CHOOSE(627, 1, 1, 627, 1, 1) /* sincos */ +#define DELTAsinh CHOOSE(1029, 1, 1, 1028, 0, 1) /* sinh */ +#define DELTAsqrt CHOOSE(489, 0, 0, 489, 0, 0) /* sqrt */ +#define DELTAtan CHOOSE(1401, 1, 1, 1401, 0.5, 0) /* tan */ +#define DELTAtanh CHOOSE(521, 1, 1, 521, 0, 0) /* tanh */ +#define DELTAtgamma CHOOSE(2, 2, 1, 2, 2, 1) /* tgamma */ +#define DELTAy0 CHOOSE(2, 3, 1, 2, 3, 1) /* y0 */ +#define DELTAy1 CHOOSE(2, 3, 2, 2, 3, 2) /* y1 */ +#define DELTAyn CHOOSE(7, 6, 3, 7, 6, 3) /* yn */ + +/* Error of single function calls. */ +#define DELTA16 CHOOSE(1, 0, 0, 1, 0, 0) /* acosh (7) == 2.633915793849633417250092694615937 */ +#define DELTA24 CHOOSE(1, 1, 0, 1, 0, 0) /* asin (0.5) == pi/6 */ +#define DELTA25 CHOOSE(1, 1, 0, 1, 0, 0) /* asin (-0.5) == -pi/6 */ +#define DELTA26 CHOOSE(1, 0, 0, 1, 0, 0) /* asin (1.0) == pi/2 */ +#define DELTA27 CHOOSE(1, 0, 0, 1, 0, 0) /* asin (-1.0) == -pi/2 */ +#define DELTA28 CHOOSE(1, 1, 0, 1, 0, 0) /* asin (0.7) == 0.77539749661075306374035335271498708 */ +#define DELTA34 CHOOSE(656, 1, 0, 656, 0, 0) /* asinh (0.7) == 0.652666566082355786 */ +#define DELTA42 CHOOSE(549, 0, 0, 549, 0, 0) /* atan (0.7) == 0.61072596438920861654375887649023613 */ +#define DELTA50 CHOOSE(1605, 1, 0, 1605, 1, 0) /* atanh (0.7) == 0.8673005276940531944 */ +#define DELTA74 CHOOSE(549, 0, 0, 549, 0, 0) /* atan2 (0.7, 1) == 0.61072596438920861654375887649023613 */ +#define DELTA78 CHOOSE(1, 0, 0, 1, 0, 0) /* atan2 (0.4, 0.0003) == 1.5700463269355215717704032607580829 */ +#define DELTA85 CHOOSE(0, 0, 1, 0, 0, 1) /* cabs (0.7 + 12.4 i) == 12.419742348374220601176836866763271 */ +#define DELTA86 CHOOSE(0, 0, 1, 0, 0, 1) /* cabs (-12.4 + 0.7 i) == 12.419742348374220601176836866763271 */ +#define DELTA87 CHOOSE(0, 0, 1, 0, 0, 1) /* cabs (-0.7 + 12.4 i) == 12.419742348374220601176836866763271 */ +#define DELTA88 CHOOSE(0, 0, 1, 0, 0, 1) /* cabs (-12.4 - 0.7 i) == 12.419742348374220601176836866763271 */ +#define DELTA89 CHOOSE(0, 0, 1, 0, 0, 1) /* cabs (-0.7 - 12.4 i) == 12.419742348374220601176836866763271 */ +#define DELTA96 CHOOSE(560, 1, 0, 560, 1, 0) /* cabs (0.7 + 1.2 i) == 1.3892443989449804508432547041028554 */ +#define DELTA130 CHOOSE(BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2), BUILD_COMPLEX (151, 329), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 2)) /* cacos (0.7 + 1.2 i) == 1.1351827477151551088992008271819053 - 1.0927647857577371459105272080819308 i */ +#define DELTA131 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0) /* cacos (-2 - 3 i) == 2.1414491111159960199416055713254211 + 1.9833870299165354323470769028940395 i */ +#define DELTA165 CHOOSE(BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (328, 151), BUILD_COMPLEX (1, 0), 0) /* cacosh (0.7 + 1.2 i) == 1.0927647857577371459105272080819308 + 1.1351827477151551088992008271819053 i */ +#define DELTA166 CHOOSE(BUILD_COMPLEX (6, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4), BUILD_COMPLEX (6, 1), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (4, 4)) /* cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i */ +#define DELTA225 CHOOSE(BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2), BUILD_COMPLEX (603, 329), BUILD_COMPLEX (3, 0), BUILD_COMPLEX (2, 2)) /* casin (0.7 + 1.2 i) == 0.4356135790797415103321208644578462 + 1.0927647857577371459105272080819308 i */ +#define DELTA226 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0) /* casin (-2 - 3 i) == -0.57065278432109940071028387968566963 - 1.9833870299165354323470769028940395 i */ +#define DELTA262 CHOOSE(BUILD_COMPLEX (892, 12), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (892, 12), 0, BUILD_COMPLEX (0, 1)) /* casinh (0.7 + 1.2 i) == 0.97865459559367387689317593222160964 + 0.91135418953156011567903546856170941 i */ +#define DELTA263 CHOOSE(BUILD_COMPLEX (6, 6), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6), BUILD_COMPLEX (6, 6), BUILD_COMPLEX (5, 3), BUILD_COMPLEX (1, 6)) /* casinh (-2 - 3 i) == -1.9686379257930962917886650952454982 - 0.96465850440760279204541105949953237 i */ +#define DELTA301 CHOOSE(BUILD_COMPLEX (251, 474), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (251, 474), 0, BUILD_COMPLEX (0, 1)) /* catan (0.7 + 1.2 i) == 1.0785743834118921877443707996386368 + 0.57705737765343067644394541889341712 i */ +#define DELTA302 CHOOSE(BUILD_COMPLEX (0, 7), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 7), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* catan (-2 - 3 i) == -1.4099210495965755225306193844604208 - 0.22907268296853876629588180294200276 i */ +#define DELTA340 CHOOSE(BUILD_COMPLEX (66, 447), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (66, 447), BUILD_COMPLEX (1, 0), 0) /* catanh (0.7 + 1.2 i) == 0.2600749516525135959200648705635915 + 0.97024030779509898497385130162655963 i */ +#define DELTA341 CHOOSE(BUILD_COMPLEX (6, 0), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (6, 0), BUILD_COMPLEX (2, 0), BUILD_COMPLEX (1, 0)) /* catanh (-2 - 3 i) == -0.14694666622552975204743278515471595 - 1.3389725222944935611241935759091443 i */ +#define DELTA347 CHOOSE(716, 0, 0, 716, 0, 0) /* cbrt (-0.001) == -0.1 */ +#define DELTA349 CHOOSE(1, 0, 0, 1, 0, 0) /* cbrt (-27.0) == -3.0 */ +#define DELTA350 CHOOSE(306, 0, 0, 306, 0, 0) /* cbrt (0.970299) == 0.99 */ +#define DELTA351 CHOOSE(346, 1, 0, 346, 1, 0) /* cbrt (0.7) == 0.8879040017426007084 */ +#define DELTA389 CHOOSE(BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (5, 1901), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0)) /* ccos (0.7 + 1.2 i) == 1.3848657645312111080 - 0.97242170335830028619 i */ +#define DELTA390 CHOOSE(BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1)) /* ccos (-2 - 3 i) == -4.1896256909688072301 - 9.1092278937553365979 i */ +#define DELTA428 CHOOSE(BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1467, 1183), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0)) /* ccosh (0.7 + 1.2 i) == 0.4548202223691477654 + 0.7070296600921537682 i */ +#define DELTA429 CHOOSE(BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* ccosh (-2 - 3 i) == -3.7245455049153225654 + 0.5118225699873846088 i */ +#define DELTA469 CHOOSE(BUILD_COMPLEX (940, 0), 0, BUILD_COMPLEX (1, 0), BUILD_COMPLEX (940, 0), 0, BUILD_COMPLEX (1, 0)) /* cexp (0.7 + 1.2 i) == 0.72969890915032360123451688642930727 + 1.8768962328348102821139467908203072 i */ +#define DELTA470 CHOOSE(BUILD_COMPLEX (4, 18), 0, 0, BUILD_COMPLEX (4, 18), 0, 0) /* cexp (-2.0 - 3.0 i) == -0.13398091492954261346140525546115575 - 0.019098516261135196432576240858800925 i */ +#define DELTA515 CHOOSE(BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0, 0) /* clog (-2 - 3 i) == 1.2824746787307683680267437207826593 - 2.1587989303424641704769327722648368 i */ +#define DELTA520 CHOOSE(0, BUILD_COMPLEX (0, 1), 0, 0, BUILD_COMPLEX (0, 1), 0) /* clog10 (-inf + inf i) == inf + 3/4 pi*log10(e) i */ +#define DELTA521 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (inf + inf i) == inf + pi/4*log10(e) i */ +#define DELTA522 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (inf - inf i) == inf - pi/4*log10(e) i */ +#define DELTA523 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (0 + inf i) == inf + pi/2*log10(e) i */ +#define DELTA524 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (3 + inf i) == inf + pi/2*log10(e) i */ +#define DELTA525 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-0 + inf i) == inf + pi/2*log10(e) i */ +#define DELTA526 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-3 + inf i) == inf + pi/2*log10(e) i */ +#define DELTA527 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (0 - inf i) == inf - pi/2*log10(e) i */ +#define DELTA528 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (3 - inf i) == inf - pi/2*log10(e) i */ +#define DELTA529 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-0 - inf i) == inf - pi/2*log10(e) i */ +#define DELTA530 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-3 - inf i) == inf - pi/2*log10(e) i */ +#define DELTA531 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-inf + 0 i) == inf + pi*log10(e) i */ +#define DELTA532 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-inf + 1 i) == inf + pi*log10(e) i */ +#define DELTA533 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-inf - 0 i) == inf - pi*log10(e) i */ +#define DELTA534 CHOOSE(0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1)) /* clog10 (-inf - 1 i) == inf - pi*log10(e) i */ +#define DELTA552 CHOOSE(BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1403, 186), BUILD_COMPLEX (2, 1), BUILD_COMPLEX (1, 0)) /* clog10 (0.7 + 1.2 i) == 0.1427786545038868803 + 0.4528483579352493248 i */ +#define DELTA553 CHOOSE(BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 1), 0) /* clog10 (-2 - 3 i) == 0.5569716761534183846 - 0.9375544629863747085 i */ +#define DELTA582 CHOOSE(0, 1, 0.5, 0, 1, 0.5) /* cos (M_PI_6l * 2.0) == 0.5 */ +#define DELTA583 CHOOSE(0.5, 2, 1, 0.5, 2, 1) /* cos (M_PI_6l * 4.0) == -0.5 */ +#define DELTA584 CHOOSE(0.25, 0.2758, 0.3667, 0.25, 0.2758, 0.3667) /* cos (pi/2) == 0 */ +#define DELTA585 CHOOSE(529, 1, 0, 529, 1, 0) /* cos (0.7) == 0.76484218728448842625585999019186495 */ +#define DELTA591 CHOOSE(309, 0, 0, 309, 0, 0) /* cosh (0.7) == 1.255169005630943018 */ +#define DELTA594 CHOOSE(BUILD_COMPLEX (0, 9), BUILD_COMPLEX (0, 1.104), BUILD_COMPLEX (0, 2.5333), BUILD_COMPLEX (0, 9), BUILD_COMPLEX (0, 1.104), BUILD_COMPLEX (0, 2.5333)) /* cpow (e + 0 i, 0 + 2 * M_PIl i) == 1.0 + 0.0 i */ +#define DELTA595 CHOOSE(BUILD_COMPLEX (2, 5), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (4, 1), BUILD_COMPLEX (2, 5), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (4, 1)) /* cpow (2 + 3 i, 4 + 0 i) == -119.0 - 120.0 i */ +#define DELTA652 CHOOSE(BUILD_COMPLEX (966, 168), 0, 0, BUILD_COMPLEX (966, 168), 0, 0) /* csin (0.7 + 1.2 i) == 1.1664563419657581376 + 1.1544997246948547371 i */ +#define DELTA691 CHOOSE(BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (413, 477), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (1, 0)) /* csinh (0.7 + 1.2 i) == 0.27487868678117583582 + 1.1698665727426565139 i */ +#define DELTA692 CHOOSE(BUILD_COMPLEX (0, 2), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (0, 2), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (0, 1)) /* csinh (-2 - 3 i) == 3.5905645899857799520 - 0.5309210862485198052 i */ +#define DELTA732 CHOOSE(BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0, BUILD_COMPLEX (237, 128), BUILD_COMPLEX (1, 0), 0) /* csqrt (0.7 + 1.2 i) == 1.022067610030026450706487883081139 + 0.58704531296356521154977678719838035 i */ +#define DELTA733 CHOOSE(BUILD_COMPLEX (1, 0), 0, 0, BUILD_COMPLEX (1, 0), 0, 0) /* csqrt (-2 - 3 i) == 0.89597747612983812471573375529004348 - 1.6741492280355400404480393008490519 i */ +#define DELTA734 CHOOSE(BUILD_COMPLEX (1, 0), 0, 0, BUILD_COMPLEX (1, 0), 0, 0) /* csqrt (-2 + 3 i) == 0.89597747612983812471573375529004348 + 1.6741492280355400404480393008490519 i */ +#define DELTA766 CHOOSE(BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (690, 367), BUILD_COMPLEX (1, 1), BUILD_COMPLEX (1, 0)) /* ctan (0.7 + 1.2 i) == 0.1720734197630349001 + 0.9544807059989405538 i */ +#define DELTA767 CHOOSE(BUILD_COMPLEX (439, 2), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (439, 2), 0, BUILD_COMPLEX (0, 1)) /* ctan (-2 - 3 i) == 0.0037640256415042482 - 1.0032386273536098014 i */ +#define DELTA799 CHOOSE(0, BUILD_COMPLEX (0, 0.5), BUILD_COMPLEX (0, 1), 0, BUILD_COMPLEX (0, 0.5), BUILD_COMPLEX (0, 1)) /* ctanh (0 + pi/4 i) == 0.0 + 1.0 i */ +#define DELTA800 CHOOSE(BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 0), BUILD_COMPLEX (286, 3074), BUILD_COMPLEX (0, 1), BUILD_COMPLEX (1, 0)) /* ctanh (0.7 + 1.2 i) == 1.3472197399061191630 + 0.4778641038326365540 i */ +#define DELTA801 CHOOSE(BUILD_COMPLEX (5, 25), 0, BUILD_COMPLEX (0, 1), BUILD_COMPLEX (5, 25), 0, BUILD_COMPLEX (0, 1)) /* ctanh (-2 - 3 i) == -0.9653858790221331242 + 0.0098843750383224937 i */ +#define DELTA817 CHOOSE(1, 1, 0, 1, 1, 0) /* erfc (0.7) == 0.32219880616258152702 */ +#define DELTA818 CHOOSE(3, 1, 2, 3, 1, 2) /* erfc (1.2) == 0.089686021770364619762 */ +#define DELTA819 CHOOSE(0, 1, 1, 0, 1, 0) /* erfc (2.0) == 0.0046777349810472658379 */ +#define DELTA820 CHOOSE(12, 24, 12, 12, 24, 12) /* erfc (4.1) == 0.67000276540848983727e-8 */ +#define DELTA821 CHOOSE(36, 0, 0, 36, 0, 0) /* erfc (9) == 0.41370317465138102381e-36 */ +#define DELTA830 CHOOSE(412, 0, 0, 412, 0, 0) /* exp (0.7) == 2.0137527074704765216 */ +#define DELTA831 CHOOSE(16, 0, 0, 16, 0, 0) /* exp (50.0) == 5184705528587072464087.45332293348538 */ +#define DELTA832 CHOOSE(754, 0, 0, 754, 0, 0) /* exp (1000.0) == 0.197007111401704699388887935224332313e435 */ +#define DELTA838 CHOOSE(8, 0, 0, 8, 0, 0) /* exp10 (3) == 1000 */ +#define DELTA839 CHOOSE(818, 0, 0, 818, 0, 0) /* exp10 (-1) == 0.1 */ +#define DELTA842 CHOOSE(1182, 1, 0, 1182, 1, 0) /* exp10 (0.7) == 5.0118723362727228500155418688494574 */ +#define DELTA852 CHOOSE(462, 0, 0, 462, 0, 0) /* exp2 (0.7) == 1.6245047927124710452 */ +#define DELTA859 CHOOSE(825, 0, 0, 825, 0, 0) /* expm1 (0.7) == 1.0137527074704765216 */ +#define DELTA972 CHOOSE(4096, 2, 1, 4096, 2, 1) /* fmod (6.5, 2.3) == 1.9 */ +#define DELTA973 CHOOSE(4096, 2, 1, 4096, 2, 1) /* fmod (-6.5, 2.3) == -1.9 */ +#define DELTA974 CHOOSE(4096, 2, 1, 4096, 2, 1) /* fmod (6.5, -2.3) == 1.9 */ +#define DELTA975 CHOOSE(4096, 2, 1, 4096, 2, 1) /* fmod (-6.5, -2.3) == -1.9 */ +#define DELTA1004 CHOOSE(1, 1, 0, 1, 1, 0) /* gamma (-0.5) == log(2*sqrt(pi)) */ +#define DELTA1013 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (0.7, 12.4) == 12.419742348374220601176836866763271 */ +#define DELTA1014 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-0.7, 12.4) == 12.419742348374220601176836866763271 */ +#define DELTA1015 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (0.7, -12.4) == 12.419742348374220601176836866763271 */ +#define DELTA1016 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-0.7, -12.4) == 12.419742348374220601176836866763271 */ +#define DELTA1017 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (12.4, 0.7) == 12.419742348374220601176836866763271 */ +#define DELTA1018 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-12.4, 0.7) == 12.419742348374220601176836866763271 */ +#define DELTA1019 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (12.4, -0.7) == 12.419742348374220601176836866763271 */ +#define DELTA1020 CHOOSE(406, 0, 1, 406, 0, 0) /* hypot (-12.4, -0.7) == 12.419742348374220601176836866763271 */ +#define DELTA1024 CHOOSE(560, 1, 0, 560, 0, 0) /* hypot (0.7, 1.2) == 1.3892443989449804508432547041028554 */ +#define DELTA1053 CHOOSE(0, 2, 2, 0, 1, 1) /* j0 (2.0) == 0.22389077914123566805 */ +#define DELTA1054 CHOOSE(0, 0, 1, 0, 0, 1) /* j0 (8.0) == 0.17165080713755390609 */ +#define DELTA1055 CHOOSE(0, 2, 2, 0, 2, 1) /* j0 (10.0) == -0.24593576445134833520 */ +#define DELTA1064 CHOOSE(0, 1, 0, 0, 1, 0) /* j1 (2.0) == 0.57672480775687338720 */ +#define DELTA1065 CHOOSE(1, 1, 1, 1, 0, 1) /* j1 (8.0) == 0.23463634685391462438 */ +#define DELTA1066 CHOOSE(2, 2, 2, 2, 2, 1) /* j1 (10.0) == 0.043472746168861436670 */ +#define DELTA1075 CHOOSE(0, 2, 2, 0, 1, 1) /* jn (0, 2.0) == 0.22389077914123566805 */ +#define DELTA1076 CHOOSE(1, 0, 1, 1, 0, 1) /* jn (0, 8.0) == 0.17165080713755390609 */ +#define DELTA1077 CHOOSE(2, 2, 1, 2, 2, 1) /* jn (0, 10.0) == -0.24593576445134833520 */ +#define DELTA1086 CHOOSE(0, 1, 0, 0, 1, 0) /* jn (1, 2.0) == 0.57672480775687338720 */ +#define DELTA1087 CHOOSE(1, 1, 1, 1, 0, 1) /* jn (1, 8.0) == 0.23463634685391462438 */ +#define DELTA1088 CHOOSE(2, 2, 2, 2, 2, 1) /* jn (1, 10.0) == 0.043472746168861436670 */ +#define DELTA1091 CHOOSE(1, 0, 0, 1, 0, 0) /* jn (3, -1.0) == -0.019563353982668405919 */ +#define DELTA1093 CHOOSE(1, 1, 0, 1, 1, 0) /* jn (3, 0.1) == 0.000020820315754756261429 */ +#define DELTA1094 CHOOSE(0, 2, 1, 0, 2, 0) /* jn (3, 0.7) == 0.0069296548267508408077 */ +#define DELTA1095 CHOOSE(1, 0, 0, 1, 0, 0) /* jn (3, 1.0) == 0.019563353982668405919 */ +#define DELTA1096 CHOOSE(0, 1, 1, 0, 1, 1) /* jn (3, 2.0) == 0.12894324947440205110 */ +#define DELTA1097 CHOOSE(1, 3, 1, 1, 3, 1) /* jn (3, 10.0) == 0.058379379305186812343 */ +#define DELTA1100 CHOOSE(1, 1, 1, 1, 1, 1) /* jn (10, -1.0) == 0.26306151236874532070e-9 */ +#define DELTA1102 CHOOSE(1, 6, 4, 1, 5, 2) /* jn (10, 0.1) == 0.26905328954342155795e-19 */ +#define DELTA1103 CHOOSE(2, 4, 1, 2, 4, 1) /* jn (10, 0.7) == 0.75175911502153953928e-11 */ +#define DELTA1104 CHOOSE(1, 1, 1, 1, 1, 1) /* jn (10, 1.0) == 0.26306151236874532070e-9 */ +#define DELTA1105 CHOOSE(1, 2, 2, 1, 2, 1) /* jn (10, 2.0) == 0.25153862827167367096e-6 */ +#define DELTA1106 CHOOSE(2, 4, 3, 2, 4, 2) /* jn (10, 10.0) == 0.20748610663335885770 */ +#define DELTA1126 CHOOSE(1, 1, 0, 1, 1, 0) /* lgamma (-0.5) == log(2*sqrt(pi)) */ +#define DELTA1128 CHOOSE(0, 1, 1, 0, 1, 1) /* lgamma (0.7) == 0.26086724653166651439 */ +#define DELTA1130 CHOOSE(1, 1, 2, 1, 1, 2) /* lgamma (1.2) == -0.853740900033158497197e-1 */ +#define DELTA1163 CHOOSE(1, 0, 0.5, 1, 0, 0.5) /* log (e) == 1 */ +#define DELTA1164 CHOOSE(1, 0, 0, 1, 0, 0) /* log (1.0 / M_El) == -1 */ +#define DELTA1167 CHOOSE(2341, 1, 1, 2341, 1, 1) /* log (0.7) == -0.35667494393873237891263871124118447 */ +#define DELTA1178 CHOOSE(1, 0, 1, 1, 0, 1) /* log10 (e) == log10(e) */ +#define DELTA1179 CHOOSE(2033, 1, 0, 2033, 1, 0) /* log10 (0.7) == -0.15490195998574316929 */ +#define DELTA1186 CHOOSE(1, 0, 0, 1, 0, 0) /* log1p (M_El - 1.0) == 1 */ +#define DELTA1187 CHOOSE(585, 1, 1, 585, 1, 1) /* log1p (-0.3) == -0.35667494393873237891263871124118447 */ +#define DELTA1198 CHOOSE(1688, 1, 1, 1688, 1, 1) /* log2 (0.7) == -0.51457317282975824043 */ +#define DELTA1398 CHOOSE(725, 0, 0, 725, 0, 0) /* pow (0.7, 1.2) == 0.65180494056638638188 */ +#define DELTA1524 CHOOSE(627, 0, 0, 627, 0, 0) /* sin (0.7) == 0.64421768723769105367261435139872014 */ +#define DELTA1536 CHOOSE(0.25, 0.2758, 0.3667, 0.25, 0.2758, 0.3667) /* sincos (pi/2, &sin_res, &cos_res) puts 0 in cos_res */ +#define DELTA1539 CHOOSE(1, 1, 1, 1, 1, 1) /* sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in sin_res */ +#define DELTA1540 CHOOSE(0, 1, 0.5, 0, 1, 0.5) /* sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.5 in cos_res */ +#define DELTA1541 CHOOSE(627, 0, 0, 627, 0, 0) /* sincos (0.7, &sin_res, &cos_res) puts 0.64421768723769105367261435139872014 in sin_res */ +#define DELTA1542 CHOOSE(528, 1, 0, 528, 1, 0) /* sincos (0.7, &sin_res, &cos_res) puts 0.76484218728448842625585999019186495 in cos_res */ +#define DELTA1548 CHOOSE(1029, 1, 1, 1028, 0, 1) /* sinh (0.7) == 0.75858370183953350346 */ +#define DELTA1562 CHOOSE(325, 0, 0, 325, 0, 0) /* sqrt (15239.9025) == 123.45 */ +#define DELTA1569 CHOOSE(0, 0.5, 0, 0, 0.5, 0) /* tan (pi/4) == 1 */ +#define DELTA1570 CHOOSE(1401, 1, 1, 1401, 0, 0) /* tan (0.7) == 0.84228838046307944812813500221293775 */ +#define DELTA1576 CHOOSE(521, 1, 1, 521, 0, 0) /* tanh (0.7) == 0.60436777711716349631 */ +#define DELTA1577 CHOOSE(1, 1, 1, 1, 0, 0) /* tanh (-0.7) == -0.60436777711716349631 */ +#define DELTA1587 CHOOSE(0, 0, 1, 0, 0, 1) /* tgamma (0.5) == sqrt (pi) */ +#define DELTA1588 CHOOSE(2, 2, 1, 2, 2, 1) /* tgamma (-0.5) == -2 sqrt (pi) */ +#define DELTA1590 CHOOSE(2, 0, 0, 2, 0, 0) /* tgamma (4) == 6 */ +#define DELTA1591 CHOOSE(0, 1, 1, 0, 1, 1) /* tgamma (0.7) == 1.29805533264755778568 */ +#define DELTA1614 CHOOSE(0, 1, 1, 0, 1, 1) /* y0 (0.1) == -1.5342386513503668441 */ +#define DELTA1615 CHOOSE(2, 3, 1, 2, 3, 1) /* y0 (0.7) == -0.19066492933739506743 */ +#define DELTA1616 CHOOSE(0, 2, 1, 0, 2, 1) /* y0 (1.0) == 0.088256964215676957983 */ +#define DELTA1617 CHOOSE(0, 1, 1, 0, 1, 1) /* y0 (1.5) == 0.38244892379775884396 */ +#define DELTA1618 CHOOSE(0, 1, 0, 0, 1, 0) /* y0 (2.0) == 0.51037567264974511960 */ +#define DELTA1619 CHOOSE(1, 1, 1, 1, 1, 1) /* y0 (8.0) == 0.22352148938756622053 */ +#define DELTA1620 CHOOSE(1, 2, 1, 2, 2, 1) /* y0 (10.0) == 0.055671167283599391424 */ +#define DELTA1625 CHOOSE(1, 1, 1, 1, 1, 1) /* y1 (0.1) == -6.4589510947020269877 */ +#define DELTA1626 CHOOSE(0, 1, 1, 0, 1, 0) /* y1 (0.7) == -1.1032498719076333697 */ +#define DELTA1627 CHOOSE(0, 1, 0, 0, 1, 0) /* y1 (1.0) == -0.78121282130028871655 */ +#define DELTA1628 CHOOSE(0, 0, 1, 0, 0, 1) /* y1 (1.5) == -0.41230862697391129595 */ +#define DELTA1629 CHOOSE(1, 1, 2, 1, 1, 2) /* y1 (2.0) == -0.10703243154093754689 */ +#define DELTA1630 CHOOSE(2, 1, 2, 2, 0, 2) /* y1 (8.0) == -0.15806046173124749426 */ +#define DELTA1631 CHOOSE(0, 3, 2, 0, 3, 2) /* y1 (10.0) == 0.24901542420695388392 */ +#define DELTA1636 CHOOSE(0, 1, 1, 0, 1, 1) /* yn (0, 0.1) == -1.5342386513503668441 */ +#define DELTA1637 CHOOSE(2, 3, 1, 2, 3, 1) /* yn (0, 0.7) == -0.19066492933739506743 */ +#define DELTA1638 CHOOSE(0, 2, 1, 0, 2, 1) /* yn (0, 1.0) == 0.088256964215676957983 */ +#define DELTA1639 CHOOSE(0, 1, 1, 0, 1, 1) /* yn (0, 1.5) == 0.38244892379775884396 */ +#define DELTA1640 CHOOSE(0, 1, 0, 0, 1, 0) /* yn (0, 2.0) == 0.51037567264974511960 */ +#define DELTA1641 CHOOSE(1, 1, 1, 1, 1, 1) /* yn (0, 8.0) == 0.22352148938756622053 */ +#define DELTA1642 CHOOSE(1, 2, 1, 1, 2, 1) /* yn (0, 10.0) == 0.055671167283599391424 */ +#define DELTA1647 CHOOSE(1, 1, 1, 1, 1, 1) /* yn (1, 0.1) == -6.4589510947020269877 */ +#define DELTA1648 CHOOSE(0, 1, 1, 0, 1, 0) /* yn (1, 0.7) == -1.1032498719076333697 */ +#define DELTA1649 CHOOSE(0, 1, 0, 0, 1, 0) /* yn (1, 1.0) == -0.78121282130028871655 */ +#define DELTA1650 CHOOSE(0, 0, 1, 0, 0, 1) /* yn (1, 1.5) == -0.41230862697391129595 */ +#define DELTA1651 CHOOSE(1, 1, 2, 1, 1, 2) /* yn (1, 2.0) == -0.10703243154093754689 */ +#define DELTA1652 CHOOSE(2, 1, 2, 2, 0, 2) /* yn (1, 8.0) == -0.15806046173124749426 */ +#define DELTA1653 CHOOSE(0, 3, 2, 0, 3, 2) /* yn (1, 10.0) == 0.24901542420695388392 */ +#define DELTA1656 CHOOSE(2, 1, 2, 2, 1, 1) /* yn (3, 0.1) == -5099.3323786129048894 */ +#define DELTA1657 CHOOSE(2, 3, 1, 2, 3, 1) /* yn (3, 0.7) == -15.819479052819633505 */ +#define DELTA1659 CHOOSE(0, 1, 1, 0, 1, 1) /* yn (3, 2.0) == -1.1277837768404277861 */ +#define DELTA1660 CHOOSE(0, 1, 1, 0, 1, 1) /* yn (3, 10.0) == -0.25136265718383732978 */ +#define DELTA1663 CHOOSE(2, 2, 2, 2, 2, 1) /* yn (10, 0.1) == -0.11831335132045197885e19 */ +#define DELTA1664 CHOOSE(7, 6, 3, 7, 6, 3) /* yn (10, 0.7) == -0.42447194260703866924e10 */ +#define DELTA1665 CHOOSE(0, 1, 2, 0, 1, 1) /* yn (10, 1.0) == -0.12161801427868918929e9 */ +#define DELTA1666 CHOOSE(1, 3, 3, 1, 2, 1) /* yn (10, 2.0) == -129184.54220803928264 */ +#define DELTA1667 CHOOSE(0, 2, 1, 0, 2, 1) /* yn (10, 10.0) == -0.35981415218340272205 */ diff --git a/src/openlibm/test/libm-test.c b/src/openlibm/test/libm-test.c new file mode 100644 index 0000000..0cef025 --- /dev/null +++ b/src/openlibm/test/libm-test.c @@ -0,0 +1,4537 @@ +/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Part of testsuite for libm. + + This file is processed by a perl script. The resulting file has to + be included by a master file that defines: + + Makros: + FUNC(function): converts general function name (like cos) to + name with correct suffix (e.g. cosl or cosf) + MATHCONST(x): like FUNC but for constants (e.g convert 0.0 to 0.0L) + FLOAT: floating point type to test + - TEST_MSG: informal message to be displayed + CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat): + chooses one of the parameters as delta for testing + equality + PRINTF_EXPR Floating point conversion specification to print a variable + of type FLOAT with printf. PRINTF_EXPR just contains + the specifier, not the percent and width arguments, + e.g. "f". + PRINTF_XEXPR Like PRINTF_EXPR, but print in hexadecimal format. + PRINTF_NEXPR Like PRINTF_EXPR, but print nice. */ + +/* This testsuite has currently tests for: + acos, acosh, asin, asinh, atan, atan2, atanh, + cbrt, ceil, copysign, cos, cosh, erf, erfc, exp, exp10, exp2, expm1, + fabs, fdim, floor, fma, fmax, fmin, fmod, fpclassify, + frexp, gamma, hypot, + ilogb, isfinite, isinf, isnan, isnormal, + isless, islessequal, isgreater, isgreaterequal, islessgreater, isunordered, + j0, j1, jn, + ldexp, lgamma, log, log10, log1p, log2, logb, + modf, nearbyint, nextafter, + pow, remainder, remquo, rint, lrint, llrint, + round, lround, llround, + scalb, scalbn, scalbln, signbit, sin, sincos, sinh, sqrt, tan, tanh, tgamma, trunc, + y0, y1, yn + + and for the following complex math functions: + cabs, cacos, cacosh, carg, casin, casinh, catan, catanh, + ccos, ccosh, cexp, clog, cpow, cproj, csin, csinh, csqrt, ctan, ctanh. + + At the moment the following functions aren't tested: + drem, significand, nan + + Parameter handling is primitive in the moment: + --verbose=[0..3] for different levels of output: + 0: only error count + 1: basic report on failed tests (default) + 2: full report on all tests + -v for full output (equals --verbose=3) + -u for generation of an ULPs file + */ + +/* "Philosophy": + + This suite tests some aspects of the correct implementation of + mathematical functions in libm. Some simple, specific parameters + are tested for correctness but there's no exhaustive + testing. Handling of specific inputs (e.g. infinity, not-a-number) + is also tested. Correct handling of exceptions is checked + against. These implemented tests should check all cases that are + specified in ISO C99. + + Exception testing: At the moment only divide-by-zero and invalid + exceptions are tested. Overflow/underflow and inexact exceptions + aren't checked at the moment. + + NaN values: There exist signalling and quiet NaNs. This implementation + only uses signalling NaN as parameter but does not differenciate + between the two kinds of NaNs as result. + + Inline functions: Inlining functions should give an improvement in + speed - but not in precission. The inlined functions return + reasonable values for a reasonable range of input values. The + result is not necessarily correct for all values and exceptions are + not correctly raised in all cases. Problematic input and return + values are infinity, not-a-number and minus zero. This suite + therefore does not check these specific inputs and the exception + handling for inlined mathematical functions - just the "reasonable" + values are checked. + + Beware: The tests might fail for any of the following reasons: + - Tests are wrong + - Functions are wrong + - Floating Point Unit not working properly + - Compiler has errors + + With e.g. gcc 2.7.2.2 the test for cexp fails because of a compiler error. + + + To Do: All parameter should be numbers that can be represented as + exact floating point values. Currently some values cannot be represented + exactly and therefore the result is not the expected result. +*/ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include "libm-test-ulps.h" +#include +#ifdef SYS_MATH_H +#include +#include +#else +#include +#endif + +#if 0 /* XXX scp XXX */ +#define FE_INEXACT FE_INEXACT +#define FE_DIVBYZERO FE_DIVBYZERO +#define FE_UNDERFLOW FE_UNDERFLOW +#define FE_OVERFLOW FE_OVERFLOW +#define FE_INVALID FE_INVALID +#endif + +#include + +#include +#include +#include +#include +#if 0 /* XXX scp XXX */ +#include +#endif + +// Some native libm implementations don't have sincos defined, so we have to do it ourselves +void FUNC(sincos) (FLOAT x, FLOAT * s, FLOAT * c); + +#ifdef __APPLE__ +#ifdef SYS_MATH_H +void sincos(FLOAT x, FLOAT * s, FLOAT * c) +{ + *s = sin(x); + *c = cos(x); +} +#endif +#endif + +/* Possible exceptions */ +#define NO_EXCEPTION 0x0 +#define INVALID_EXCEPTION 0x1 +#define DIVIDE_BY_ZERO_EXCEPTION 0x2 +/* The next flags signals that those exceptions are allowed but not required. */ +#define INVALID_EXCEPTION_OK 0x4 +#define DIVIDE_BY_ZERO_EXCEPTION_OK 0x8 +#define EXCEPTIONS_OK INVALID_EXCEPTION_OK+DIVIDE_BY_ZERO_EXCEPTION_OK +/* Some special test flags, passed togther with exceptions. */ +#define IGNORE_ZERO_INF_SIGN 0x10 + +/* Various constants (we must supply them precalculated for accuracy). */ +#define M_PI_6l .52359877559829887307710723054658383L +#define M_E2l 7.389056098930650227230427460575008L +#define M_E3l 20.085536923187667740928529654581719L +#define M_2_SQRT_PIl 3.5449077018110320545963349666822903L /* 2 sqrt (M_PIl) */ +#define M_SQRT_PIl 1.7724538509055160272981674833411451L /* sqrt (M_PIl) */ +#define M_LOG_SQRT_PIl 0.57236494292470008707171367567652933L /* log(sqrt(M_PIl)) */ +#define M_LOG_2_SQRT_PIl 1.265512123484645396488945797134706L /* log(2*sqrt(M_PIl)) */ +#define M_PI_34l (M_PIl - M_PI_4l) /* 3*pi/4 */ +#define M_PI_34_LOG10El (M_PIl - M_PI_4l) * M_LOG10El +#define M_PI2_LOG10El M_PI_2l * M_LOG10El +#define M_PI4_LOG10El M_PI_4l * M_LOG10El +#define M_PI_LOG10El M_PIl * M_LOG10El + +#if 1 /* XXX scp XXX */ +# define M_El 2.7182818284590452353602874713526625L /* e */ +# define M_LOG2El 1.4426950408889634073599246810018922L /* log_2 e */ +# define M_LOG10El 0.4342944819032518276511289189166051L /* log_10 e */ +# define M_LN2l 0.6931471805599453094172321214581766L /* log_e 2 */ +# define M_LN10l 2.3025850929940456840179914546843642L /* log_e 10 */ +# define M_PIl 3.1415926535897932384626433832795029L /* pi */ +# define M_PI_2l 1.5707963267948966192313216916397514L /* pi/2 */ +# define M_PI_4l 0.7853981633974483096156608458198757L /* pi/4 */ +# define M_1_PIl 0.3183098861837906715377675267450287L /* 1/pi */ +# define M_2_PIl 0.6366197723675813430755350534900574L /* 2/pi */ +# define M_2_SQRTPIl 1.1283791670955125738961589031215452L /* 2/sqrt(pi) */ +# define M_SQRT2l 1.4142135623730950488016887242096981L /* sqrt(2) */ +# define M_SQRT1_2l 0.7071067811865475244008443621048490L /* 1/sqrt(2) */ +#endif + +static FILE *ulps_file; /* File to document difference. */ +static int output_ulps; /* Should ulps printed? */ + +static int noErrors; /* number of errors */ +static int noTests; /* number of tests (without testing exceptions) */ +static int noExcTests; /* number of tests for exception flags */ +static int noXFails; /* number of expected failures. */ +static int noXPasses; /* number of unexpected passes. */ + +static int verbose; +static int output_max_error; /* Should the maximal errors printed? */ +static int output_points; /* Should the single function results printed? */ +static int ignore_max_ulp; /* Should we ignore max_ulp? */ + +static FLOAT minus_zero, plus_zero; +static FLOAT plus_infty, minus_infty, nan_value; + +static FLOAT max_error, real_max_error, imag_max_error; + + +#if 0 /* XXX scp XXX */ +#define BUILD_COMPLEX(real, imag) \ + ({ __complex__ FLOAT __retval; \ + __real__ __retval = (real); \ + __imag__ __retval = (imag); \ + __retval; }) + +#define BUILD_COMPLEX_INT(real, imag) \ + ({ __complex__ int __retval; \ + __real__ __retval = (real); \ + __imag__ __retval = (imag); \ + __retval; }) +#endif + + +#define MANT_DIG CHOOSE ((LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1), \ + (LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1)) + + +static void +init_max_error (void) +{ + max_error = 0; + real_max_error = 0; + imag_max_error = 0; + feclearexcept (FE_ALL_EXCEPT); +} + +static void +set_max_error (FLOAT current, FLOAT *curr_max_error) +{ + if (current > *curr_max_error) + *curr_max_error = current; +} + + +/* Should the message print to screen? This depends on the verbose flag, + and the test status. */ +static int +print_screen (int ok, int xfail) +{ + if (output_points + && (verbose > 1 + || (verbose == 1 && ok == xfail))) + return 1; + return 0; +} + + +/* Should the message print to screen? This depends on the verbose flag, + and the test status. */ +static int +print_screen_max_error (int ok, int xfail) +{ + if (output_max_error + && (verbose > 1 + || ((verbose == 1) && (ok == xfail)))) + return 1; + return 0; +} + +/* Update statistic counters. */ +static void +update_stats (int ok, int xfail) +{ + ++noTests; + if (ok && xfail) + ++noXPasses; + else if (!ok && xfail) + ++noXFails; + else if (!ok && !xfail) + ++noErrors; +} + +static void +print_ulps (const char *test_name, FLOAT ulp) +{ + if (output_ulps) + { + fprintf (ulps_file, "Test \"%s\":\n", test_name); + fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n", + CHOOSE("ldouble", "double", "float", + "ildouble", "idouble", "ifloat"), ulp); + } +} + +static void +print_function_ulps (const char *function_name, FLOAT ulp) +{ + if (output_ulps) + { + fprintf (ulps_file, "Function: \"%s\":\n", function_name); + fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n", + CHOOSE("ldouble", "double", "float", + "ildouble", "idouble", "ifloat"), ulp); + } +} + + +#if 0 /* XXX scp XXX */ +static void +print_complex_function_ulps (const char *function_name, FLOAT real_ulp, + FLOAT imag_ulp) +{ + if (output_ulps) + { + if (real_ulp != 0.0) + { + fprintf (ulps_file, "Function: Real part of \"%s\":\n", function_name); + fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n", + CHOOSE("ldouble", "double", "float", + "ildouble", "idouble", "ifloat"), real_ulp); + } + if (imag_ulp != 0.0) + { + fprintf (ulps_file, "Function: Imaginary part of \"%s\":\n", function_name); + fprintf (ulps_file, "%s: % .4" PRINTF_NEXPR "\n", + CHOOSE("ldouble", "double", "float", + "ildouble", "idouble", "ifloat"), imag_ulp); + } + + + } +} +#endif + + +static void +print_max_error (const char *func_name, FLOAT allowed, int xfail) +{ + int ok = 0; + + if (max_error == 0.0 || (max_error <= allowed && !ignore_max_ulp)) + { + ok = 1; + } + + if (!ok) + print_function_ulps (func_name, max_error); + + + if (print_screen_max_error (ok, xfail)) + { + printf ("Maximal error of `%s'\n", func_name); + printf (" is : % .4" PRINTF_NEXPR " ulp\n", max_error); + printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", allowed); + } + + update_stats (ok, xfail); +} + + +#if 0 /* XXX scp XXX */ +static void +print_complex_max_error (const char *func_name, __complex__ FLOAT allowed, + __complex__ int xfail) +{ + int ok = 0; + + if ((real_max_error <= __real__ allowed) + && (imag_max_error <= __imag__ allowed)) + { + ok = 1; + } + + if (!ok) + print_complex_function_ulps (func_name, real_max_error, imag_max_error); + + + if (print_screen_max_error (ok, xfail)) + { + printf ("Maximal error of real part of: %s\n", func_name); + printf (" is : % .4" PRINTF_NEXPR " ulp\n", real_max_error); + printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", __real__ allowed); + printf ("Maximal error of imaginary part of: %s\n", func_name); + printf (" is : % .4" PRINTF_NEXPR " ulp\n", imag_max_error); + printf (" accepted: % .4" PRINTF_NEXPR " ulp\n", __imag__ allowed); + } + + update_stats (ok, xfail); +} +#endif + + +/* Test whether a given exception was raised. */ +static void +test_single_exception (const char *test_name, + int exception, + int exc_flag, + int fe_flag, + const char *flag_name) +{ +/* Don't perform these checks if we're compiling with clang, because clang + doesn't bother to set floating-point exceptions properly */ +#ifndef __clang__ +#ifndef TEST_INLINE + int ok = 1; + if (exception & exc_flag) + { + if (fetestexcept (fe_flag)) + { + if (print_screen (1, 0)) + printf ("Pass: %s: Exception \"%s\" set\n", test_name, flag_name); + } + else + { + ok = 0; + if (print_screen (0, 0)) + printf ("Failure: %s: Exception \"%s\" not set\n", + test_name, flag_name); + } + } + else + { + if (fetestexcept (fe_flag)) + { + ok = 0; + if (print_screen (0, 0)) + printf ("Failure: %s: Exception \"%s\" set\n", + test_name, flag_name); + } + else + { + if (print_screen (1, 0)) + printf ("%s: Exception \"%s\" not set\n", test_name, + flag_name); + } + } + if (!ok) + ++noErrors; + +#endif +#endif // __clang__ +} + + +/* Test whether exceptions given by EXCEPTION are raised. Ignore thereby + allowed but not required exceptions. +*/ +static void +test_exceptions (const char *test_name, int exception) +{ + ++noExcTests; +#ifdef FE_DIVBYZERO + if ((exception & DIVIDE_BY_ZERO_EXCEPTION_OK) == 0) + test_single_exception (test_name, exception, + DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO, + "Divide by zero"); +#endif +#ifdef FE_INVALID + if ((exception & INVALID_EXCEPTION_OK) == 0) + test_single_exception (test_name, exception, INVALID_EXCEPTION, FE_INVALID, + "Invalid operation"); +#endif + feclearexcept (FE_ALL_EXCEPT); +} + + +static void +check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, + FLOAT max_ulp, int xfail, int exceptions, + FLOAT *curr_max_error) +{ + int ok = 0; + int print_diff = 0; + FLOAT diff = 0; + FLOAT ulp = 0; + + test_exceptions (test_name, exceptions); + if (isnan (computed) && isnan (expected)) + ok = 1; + else if (isinf (computed) && isinf (expected)) + { + /* Test for sign of infinities. */ + if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0 + && signbit (computed) != signbit (expected)) + { + ok = 0; + printf ("infinity has wrong sign.\n"); + } + else + ok = 1; + } + /* Don't calc ulp for NaNs or infinities. */ + else if (isinf (computed) || isnan (computed) || isinf (expected) || isnan (expected)) + ok = 0; + else + { + diff = FUNC(fabs) (computed - expected); + /* ilogb (0) isn't allowed. */ + if (expected == 0.0) + ulp = diff / FUNC(ldexp) (1.0, - MANT_DIG); + else + ulp = diff / FUNC(ldexp) (1.0, FUNC(ilogb) (expected) - MANT_DIG); + set_max_error (ulp, curr_max_error); + print_diff = 1; + if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0 + && computed == 0.0 && expected == 0.0 + && signbit(computed) != signbit (expected)) + ok = 0; + else if (ulp == 0.0 || (ulp <= max_ulp && !ignore_max_ulp)) + ok = 1; + else + { + ok = 0; + print_ulps (test_name, ulp); + } + + } + if (print_screen (ok, xfail)) + { + if (!ok) + printf ("Failure: "); + printf ("Test: %s\n", test_name); + printf ("Result:\n"); + printf (" is: % .20" PRINTF_EXPR " % .20" PRINTF_XEXPR "\n", + computed, computed); + printf (" should be: % .20" PRINTF_EXPR " % .20" PRINTF_XEXPR "\n", + expected, expected); + if (print_diff) + { + printf (" difference: % .20" PRINTF_EXPR " % .20" PRINTF_XEXPR + "\n", diff, diff); + printf (" ulp : % .4" PRINTF_NEXPR "\n", ulp); + printf (" max.ulp : % .4" PRINTF_NEXPR "\n", max_ulp); + } + } + update_stats (ok, xfail); +} + + +static void +check_float (const char *test_name, FLOAT computed, FLOAT expected, + FLOAT max_ulp, int xfail, int exceptions) +{ + check_float_internal (test_name, computed, expected, max_ulp, xfail, + exceptions, &max_error); +} + +#if 0 /* XXX scp XXX */ +static void +check_complex (const char *test_name, __complex__ FLOAT computed, + __complex__ FLOAT expected, + __complex__ FLOAT max_ulp, __complex__ int xfail, + int exception) +{ + FLOAT part_comp, part_exp, part_max_ulp; + int part_xfail; + char str[200]; + + sprintf (str, "Real part of: %s", test_name); + part_comp = __real__ computed; + part_exp = __real__ expected; + part_max_ulp = __real__ max_ulp; + part_xfail = __real__ xfail; + + check_float_internal (str, part_comp, part_exp, part_max_ulp, part_xfail, + exception, &real_max_error); + + sprintf (str, "Imaginary part of: %s", test_name); + part_comp = __imag__ computed; + part_exp = __imag__ expected; + part_max_ulp = __imag__ max_ulp; + part_xfail = __imag__ xfail; + + /* Don't check again for exceptions, just pass through the + zero/inf sign test. */ + check_float_internal (str, part_comp, part_exp, part_max_ulp, part_xfail, + exception & IGNORE_ZERO_INF_SIGN, + &imag_max_error); +} +#endif + +/* Check that computed and expected values are equal (int values). */ +static void +check_int (const char *test_name, int computed, int expected, int max_ulp, + int xfail, int exceptions) +{ + int diff = computed - expected; + int ok = 0; + + test_exceptions (test_name, exceptions); + noTests++; + if (abs (diff) <= max_ulp) + ok = 1; + + if (!ok) + print_ulps (test_name, diff); + + if (print_screen (ok, xfail)) + { + if (!ok) + printf ("Failure: "); + printf ("Test: %s\n", test_name); + printf ("Result:\n"); + printf (" is: %d\n", computed); + printf (" should be: %d\n", expected); + } + + update_stats (ok, xfail); +} + + +/* Check that computed and expected values are equal (long int values). */ +static void +check_long (const char *test_name, long int computed, long int expected, + long int max_ulp, int xfail, int exceptions) +{ + long int diff = computed - expected; + int ok = 0; + + test_exceptions (test_name, exceptions); + noTests++; + if (labs (diff) <= max_ulp) + ok = 1; + + if (!ok) + print_ulps (test_name, diff); + + if (print_screen (ok, xfail)) + { + if (!ok) + printf ("Failure: "); + printf ("Test: %s\n", test_name); + printf ("Result:\n"); + printf (" is: %ld\n", computed); + printf (" should be: %ld\n", expected); + } + + update_stats (ok, xfail); +} + + +/* Check that computed value is true/false. */ +static void +check_bool (const char *test_name, int computed, int expected, + long int max_ulp, int xfail, int exceptions) +{ + int ok = 0; + + test_exceptions (test_name, exceptions); + noTests++; + if ((computed == 0) == (expected == 0)) + ok = 1; + + if (print_screen (ok, xfail)) + { + if (!ok) + printf ("Failure: "); + printf ("Test: %s\n", test_name); + printf ("Result:\n"); + printf (" is: %d\n", computed); + printf (" should be: %d\n", expected); + } + + update_stats (ok, xfail); +} + + +/* check that computed and expected values are equal (long int values) */ +static void +check_longlong (const char *test_name, long long int computed, + long long int expected, + long long int max_ulp, int xfail, + int exceptions) +{ + long long int diff = computed - expected; + int ok = 0; + + test_exceptions (test_name, exceptions); + noTests++; + if (llabs (diff) <= max_ulp) + ok = 1; + + if (!ok) + print_ulps (test_name, diff); + + if (print_screen (ok, xfail)) + { + if (!ok) + printf ("Failure:"); + printf ("Test: %s\n", test_name); + printf ("Result:\n"); + printf (" is: %lld\n", computed); + printf (" should be: %lld\n", expected); + } + + update_stats (ok, xfail); +} + + +#if 0 /* XXX scp XXX */ +/* This is to prevent messages from the SVID libm emulation. */ +int +matherr (struct exception *x __attribute__ ((unused))) +{ + return 1; +} +#endif + +/**************************************************************************** + Tests for single functions of libm. + Please keep them alphabetically sorted! +****************************************************************************/ + +static void +acos_test (void) +{ + errno = 0; + FUNC(acos) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("acos (inf) == NaN plus invalid exception", FUNC(acos) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("acos (-inf) == NaN plus invalid exception", FUNC(acos) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("acos (NaN) == NaN", FUNC(acos) (nan_value), nan_value, 0, 0, 0); + + /* |x| > 1: */ + check_float ("acos (1.1) == NaN plus invalid exception", FUNC(acos) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("acos (-1.1) == NaN plus invalid exception", FUNC(acos) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("acos (0) == pi/2", FUNC(acos) (0), M_PI_2l, 0, 0, 0); + check_float ("acos (-0) == pi/2", FUNC(acos) (minus_zero), M_PI_2l, 0, 0, 0); + check_float ("acos (1) == 0", FUNC(acos) (1), 0, 0, 0, 0); + check_float ("acos (-1) == pi", FUNC(acos) (-1), M_PIl, 0, 0, 0); + check_float ("acos (0.5) == M_PI_6l*2.0", FUNC(acos) (0.5), M_PI_6l*2.0, 1, 0, 0); + check_float ("acos (-0.5) == M_PI_6l*4.0", FUNC(acos) (-0.5), M_PI_6l*4.0, 0, 0, 0); + check_float ("acos (0.7) == 0.79539883018414355549096833892476432", FUNC(acos) (0.7L), 0.79539883018414355549096833892476432L, 0, 0, 0); + + print_max_error ("acos", DELTAacos, 0); +} + +static void +acosh_test (void) +{ + errno = 0; + FUNC(acosh) (7); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("acosh (inf) == inf", FUNC(acosh) (plus_infty), plus_infty, 0, 0, 0); + check_float ("acosh (-inf) == NaN plus invalid exception", FUNC(acosh) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + + /* x < 1: */ + check_float ("acosh (-1.1) == NaN plus invalid exception", FUNC(acosh) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("acosh (1) == 0", FUNC(acosh) (1), 0, 0, 0, 0); + check_float ("acosh (7) == 2.633915793849633417250092694615937", FUNC(acosh) (7), 2.633915793849633417250092694615937L, DELTA16, 0, 0); + + print_max_error ("acosh", DELTAacosh, 0); +} + +static void +asin_test (void) +{ + errno = 0; + FUNC(asin) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("asin (inf) == NaN plus invalid exception", FUNC(asin) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("asin (-inf) == NaN plus invalid exception", FUNC(asin) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("asin (NaN) == NaN", FUNC(asin) (nan_value), nan_value, 0, 0, 0); + + /* asin x == NaN plus invalid exception for |x| > 1. */ + check_float ("asin (1.1) == NaN plus invalid exception", FUNC(asin) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("asin (-1.1) == NaN plus invalid exception", FUNC(asin) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("asin (0) == 0", FUNC(asin) (0), 0, 0, 0, 0); + check_float ("asin (-0) == -0", FUNC(asin) (minus_zero), minus_zero, 0, 0, 0); + check_float ("asin (0.5) == pi/6", FUNC(asin) (0.5), M_PI_6l, DELTA24, 0, 0); + check_float ("asin (-0.5) == -pi/6", FUNC(asin) (-0.5), -M_PI_6l, DELTA25, 0, 0); + check_float ("asin (1.0) == pi/2", FUNC(asin) (1.0), M_PI_2l, DELTA26, 0, 0); + check_float ("asin (-1.0) == -pi/2", FUNC(asin) (-1.0), -M_PI_2l, DELTA27, 0, 0); + check_float ("asin (0.7) == 0.77539749661075306374035335271498708", FUNC(asin) (0.7L), 0.77539749661075306374035335271498708L, DELTA28, 0, 0); + + print_max_error ("asin", DELTAasin, 0); +} + +static void +asinh_test (void) +{ + errno = 0; + FUNC(asinh) (0.7L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("asinh (0) == 0", FUNC(asinh) (0), 0, 0, 0, 0); + check_float ("asinh (-0) == -0", FUNC(asinh) (minus_zero), minus_zero, 0, 0, 0); +#ifndef TEST_INLINE + check_float ("asinh (inf) == inf", FUNC(asinh) (plus_infty), plus_infty, 0, 0, 0); + check_float ("asinh (-inf) == -inf", FUNC(asinh) (minus_infty), minus_infty, 0, 0, 0); +#endif + check_float ("asinh (NaN) == NaN", FUNC(asinh) (nan_value), nan_value, 0, 0, 0); + check_float ("asinh (0.7) == 0.652666566082355786", FUNC(asinh) (0.7L), 0.652666566082355786L, DELTA34, 0, 0); + + print_max_error ("asinh", DELTAasinh, 0); +} + +static void +atan_test (void) +{ + errno = 0; + FUNC(atan) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("atan (0) == 0", FUNC(atan) (0), 0, 0, 0, 0); + check_float ("atan (-0) == -0", FUNC(atan) (minus_zero), minus_zero, 0, 0, 0); + + check_float ("atan (inf) == pi/2", FUNC(atan) (plus_infty), M_PI_2l, 0, 0, 0); + check_float ("atan (-inf) == -pi/2", FUNC(atan) (minus_infty), -M_PI_2l, 0, 0, 0); + check_float ("atan (NaN) == NaN", FUNC(atan) (nan_value), nan_value, 0, 0, 0); + + check_float ("atan (1) == pi/4", FUNC(atan) (1), M_PI_4l, 0, 0, 0); + check_float ("atan (-1) == -pi/4", FUNC(atan) (-1), -M_PI_4l, 0, 0, 0); + + check_float ("atan (0.7) == 0.61072596438920861654375887649023613", FUNC(atan) (0.7L), 0.61072596438920861654375887649023613L, DELTA42, 0, 0); + + print_max_error ("atan", DELTAatan, 0); +} + + + +static void +atanh_test (void) +{ + errno = 0; + FUNC(atanh) (0.7L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + + check_float ("atanh (0) == 0", FUNC(atanh) (0), 0, 0, 0, 0); + check_float ("atanh (-0) == -0", FUNC(atanh) (minus_zero), minus_zero, 0, 0, 0); + + check_float ("atanh (1) == inf plus division by zero exception", FUNC(atanh) (1), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("atanh (-1) == -inf plus division by zero exception", FUNC(atanh) (-1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("atanh (NaN) == NaN", FUNC(atanh) (nan_value), nan_value, 0, 0, 0); + + /* atanh (x) == NaN plus invalid exception if |x| > 1. */ + check_float ("atanh (1.1) == NaN plus invalid exception", FUNC(atanh) (1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("atanh (-1.1) == NaN plus invalid exception", FUNC(atanh) (-1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("atanh (0.7) == 0.8673005276940531944", FUNC(atanh) (0.7L), 0.8673005276940531944L, DELTA50, 0, 0); + + print_max_error ("atanh", DELTAatanh, 0); +} + +static void +atan2_test (void) +{ + errno = 0; + FUNC(atan2) (-0, 1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + /* atan2 (0,x) == 0 for x > 0. */ + check_float ("atan2 (0, 1) == 0", FUNC(atan2) (0, 1), 0, 0, 0, 0); + + /* atan2 (-0,x) == -0 for x > 0. */ + check_float ("atan2 (-0, 1) == -0", FUNC(atan2) (minus_zero, 1), minus_zero, 0, 0, 0); + + check_float ("atan2 (0, 0) == 0", FUNC(atan2) (0, 0), 0, 0, 0, 0); + check_float ("atan2 (-0, 0) == -0", FUNC(atan2) (minus_zero, 0), minus_zero, 0, 0, 0); + + /* atan2 (+0,x) == +pi for x < 0. */ + check_float ("atan2 (0, -1) == pi", FUNC(atan2) (0, -1), M_PIl, 0, 0, 0); + + /* atan2 (-0,x) == -pi for x < 0. */ + check_float ("atan2 (-0, -1) == -pi", FUNC(atan2) (minus_zero, -1), -M_PIl, 0, 0, 0); + + check_float ("atan2 (0, -0) == pi", FUNC(atan2) (0, minus_zero), M_PIl, 0, 0, 0); + check_float ("atan2 (-0, -0) == -pi", FUNC(atan2) (minus_zero, minus_zero), -M_PIl, 0, 0, 0); + + /* atan2 (y,+0) == pi/2 for y > 0. */ + check_float ("atan2 (1, 0) == pi/2", FUNC(atan2) (1, 0), M_PI_2l, 0, 0, 0); + + /* atan2 (y,-0) == pi/2 for y > 0. */ + check_float ("atan2 (1, -0) == pi/2", FUNC(atan2) (1, minus_zero), M_PI_2l, 0, 0, 0); + + /* atan2 (y,+0) == -pi/2 for y < 0. */ + check_float ("atan2 (-1, 0) == -pi/2", FUNC(atan2) (-1, 0), -M_PI_2l, 0, 0, 0); + + /* atan2 (y,-0) == -pi/2 for y < 0. */ + check_float ("atan2 (-1, -0) == -pi/2", FUNC(atan2) (-1, minus_zero), -M_PI_2l, 0, 0, 0); + + /* atan2 (y,inf) == +0 for finite y > 0. */ + check_float ("atan2 (1, inf) == 0", FUNC(atan2) (1, plus_infty), 0, 0, 0, 0); + + /* atan2 (y,inf) == -0 for finite y < 0. */ + check_float ("atan2 (-1, inf) == -0", FUNC(atan2) (-1, plus_infty), minus_zero, 0, 0, 0); + + /* atan2(+inf, x) == pi/2 for finite x. */ + check_float ("atan2 (inf, -1) == pi/2", FUNC(atan2) (plus_infty, -1), M_PI_2l, 0, 0, 0); + + /* atan2(-inf, x) == -pi/2 for finite x. */ + check_float ("atan2 (-inf, 1) == -pi/2", FUNC(atan2) (minus_infty, 1), -M_PI_2l, 0, 0, 0); + + /* atan2 (y,-inf) == +pi for finite y > 0. */ + check_float ("atan2 (1, -inf) == pi", FUNC(atan2) (1, minus_infty), M_PIl, 0, 0, 0); + + /* atan2 (y,-inf) == -pi for finite y < 0. */ + check_float ("atan2 (-1, -inf) == -pi", FUNC(atan2) (-1, minus_infty), -M_PIl, 0, 0, 0); + + check_float ("atan2 (inf, inf) == pi/4", FUNC(atan2) (plus_infty, plus_infty), M_PI_4l, 0, 0, 0); + check_float ("atan2 (-inf, inf) == -pi/4", FUNC(atan2) (minus_infty, plus_infty), -M_PI_4l, 0, 0, 0); + check_float ("atan2 (inf, -inf) == 3/4 pi", FUNC(atan2) (plus_infty, minus_infty), M_PI_34l, 0, 0, 0); + check_float ("atan2 (-inf, -inf) == -3/4 pi", FUNC(atan2) (minus_infty, minus_infty), -M_PI_34l, 0, 0, 0); + check_float ("atan2 (NaN, NaN) == NaN", FUNC(atan2) (nan_value, nan_value), nan_value, 0, 0, 0); + + check_float ("atan2 (0.7, 1) == 0.61072596438920861654375887649023613", FUNC(atan2) (0.7L, 1), 0.61072596438920861654375887649023613L, DELTA74, 0, 0); + check_float ("atan2 (-0.7, 1.0) == -0.61072596438920861654375887649023613", FUNC(atan2) (-0.7L, 1.0L), -0.61072596438920861654375887649023613L, 0, 0, 0); + check_float ("atan2 (0.7, -1.0) == 2.530866689200584621918884506789267", FUNC(atan2) (0.7L, -1.0L), 2.530866689200584621918884506789267L, 0, 0, 0); + check_float ("atan2 (-0.7, -1.0) == -2.530866689200584621918884506789267", FUNC(atan2) (-0.7L, -1.0L), -2.530866689200584621918884506789267L, 0, 0, 0); + check_float ("atan2 (0.4, 0.0003) == 1.5700463269355215717704032607580829", FUNC(atan2) (0.4L, 0.0003L), 1.5700463269355215717704032607580829L, DELTA78, 0, 0); + check_float ("atan2 (1.4, -0.93) == 2.1571487668237843754887415992772736", FUNC(atan2) (1.4L, -0.93L), 2.1571487668237843754887415992772736L, 0, 0, 0); + + print_max_error ("atan2", DELTAatan2, 0); +} + + +#if 0 /* XXX scp XXX */ +static void +cabs_test (void) +{ + errno = 0; + FUNC(cabs) (BUILD_COMPLEX (0.7L, 12.4L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + /* cabs (x + iy) is specified as hypot (x,y) */ + + /* cabs (+inf + i x) == +inf. */ + check_float ("cabs (inf + 1.0 i) == inf", FUNC(cabs) (BUILD_COMPLEX (plus_infty, 1.0)), plus_infty, 0, 0, 0); + /* cabs (-inf + i x) == +inf. */ + check_float ("cabs (-inf + 1.0 i) == inf", FUNC(cabs) (BUILD_COMPLEX (minus_infty, 1.0)), plus_infty, 0, 0, 0); + + check_float ("cabs (-inf + NaN i) == inf", FUNC(cabs) (BUILD_COMPLEX (minus_infty, nan_value)), plus_infty, 0, 0, 0); + check_float ("cabs (-inf + NaN i) == inf", FUNC(cabs) (BUILD_COMPLEX (minus_infty, nan_value)), plus_infty, 0, 0, 0); + + check_float ("cabs (NaN + NaN i) == NaN", FUNC(cabs) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0); + + /* cabs (x,y) == cabs (y,x). */ + check_float ("cabs (0.7 + 12.4 i) == 12.419742348374220601176836866763271", FUNC(cabs) (BUILD_COMPLEX (0.7L, 12.4L)), 12.419742348374220601176836866763271L, DELTA85, 0, 0); + /* cabs (x,y) == cabs (-x,y). */ + check_float ("cabs (-12.4 + 0.7 i) == 12.419742348374220601176836866763271", FUNC(cabs) (BUILD_COMPLEX (-12.4L, 0.7L)), 12.419742348374220601176836866763271L, DELTA86, 0, 0); + /* cabs (x,y) == cabs (-y,x). */ + check_float ("cabs (-0.7 + 12.4 i) == 12.419742348374220601176836866763271", FUNC(cabs) (BUILD_COMPLEX (-0.7L, 12.4L)), 12.419742348374220601176836866763271L, DELTA87, 0, 0); + /* cabs (x,y) == cabs (-x,-y). */ + check_float ("cabs (-12.4 - 0.7 i) == 12.419742348374220601176836866763271", FUNC(cabs) (BUILD_COMPLEX (-12.4L, -0.7L)), 12.419742348374220601176836866763271L, DELTA88, 0, 0); + /* cabs (x,y) == cabs (-y,-x). */ + check_float ("cabs (-0.7 - 12.4 i) == 12.419742348374220601176836866763271", FUNC(cabs) (BUILD_COMPLEX (-0.7L, -12.4L)), 12.419742348374220601176836866763271L, DELTA89, 0, 0); + /* cabs (x,0) == fabs (x). */ + check_float ("cabs (-0.7 + 0 i) == 0.7", FUNC(cabs) (BUILD_COMPLEX (-0.7L, 0)), 0.7L, 0, 0, 0); + check_float ("cabs (0.7 + 0 i) == 0.7", FUNC(cabs) (BUILD_COMPLEX (0.7L, 0)), 0.7L, 0, 0, 0); + check_float ("cabs (-1.0 + 0 i) == 1.0", FUNC(cabs) (BUILD_COMPLEX (-1.0L, 0)), 1.0L, 0, 0, 0); + check_float ("cabs (1.0 + 0 i) == 1.0", FUNC(cabs) (BUILD_COMPLEX (1.0L, 0)), 1.0L, 0, 0, 0); + check_float ("cabs (-5.7e7 + 0 i) == 5.7e7", FUNC(cabs) (BUILD_COMPLEX (-5.7e7L, 0)), 5.7e7L, 0, 0, 0); + check_float ("cabs (5.7e7 + 0 i) == 5.7e7", FUNC(cabs) (BUILD_COMPLEX (5.7e7L, 0)), 5.7e7L, 0, 0, 0); + + check_float ("cabs (0.7 + 1.2 i) == 1.3892443989449804508432547041028554", FUNC(cabs) (BUILD_COMPLEX (0.7L, 1.2L)), 1.3892443989449804508432547041028554L, DELTA96, 0, 0); + + print_max_error ("cabs", DELTAcabs, 0); +} + +static void +cacos_test (void) +{ + errno = 0; + FUNC(cacos) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + + check_complex ("cacos (0 + 0 i) == pi/2 - 0 i", FUNC(cacos) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("cacos (-0 + 0 i) == pi/2 - 0 i", FUNC(cacos) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("cacos (-0 - 0 i) == pi/2 + 0.0 i", FUNC(cacos) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (M_PI_2l, 0.0), 0, 0, 0); + check_complex ("cacos (0 - 0 i) == pi/2 + 0.0 i", FUNC(cacos) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (M_PI_2l, 0.0), 0, 0, 0); + + check_complex ("cacos (-inf + inf i) == 3/4 pi - inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (M_PI_34l, minus_infty), 0, 0, 0); + check_complex ("cacos (-inf - inf i) == 3/4 pi + inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (M_PI_34l, plus_infty), 0, 0, 0); + + check_complex ("cacos (inf + inf i) == pi/4 - inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_4l, minus_infty), 0, 0, 0); + check_complex ("cacos (inf - inf i) == pi/4 + inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_4l, plus_infty), 0, 0, 0); + + check_complex ("cacos (-10.0 + inf i) == pi/2 - inf i", FUNC(cacos) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0); + check_complex ("cacos (-10.0 - inf i) == pi/2 + inf i", FUNC(cacos) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("cacos (0 + inf i) == pi/2 - inf i", FUNC(cacos) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0); + check_complex ("cacos (0 - inf i) == pi/2 + inf i", FUNC(cacos) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("cacos (0.1 + inf i) == pi/2 - inf i", FUNC(cacos) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0); + check_complex ("cacos (0.1 - inf i) == pi/2 + inf i", FUNC(cacos) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0); + + check_complex ("cacos (-inf + 0 i) == pi - inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (M_PIl, minus_infty), 0, 0, 0); + check_complex ("cacos (-inf - 0 i) == pi + inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (M_PIl, plus_infty), 0, 0, 0); + check_complex ("cacos (-inf + 100 i) == pi - inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (M_PIl, minus_infty), 0, 0, 0); + check_complex ("cacos (-inf - 100 i) == pi + inf i", FUNC(cacos) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (M_PIl, plus_infty), 0, 0, 0); + + check_complex ("cacos (inf + 0 i) == 0.0 - inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + check_complex ("cacos (inf - 0 i) == 0.0 + inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("cacos (inf + 0.5 i) == 0.0 - inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + check_complex ("cacos (inf - 0.5 i) == 0.0 + inf i", FUNC(cacos) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + + check_complex ("cacos (inf + NaN i) == NaN + inf i plus sign of zero/inf not specified", FUNC(cacos) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("cacos (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified", FUNC(cacos) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("cacos (0 + NaN i) == pi/2 + NaN i", FUNC(cacos) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (M_PI_2l, nan_value), 0, 0, 0); + check_complex ("cacos (-0 + NaN i) == pi/2 + NaN i", FUNC(cacos) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (M_PI_2l, nan_value), 0, 0, 0); + + check_complex ("cacos (NaN + inf i) == NaN - inf i", FUNC(cacos) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, minus_infty), 0, 0, 0); + check_complex ("cacos (NaN - inf i) == NaN + inf i", FUNC(cacos) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, 0); + + check_complex ("cacos (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cacos) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cacos (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cacos) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("cacos (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(cacos) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cacos (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(cacos) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("cacos (NaN + NaN i) == NaN + NaN i", FUNC(cacos) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("cacos (0.7 + 1.2 i) == 1.1351827477151551088992008271819053 - 1.0927647857577371459105272080819308 i", FUNC(cacos) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.1351827477151551088992008271819053L, -1.0927647857577371459105272080819308L), DELTA130, 0, 0); + check_complex ("cacos (-2 - 3 i) == 2.1414491111159960199416055713254211 + 1.9833870299165354323470769028940395 i", FUNC(cacos) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (2.1414491111159960199416055713254211L, 1.9833870299165354323470769028940395L), DELTA131, 0, 0); + + print_complex_max_error ("cacos", DELTAcacos, 0); +} + + +static void +cacosh_test (void) +{ + errno = 0; + FUNC(cacosh) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + + check_complex ("cacosh (0 + 0 i) == 0.0 + pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("cacosh (-0 + 0 i) == 0.0 + pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("cacosh (0 - 0 i) == 0.0 - pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + check_complex ("cacosh (-0 - 0 i) == 0.0 - pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + check_complex ("cacosh (-inf + inf i) == inf + 3/4 pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34l), 0, 0, 0); + check_complex ("cacosh (-inf - inf i) == inf - 3/4 pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_34l), 0, 0, 0); + + check_complex ("cacosh (inf + inf i) == inf + pi/4 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0); + check_complex ("cacosh (inf - inf i) == inf - pi/4 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0); + + check_complex ("cacosh (-10.0 + inf i) == inf + pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("cacosh (-10.0 - inf i) == inf - pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("cacosh (0 + inf i) == inf + pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("cacosh (0 - inf i) == inf - pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("cacosh (0.1 + inf i) == inf + pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("cacosh (0.1 - inf i) == inf - pi/2 i", FUNC(cacosh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + + check_complex ("cacosh (-inf + 0 i) == inf + pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0); + check_complex ("cacosh (-inf - 0 i) == inf - pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0); + check_complex ("cacosh (-inf + 100 i) == inf + pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0); + check_complex ("cacosh (-inf - 100 i) == inf - pi i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0); + + check_complex ("cacosh (inf + 0 i) == inf + 0.0 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("cacosh (inf - 0 i) == inf - 0 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("cacosh (inf + 0.5 i) == inf + 0.0 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("cacosh (inf - 0.5 i) == inf - 0 i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("cacosh (inf + NaN i) == inf + NaN i", FUNC(cacosh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("cacosh (-inf + NaN i) == inf + NaN i", FUNC(cacosh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("cacosh (0 + NaN i) == NaN + NaN i", FUNC(cacosh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + check_complex ("cacosh (-0 + NaN i) == NaN + NaN i", FUNC(cacosh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("cacosh (NaN + inf i) == inf + NaN i", FUNC(cacosh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("cacosh (NaN - inf i) == inf + NaN i", FUNC(cacosh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("cacosh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cacosh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cacosh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cacosh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("cacosh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(cacosh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cacosh (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(cacosh) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("cacosh (NaN + NaN i) == NaN + NaN i", FUNC(cacosh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("cacosh (0.7 + 1.2 i) == 1.0927647857577371459105272080819308 + 1.1351827477151551088992008271819053 i", FUNC(cacosh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.0927647857577371459105272080819308L, 1.1351827477151551088992008271819053L), DELTA165, 0, 0); + check_complex ("cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i", FUNC(cacosh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.9833870299165354323470769028940395L, 2.1414491111159960199416055713254211L), DELTA166, 0, 0); + + print_complex_max_error ("cacosh", DELTAcacosh, 0); +} + +static void +carg_test (void) +{ + init_max_error (); + + /* carg (x + iy) is specified as atan2 (y, x) */ + + /* carg (x + i 0) == 0 for x > 0. */ + check_float ("carg (2.0 + 0 i) == 0", FUNC(carg) (BUILD_COMPLEX (2.0, 0)), 0, 0, 0, 0); + /* carg (x - i 0) == -0 for x > 0. */ + check_float ("carg (2.0 - 0 i) == -0", FUNC(carg) (BUILD_COMPLEX (2.0, minus_zero)), minus_zero, 0, 0, 0); + + check_float ("carg (0 + 0 i) == 0", FUNC(carg) (BUILD_COMPLEX (0, 0)), 0, 0, 0, 0); + check_float ("carg (0 - 0 i) == -0", FUNC(carg) (BUILD_COMPLEX (0, minus_zero)), minus_zero, 0, 0, 0); + + /* carg (x + i 0) == +pi for x < 0. */ + check_float ("carg (-2.0 + 0 i) == pi", FUNC(carg) (BUILD_COMPLEX (-2.0, 0)), M_PIl, 0, 0, 0); + + /* carg (x - i 0) == -pi for x < 0. */ + check_float ("carg (-2.0 - 0 i) == -pi", FUNC(carg) (BUILD_COMPLEX (-2.0, minus_zero)), -M_PIl, 0, 0, 0); + + check_float ("carg (-0 + 0 i) == pi", FUNC(carg) (BUILD_COMPLEX (minus_zero, 0)), M_PIl, 0, 0, 0); + check_float ("carg (-0 - 0 i) == -pi", FUNC(carg) (BUILD_COMPLEX (minus_zero, minus_zero)), -M_PIl, 0, 0, 0); + + /* carg (+0 + i y) == pi/2 for y > 0. */ + check_float ("carg (0 + 2.0 i) == pi/2", FUNC(carg) (BUILD_COMPLEX (0, 2.0)), M_PI_2l, 0, 0, 0); + + /* carg (-0 + i y) == pi/2 for y > 0. */ + check_float ("carg (-0 + 2.0 i) == pi/2", FUNC(carg) (BUILD_COMPLEX (minus_zero, 2.0)), M_PI_2l, 0, 0, 0); + + /* carg (+0 + i y) == -pi/2 for y < 0. */ + check_float ("carg (0 - 2.0 i) == -pi/2", FUNC(carg) (BUILD_COMPLEX (0, -2.0)), -M_PI_2l, 0, 0, 0); + + /* carg (-0 + i y) == -pi/2 for y < 0. */ + check_float ("carg (-0 - 2.0 i) == -pi/2", FUNC(carg) (BUILD_COMPLEX (minus_zero, -2.0)), -M_PI_2l, 0, 0, 0); + + /* carg (inf + i y) == +0 for finite y > 0. */ + check_float ("carg (inf + 2.0 i) == 0", FUNC(carg) (BUILD_COMPLEX (plus_infty, 2.0)), 0, 0, 0, 0); + + /* carg (inf + i y) == -0 for finite y < 0. */ + check_float ("carg (inf - 2.0 i) == -0", FUNC(carg) (BUILD_COMPLEX (plus_infty, -2.0)), minus_zero, 0, 0, 0); + + /* carg(x + i inf) == pi/2 for finite x. */ + check_float ("carg (10.0 + inf i) == pi/2", FUNC(carg) (BUILD_COMPLEX (10.0, plus_infty)), M_PI_2l, 0, 0, 0); + + /* carg(x - i inf) == -pi/2 for finite x. */ + check_float ("carg (10.0 - inf i) == -pi/2", FUNC(carg) (BUILD_COMPLEX (10.0, minus_infty)), -M_PI_2l, 0, 0, 0); + + /* carg (-inf + i y) == +pi for finite y > 0. */ + check_float ("carg (-inf + 10.0 i) == pi", FUNC(carg) (BUILD_COMPLEX (minus_infty, 10.0)), M_PIl, 0, 0, 0); + + /* carg (-inf + i y) == -pi for finite y < 0. */ + check_float ("carg (-inf - 10.0 i) == -pi", FUNC(carg) (BUILD_COMPLEX (minus_infty, -10.0)), -M_PIl, 0, 0, 0); + + check_float ("carg (inf + inf i) == pi/4", FUNC(carg) (BUILD_COMPLEX (plus_infty, plus_infty)), M_PI_4l, 0, 0, 0); + + check_float ("carg (inf - inf i) == -pi/4", FUNC(carg) (BUILD_COMPLEX (plus_infty, minus_infty)), -M_PI_4l, 0, 0, 0); + + check_float ("carg (-inf + inf i) == 3 * M_PI_4l", FUNC(carg) (BUILD_COMPLEX (minus_infty, plus_infty)), 3 * M_PI_4l, 0, 0, 0); + + check_float ("carg (-inf - inf i) == -3 * M_PI_4l", FUNC(carg) (BUILD_COMPLEX (minus_infty, minus_infty)), -3 * M_PI_4l, 0, 0, 0); + + check_float ("carg (NaN + NaN i) == NaN", FUNC(carg) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0); + + print_max_error ("carg", 0, 0); +} + +static void +casin_test (void) +{ + errno = 0; + FUNC(casin) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("casin (0 + 0 i) == 0.0 + 0.0 i", FUNC(casin) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("casin (-0 + 0 i) == -0 + 0.0 i", FUNC(casin) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("casin (0 - 0 i) == 0.0 - 0 i", FUNC(casin) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("casin (-0 - 0 i) == -0 - 0 i", FUNC(casin) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("casin (inf + inf i) == pi/4 + inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_4l, plus_infty), 0, 0, 0); + check_complex ("casin (inf - inf i) == pi/4 - inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_4l, minus_infty), 0, 0, 0); + check_complex ("casin (-inf + inf i) == -pi/4 + inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (-M_PI_4l, plus_infty), 0, 0, 0); + check_complex ("casin (-inf - inf i) == -pi/4 - inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (-M_PI_4l, minus_infty), 0, 0, 0); + + check_complex ("casin (-10.0 + inf i) == -0 + inf i", FUNC(casin) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0); + check_complex ("casin (-10.0 - inf i) == -0 - inf i", FUNC(casin) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0); + check_complex ("casin (0 + inf i) == 0.0 + inf i", FUNC(casin) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("casin (0 - inf i) == 0.0 - inf i", FUNC(casin) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + check_complex ("casin (-0 + inf i) == -0 + inf i", FUNC(casin) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0); + check_complex ("casin (-0 - inf i) == -0 - inf i", FUNC(casin) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0); + check_complex ("casin (0.1 + inf i) == 0.0 + inf i", FUNC(casin) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("casin (0.1 - inf i) == 0.0 - inf i", FUNC(casin) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + + check_complex ("casin (-inf + 0 i) == -pi/2 + inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (-M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("casin (-inf - 0 i) == -pi/2 - inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-M_PI_2l, minus_infty), 0, 0, 0); + check_complex ("casin (-inf + 100 i) == -pi/2 + inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (-M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("casin (-inf - 100 i) == -pi/2 - inf i", FUNC(casin) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (-M_PI_2l, minus_infty), 0, 0, 0); + + check_complex ("casin (inf + 0 i) == pi/2 + inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("casin (inf - 0 i) == pi/2 - inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0); + check_complex ("casin (inf + 0.5 i) == pi/2 + inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (M_PI_2l, plus_infty), 0, 0, 0); + check_complex ("casin (inf - 0.5 i) == pi/2 - inf i", FUNC(casin) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (M_PI_2l, minus_infty), 0, 0, 0); + + check_complex ("casin (NaN + inf i) == NaN + inf i", FUNC(casin) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, 0); + check_complex ("casin (NaN - inf i) == NaN - inf i", FUNC(casin) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, minus_infty), 0, 0, 0); + + check_complex ("casin (0.0 + NaN i) == 0.0 + NaN i", FUNC(casin) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0); + check_complex ("casin (-0 + NaN i) == -0 + NaN i", FUNC(casin) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0); + + check_complex ("casin (inf + NaN i) == NaN + inf i plus sign of zero/inf not specified", FUNC(casin) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("casin (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified", FUNC(casin) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("casin (NaN + 10.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(casin) (BUILD_COMPLEX (nan_value, 10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("casin (NaN - 10.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(casin) (BUILD_COMPLEX (nan_value, -10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("casin (0.75 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(casin) (BUILD_COMPLEX (0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("casin (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(casin) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("casin (NaN + NaN i) == NaN + NaN i", FUNC(casin) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("casin (0.7 + 1.2 i) == 0.4356135790797415103321208644578462 + 1.0927647857577371459105272080819308 i", FUNC(casin) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.4356135790797415103321208644578462L, 1.0927647857577371459105272080819308L), DELTA225, 0, 0); + check_complex ("casin (-2 - 3 i) == -0.57065278432109940071028387968566963 - 1.9833870299165354323470769028940395 i", FUNC(casin) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.57065278432109940071028387968566963L, -1.9833870299165354323470769028940395L), DELTA226, 0, 0); + + print_complex_max_error ("casin", DELTAcasin, 0); +} + + +static void +casinh_test (void) +{ + errno = 0; + FUNC(casinh) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("casinh (0 + 0 i) == 0.0 + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("casinh (-0 + 0 i) == -0 + 0 i", FUNC(casinh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0), 0, 0, 0); + check_complex ("casinh (0 - 0 i) == 0.0 - 0 i", FUNC(casinh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("casinh (-0 - 0 i) == -0 - 0 i", FUNC(casinh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("casinh (inf + inf i) == inf + pi/4 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0); + check_complex ("casinh (inf - inf i) == inf - pi/4 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0); + check_complex ("casinh (-inf + inf i) == -inf + pi/4 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_4l), 0, 0, 0); + check_complex ("casinh (-inf - inf i) == -inf - pi/4 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_4l), 0, 0, 0); + + check_complex ("casinh (-10.0 + inf i) == -inf + pi/2 i", FUNC(casinh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_2l), 0, 0, 0); + check_complex ("casinh (-10.0 - inf i) == -inf - pi/2 i", FUNC(casinh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("casinh (0 + inf i) == inf + pi/2 i", FUNC(casinh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("casinh (0 - inf i) == inf - pi/2 i", FUNC(casinh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("casinh (-0 + inf i) == -inf + pi/2 i", FUNC(casinh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_infty, M_PI_2l), 0, 0, 0); + check_complex ("casinh (-0 - inf i) == -inf - pi/2 i", FUNC(casinh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("casinh (0.1 + inf i) == inf + pi/2 i", FUNC(casinh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("casinh (0.1 - inf i) == inf - pi/2 i", FUNC(casinh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + + check_complex ("casinh (-inf + 0 i) == -inf + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0); + check_complex ("casinh (-inf - 0 i) == -inf - 0 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0); + check_complex ("casinh (-inf + 100 i) == -inf + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0); + check_complex ("casinh (-inf - 100 i) == -inf - 0 i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0); + + check_complex ("casinh (inf + 0 i) == inf + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("casinh (inf - 0 i) == inf - 0 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("casinh (inf + 0.5 i) == inf + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("casinh (inf - 0.5 i) == inf - 0 i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("casinh (inf + NaN i) == inf + NaN i", FUNC(casinh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("casinh (-inf + NaN i) == -inf + NaN i", FUNC(casinh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (minus_infty, nan_value), 0, 0, 0); + + check_complex ("casinh (NaN + 0 i) == NaN + 0.0 i", FUNC(casinh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0); + check_complex ("casinh (NaN - 0 i) == NaN - 0 i", FUNC(casinh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0); + + check_complex ("casinh (NaN + inf i) == inf + NaN i plus sign of zero/inf not specified", FUNC(casinh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("casinh (NaN - inf i) == inf + NaN i plus sign of zero/inf not specified", FUNC(casinh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("casinh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(casinh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("casinh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(casinh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("casinh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(casinh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("casinh (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(casinh) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("casinh (NaN + NaN i) == NaN + NaN i", FUNC(casinh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("casinh (0.7 + 1.2 i) == 0.97865459559367387689317593222160964 + 0.91135418953156011567903546856170941 i", FUNC(casinh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.97865459559367387689317593222160964L, 0.91135418953156011567903546856170941L), DELTA262, 0, 0); + check_complex ("casinh (-2 - 3 i) == -1.9686379257930962917886650952454982 - 0.96465850440760279204541105949953237 i", FUNC(casinh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.9686379257930962917886650952454982L, -0.96465850440760279204541105949953237L), DELTA263, 0, 0); + + print_complex_max_error ("casinh", DELTAcasinh, 0); +} + + +static void +catan_test (void) +{ + errno = 0; + FUNC(catan) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("catan (0 + 0 i) == 0 + 0 i", FUNC(catan) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0, 0), 0, 0, 0); + check_complex ("catan (-0 + 0 i) == -0 + 0 i", FUNC(catan) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0), 0, 0, 0); + check_complex ("catan (0 - 0 i) == 0 - 0 i", FUNC(catan) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0); + check_complex ("catan (-0 - 0 i) == -0 - 0 i", FUNC(catan) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("catan (inf + inf i) == pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (inf - inf i) == pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (-inf + inf i) == -pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (-inf - inf i) == -pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0); + + + check_complex ("catan (inf - 10.0 i) == pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, -10.0)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (-inf - 10.0 i) == -pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, -10.0)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (inf - 0 i) == pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (-inf - 0 i) == -pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (inf + 0.0 i) == pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (-inf + 0.0 i) == -pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (inf + 0.1 i) == pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (plus_infty, 0.1L)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (-inf + 0.1 i) == -pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (minus_infty, 0.1L)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0); + + check_complex ("catan (0.0 - inf i) == pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (-0 - inf i) == -pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (100.0 - inf i) == pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (100.0, minus_infty)), BUILD_COMPLEX (M_PI_2l, minus_zero), 0, 0, 0); + check_complex ("catan (-100.0 - inf i) == -pi/2 - 0 i", FUNC(catan) (BUILD_COMPLEX (-100.0, minus_infty)), BUILD_COMPLEX (-M_PI_2l, minus_zero), 0, 0, 0); + + check_complex ("catan (0.0 + inf i) == pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (-0 + inf i) == -pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (0.5 + inf i) == pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (0.5, plus_infty)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, 0); + check_complex ("catan (-0.5 + inf i) == -pi/2 + 0 i", FUNC(catan) (BUILD_COMPLEX (-0.5, plus_infty)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, 0); + + check_complex ("catan (NaN + 0.0 i) == NaN + 0 i", FUNC(catan) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0), 0, 0, 0); + check_complex ("catan (NaN - 0 i) == NaN - 0 i", FUNC(catan) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0); + + check_complex ("catan (NaN + inf i) == NaN + 0 i", FUNC(catan) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, 0), 0, 0, 0); + check_complex ("catan (NaN - inf i) == NaN - 0 i", FUNC(catan) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0); + + check_complex ("catan (0.0 + NaN i) == NaN + NaN i", FUNC(catan) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + check_complex ("catan (-0 + NaN i) == NaN + NaN i", FUNC(catan) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("catan (inf + NaN i) == pi/2 + 0 i plus sign of zero/inf not specified", FUNC(catan) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (M_PI_2l, 0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("catan (-inf + NaN i) == -pi/2 + 0 i plus sign of zero/inf not specified", FUNC(catan) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (-M_PI_2l, 0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("catan (NaN + 10.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(catan) (BUILD_COMPLEX (nan_value, 10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("catan (NaN - 10.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(catan) (BUILD_COMPLEX (nan_value, -10.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("catan (0.75 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(catan) (BUILD_COMPLEX (0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("catan (-0.75 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(catan) (BUILD_COMPLEX (-0.75, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("catan (NaN + NaN i) == NaN + NaN i", FUNC(catan) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("catan (0.7 + 1.2 i) == 1.0785743834118921877443707996386368 + 0.57705737765343067644394541889341712 i", FUNC(catan) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.0785743834118921877443707996386368L, 0.57705737765343067644394541889341712L), DELTA301, 0, 0); + + check_complex ("catan (-2 - 3 i) == -1.4099210495965755225306193844604208 - 0.22907268296853876629588180294200276 i", FUNC(catan) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-1.4099210495965755225306193844604208L, -0.22907268296853876629588180294200276L), DELTA302, 0, 0); + + print_complex_max_error ("catan", DELTAcatan, 0); +} + +static void +catanh_test (void) +{ + errno = 0; + FUNC(catanh) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("catanh (0 + 0 i) == 0.0 + 0.0 i", FUNC(catanh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("catanh (-0 + 0 i) == -0 + 0.0 i", FUNC(catanh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("catanh (0 - 0 i) == 0.0 - 0 i", FUNC(catanh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("catanh (-0 - 0 i) == -0 - 0 i", FUNC(catanh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("catanh (inf + inf i) == 0.0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("catanh (inf - inf i) == 0.0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (-inf + inf i) == -0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0); + check_complex ("catanh (-inf - inf i) == -0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0); + + check_complex ("catanh (-10.0 + inf i) == -0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (-10.0, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0); + check_complex ("catanh (-10.0 - inf i) == -0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (-10.0, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (-0 + inf i) == -0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0); + check_complex ("catanh (-0 - inf i) == -0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (0 + inf i) == 0.0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("catanh (0 - inf i) == 0.0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (0.1 + inf i) == 0.0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (0.1L, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("catanh (0.1 - inf i) == 0.0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (0.1L, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + + check_complex ("catanh (-inf + 0 i) == -0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0); + check_complex ("catanh (-inf - 0 i) == -0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (-inf + 100 i) == -0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, 100)), BUILD_COMPLEX (minus_zero, M_PI_2l), 0, 0, 0); + check_complex ("catanh (-inf - 100 i) == -0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, -100)), BUILD_COMPLEX (minus_zero, -M_PI_2l), 0, 0, 0); + + check_complex ("catanh (inf + 0 i) == 0.0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("catanh (inf - 0 i) == 0.0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + check_complex ("catanh (inf + 0.5 i) == 0.0 + pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, 0.5)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, 0); + check_complex ("catanh (inf - 0.5 i) == 0.0 - pi/2 i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, -0.5)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, 0); + + check_complex ("catanh (0 + NaN i) == 0.0 + NaN i", FUNC(catanh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0); + check_complex ("catanh (-0 + NaN i) == -0 + NaN i", FUNC(catanh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0); + + check_complex ("catanh (inf + NaN i) == 0.0 + NaN i", FUNC(catanh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0); + check_complex ("catanh (-inf + NaN i) == -0 + NaN i", FUNC(catanh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0); + + check_complex ("catanh (NaN + 0 i) == NaN + NaN i", FUNC(catanh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + check_complex ("catanh (NaN - 0 i) == NaN + NaN i", FUNC(catanh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("catanh (NaN + inf i) == 0.0 + pi/2 i plus sign of zero/inf not specified", FUNC(catanh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (0.0, M_PI_2l), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("catanh (NaN - inf i) == 0.0 - pi/2 i plus sign of zero/inf not specified", FUNC(catanh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (0.0, -M_PI_2l), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("catanh (10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(catanh) (BUILD_COMPLEX (10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("catanh (-10.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(catanh) (BUILD_COMPLEX (-10.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("catanh (NaN + 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(catanh) (BUILD_COMPLEX (nan_value, 0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("catanh (NaN - 0.75 i) == NaN + NaN i plus invalid exception allowed", FUNC(catanh) (BUILD_COMPLEX (nan_value, -0.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("catanh (NaN + NaN i) == NaN + NaN i", FUNC(catanh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("catanh (0.7 + 1.2 i) == 0.2600749516525135959200648705635915 + 0.97024030779509898497385130162655963 i", FUNC(catanh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.2600749516525135959200648705635915L, 0.97024030779509898497385130162655963L), DELTA340, 0, 0); + check_complex ("catanh (-2 - 3 i) == -0.14694666622552975204743278515471595 - 1.3389725222944935611241935759091443 i", FUNC(catanh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.14694666622552975204743278515471595L, -1.3389725222944935611241935759091443L), DELTA341, 0, 0); + + print_complex_max_error ("catanh", DELTAcatanh, 0); +} +#endif + +static void +cbrt_test (void) +{ + errno = 0; + FUNC(cbrt) (8); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("cbrt (0.0) == 0.0", FUNC(cbrt) (0.0), 0.0, 0, 0, 0); + check_float ("cbrt (-0) == -0", FUNC(cbrt) (minus_zero), minus_zero, 0, 0, 0); + + check_float ("cbrt (inf) == inf", FUNC(cbrt) (plus_infty), plus_infty, 0, 0, 0); + check_float ("cbrt (-inf) == -inf", FUNC(cbrt) (minus_infty), minus_infty, 0, 0, 0); + check_float ("cbrt (NaN) == NaN", FUNC(cbrt) (nan_value), nan_value, 0, 0, 0); + + check_float ("cbrt (-0.001) == -0.1", FUNC(cbrt) (-0.001L), -0.1L, DELTA347, 0, 0); + check_float ("cbrt (8) == 2", FUNC(cbrt) (8), 2, 0, 0, 0); + check_float ("cbrt (-27.0) == -3.0", FUNC(cbrt) (-27.0), -3.0, DELTA349, 0, 0); + check_float ("cbrt (0.970299) == 0.99", FUNC(cbrt) (0.970299L), 0.99L, DELTA350, 0, 0); + check_float ("cbrt (0.7) == 0.8879040017426007084", FUNC(cbrt) (0.7L), 0.8879040017426007084L, DELTA351, 0, 0); + + print_max_error ("cbrt", DELTAcbrt, 0); +} + +#if 0 /* XXX scp XXX */ +static void +ccos_test (void) +{ + errno = 0; + FUNC(ccos) (BUILD_COMPLEX (0, 0)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("ccos (0.0 + 0.0 i) == 1.0 - 0 i", FUNC(ccos) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + check_complex ("ccos (-0 + 0.0 i) == 1.0 + 0.0 i", FUNC(ccos) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("ccos (0.0 - 0 i) == 1.0 + 0.0 i", FUNC(ccos) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("ccos (-0 - 0 i) == 1.0 - 0 i", FUNC(ccos) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + + check_complex ("ccos (inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccos (inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccos (-inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccos (-inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("ccos (0.0 + inf i) == inf - 0 i", FUNC(ccos) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("ccos (0.0 - inf i) == inf + 0.0 i", FUNC(ccos) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("ccos (-0 + inf i) == inf + 0.0 i", FUNC(ccos) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("ccos (-0 - inf i) == inf - 0 i", FUNC(ccos) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("ccos (inf + inf i) == inf + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (-inf + inf i) == inf + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (inf - inf i) == inf + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (-inf - inf i) == inf + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ccos (4.625 + inf i) == -inf + inf i", FUNC(ccos) (BUILD_COMPLEX (4.625, plus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("ccos (4.625 - inf i) == -inf - inf i", FUNC(ccos) (BUILD_COMPLEX (4.625, minus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + check_complex ("ccos (-4.625 + inf i) == -inf - inf i", FUNC(ccos) (BUILD_COMPLEX (-4.625, plus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + check_complex ("ccos (-4.625 - inf i) == -inf + inf i", FUNC(ccos) (BUILD_COMPLEX (-4.625, minus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + + check_complex ("ccos (inf + 6.75 i) == NaN + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (plus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (inf - 6.75 i) == NaN + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (plus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (-inf + 6.75 i) == NaN + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (minus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccos (-inf - 6.75 i) == NaN + NaN i plus invalid exception", FUNC(ccos) (BUILD_COMPLEX (minus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ccos (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ccos (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ccos (NaN + inf i) == inf + NaN i", FUNC(ccos) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("ccos (NaN - inf i) == inf + NaN i", FUNC(ccos) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("ccos (NaN + 9.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (nan_value, 9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccos (NaN - 9.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (nan_value, -9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccos (0.0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ccos (-0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccos) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ccos (10.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccos (-10.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (-10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccos (inf + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccos (-inf + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccos) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccos (NaN + NaN i) == NaN + NaN i", FUNC(ccos) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("ccos (0.7 + 1.2 i) == 1.3848657645312111080 - 0.97242170335830028619 i", FUNC(ccos) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.3848657645312111080L, -0.97242170335830028619L), DELTA389, 0, 0); + + check_complex ("ccos (-2 - 3 i) == -4.1896256909688072301 - 9.1092278937553365979 i", FUNC(ccos) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-4.1896256909688072301L, -9.1092278937553365979L), DELTA390, 0, 0); + + print_complex_max_error ("ccos", DELTAccos, 0); +} + + +static void +ccosh_test (void) +{ + errno = 0; + FUNC(ccosh) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("ccosh (0.0 + 0.0 i) == 1.0 + 0.0 i", FUNC(ccosh) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("ccosh (-0 + 0.0 i) == 1.0 - 0 i", FUNC(ccosh) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + check_complex ("ccosh (0.0 - 0 i) == 1.0 - 0 i", FUNC(ccosh) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + check_complex ("ccosh (-0 - 0 i) == 1.0 + 0.0 i", FUNC(ccosh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + + check_complex ("ccosh (0.0 + inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccosh (-0 + inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccosh (0.0 - inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("ccosh (-0 - inf i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("ccosh (inf + 0.0 i) == inf + 0.0 i", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("ccosh (-inf + 0.0 i) == inf - 0 i", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("ccosh (inf - 0 i) == inf - 0 i", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("ccosh (-inf - 0 i) == inf + 0.0 i", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + + check_complex ("ccosh (inf + inf i) == inf + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (-inf + inf i) == inf + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (inf - inf i) == inf + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (-inf - inf i) == inf + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ccosh (inf + 4.625 i) == -inf - inf i", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, 4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + check_complex ("ccosh (-inf + 4.625 i) == -inf + inf i", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, 4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("ccosh (inf - 4.625 i) == -inf + inf i", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, -4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("ccosh (-inf - 4.625 i) == -inf - inf i", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, -4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + + check_complex ("ccosh (6.75 + inf i) == NaN + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (-6.75 + inf i) == NaN + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (-6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (6.75 - inf i) == NaN + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ccosh (-6.75 - inf i) == NaN + NaN i plus invalid exception", FUNC(ccosh) (BUILD_COMPLEX (-6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ccosh (0.0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ccosh (-0 + NaN i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ccosh (inf + NaN i) == inf + NaN i", FUNC(ccosh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("ccosh (-inf + NaN i) == inf + NaN i", FUNC(ccosh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("ccosh (9.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccosh (-9.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (-9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccosh (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ccosh (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(ccosh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ccosh (NaN + 10.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (nan_value, 10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccosh (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccosh (NaN + inf i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ccosh (NaN - inf i) == NaN + NaN i plus invalid exception allowed", FUNC(ccosh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ccosh (NaN + NaN i) == NaN + NaN i", FUNC(ccosh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("ccosh (0.7 + 1.2 i) == 0.4548202223691477654 + 0.7070296600921537682 i", FUNC(ccosh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.4548202223691477654L, 0.7070296600921537682L), DELTA428, 0, 0); + + check_complex ("ccosh (-2 - 3 i) == -3.7245455049153225654 + 0.5118225699873846088 i", FUNC(ccosh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-3.7245455049153225654L, 0.5118225699873846088L), DELTA429, 0, 0); + + print_complex_max_error ("ccosh", DELTAccosh, 0); +} +#endif + + +static void +ceil_test (void) +{ + init_max_error (); + + check_float ("ceil (0.0) == 0.0", FUNC(ceil) (0.0), 0.0, 0, 0, 0); + check_float ("ceil (-0) == -0", FUNC(ceil) (minus_zero), minus_zero, 0, 0, 0); + check_float ("ceil (inf) == inf", FUNC(ceil) (plus_infty), plus_infty, 0, 0, 0); + check_float ("ceil (-inf) == -inf", FUNC(ceil) (minus_infty), minus_infty, 0, 0, 0); + check_float ("ceil (NaN) == NaN", FUNC(ceil) (nan_value), nan_value, 0, 0, 0); + + check_float ("ceil (pi) == 4.0", FUNC(ceil) (M_PIl), 4.0, 0, 0, 0); + check_float ("ceil (-pi) == -3.0", FUNC(ceil) (-M_PIl), -3.0, 0, 0, 0); + + print_max_error ("ceil", 0, 0); +} + + +#if 0 /* XXX scp XXX */ +static void +cexp_test (void) +{ + errno = 0; + FUNC(cexp) (BUILD_COMPLEX (0, 0)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("cexp (+0 + +0 i) == 1 + 0.0 i", FUNC(cexp) (BUILD_COMPLEX (plus_zero, plus_zero)), BUILD_COMPLEX (1, 0.0), 0, 0, 0); + check_complex ("cexp (-0 + +0 i) == 1 + 0.0 i", FUNC(cexp) (BUILD_COMPLEX (minus_zero, plus_zero)), BUILD_COMPLEX (1, 0.0), 0, 0, 0); + check_complex ("cexp (+0 - 0 i) == 1 - 0 i", FUNC(cexp) (BUILD_COMPLEX (plus_zero, minus_zero)), BUILD_COMPLEX (1, minus_zero), 0, 0, 0); + check_complex ("cexp (-0 - 0 i) == 1 - 0 i", FUNC(cexp) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (1, minus_zero), 0, 0, 0); + + check_complex ("cexp (inf + +0 i) == inf + 0.0 i", FUNC(cexp) (BUILD_COMPLEX (plus_infty, plus_zero)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("cexp (inf - 0 i) == inf - 0 i", FUNC(cexp) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("cexp (-inf + +0 i) == 0.0 + 0.0 i", FUNC(cexp) (BUILD_COMPLEX (minus_infty, plus_zero)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("cexp (-inf - 0 i) == 0.0 - 0 i", FUNC(cexp) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + + check_complex ("cexp (0.0 + inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("cexp (-0 + inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("cexp (0.0 - inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("cexp (-0 - inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("cexp (100.0 + inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (100.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("cexp (-100.0 + inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (-100.0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("cexp (100.0 - inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (100.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("cexp (-100.0 - inf i) == NaN + NaN i plus invalid exception", FUNC(cexp) (BUILD_COMPLEX (-100.0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("cexp (-inf + 2.0 i) == -0 + 0.0 i", FUNC(cexp) (BUILD_COMPLEX (minus_infty, 2.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("cexp (-inf + 4.0 i) == -0 - 0 i", FUNC(cexp) (BUILD_COMPLEX (minus_infty, 4.0)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + check_complex ("cexp (inf + 2.0 i) == -inf + inf i", FUNC(cexp) (BUILD_COMPLEX (plus_infty, 2.0)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("cexp (inf + 4.0 i) == -inf - inf i", FUNC(cexp) (BUILD_COMPLEX (plus_infty, 4.0)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + + check_complex ("cexp (inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(cexp) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("cexp (inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(cexp) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("cexp (-inf + inf i) == 0.0 + 0.0 i plus sign of zero/inf not specified", FUNC(cexp) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (0.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("cexp (-inf - inf i) == 0.0 - 0 i plus sign of zero/inf not specified", FUNC(cexp) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("cexp (-inf + NaN i) == 0 + 0 i plus sign of zero/inf not specified", FUNC(cexp) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (0, 0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("cexp (inf + NaN i) == inf + NaN i", FUNC(cexp) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("cexp (NaN + 0.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(cexp) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cexp (NaN + 1.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(cexp) (BUILD_COMPLEX (nan_value, 1.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("cexp (NaN + inf i) == NaN + NaN i plus invalid exception allowed", FUNC(cexp) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cexp (0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cexp) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cexp (1 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(cexp) (BUILD_COMPLEX (1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("cexp (NaN + NaN i) == NaN + NaN i", FUNC(cexp) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("cexp (0.7 + 1.2 i) == 0.72969890915032360123451688642930727 + 1.8768962328348102821139467908203072 i", FUNC(cexp) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.72969890915032360123451688642930727L, 1.8768962328348102821139467908203072L), DELTA469, 0, 0); + check_complex ("cexp (-2.0 - 3.0 i) == -0.13398091492954261346140525546115575 - 0.019098516261135196432576240858800925 i", FUNC(cexp) (BUILD_COMPLEX (-2.0, -3.0)), BUILD_COMPLEX (-0.13398091492954261346140525546115575L, -0.019098516261135196432576240858800925L), DELTA470, 0, 0); + + print_complex_max_error ("cexp", DELTAcexp, 0); +} + +static void +cimag_test (void) +{ + init_max_error (); + check_float ("cimag (1.0 + 0.0 i) == 0.0", FUNC(cimag) (BUILD_COMPLEX (1.0, 0.0)), 0.0, 0, 0, 0); + check_float ("cimag (1.0 - 0 i) == -0", FUNC(cimag) (BUILD_COMPLEX (1.0, minus_zero)), minus_zero, 0, 0, 0); + check_float ("cimag (1.0 + NaN i) == NaN", FUNC(cimag) (BUILD_COMPLEX (1.0, nan_value)), nan_value, 0, 0, 0); + check_float ("cimag (NaN + NaN i) == NaN", FUNC(cimag) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0); + check_float ("cimag (1.0 + inf i) == inf", FUNC(cimag) (BUILD_COMPLEX (1.0, plus_infty)), plus_infty, 0, 0, 0); + check_float ("cimag (1.0 - inf i) == -inf", FUNC(cimag) (BUILD_COMPLEX (1.0, minus_infty)), minus_infty, 0, 0, 0); + check_float ("cimag (2.0 + 3.0 i) == 3.0", FUNC(cimag) (BUILD_COMPLEX (2.0, 3.0)), 3.0, 0, 0, 0); + + print_max_error ("cimag", 0, 0); +} + +static void +clog_test (void) +{ + errno = 0; + FUNC(clog) (BUILD_COMPLEX (-2, -3)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("clog (-0 + 0 i) == -inf + pi i plus division by zero exception", FUNC(clog) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_infty, M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_complex ("clog (-0 - 0 i) == -inf - pi i plus division by zero exception", FUNC(clog) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_infty, -M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_complex ("clog (0 + 0 i) == -inf + 0.0 i plus division by zero exception", FUNC(clog) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_complex ("clog (0 - 0 i) == -inf - 0 i plus division by zero exception", FUNC(clog) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_complex ("clog (-inf + inf i) == inf + 3/4 pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34l), 0, 0, 0); + check_complex ("clog (-inf - inf i) == inf - 3/4 pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_34l), 0, 0, 0); + + check_complex ("clog (inf + inf i) == inf + pi/4 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_4l), 0, 0, 0); + check_complex ("clog (inf - inf i) == inf - pi/4 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_4l), 0, 0, 0); + + check_complex ("clog (0 + inf i) == inf + pi/2 i", FUNC(clog) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("clog (3 + inf i) == inf + pi/2 i", FUNC(clog) (BUILD_COMPLEX (3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("clog (-0 + inf i) == inf + pi/2 i", FUNC(clog) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("clog (-3 + inf i) == inf + pi/2 i", FUNC(clog) (BUILD_COMPLEX (-3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_2l), 0, 0, 0); + check_complex ("clog (0 - inf i) == inf - pi/2 i", FUNC(clog) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("clog (3 - inf i) == inf - pi/2 i", FUNC(clog) (BUILD_COMPLEX (3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("clog (-0 - inf i) == inf - pi/2 i", FUNC(clog) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + check_complex ("clog (-3 - inf i) == inf - pi/2 i", FUNC(clog) (BUILD_COMPLEX (-3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI_2l), 0, 0, 0); + + check_complex ("clog (-inf + 0 i) == inf + pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0); + check_complex ("clog (-inf + 1 i) == inf + pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (plus_infty, M_PIl), 0, 0, 0); + check_complex ("clog (-inf - 0 i) == inf - pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0); + check_complex ("clog (-inf - 1 i) == inf - pi i", FUNC(clog) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (plus_infty, -M_PIl), 0, 0, 0); + + check_complex ("clog (inf + 0 i) == inf + 0.0 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("clog (inf + 1 i) == inf + 0.0 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("clog (inf - 0 i) == inf - 0 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("clog (inf - 1 i) == inf - 0 i", FUNC(clog) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("clog (inf + NaN i) == inf + NaN i", FUNC(clog) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("clog (-inf + NaN i) == inf + NaN i", FUNC(clog) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("clog (NaN + inf i) == inf + NaN i", FUNC(clog) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("clog (NaN - inf i) == inf + NaN i", FUNC(clog) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("clog (0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (3 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (-0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (-3 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (-3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("clog (NaN + 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (NaN + 5 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (NaN - 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog (NaN - 5 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog) (BUILD_COMPLEX (nan_value, -5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("clog (NaN + NaN i) == NaN + NaN i", FUNC(clog) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + check_complex ("clog (-2 - 3 i) == 1.2824746787307683680267437207826593 - 2.1587989303424641704769327722648368 i", FUNC(clog) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (1.2824746787307683680267437207826593L, -2.1587989303424641704769327722648368L), DELTA515, 0, 0); + + print_complex_max_error ("clog", DELTAclog, 0); +} + + +static void +clog10_test (void) +{ + errno = 0; + FUNC(clog10) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("clog10 (-0 + 0 i) == -inf + pi i plus division by zero exception", FUNC(clog10) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_infty, M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_complex ("clog10 (-0 - 0 i) == -inf - pi i plus division by zero exception", FUNC(clog10) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_infty, -M_PIl), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_complex ("clog10 (0 + 0 i) == -inf + 0.0 i plus division by zero exception", FUNC(clog10) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_complex ("clog10 (0 - 0 i) == -inf - 0 i plus division by zero exception", FUNC(clog10) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_complex ("clog10 (-inf + inf i) == inf + 3/4 pi*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI_34_LOG10El), DELTA520, 0, 0); + + check_complex ("clog10 (inf + inf i) == inf + pi/4*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI4_LOG10El), DELTA521, 0, 0); + check_complex ("clog10 (inf - inf i) == inf - pi/4*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI4_LOG10El), DELTA522, 0, 0); + + check_complex ("clog10 (0 + inf i) == inf + pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA523, 0, 0); + check_complex ("clog10 (3 + inf i) == inf + pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA524, 0, 0); + check_complex ("clog10 (-0 + inf i) == inf + pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA525, 0, 0); + check_complex ("clog10 (-3 + inf i) == inf + pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (-3, plus_infty)), BUILD_COMPLEX (plus_infty, M_PI2_LOG10El), DELTA526, 0, 0); + check_complex ("clog10 (0 - inf i) == inf - pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA527, 0, 0); + check_complex ("clog10 (3 - inf i) == inf - pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA528, 0, 0); + check_complex ("clog10 (-0 - inf i) == inf - pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA529, 0, 0); + check_complex ("clog10 (-3 - inf i) == inf - pi/2*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (-3, minus_infty)), BUILD_COMPLEX (plus_infty, -M_PI2_LOG10El), DELTA530, 0, 0); + + check_complex ("clog10 (-inf + 0 i) == inf + pi*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (plus_infty, M_PI_LOG10El), DELTA531, 0, 0); + check_complex ("clog10 (-inf + 1 i) == inf + pi*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (plus_infty, M_PI_LOG10El), DELTA532, 0, 0); + check_complex ("clog10 (-inf - 0 i) == inf - pi*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, -M_PI_LOG10El), DELTA533, 0, 0); + check_complex ("clog10 (-inf - 1 i) == inf - pi*log10(e) i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (plus_infty, -M_PI_LOG10El), DELTA534, 0, 0); + + check_complex ("clog10 (inf + 0 i) == inf + 0.0 i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("clog10 (inf + 1 i) == inf + 0.0 i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("clog10 (inf - 0 i) == inf - 0 i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("clog10 (inf - 1 i) == inf - 0 i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("clog10 (inf + NaN i) == inf + NaN i", FUNC(clog10) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("clog10 (-inf + NaN i) == inf + NaN i", FUNC(clog10) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("clog10 (NaN + inf i) == inf + NaN i", FUNC(clog10) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + check_complex ("clog10 (NaN - inf i) == inf + NaN i", FUNC(clog10) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("clog10 (0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (3 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (-0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (-3 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (-3, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("clog10 (NaN + 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (NaN + 5 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (NaN - 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("clog10 (NaN - 5 i) == NaN + NaN i plus invalid exception allowed", FUNC(clog10) (BUILD_COMPLEX (nan_value, -5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("clog10 (NaN + NaN i) == NaN + NaN i", FUNC(clog10) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("clog10 (0.7 + 1.2 i) == 0.1427786545038868803 + 0.4528483579352493248 i", FUNC(clog10) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.1427786545038868803L, 0.4528483579352493248L), DELTA552, 0, 0); + check_complex ("clog10 (-2 - 3 i) == 0.5569716761534183846 - 0.9375544629863747085 i", FUNC(clog10) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.5569716761534183846L, -0.9375544629863747085L), DELTA553, 0, 0); + + print_complex_max_error ("clog10", DELTAclog10, 0); +} + +static void +conj_test (void) +{ + init_max_error (); + check_complex ("conj (0.0 + 0.0 i) == 0.0 - 0 i", FUNC(conj) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("conj (0.0 - 0 i) == 0.0 + 0.0 i", FUNC(conj) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("conj (NaN + NaN i) == NaN + NaN i", FUNC(conj) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + check_complex ("conj (inf - inf i) == inf + inf i", FUNC(conj) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("conj (inf + inf i) == inf - inf i", FUNC(conj) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("conj (1.0 + 2.0 i) == 1.0 - 2.0 i", FUNC(conj) (BUILD_COMPLEX (1.0, 2.0)), BUILD_COMPLEX (1.0, -2.0), 0, 0, 0); + check_complex ("conj (3.0 - 4.0 i) == 3.0 + 4.0 i", FUNC(conj) (BUILD_COMPLEX (3.0, -4.0)), BUILD_COMPLEX (3.0, 4.0), 0, 0, 0); + + print_complex_max_error ("conj", 0, 0); +} +#endif + + +static void +copysign_test (void) +{ + init_max_error (); + + check_float ("copysign (0, 4) == 0", FUNC(copysign) (0, 4), 0, 0, 0, 0); + check_float ("copysign (0, -4) == -0", FUNC(copysign) (0, -4), minus_zero, 0, 0, 0); + check_float ("copysign (-0, 4) == 0", FUNC(copysign) (minus_zero, 4), 0, 0, 0, 0); + check_float ("copysign (-0, -4) == -0", FUNC(copysign) (minus_zero, -4), minus_zero, 0, 0, 0); + + check_float ("copysign (inf, 0) == inf", FUNC(copysign) (plus_infty, 0), plus_infty, 0, 0, 0); + check_float ("copysign (inf, -0) == -inf", FUNC(copysign) (plus_infty, minus_zero), minus_infty, 0, 0, 0); + check_float ("copysign (-inf, 0) == inf", FUNC(copysign) (minus_infty, 0), plus_infty, 0, 0, 0); + check_float ("copysign (-inf, -0) == -inf", FUNC(copysign) (minus_infty, minus_zero), minus_infty, 0, 0, 0); + + check_float ("copysign (0, inf) == 0", FUNC(copysign) (0, plus_infty), 0, 0, 0, 0); + check_float ("copysign (0, -0) == -0", FUNC(copysign) (0, minus_zero), minus_zero, 0, 0, 0); + check_float ("copysign (-0, inf) == 0", FUNC(copysign) (minus_zero, plus_infty), 0, 0, 0, 0); + check_float ("copysign (-0, -0) == -0", FUNC(copysign) (minus_zero, minus_zero), minus_zero, 0, 0, 0); + + /* XXX More correctly we would have to check the sign of the NaN. */ + check_float ("copysign (NaN, 0) == NaN", FUNC(copysign) (nan_value, 0), nan_value, 0, 0, 0); + check_float ("copysign (NaN, -0) == NaN", FUNC(copysign) (nan_value, minus_zero), nan_value, 0, 0, 0); + check_float ("copysign (-NaN, 0) == NaN", FUNC(copysign) (-nan_value, 0), nan_value, 0, 0, 0); + check_float ("copysign (-NaN, -0) == NaN", FUNC(copysign) (-nan_value, minus_zero), nan_value, 0, 0, 0); + + print_max_error ("copysign", 0, 0); +} + +static void +cos_test (void) +{ + errno = 0; + FUNC(cos) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("cos (0) == 1", FUNC(cos) (0), 1, 0, 0, 0); + check_float ("cos (-0) == 1", FUNC(cos) (minus_zero), 1, 0, 0, 0); + check_float ("cos (inf) == NaN plus invalid exception", FUNC(cos) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("cos (-inf) == NaN plus invalid exception", FUNC(cos) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("cos (NaN) == NaN", FUNC(cos) (nan_value), nan_value, 0, 0, 0); + + check_float ("cos (M_PI_6l * 2.0) == 0.5", FUNC(cos) (M_PI_6l * 2.0), 0.5, DELTA582, 0, 0); + check_float ("cos (M_PI_6l * 4.0) == -0.5", FUNC(cos) (M_PI_6l * 4.0), -0.5, DELTA583, 0, 0); + check_float ("cos (pi/2) == 0", FUNC(cos) (M_PI_2l), 0, DELTA584, 0, 0); + + check_float ("cos (0.7) == 0.76484218728448842625585999019186495", FUNC(cos) (0.7L), 0.76484218728448842625585999019186495L, DELTA585, 0, 0); + + print_max_error ("cos", DELTAcos, 0); +} + +static void +cosh_test (void) +{ + errno = 0; + FUNC(cosh) (0.7L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + check_float ("cosh (0) == 1", FUNC(cosh) (0), 1, 0, 0, 0); + check_float ("cosh (-0) == 1", FUNC(cosh) (minus_zero), 1, 0, 0, 0); + +#ifndef TEST_INLINE + check_float ("cosh (inf) == inf", FUNC(cosh) (plus_infty), plus_infty, 0, 0, 0); + check_float ("cosh (-inf) == inf", FUNC(cosh) (minus_infty), plus_infty, 0, 0, 0); +#endif + check_float ("cosh (NaN) == NaN", FUNC(cosh) (nan_value), nan_value, 0, 0, 0); + + check_float ("cosh (0.7) == 1.255169005630943018", FUNC(cosh) (0.7L), 1.255169005630943018L, DELTA591, 0, 0); + print_max_error ("cosh", DELTAcosh, 0); +} + + +#if 0 /* XXX scp XXX */ +static void +cpow_test (void) +{ + errno = 0; + FUNC(cpow) (BUILD_COMPLEX (1, 0), BUILD_COMPLEX (0, 0)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("cpow (1 + 0 i, 0 + 0 i) == 1.0 + 0.0 i", FUNC(cpow) (BUILD_COMPLEX (1, 0), BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("cpow (2 + 0 i, 10 + 0 i) == 1024.0 + 0.0 i", FUNC(cpow) (BUILD_COMPLEX (2, 0), BUILD_COMPLEX (10, 0)), BUILD_COMPLEX (1024.0, 0.0), 0, 0, 0); + + check_complex ("cpow (e + 0 i, 0 + 2 * M_PIl i) == 1.0 + 0.0 i", FUNC(cpow) (BUILD_COMPLEX (M_El, 0), BUILD_COMPLEX (0, 2 * M_PIl)), BUILD_COMPLEX (1.0, 0.0), DELTA594, 0, 0); + check_complex ("cpow (2 + 3 i, 4 + 0 i) == -119.0 - 120.0 i", FUNC(cpow) (BUILD_COMPLEX (2, 3), BUILD_COMPLEX (4, 0)), BUILD_COMPLEX (-119.0, -120.0), DELTA595, 0, 0); + + check_complex ("cpow (NaN + NaN i, NaN + NaN i) == NaN + NaN i", FUNC(cpow) (BUILD_COMPLEX (nan_value, nan_value), BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + print_complex_max_error ("cpow", DELTAcpow, 0); +} + +static void +cproj_test (void) +{ + init_max_error (); + check_complex ("cproj (0.0 + 0.0 i) == 0.0 + 0.0 i", FUNC(cproj) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("cproj (-0 - 0 i) == -0 - 0 i", FUNC(cproj) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + check_complex ("cproj (0.0 - 0 i) == 0.0 - 0 i", FUNC(cproj) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("cproj (-0 + 0.0 i) == -0 + 0.0 i", FUNC(cproj) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + + check_complex ("cproj (NaN + NaN i) == NaN + NaN i", FUNC(cproj) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("cproj (inf + inf i) == inf + 0.0 i", FUNC(cproj) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("cproj (inf - inf i) == inf - 0 i", FUNC(cproj) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("cproj (-inf + inf i) == inf + 0.0 i", FUNC(cproj) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("cproj (-inf - inf i) == inf - 0 i", FUNC(cproj) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("cproj (1.0 + 0.0 i) == 1.0 + 0.0 i", FUNC(cproj) (BUILD_COMPLEX (1.0, 0.0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("cproj (2.0 + 3.0 i) == 0.2857142857142857142857142857142857 + 0.42857142857142857142857142857142855 i", FUNC(cproj) (BUILD_COMPLEX (2.0, 3.0)), BUILD_COMPLEX (0.2857142857142857142857142857142857L, 0.42857142857142857142857142857142855L), 0, 0, 0); + + print_complex_max_error ("cproj", 0, 0); +} + +static void +creal_test (void) +{ + init_max_error (); + check_float ("creal (0.0 + 1.0 i) == 0.0", FUNC(creal) (BUILD_COMPLEX (0.0, 1.0)), 0.0, 0, 0, 0); + check_float ("creal (-0 + 1.0 i) == -0", FUNC(creal) (BUILD_COMPLEX (minus_zero, 1.0)), minus_zero, 0, 0, 0); + check_float ("creal (NaN + 1.0 i) == NaN", FUNC(creal) (BUILD_COMPLEX (nan_value, 1.0)), nan_value, 0, 0, 0); + check_float ("creal (NaN + NaN i) == NaN", FUNC(creal) (BUILD_COMPLEX (nan_value, nan_value)), nan_value, 0, 0, 0); + check_float ("creal (inf + 1.0 i) == inf", FUNC(creal) (BUILD_COMPLEX (plus_infty, 1.0)), plus_infty, 0, 0, 0); + check_float ("creal (-inf + 1.0 i) == -inf", FUNC(creal) (BUILD_COMPLEX (minus_infty, 1.0)), minus_infty, 0, 0, 0); + check_float ("creal (2.0 + 3.0 i) == 2.0", FUNC(creal) (BUILD_COMPLEX (2.0, 3.0)), 2.0, 0, 0, 0); + + print_max_error ("creal", 0, 0); +} + +static void +csin_test (void) +{ + errno = 0; + FUNC(csin) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("csin (0.0 + 0.0 i) == 0.0 + 0.0 i", FUNC(csin) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("csin (-0 + 0.0 i) == -0 + 0.0 i", FUNC(csin) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("csin (0.0 - 0 i) == 0 - 0 i", FUNC(csin) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0); + check_complex ("csin (-0 - 0 i) == -0 - 0 i", FUNC(csin) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("csin (0.0 + inf i) == 0.0 + inf i", FUNC(csin) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("csin (-0 + inf i) == -0 + inf i", FUNC(csin) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, plus_infty), 0, 0, 0); + check_complex ("csin (0.0 - inf i) == 0.0 - inf i", FUNC(csin) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + check_complex ("csin (-0 - inf i) == -0 - inf i", FUNC(csin) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, minus_infty), 0, 0, 0); + + check_complex ("csin (inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (-inf + 0.0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (-inf - 0 i) == NaN + 0.0 i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("csin (inf + inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (-inf + inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (inf - inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csin (-inf - inf i) == NaN + inf i plus invalid exception and sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("csin (inf + 6.75 i) == NaN + NaN i plus invalid exception", FUNC(csin) (BUILD_COMPLEX (plus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csin (inf - 6.75 i) == NaN + NaN i plus invalid exception", FUNC(csin) (BUILD_COMPLEX (plus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csin (-inf + 6.75 i) == NaN + NaN i plus invalid exception", FUNC(csin) (BUILD_COMPLEX (minus_infty, 6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csin (-inf - 6.75 i) == NaN + NaN i plus invalid exception", FUNC(csin) (BUILD_COMPLEX (minus_infty, -6.75)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("csin (4.625 + inf i) == -inf - inf i", FUNC(csin) (BUILD_COMPLEX (4.625, plus_infty)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + check_complex ("csin (4.625 - inf i) == -inf + inf i", FUNC(csin) (BUILD_COMPLEX (4.625, minus_infty)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("csin (-4.625 + inf i) == inf - inf i", FUNC(csin) (BUILD_COMPLEX (-4.625, plus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csin (-4.625 - inf i) == inf + inf i", FUNC(csin) (BUILD_COMPLEX (-4.625, minus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + + check_complex ("csin (NaN + 0.0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("csin (NaN - 0 i) == NaN + 0.0 i plus sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("csin (NaN + inf i) == NaN + inf i plus sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("csin (NaN - inf i) == NaN + inf i plus sign of zero/inf not specified", FUNC(csin) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("csin (NaN + 9.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (nan_value, 9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csin (NaN - 9.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (nan_value, -9.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csin (0.0 + NaN i) == 0.0 + NaN i", FUNC(csin) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0); + check_complex ("csin (-0 + NaN i) == -0 + NaN i", FUNC(csin) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0); + + check_complex ("csin (10.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (10.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csin (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csin (inf + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csin (-inf + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csin) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csin (NaN + NaN i) == NaN + NaN i", FUNC(csin) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("csin (0.7 + 1.2 i) == 1.1664563419657581376 + 1.1544997246948547371 i", FUNC(csin) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.1664563419657581376L, 1.1544997246948547371L), DELTA652, 0, 0); + + check_complex ("csin (-2 - 3 i) == -9.1544991469114295734 + 4.1689069599665643507 i", FUNC(csin) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-9.1544991469114295734L, 4.1689069599665643507L), 0, 0, 0); + + print_complex_max_error ("csin", DELTAcsin, 0); +} + + +static void +csinh_test (void) +{ + errno = 0; + FUNC(csinh) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("csinh (0.0 + 0.0 i) == 0.0 + 0.0 i", FUNC(csinh) (BUILD_COMPLEX (0.0, 0.0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("csinh (-0 + 0.0 i) == -0 + 0.0 i", FUNC(csinh) (BUILD_COMPLEX (minus_zero, 0.0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("csinh (0.0 - 0 i) == 0.0 - 0 i", FUNC(csinh) (BUILD_COMPLEX (0.0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("csinh (-0 - 0 i) == -0 - 0 i", FUNC(csinh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("csinh (0.0 + inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (0.0, plus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-0 + inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (0.0 - inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (0.0, minus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-0 - inf i) == 0.0 + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (0.0, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("csinh (inf + 0.0 i) == inf + 0.0 i", FUNC(csinh) (BUILD_COMPLEX (plus_infty, 0.0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("csinh (-inf + 0.0 i) == -inf + 0.0 i", FUNC(csinh) (BUILD_COMPLEX (minus_infty, 0.0)), BUILD_COMPLEX (minus_infty, 0.0), 0, 0, 0); + check_complex ("csinh (inf - 0 i) == inf - 0 i", FUNC(csinh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("csinh (-inf - 0 i) == -inf - 0 i", FUNC(csinh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (minus_infty, minus_zero), 0, 0, 0); + + check_complex ("csinh (inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-inf + inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-inf - inf i) == inf + NaN i plus invalid exception and sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN); + + check_complex ("csinh (inf + 4.625 i) == -inf - inf i", FUNC(csinh) (BUILD_COMPLEX (plus_infty, 4.625)), BUILD_COMPLEX (minus_infty, minus_infty), 0, 0, 0); + check_complex ("csinh (-inf + 4.625 i) == inf - inf i", FUNC(csinh) (BUILD_COMPLEX (minus_infty, 4.625)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csinh (inf - 4.625 i) == -inf + inf i", FUNC(csinh) (BUILD_COMPLEX (plus_infty, -4.625)), BUILD_COMPLEX (minus_infty, plus_infty), 0, 0, 0); + check_complex ("csinh (-inf - 4.625 i) == inf + inf i", FUNC(csinh) (BUILD_COMPLEX (minus_infty, -4.625)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + + check_complex ("csinh (6.75 + inf i) == NaN + NaN i plus invalid exception", FUNC(csinh) (BUILD_COMPLEX (6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csinh (-6.75 + inf i) == NaN + NaN i plus invalid exception", FUNC(csinh) (BUILD_COMPLEX (-6.75, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csinh (6.75 - inf i) == NaN + NaN i plus invalid exception", FUNC(csinh) (BUILD_COMPLEX (6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("csinh (-6.75 - inf i) == NaN + NaN i plus invalid exception", FUNC(csinh) (BUILD_COMPLEX (-6.75, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("csinh (0.0 + NaN i) == 0.0 + NaN i plus sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (0.0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-0 + NaN i) == 0.0 + NaN i plus sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("csinh (inf + NaN i) == inf + NaN i plus sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("csinh (-inf + NaN i) == inf + NaN i plus sign of zero/inf not specified", FUNC(csinh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("csinh (9.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csinh (-9.0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (-9.0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csinh (NaN + 0.0 i) == NaN + 0.0 i", FUNC(csinh) (BUILD_COMPLEX (nan_value, 0.0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0); + check_complex ("csinh (NaN - 0 i) == NaN - 0 i", FUNC(csinh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0); + + check_complex ("csinh (NaN + 10.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (nan_value, 10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csinh (NaN - 10.0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (nan_value, -10.0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csinh (NaN + inf i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csinh (NaN - inf i) == NaN + NaN i plus invalid exception allowed", FUNC(csinh) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csinh (NaN + NaN i) == NaN + NaN i", FUNC(csinh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("csinh (0.7 + 1.2 i) == 0.27487868678117583582 + 1.1698665727426565139 i", FUNC(csinh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.27487868678117583582L, 1.1698665727426565139L), DELTA691, 0, 0); + check_complex ("csinh (-2 - 3 i) == 3.5905645899857799520 - 0.5309210862485198052 i", FUNC(csinh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (3.5905645899857799520L, -0.5309210862485198052L), DELTA692, 0, 0); + + print_complex_max_error ("csinh", DELTAcsinh, 0); +} + +static void +csqrt_test (void) +{ + errno = 0; + FUNC(csqrt) (BUILD_COMPLEX (-1, 0)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("csqrt (0 + 0 i) == 0.0 + 0.0 i", FUNC(csqrt) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("csqrt (0 - 0 i) == 0 - 0 i", FUNC(csqrt) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0, minus_zero), 0, 0, 0); + check_complex ("csqrt (-0 + 0 i) == 0.0 + 0.0 i", FUNC(csqrt) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("csqrt (-0 - 0 i) == 0.0 - 0 i", FUNC(csqrt) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + + check_complex ("csqrt (-inf + 0 i) == 0.0 + inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("csqrt (-inf + 6 i) == 0.0 + inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, 6)), BUILD_COMPLEX (0.0, plus_infty), 0, 0, 0); + check_complex ("csqrt (-inf - 0 i) == 0.0 - inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + check_complex ("csqrt (-inf - 6 i) == 0.0 - inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, -6)), BUILD_COMPLEX (0.0, minus_infty), 0, 0, 0); + + check_complex ("csqrt (inf + 0 i) == inf + 0.0 i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("csqrt (inf + 6 i) == inf + 0.0 i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, 6)), BUILD_COMPLEX (plus_infty, 0.0), 0, 0, 0); + check_complex ("csqrt (inf - 0 i) == inf - 0 i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + check_complex ("csqrt (inf - 6 i) == inf - 0 i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, -6)), BUILD_COMPLEX (plus_infty, minus_zero), 0, 0, 0); + + check_complex ("csqrt (0 + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (4 + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (4, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (inf + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (-0 + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (-4 + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (-4, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (-inf + inf i) == inf + inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, plus_infty)), BUILD_COMPLEX (plus_infty, plus_infty), 0, 0, 0); + check_complex ("csqrt (0 - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csqrt (4 - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (4, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csqrt (inf - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csqrt (-0 - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csqrt (-4 - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (-4, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + check_complex ("csqrt (-inf - inf i) == inf - inf i", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, minus_infty)), BUILD_COMPLEX (plus_infty, minus_infty), 0, 0, 0); + + check_complex ("csqrt (-inf + NaN i) == NaN + inf i plus sign of zero/inf not specified", FUNC(csqrt) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (nan_value, plus_infty), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("csqrt (inf + NaN i) == inf + NaN i", FUNC(csqrt) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (plus_infty, nan_value), 0, 0, 0); + + check_complex ("csqrt (0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (1 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (-0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (-1 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (-1, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csqrt (NaN + 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (NaN + 8 i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (nan_value, 8)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (NaN - 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("csqrt (NaN - 8 i) == NaN + NaN i plus invalid exception allowed", FUNC(csqrt) (BUILD_COMPLEX (nan_value, -8)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("csqrt (NaN + NaN i) == NaN + NaN i", FUNC(csqrt) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("csqrt (16.0 - 30.0 i) == 5.0 - 3.0 i", FUNC(csqrt) (BUILD_COMPLEX (16.0, -30.0)), BUILD_COMPLEX (5.0, -3.0), 0, 0, 0); + check_complex ("csqrt (-1 + 0 i) == 0.0 + 1.0 i", FUNC(csqrt) (BUILD_COMPLEX (-1, 0)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0); + check_complex ("csqrt (0 + 2 i) == 1.0 + 1.0 i", FUNC(csqrt) (BUILD_COMPLEX (0, 2)), BUILD_COMPLEX (1.0, 1.0), 0, 0, 0); + check_complex ("csqrt (119 + 120 i) == 12.0 + 5.0 i", FUNC(csqrt) (BUILD_COMPLEX (119, 120)), BUILD_COMPLEX (12.0, 5.0), 0, 0, 0); + check_complex ("csqrt (0.7 + 1.2 i) == 1.022067610030026450706487883081139 + 0.58704531296356521154977678719838035 i", FUNC(csqrt) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.022067610030026450706487883081139L, 0.58704531296356521154977678719838035L), DELTA732, 0, 0); + check_complex ("csqrt (-2 - 3 i) == 0.89597747612983812471573375529004348 - 1.6741492280355400404480393008490519 i", FUNC(csqrt) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.89597747612983812471573375529004348L, -1.6741492280355400404480393008490519L), DELTA733, 0, 0); + check_complex ("csqrt (-2 + 3 i) == 0.89597747612983812471573375529004348 + 1.6741492280355400404480393008490519 i", FUNC(csqrt) (BUILD_COMPLEX (-2, 3)), BUILD_COMPLEX (0.89597747612983812471573375529004348L, 1.6741492280355400404480393008490519L), DELTA734, 0, 0); + + print_complex_max_error ("csqrt", DELTAcsqrt, 0); +} + +static void +ctan_test (void) +{ + errno = 0; + FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("ctan (0 + 0 i) == 0.0 + 0.0 i", FUNC(ctan) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("ctan (0 - 0 i) == 0.0 - 0 i", FUNC(ctan) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("ctan (-0 + 0 i) == -0 + 0.0 i", FUNC(ctan) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("ctan (-0 - 0 i) == -0 - 0 i", FUNC(ctan) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("ctan (0 + inf i) == 0.0 + 1.0 i", FUNC(ctan) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0); + check_complex ("ctan (1 + inf i) == 0.0 + 1.0 i", FUNC(ctan) (BUILD_COMPLEX (1, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, 0); + check_complex ("ctan (-0 + inf i) == -0 + 1.0 i", FUNC(ctan) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (minus_zero, 1.0), 0, 0, 0); + check_complex ("ctan (-1 + inf i) == -0 + 1.0 i", FUNC(ctan) (BUILD_COMPLEX (-1, plus_infty)), BUILD_COMPLEX (minus_zero, 1.0), 0, 0, 0); + + check_complex ("ctan (0 - inf i) == 0.0 - 1.0 i", FUNC(ctan) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, 0); + check_complex ("ctan (1 - inf i) == 0.0 - 1.0 i", FUNC(ctan) (BUILD_COMPLEX (1, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, 0); + check_complex ("ctan (-0 - inf i) == -0 - 1.0 i", FUNC(ctan) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (minus_zero, -1.0), 0, 0, 0); + check_complex ("ctan (-1 - inf i) == -0 - 1.0 i", FUNC(ctan) (BUILD_COMPLEX (-1, minus_infty)), BUILD_COMPLEX (minus_zero, -1.0), 0, 0, 0); + + check_complex ("ctan (inf + 0 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (inf + 2 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (plus_infty, 2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (-inf + 0 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (-inf + 2 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (minus_infty, 2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (inf - 0 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (inf - 2 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (plus_infty, -2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (-inf - 0 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctan (-inf - 2 i) == NaN + NaN i plus invalid exception", FUNC(ctan) (BUILD_COMPLEX (minus_infty, -2)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ctan (NaN + inf i) == 0.0 + 1.0 i plus sign of zero/inf not specified", FUNC(ctan) (BUILD_COMPLEX (nan_value, plus_infty)), BUILD_COMPLEX (0.0, 1.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ctan (NaN - inf i) == 0.0 - 1.0 i plus sign of zero/inf not specified", FUNC(ctan) (BUILD_COMPLEX (nan_value, minus_infty)), BUILD_COMPLEX (0.0, -1.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ctan (0 + NaN i) == 0.0 + NaN i", FUNC(ctan) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (0.0, nan_value), 0, 0, 0); + check_complex ("ctan (-0 + NaN i) == -0 + NaN i", FUNC(ctan) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (minus_zero, nan_value), 0, 0, 0); + + check_complex ("ctan (0.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (0.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctan (-4.5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (-4.5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ctan (NaN + 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctan (NaN + 5 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (nan_value, 5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctan (NaN - 0 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctan (NaN - 0.25 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctan) (BUILD_COMPLEX (nan_value, -0.25)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ctan (NaN + NaN i) == NaN + NaN i", FUNC(ctan) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("ctan (0.7 + 1.2 i) == 0.1720734197630349001 + 0.9544807059989405538 i", FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (0.1720734197630349001L, 0.9544807059989405538L), DELTA766, 0, 0); + check_complex ("ctan (-2 - 3 i) == 0.0037640256415042482 - 1.0032386273536098014 i", FUNC(ctan) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (0.0037640256415042482L, -1.0032386273536098014L), DELTA767, 0, 0); + + print_complex_max_error ("ctan", DELTActan, 0); +} + + +static void +ctanh_test (void) +{ + errno = 0; + FUNC(ctanh) (BUILD_COMPLEX (0, 0)); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_complex ("ctanh (0 + 0 i) == 0.0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (0, 0)), BUILD_COMPLEX (0.0, 0.0), 0, 0, 0); + check_complex ("ctanh (0 - 0 i) == 0.0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (0, minus_zero)), BUILD_COMPLEX (0.0, minus_zero), 0, 0, 0); + check_complex ("ctanh (-0 + 0 i) == -0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_zero, 0)), BUILD_COMPLEX (minus_zero, 0.0), 0, 0, 0); + check_complex ("ctanh (-0 - 0 i) == -0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_zero, minus_zero)), BUILD_COMPLEX (minus_zero, minus_zero), 0, 0, 0); + + check_complex ("ctanh (inf + 0 i) == 1.0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (plus_infty, 0)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("ctanh (inf + 1 i) == 1.0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (plus_infty, 1)), BUILD_COMPLEX (1.0, 0.0), 0, 0, 0); + check_complex ("ctanh (inf - 0 i) == 1.0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (plus_infty, minus_zero)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + check_complex ("ctanh (inf - 1 i) == 1.0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (plus_infty, -1)), BUILD_COMPLEX (1.0, minus_zero), 0, 0, 0); + check_complex ("ctanh (-inf + 0 i) == -1.0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_infty, 0)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, 0); + check_complex ("ctanh (-inf + 1 i) == -1.0 + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_infty, 1)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, 0); + check_complex ("ctanh (-inf - 0 i) == -1.0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_infty, minus_zero)), BUILD_COMPLEX (-1.0, minus_zero), 0, 0, 0); + check_complex ("ctanh (-inf - 1 i) == -1.0 - 0 i", FUNC(ctanh) (BUILD_COMPLEX (minus_infty, -1)), BUILD_COMPLEX (-1.0, minus_zero), 0, 0, 0); + + check_complex ("ctanh (0 + inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (0, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (2 + inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (2, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (0 - inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (0, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (2 - inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (2, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (-0 + inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (minus_zero, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (-2 + inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (-2, plus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (-0 - inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (minus_zero, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + check_complex ("ctanh (-2 - inf i) == NaN + NaN i plus invalid exception", FUNC(ctanh) (BUILD_COMPLEX (-2, minus_infty)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION); + + check_complex ("ctanh (inf + NaN i) == 1.0 + 0.0 i plus sign of zero/inf not specified", FUNC(ctanh) (BUILD_COMPLEX (plus_infty, nan_value)), BUILD_COMPLEX (1.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + check_complex ("ctanh (-inf + NaN i) == -1.0 + 0.0 i plus sign of zero/inf not specified", FUNC(ctanh) (BUILD_COMPLEX (minus_infty, nan_value)), BUILD_COMPLEX (-1.0, 0.0), 0, 0, IGNORE_ZERO_INF_SIGN); + + check_complex ("ctanh (NaN + 0 i) == NaN + 0.0 i", FUNC(ctanh) (BUILD_COMPLEX (nan_value, 0)), BUILD_COMPLEX (nan_value, 0.0), 0, 0, 0); + check_complex ("ctanh (NaN - 0 i) == NaN - 0 i", FUNC(ctanh) (BUILD_COMPLEX (nan_value, minus_zero)), BUILD_COMPLEX (nan_value, minus_zero), 0, 0, 0); + + check_complex ("ctanh (NaN + 0.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (nan_value, 0.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctanh (NaN - 4.5 i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (nan_value, -4.5)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ctanh (0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (0, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctanh (5 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (5, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctanh (-0 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (minus_zero, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + check_complex ("ctanh (-0.25 + NaN i) == NaN + NaN i plus invalid exception allowed", FUNC(ctanh) (BUILD_COMPLEX (-0.25, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, INVALID_EXCEPTION_OK); + + check_complex ("ctanh (NaN + NaN i) == NaN + NaN i", FUNC(ctanh) (BUILD_COMPLEX (nan_value, nan_value)), BUILD_COMPLEX (nan_value, nan_value), 0, 0, 0); + + check_complex ("ctanh (0 + pi/4 i) == 0.0 + 1.0 i", FUNC(ctanh) (BUILD_COMPLEX (0, M_PI_4l)), BUILD_COMPLEX (0.0, 1.0), DELTA799, 0, 0); + + check_complex ("ctanh (0.7 + 1.2 i) == 1.3472197399061191630 + 0.4778641038326365540 i", FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L)), BUILD_COMPLEX (1.3472197399061191630L, 0.4778641038326365540L), DELTA800, 0, 0); + check_complex ("ctanh (-2 - 3 i) == -0.9653858790221331242 + 0.0098843750383224937 i", FUNC(ctanh) (BUILD_COMPLEX (-2, -3)), BUILD_COMPLEX (-0.9653858790221331242L, 0.0098843750383224937L), DELTA801, 0, 0); + + print_complex_max_error ("ctanh", DELTActanh, 0); +} +#endif + +static void +erf_test (void) +{ + errno = 0; + FUNC(erf) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("erf (0) == 0", FUNC(erf) (0), 0, 0, 0, 0); + check_float ("erf (-0) == -0", FUNC(erf) (minus_zero), minus_zero, 0, 0, 0); + check_float ("erf (inf) == 1", FUNC(erf) (plus_infty), 1, 0, 0, 0); + check_float ("erf (-inf) == -1", FUNC(erf) (minus_infty), -1, 0, 0, 0); + check_float ("erf (NaN) == NaN", FUNC(erf) (nan_value), nan_value, 0, 0, 0); + + check_float ("erf (0.7) == 0.67780119383741847297", FUNC(erf) (0.7L), 0.67780119383741847297L, 0, 0, 0); + + check_float ("erf (1.2) == 0.91031397822963538024", FUNC(erf) (1.2L), 0.91031397822963538024L, 0, 0, 0); + check_float ("erf (2.0) == 0.99532226501895273416", FUNC(erf) (2.0), 0.99532226501895273416L, 0, 0, 0); + check_float ("erf (4.1) == 0.99999999329997234592", FUNC(erf) (4.1L), 0.99999999329997234592L, 0, 0, 0); + check_float ("erf (27) == 1.0", FUNC(erf) (27), 1.0L, 0, 0, 0); + + print_max_error ("erf", 0, 0); +} + + +static void +erfc_test (void) +{ + errno = 0; + FUNC(erfc) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("erfc (inf) == 0.0", FUNC(erfc) (plus_infty), 0.0, 0, 0, 0); + check_float ("erfc (-inf) == 2.0", FUNC(erfc) (minus_infty), 2.0, 0, 0, 0); + check_float ("erfc (0.0) == 1.0", FUNC(erfc) (0.0), 1.0, 0, 0, 0); + check_float ("erfc (-0) == 1.0", FUNC(erfc) (minus_zero), 1.0, 0, 0, 0); + check_float ("erfc (NaN) == NaN", FUNC(erfc) (nan_value), nan_value, 0, 0, 0); + + check_float ("erfc (0.7) == 0.32219880616258152702", FUNC(erfc) (0.7L), 0.32219880616258152702L, DELTA817, 0, 0); + + check_float ("erfc (1.2) == 0.089686021770364619762", FUNC(erfc) (1.2L), 0.089686021770364619762L, DELTA818, 0, 0); + check_float ("erfc (2.0) == 0.0046777349810472658379", FUNC(erfc) (2.0), 0.0046777349810472658379L, DELTA819, 0, 0); + check_float ("erfc (4.1) == 0.67000276540848983727e-8", FUNC(erfc) (4.1L), 0.67000276540848983727e-8L, DELTA820, 0, 0); + check_float ("erfc (9) == 0.41370317465138102381e-36", FUNC(erfc) (9), 0.41370317465138102381e-36L, DELTA821, 0, 0); + + print_max_error ("erfc", DELTAerfc, 0); +} + +static void +exp_test (void) +{ + errno = 0; + FUNC(exp) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("exp (0) == 1", FUNC(exp) (0), 1, 0, 0, 0); + check_float ("exp (-0) == 1", FUNC(exp) (minus_zero), 1, 0, 0, 0); + +#ifndef TEST_INLINE + check_float ("exp (inf) == inf", FUNC(exp) (plus_infty), plus_infty, 0, 0, 0); + check_float ("exp (-inf) == 0", FUNC(exp) (minus_infty), 0, 0, 0, 0); +#endif + check_float ("exp (NaN) == NaN", FUNC(exp) (nan_value), nan_value, 0, 0, 0); + check_float ("exp (1) == e", FUNC(exp) (1), M_El, 0, 0, 0); + + check_float ("exp (2) == e^2", FUNC(exp) (2), M_E2l, 0, 0, 0); + check_float ("exp (3) == e^3", FUNC(exp) (3), M_E3l, 0, 0, 0); + check_float ("exp (0.7) == 2.0137527074704765216", FUNC(exp) (0.7L), 2.0137527074704765216L, DELTA830, 0, 0); + check_float ("exp (50.0) == 5184705528587072464087.45332293348538", FUNC(exp) (50.0L), 5184705528587072464087.45332293348538L, DELTA831, 0, 0); +#ifdef TEST_LDOUBLE + /* The result can only be represented in long double. */ + check_float ("exp (1000.0) == 0.197007111401704699388887935224332313e435", FUNC(exp) (1000.0L), 0.197007111401704699388887935224332313e435L, DELTA832, 0, 0); +#endif + print_max_error ("exp", DELTAexp, 0); +} + + +#if 0 /* XXX scp XXX */ +static void +exp10_test (void) +{ + errno = 0; + FUNC(exp10) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("exp10 (0) == 1", FUNC(exp10) (0), 1, 0, 0, 0); + check_float ("exp10 (-0) == 1", FUNC(exp10) (minus_zero), 1, 0, 0, 0); + + check_float ("exp10 (inf) == inf", FUNC(exp10) (plus_infty), plus_infty, 0, 0, 0); + check_float ("exp10 (-inf) == 0", FUNC(exp10) (minus_infty), 0, 0, 0, 0); + check_float ("exp10 (NaN) == NaN", FUNC(exp10) (nan_value), nan_value, 0, 0, 0); + check_float ("exp10 (3) == 1000", FUNC(exp10) (3), 1000, DELTA838, 0, 0); + check_float ("exp10 (-1) == 0.1", FUNC(exp10) (-1), 0.1L, DELTA839, 0, 0); + check_float ("exp10 (1e6) == inf", FUNC(exp10) (1e6), plus_infty, 0, 0, 0); + check_float ("exp10 (-1e6) == 0", FUNC(exp10) (-1e6), 0, 0, 0, 0); + check_float ("exp10 (0.7) == 5.0118723362727228500155418688494574", FUNC(exp10) (0.7L), 5.0118723362727228500155418688494574L, DELTA842, 0, 0); + + print_max_error ("exp10", DELTAexp10, 0); +} +#endif + +static void +exp2_test (void) +{ + errno = 0; + FUNC(exp2) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("exp2 (0) == 1", FUNC(exp2) (0), 1, 0, 0, 0); + check_float ("exp2 (-0) == 1", FUNC(exp2) (minus_zero), 1, 0, 0, 0); + check_float ("exp2 (inf) == inf", FUNC(exp2) (plus_infty), plus_infty, 0, 0, 0); + check_float ("exp2 (-inf) == 0", FUNC(exp2) (minus_infty), 0, 0, 0, 0); + check_float ("exp2 (NaN) == NaN", FUNC(exp2) (nan_value), nan_value, 0, 0, 0); + + check_float ("exp2 (10) == 1024", FUNC(exp2) (10), 1024, 0, 0, 0); + check_float ("exp2 (-1) == 0.5", FUNC(exp2) (-1), 0.5, 0, 0, 0); + check_float ("exp2 (1e6) == inf", FUNC(exp2) (1e6), plus_infty, 0, 0, 0); + check_float ("exp2 (-1e6) == 0", FUNC(exp2) (-1e6), 0, 0, 0, 0); + check_float ("exp2 (0.7) == 1.6245047927124710452", FUNC(exp2) (0.7L), 1.6245047927124710452L, DELTA852, 0, 0); + + print_max_error ("exp2", DELTAexp2, 0); +} + +static void +expm1_test (void) +{ + errno = 0; + FUNC(expm1) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("expm1 (0) == 0", FUNC(expm1) (0), 0, 0, 0, 0); + check_float ("expm1 (-0) == -0", FUNC(expm1) (minus_zero), minus_zero, 0, 0, 0); + +#ifndef TEST_INLINE + check_float ("expm1 (inf) == inf", FUNC(expm1) (plus_infty), plus_infty, 0, 0, 0); + check_float ("expm1 (-inf) == -1", FUNC(expm1) (minus_infty), -1, 0, 0, 0); +#endif + check_float ("expm1 (NaN) == NaN", FUNC(expm1) (nan_value), nan_value, 0, 0, 0); + + check_float ("expm1 (1) == M_El - 1.0", FUNC(expm1) (1), M_El - 1.0, 1, 0, 0); + check_float ("expm1 (0.7) == 1.0137527074704765216", FUNC(expm1) (0.7L), 1.0137527074704765216L, DELTA859, 0, 0); + + print_max_error ("expm1", DELTAexpm1, 0); +} + +static void +fabs_test (void) +{ + init_max_error (); + + check_float ("fabs (0) == 0", FUNC(fabs) ((FLOAT)0.0), 0, 0, 0, 0); + check_float ("fabs (-0) == 0", FUNC(fabs) (minus_zero), 0, 0, 0, 0); + + check_float ("fabs (inf) == inf", FUNC(fabs) (plus_infty), plus_infty, 0, 0, 0); + check_float ("fabs (-inf) == inf", FUNC(fabs) (minus_infty), plus_infty, 0, 0, 0); + check_float ("fabs (NaN) == NaN", FUNC(fabs) (nan_value), nan_value, 0, 0, 0); + + check_float ("fabs (38.0) == 38.0", FUNC(fabs) ((FLOAT)38.0), 38.0, 0, 0, 0); + check_float ("fabs (-e) == e", FUNC(fabs) ((FLOAT)-M_El), M_El, 0, 0, 0); + + print_max_error ("fabs", 0, 0); +} + +static void +fdim_test (void) +{ + init_max_error (); + + check_float ("fdim (0, 0) == 0", FUNC(fdim) (0, 0), 0, 0, 0, 0); + check_float ("fdim (9, 0) == 9", FUNC(fdim) (9, 0), 9, 0, 0, 0); + check_float ("fdim (0, 9) == 0", FUNC(fdim) (0, 9), 0, 0, 0, 0); + check_float ("fdim (-9, 0) == 0", FUNC(fdim) (-9, 0), 0, 0, 0, 0); + check_float ("fdim (0, -9) == 9", FUNC(fdim) (0, -9), 9, 0, 0, 0); + + check_float ("fdim (inf, 9) == inf", FUNC(fdim) (plus_infty, 9), plus_infty, 0, 0, 0); + check_float ("fdim (inf, -9) == inf", FUNC(fdim) (plus_infty, -9), plus_infty, 0, 0, 0); + check_float ("fdim (-inf, 9) == 0", FUNC(fdim) (minus_infty, 9), 0, 0, 0, 0); + check_float ("fdim (-inf, -9) == 0", FUNC(fdim) (minus_infty, -9), 0, 0, 0, 0); + check_float ("fdim (9, -inf) == inf", FUNC(fdim) (9, minus_infty), plus_infty, 0, 0, 0); + check_float ("fdim (-9, -inf) == inf", FUNC(fdim) (-9, minus_infty), plus_infty, 0, 0, 0); + check_float ("fdim (9, inf) == 0", FUNC(fdim) (9, plus_infty), 0, 0, 0, 0); + check_float ("fdim (-9, inf) == 0", FUNC(fdim) (-9, plus_infty), 0, 0, 0, 0); + + check_float ("fdim (0, NaN) == NaN", FUNC(fdim) (0, nan_value), nan_value, 0, 0, 0); + check_float ("fdim (9, NaN) == NaN", FUNC(fdim) (9, nan_value), nan_value, 0, 0, 0); + check_float ("fdim (-9, NaN) == NaN", FUNC(fdim) (-9, nan_value), nan_value, 0, 0, 0); + check_float ("fdim (NaN, 9) == NaN", FUNC(fdim) (nan_value, 9), nan_value, 0, 0, 0); + check_float ("fdim (NaN, -9) == NaN", FUNC(fdim) (nan_value, -9), nan_value, 0, 0, 0); + check_float ("fdim (inf, NaN) == NaN", FUNC(fdim) (plus_infty, nan_value), nan_value, 0, 0, 0); + check_float ("fdim (-inf, NaN) == NaN", FUNC(fdim) (minus_infty, nan_value), nan_value, 0, 0, 0); + check_float ("fdim (NaN, inf) == NaN", FUNC(fdim) (nan_value, plus_infty), nan_value, 0, 0, 0); + check_float ("fdim (NaN, -inf) == NaN", FUNC(fdim) (nan_value, minus_infty), nan_value, 0, 0, 0); + check_float ("fdim (NaN, NaN) == NaN", FUNC(fdim) (nan_value, nan_value), nan_value, 0, 0, 0); + + print_max_error ("fdim", 0, 0); +} + +static void +floor_test (void) +{ + init_max_error (); + + check_float ("floor (0.0) == 0.0", FUNC(floor) (0.0), 0.0, 0, 0, 0); + check_float ("floor (-0) == -0", FUNC(floor) (minus_zero), minus_zero, 0, 0, 0); + check_float ("floor (inf) == inf", FUNC(floor) (plus_infty), plus_infty, 0, 0, 0); + check_float ("floor (-inf) == -inf", FUNC(floor) (minus_infty), minus_infty, 0, 0, 0); + check_float ("floor (NaN) == NaN", FUNC(floor) (nan_value), nan_value, 0, 0, 0); + + check_float ("floor (pi) == 3.0", FUNC(floor) (M_PIl), 3.0, 0, 0, 0); + check_float ("floor (-pi) == -4.0", FUNC(floor) (-M_PIl), -4.0, 0, 0, 0); + + print_max_error ("floor", 0, 0); +} + +static void +fma_test (void) +{ + init_max_error (); + + check_float ("fma (1.0, 2.0, 3.0) == 5.0", FUNC(fma) (1.0, 2.0, 3.0), 5.0, 0, 0, 0); + check_float ("fma (NaN, 2.0, 3.0) == NaN", FUNC(fma) (nan_value, 2.0, 3.0), nan_value, 0, 0, 0); + check_float ("fma (1.0, NaN, 3.0) == NaN", FUNC(fma) (1.0, nan_value, 3.0), nan_value, 0, 0, 0); + check_float ("fma (1.0, 2.0, NaN) == NaN plus invalid exception allowed", FUNC(fma) (1.0, 2.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK); + check_float ("fma (inf, 0.0, NaN) == NaN plus invalid exception allowed", FUNC(fma) (plus_infty, 0.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK); + check_float ("fma (-inf, 0.0, NaN) == NaN plus invalid exception allowed", FUNC(fma) (minus_infty, 0.0, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK); + check_float ("fma (0.0, inf, NaN) == NaN plus invalid exception allowed", FUNC(fma) (0.0, plus_infty, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK); + check_float ("fma (0.0, -inf, NaN) == NaN plus invalid exception allowed", FUNC(fma) (0.0, minus_infty, nan_value), nan_value, 0, 0, INVALID_EXCEPTION_OK); + check_float ("fma (inf, 0.0, 1.0) == NaN plus invalid exception", FUNC(fma) (plus_infty, 0.0, 1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (-inf, 0.0, 1.0) == NaN plus invalid exception", FUNC(fma) (minus_infty, 0.0, 1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (0.0, inf, 1.0) == NaN plus invalid exception", FUNC(fma) (0.0, plus_infty, 1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (0.0, -inf, 1.0) == NaN plus invalid exception", FUNC(fma) (0.0, minus_infty, 1.0), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("fma (inf, inf, -inf) == NaN plus invalid exception", FUNC(fma) (plus_infty, plus_infty, minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (-inf, inf, inf) == NaN plus invalid exception", FUNC(fma) (minus_infty, plus_infty, plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (inf, -inf, inf) == NaN plus invalid exception", FUNC(fma) (plus_infty, minus_infty, plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("fma (-inf, -inf, -inf) == NaN plus invalid exception", FUNC(fma) (minus_infty, minus_infty, minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + + print_max_error ("fma", 0, 0); +} + + +static void +fmax_test (void) +{ + init_max_error (); + + check_float ("fmax (0, 0) == 0", FUNC(fmax) (0, 0), 0, 0, 0, 0); + check_float ("fmax (-0, -0) == -0", FUNC(fmax) (minus_zero, minus_zero), minus_zero, 0, 0, 0); + check_float ("fmax (9, 0) == 9", FUNC(fmax) (9, 0), 9, 0, 0, 0); + check_float ("fmax (0, 9) == 9", FUNC(fmax) (0, 9), 9, 0, 0, 0); + check_float ("fmax (-9, 0) == 0", FUNC(fmax) (-9, 0), 0, 0, 0, 0); + check_float ("fmax (0, -9) == 0", FUNC(fmax) (0, -9), 0, 0, 0, 0); + + check_float ("fmax (inf, 9) == inf", FUNC(fmax) (plus_infty, 9), plus_infty, 0, 0, 0); + check_float ("fmax (0, inf) == inf", FUNC(fmax) (0, plus_infty), plus_infty, 0, 0, 0); + check_float ("fmax (-9, inf) == inf", FUNC(fmax) (-9, plus_infty), plus_infty, 0, 0, 0); + check_float ("fmax (inf, -9) == inf", FUNC(fmax) (plus_infty, -9), plus_infty, 0, 0, 0); + + check_float ("fmax (-inf, 9) == 9", FUNC(fmax) (minus_infty, 9), 9, 0, 0, 0); + check_float ("fmax (-inf, -9) == -9", FUNC(fmax) (minus_infty, -9), -9, 0, 0, 0); + check_float ("fmax (9, -inf) == 9", FUNC(fmax) (9, minus_infty), 9, 0, 0, 0); + check_float ("fmax (-9, -inf) == -9", FUNC(fmax) (-9, minus_infty), -9, 0, 0, 0); + + check_float ("fmax (0, NaN) == 0", FUNC(fmax) (0, nan_value), 0, 0, 0, 0); + check_float ("fmax (9, NaN) == 9", FUNC(fmax) (9, nan_value), 9, 0, 0, 0); + check_float ("fmax (-9, NaN) == -9", FUNC(fmax) (-9, nan_value), -9, 0, 0, 0); + check_float ("fmax (NaN, 0) == 0", FUNC(fmax) (nan_value, 0), 0, 0, 0, 0); + check_float ("fmax (NaN, 9) == 9", FUNC(fmax) (nan_value, 9), 9, 0, 0, 0); + check_float ("fmax (NaN, -9) == -9", FUNC(fmax) (nan_value, -9), -9, 0, 0, 0); + check_float ("fmax (inf, NaN) == inf", FUNC(fmax) (plus_infty, nan_value), plus_infty, 0, 0, 0); + check_float ("fmax (-inf, NaN) == -inf", FUNC(fmax) (minus_infty, nan_value), minus_infty, 0, 0, 0); + check_float ("fmax (NaN, inf) == inf", FUNC(fmax) (nan_value, plus_infty), plus_infty, 0, 0, 0); + check_float ("fmax (NaN, -inf) == -inf", FUNC(fmax) (nan_value, minus_infty), minus_infty, 0, 0, 0); + check_float ("fmax (NaN, NaN) == NaN", FUNC(fmax) (nan_value, nan_value), nan_value, 0, 0, 0); + + print_max_error ("fmax", 0, 0); +} + + +static void +fmin_test (void) +{ + init_max_error (); + + check_float ("fmin (0, 0) == 0", FUNC(fmin) (0, 0), 0, 0, 0, 0); + check_float ("fmin (-0, -0) == -0", FUNC(fmin) (minus_zero, minus_zero), minus_zero, 0, 0, 0); + check_float ("fmin (9, 0) == 0", FUNC(fmin) (9, 0), 0, 0, 0, 0); + check_float ("fmin (0, 9) == 0", FUNC(fmin) (0, 9), 0, 0, 0, 0); + check_float ("fmin (-9, 0) == -9", FUNC(fmin) (-9, 0), -9, 0, 0, 0); + check_float ("fmin (0, -9) == -9", FUNC(fmin) (0, -9), -9, 0, 0, 0); + + check_float ("fmin (inf, 9) == 9", FUNC(fmin) (plus_infty, 9), 9, 0, 0, 0); + check_float ("fmin (9, inf) == 9", FUNC(fmin) (9, plus_infty), 9, 0, 0, 0); + check_float ("fmin (inf, -9) == -9", FUNC(fmin) (plus_infty, -9), -9, 0, 0, 0); + check_float ("fmin (-9, inf) == -9", FUNC(fmin) (-9, plus_infty), -9, 0, 0, 0); + check_float ("fmin (-inf, 9) == -inf", FUNC(fmin) (minus_infty, 9), minus_infty, 0, 0, 0); + check_float ("fmin (-inf, -9) == -inf", FUNC(fmin) (minus_infty, -9), minus_infty, 0, 0, 0); + check_float ("fmin (9, -inf) == -inf", FUNC(fmin) (9, minus_infty), minus_infty, 0, 0, 0); + check_float ("fmin (-9, -inf) == -inf", FUNC(fmin) (-9, minus_infty), minus_infty, 0, 0, 0); + + check_float ("fmin (0, NaN) == 0", FUNC(fmin) (0, nan_value), 0, 0, 0, 0); + check_float ("fmin (9, NaN) == 9", FUNC(fmin) (9, nan_value), 9, 0, 0, 0); + check_float ("fmin (-9, NaN) == -9", FUNC(fmin) (-9, nan_value), -9, 0, 0, 0); + check_float ("fmin (NaN, 0) == 0", FUNC(fmin) (nan_value, 0), 0, 0, 0, 0); + check_float ("fmin (NaN, 9) == 9", FUNC(fmin) (nan_value, 9), 9, 0, 0, 0); + check_float ("fmin (NaN, -9) == -9", FUNC(fmin) (nan_value, -9), -9, 0, 0, 0); + check_float ("fmin (inf, NaN) == inf", FUNC(fmin) (plus_infty, nan_value), plus_infty, 0, 0, 0); + check_float ("fmin (-inf, NaN) == -inf", FUNC(fmin) (minus_infty, nan_value), minus_infty, 0, 0, 0); + check_float ("fmin (NaN, inf) == inf", FUNC(fmin) (nan_value, plus_infty), plus_infty, 0, 0, 0); + check_float ("fmin (NaN, -inf) == -inf", FUNC(fmin) (nan_value, minus_infty), minus_infty, 0, 0, 0); + check_float ("fmin (NaN, NaN) == NaN", FUNC(fmin) (nan_value, nan_value), nan_value, 0, 0, 0); + + print_max_error ("fmin", 0, 0); +} + + +static void +fmod_test (void) +{ + errno = 0; + FUNC(fmod) (6.5, 2.3L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + /* fmod (+0, y) == +0 for y != 0. */ + check_float ("fmod (0, 3) == 0", FUNC(fmod) (0, 3), 0, 0, 0, 0); + + /* fmod (-0, y) == -0 for y != 0. */ + check_float ("fmod (-0, 3) == -0", FUNC(fmod) (minus_zero, 3), minus_zero, 0, 0, 0); + + /* fmod (+inf, y) == NaN plus invalid exception. */ + check_float ("fmod (inf, 3) == NaN plus invalid exception", FUNC(fmod) (plus_infty, 3), nan_value, 0, 0, INVALID_EXCEPTION); + /* fmod (-inf, y) == NaN plus invalid exception. */ + check_float ("fmod (-inf, 3) == NaN plus invalid exception", FUNC(fmod) (minus_infty, 3), nan_value, 0, 0, INVALID_EXCEPTION); + /* fmod (x, +0) == NaN plus invalid exception. */ + check_float ("fmod (3, 0) == NaN plus invalid exception", FUNC(fmod) (3, 0), nan_value, 0, 0, INVALID_EXCEPTION); + /* fmod (x, -0) == NaN plus invalid exception. */ + check_float ("fmod (3, -0) == NaN plus invalid exception", FUNC(fmod) (3, minus_zero), nan_value, 0, 0, INVALID_EXCEPTION); + + /* fmod (x, +inf) == x for x not infinite. */ + check_float ("fmod (3.0, inf) == 3.0", FUNC(fmod) (3.0, plus_infty), 3.0, 0, 0, 0); + /* fmod (x, -inf) == x for x not infinite. */ + check_float ("fmod (3.0, -inf) == 3.0", FUNC(fmod) (3.0, minus_infty), 3.0, 0, 0, 0); + + check_float ("fmod (NaN, NaN) == NaN", FUNC(fmod) (nan_value, nan_value), nan_value, 0, 0, 0); + + check_float ("fmod (6.5, 2.3) == 1.9", FUNC(fmod) (6.5, 2.3L), 1.9L, DELTA972, 0, 0); + check_float ("fmod (-6.5, 2.3) == -1.9", FUNC(fmod) (-6.5, 2.3L), -1.9L, DELTA973, 0, 0); + check_float ("fmod (6.5, -2.3) == 1.9", FUNC(fmod) (6.5, -2.3L), 1.9L, DELTA974, 0, 0); + check_float ("fmod (-6.5, -2.3) == -1.9", FUNC(fmod) (-6.5, -2.3L), -1.9L, DELTA975, 0, 0); + + print_max_error ("fmod", DELTAfmod, 0); +} + +static void +fpclassify_test (void) +{ + init_max_error (); + + check_int ("fpclassify (NaN) == FP_NAN", fpclassify (nan_value), FP_NAN, 0, 0, 0); + check_int ("fpclassify (inf) == FP_INFINITE", fpclassify (plus_infty), FP_INFINITE, 0, 0, 0); + check_int ("fpclassify (-inf) == FP_INFINITE", fpclassify (minus_infty), FP_INFINITE, 0, 0, 0); + check_int ("fpclassify (+0) == FP_ZERO", fpclassify (plus_zero), FP_ZERO, 0, 0, 0); + check_int ("fpclassify (-0) == FP_ZERO", fpclassify (minus_zero), FP_ZERO, 0, 0, 0); + check_int ("fpclassify (1000) == FP_NORMAL", fpclassify (1000.0), FP_NORMAL, 0, 0, 0); + + print_max_error ("fpclassify", 0, 0); +} + + +static void +frexp_test (void) +{ + int x; + + init_max_error (); + + check_float ("frexp (inf, &x) == inf", FUNC(frexp) (plus_infty, &x), plus_infty, 0, 0, 0); + check_float ("frexp (-inf, &x) == -inf", FUNC(frexp) (minus_infty, &x), minus_infty, 0, 0, 0); + check_float ("frexp (NaN, &x) == NaN", FUNC(frexp) (nan_value, &x), nan_value, 0, 0, 0); + + check_float ("frexp (0.0, &x) == 0.0", FUNC(frexp) (0.0, &x), 0.0, 0, 0, 0); + check_int ("frexp (0.0, &x) sets x to 0.0", x, 0.0, 0, 0, 0); + check_float ("frexp (-0, &x) == -0", FUNC(frexp) (minus_zero, &x), minus_zero, 0, 0, 0); + check_int ("frexp (-0, &x) sets x to 0.0", x, 0.0, 0, 0, 0); + + check_float ("frexp (12.8, &x) == 0.8", FUNC(frexp) (12.8L, &x), 0.8L, 0, 0, 0); + check_int ("frexp (12.8, &x) sets x to 4", x, 4, 0, 0, 0); + check_float ("frexp (-27.34, &x) == -0.854375", FUNC(frexp) (-27.34L, &x), -0.854375L, 0, 0, 0); + check_int ("frexp (-27.34, &x) sets x to 5", x, 5, 0, 0, 0); + + print_max_error ("frexp", 0, 0); +} + +#define gamma lgamma /* XXX scp XXX */ +#define gammaf lgammaf /* XXX scp XXX */ +static void +gamma_test (void) +{ + errno = 0; + FUNC(gamma) (1); + + if (errno == ENOSYS) + /* Function not implemented. */ + return; + feclearexcept (FE_ALL_EXCEPT); + + init_max_error (); + + signgam = 0; + check_float ("gamma (inf) == inf", FUNC(gamma) (plus_infty), plus_infty, 0, 0, 0); + signgam = 0; + check_float ("gamma (0) == inf plus division by zero exception", FUNC(gamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + signgam = 0; + check_float ("gamma (-3) == inf plus division by zero exception", FUNC(gamma) (-3), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + signgam = 0; + check_float ("gamma (-inf) == inf", FUNC(gamma) (minus_infty), plus_infty, 0, 0, 0); + signgam = 0; + check_float ("gamma (NaN) == NaN", FUNC(gamma) (nan_value), nan_value, 0, 0, 0); + + signgam = 0; + check_float ("gamma (1) == 0", FUNC(gamma) (1), 0, 0, 0, 0); + check_int ("gamma (1) sets signgam to 1", signgam, 1, 0, 0, 0); + signgam = 0; + check_float ("gamma (3) == M_LN2l", FUNC(gamma) (3), M_LN2l, 0, 0, 0); + check_int ("gamma (3) sets signgam to 1", signgam, 1, 0, 0, 0); + + signgam = 0; + check_float ("gamma (0.5) == log(sqrt(pi))", FUNC(gamma) (0.5), M_LOG_SQRT_PIl, 0, 0, 0); + check_int ("gamma (0.5) sets signgam to 1", signgam, 1, 0, 0, 0); + signgam = 0; + check_float ("gamma (-0.5) == log(2*sqrt(pi))", FUNC(gamma) (-0.5), M_LOG_2_SQRT_PIl, DELTA1004, 0, 0); + check_int ("gamma (-0.5) sets signgam to -1", signgam, -1, 0, 0, 0); + + print_max_error ("gamma", DELTAgamma, 0); +} +#undef gamma /* XXX scp XXX */ +#undef gammaf /* XXX scp XXX */ + +static void +hypot_test (void) +{ + errno = 0; + FUNC(hypot) (0.7L, 12.4L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("hypot (inf, 1) == inf plus sign of zero/inf not specified", FUNC(hypot) (plus_infty, 1), plus_infty, 0, 0, IGNORE_ZERO_INF_SIGN); + check_float ("hypot (-inf, 1) == inf plus sign of zero/inf not specified", FUNC(hypot) (minus_infty, 1), plus_infty, 0, 0, IGNORE_ZERO_INF_SIGN); + +#ifndef TEST_INLINE + check_float ("hypot (inf, NaN) == inf", FUNC(hypot) (plus_infty, nan_value), plus_infty, 0, 0, 0); + check_float ("hypot (-inf, NaN) == inf", FUNC(hypot) (minus_infty, nan_value), plus_infty, 0, 0, 0); + check_float ("hypot (NaN, inf) == inf", FUNC(hypot) (nan_value, plus_infty), plus_infty, 0, 0, 0); + check_float ("hypot (NaN, -inf) == inf", FUNC(hypot) (nan_value, minus_infty), plus_infty, 0, 0, 0); +#endif + + check_float ("hypot (NaN, NaN) == NaN", FUNC(hypot) (nan_value, nan_value), nan_value, 0, 0, 0); + + /* hypot (x,y) == hypot (+-x, +-y) */ + check_float ("hypot (0.7, 12.4) == 12.419742348374220601176836866763271", FUNC(hypot) (0.7L, 12.4L), 12.419742348374220601176836866763271L, DELTA1013, 0, 0); + check_float ("hypot (-0.7, 12.4) == 12.419742348374220601176836866763271", FUNC(hypot) (-0.7L, 12.4L), 12.419742348374220601176836866763271L, DELTA1014, 0, 0); + check_float ("hypot (0.7, -12.4) == 12.419742348374220601176836866763271", FUNC(hypot) (0.7L, -12.4L), 12.419742348374220601176836866763271L, DELTA1015, 0, 0); + check_float ("hypot (-0.7, -12.4) == 12.419742348374220601176836866763271", FUNC(hypot) (-0.7L, -12.4L), 12.419742348374220601176836866763271L, DELTA1016, 0, 0); + check_float ("hypot (12.4, 0.7) == 12.419742348374220601176836866763271", FUNC(hypot) (12.4L, 0.7L), 12.419742348374220601176836866763271L, DELTA1017, 0, 0); + check_float ("hypot (-12.4, 0.7) == 12.419742348374220601176836866763271", FUNC(hypot) (-12.4L, 0.7L), 12.419742348374220601176836866763271L, DELTA1018, 0, 0); + check_float ("hypot (12.4, -0.7) == 12.419742348374220601176836866763271", FUNC(hypot) (12.4L, -0.7L), 12.419742348374220601176836866763271L, DELTA1019, 0, 0); + check_float ("hypot (-12.4, -0.7) == 12.419742348374220601176836866763271", FUNC(hypot) (-12.4L, -0.7L), 12.419742348374220601176836866763271L, DELTA1020, 0, 0); + + /* hypot (x,0) == fabs (x) */ + check_float ("hypot (0.7, 0) == 0.7", FUNC(hypot) (0.7L, 0), 0.7L, 0, 0, 0); + check_float ("hypot (-0.7, 0) == 0.7", FUNC(hypot) (-0.7L, 0), 0.7L, 0, 0, 0); + check_float ("hypot (-5.7e7, 0) == 5.7e7", FUNC(hypot) (-5.7e7, 0), 5.7e7L, 0, 0, 0); + + check_float ("hypot (0.7, 1.2) == 1.3892443989449804508432547041028554", FUNC(hypot) (0.7L, 1.2L), 1.3892443989449804508432547041028554L, DELTA1024, 0, 0); + + print_max_error ("hypot", DELTAhypot, 0); +} + + +static void +ilogb_test (void) +{ + init_max_error (); + + check_int ("ilogb (1) == 0", FUNC(ilogb) (1), 0, 0, 0, 0); + check_int ("ilogb (e) == 1", FUNC(ilogb) (M_El), 1, 0, 0, 0); + check_int ("ilogb (1024) == 10", FUNC(ilogb) (1024), 10, 0, 0, 0); + check_int ("ilogb (-2000) == 10", FUNC(ilogb) (-2000), 10, 0, 0, 0); + + /* XXX We have a problem here: the standard does not tell us whether + exceptions are allowed/required. ignore them for now. */ + + check_int ("ilogb (0.0) == FP_ILOGB0 plus exceptions allowed", FUNC(ilogb) (0.0), FP_ILOGB0, 0, 0, EXCEPTIONS_OK); + check_int ("ilogb (NaN) == FP_ILOGBNAN plus exceptions allowed", FUNC(ilogb) (nan_value), FP_ILOGBNAN, 0, 0, EXCEPTIONS_OK); + check_int ("ilogb (inf) == INT_MAX plus exceptions allowed", FUNC(ilogb) (plus_infty), INT_MAX, 0, 0, EXCEPTIONS_OK); + check_int ("ilogb (-inf) == INT_MAX plus exceptions allowed", FUNC(ilogb) (minus_infty), INT_MAX, 0, 0, EXCEPTIONS_OK); + + print_max_error ("ilogb", 0, 0); +} + +static void +isfinite_test (void) +{ + init_max_error (); + + check_bool ("isfinite (0) == true", isfinite (0.0), 1, 0, 0, 0); + check_bool ("isfinite (-0) == true", isfinite (minus_zero), 1, 0, 0, 0); + check_bool ("isfinite (10) == true", isfinite (10.0), 1, 0, 0, 0); + check_bool ("isfinite (inf) == false", isfinite (plus_infty), 0, 0, 0, 0); + check_bool ("isfinite (-inf) == false", isfinite (minus_infty), 0, 0, 0, 0); + check_bool ("isfinite (NaN) == false", isfinite (nan_value), 0, 0, 0, 0); + + print_max_error ("isfinite", 0, 0); +} + +static void +isnormal_test (void) +{ + init_max_error (); + + check_bool ("isnormal (0) == false", isnormal (0.0), 0, 0, 0, 0); + check_bool ("isnormal (-0) == false", isnormal (minus_zero), 0, 0, 0, 0); + check_bool ("isnormal (10) == true", isnormal (10.0), 1, 0, 0, 0); + check_bool ("isnormal (inf) == false", isnormal (plus_infty), 0, 0, 0, 0); + check_bool ("isnormal (-inf) == false", isnormal (minus_infty), 0, 0, 0, 0); + check_bool ("isnormal (NaN) == false", isnormal (nan_value), 0, 0, 0, 0); + + print_max_error ("isnormal", 0, 0); +} + +static void +j0_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(j0) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + /* j0 is the Bessel function of the first kind of order 0 */ + check_float ("j0 (NaN) == NaN", FUNC(j0) (nan_value), nan_value, 0, 0, 0); + check_float ("j0 (inf) == 0", FUNC(j0) (plus_infty), 0, 0, 0, 0); + check_float ("j0 (-1.0) == 0.76519768655796655145", FUNC(j0) (-1.0), 0.76519768655796655145L, 0, 0, 0); + check_float ("j0 (0.0) == 1.0", FUNC(j0) (0.0), 1.0, 0, 0, 0); + check_float ("j0 (0.1) == 0.99750156206604003228", FUNC(j0) (0.1L), 0.99750156206604003228L, 0, 0, 0); + check_float ("j0 (0.7) == 0.88120088860740528084", FUNC(j0) (0.7L), 0.88120088860740528084L, 0, 0, 0); + check_float ("j0 (1.0) == 0.76519768655796655145", FUNC(j0) (1.0), 0.76519768655796655145L, 0, 0, 0); + check_float ("j0 (1.5) == 0.51182767173591812875", FUNC(j0) (1.5), 0.51182767173591812875L, 0, 0, 0); + check_float ("j0 (2.0) == 0.22389077914123566805", FUNC(j0) (2.0), 0.22389077914123566805L, DELTA1053, 0, 0); + check_float ("j0 (8.0) == 0.17165080713755390609", FUNC(j0) (8.0), 0.17165080713755390609L, DELTA1054, 0, 0); + check_float ("j0 (10.0) == -0.24593576445134833520", FUNC(j0) (10.0), -0.24593576445134833520L, DELTA1055, 0, 0); + + print_max_error ("j0", DELTAj0, 0); +} + + +static void +j1_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(j1) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + /* j1 is the Bessel function of the first kind of order 1 */ + + init_max_error (); + + check_float ("j1 (NaN) == NaN", FUNC(j1) (nan_value), nan_value, 0, 0, 0); + check_float ("j1 (inf) == 0", FUNC(j1) (plus_infty), 0, 0, 0, 0); + + check_float ("j1 (-1.0) == -0.44005058574493351596", FUNC(j1) (-1.0), -0.44005058574493351596L, 0, 0, 0); + check_float ("j1 (0.0) == 0.0", FUNC(j1) (0.0), 0.0, 0, 0, 0); + check_float ("j1 (0.1) == 0.049937526036241997556", FUNC(j1) (0.1L), 0.049937526036241997556L, 0, 0, 0); + check_float ("j1 (0.7) == 0.32899574154005894785", FUNC(j1) (0.7L), 0.32899574154005894785L, 0, 0, 0); + check_float ("j1 (1.0) == 0.44005058574493351596", FUNC(j1) (1.0), 0.44005058574493351596L, 0, 0, 0); + check_float ("j1 (1.5) == 0.55793650791009964199", FUNC(j1) (1.5), 0.55793650791009964199L, 0, 0, 0); + check_float ("j1 (2.0) == 0.57672480775687338720", FUNC(j1) (2.0), 0.57672480775687338720L, DELTA1064, 0, 0); + check_float ("j1 (8.0) == 0.23463634685391462438", FUNC(j1) (8.0), 0.23463634685391462438L, DELTA1065, 0, 0); + check_float ("j1 (10.0) == 0.043472746168861436670", FUNC(j1) (10.0), 0.043472746168861436670L, DELTA1066, 0, 0); + + print_max_error ("j1", DELTAj1, 0); +} + +static void +jn_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(jn) (1, 1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + /* jn is the Bessel function of the first kind of order n. */ + init_max_error (); + + /* jn (0, x) == j0 (x) */ + check_float ("jn (0, NaN) == NaN", FUNC(jn) (0, nan_value), nan_value, 0, 0, 0); + check_float ("jn (0, inf) == 0", FUNC(jn) (0, plus_infty), 0, 0, 0, 0); + check_float ("jn (0, -1.0) == 0.76519768655796655145", FUNC(jn) (0, -1.0), 0.76519768655796655145L, 0, 0, 0); + check_float ("jn (0, 0.0) == 1.0", FUNC(jn) (0, 0.0), 1.0, 0, 0, 0); + check_float ("jn (0, 0.1) == 0.99750156206604003228", FUNC(jn) (0, 0.1L), 0.99750156206604003228L, 0, 0, 0); + check_float ("jn (0, 0.7) == 0.88120088860740528084", FUNC(jn) (0, 0.7L), 0.88120088860740528084L, 0, 0, 0); + check_float ("jn (0, 1.0) == 0.76519768655796655145", FUNC(jn) (0, 1.0), 0.76519768655796655145L, 0, 0, 0); + check_float ("jn (0, 1.5) == 0.51182767173591812875", FUNC(jn) (0, 1.5), 0.51182767173591812875L, 0, 0, 0); + check_float ("jn (0, 2.0) == 0.22389077914123566805", FUNC(jn) (0, 2.0), 0.22389077914123566805L, DELTA1075, 0, 0); + check_float ("jn (0, 8.0) == 0.17165080713755390609", FUNC(jn) (0, 8.0), 0.17165080713755390609L, DELTA1076, 0, 0); + check_float ("jn (0, 10.0) == -0.24593576445134833520", FUNC(jn) (0, 10.0), -0.24593576445134833520L, DELTA1077, 0, 0); + + /* jn (1, x) == j1 (x) */ + check_float ("jn (1, NaN) == NaN", FUNC(jn) (1, nan_value), nan_value, 0, 0, 0); + check_float ("jn (1, inf) == 0", FUNC(jn) (1, plus_infty), 0, 0, 0, 0); + + check_float ("jn (1, -1.0) == -0.44005058574493351596", FUNC(jn) (1, -1.0), -0.44005058574493351596L, 0, 0, 0); + check_float ("jn (1, 0.0) == 0.0", FUNC(jn) (1, 0.0), 0.0, 0, 0, 0); + check_float ("jn (1, 0.1) == 0.049937526036241997556", FUNC(jn) (1, 0.1L), 0.049937526036241997556L, 0, 0, 0); + check_float ("jn (1, 0.7) == 0.32899574154005894785", FUNC(jn) (1, 0.7L), 0.32899574154005894785L, 0, 0, 0); + check_float ("jn (1, 1.0) == 0.44005058574493351596", FUNC(jn) (1, 1.0), 0.44005058574493351596L, 0, 0, 0); + check_float ("jn (1, 1.5) == 0.55793650791009964199", FUNC(jn) (1, 1.5), 0.55793650791009964199L, 0, 0, 0); + check_float ("jn (1, 2.0) == 0.57672480775687338720", FUNC(jn) (1, 2.0), 0.57672480775687338720L, DELTA1086, 0, 0); + check_float ("jn (1, 8.0) == 0.23463634685391462438", FUNC(jn) (1, 8.0), 0.23463634685391462438L, DELTA1087, 0, 0); + check_float ("jn (1, 10.0) == 0.043472746168861436670", FUNC(jn) (1, 10.0), 0.043472746168861436670L, DELTA1088, 0, 0); + + /* jn (3, x) */ + check_float ("jn (3, NaN) == NaN", FUNC(jn) (3, nan_value), nan_value, 0, 0, 0); + check_float ("jn (3, inf) == 0", FUNC(jn) (3, plus_infty), 0, 0, 0, 0); + + check_float ("jn (3, -1.0) == -0.019563353982668405919", FUNC(jn) (3, -1.0), -0.019563353982668405919L, DELTA1091, 0, 0); + check_float ("jn (3, 0.0) == 0.0", FUNC(jn) (3, 0.0), 0.0, 0, 0, 0); + check_float ("jn (3, 0.1) == 0.000020820315754756261429", FUNC(jn) (3, 0.1L), 0.000020820315754756261429L, DELTA1093, 0, 0); + check_float ("jn (3, 0.7) == 0.0069296548267508408077", FUNC(jn) (3, 0.7L), 0.0069296548267508408077L, DELTA1094, 0, 0); + check_float ("jn (3, 1.0) == 0.019563353982668405919", FUNC(jn) (3, 1.0), 0.019563353982668405919L, DELTA1095, 0, 0); + check_float ("jn (3, 2.0) == 0.12894324947440205110", FUNC(jn) (3, 2.0), 0.12894324947440205110L, DELTA1096, 0, 0); + check_float ("jn (3, 10.0) == 0.058379379305186812343", FUNC(jn) (3, 10.0), 0.058379379305186812343L, DELTA1097, 0, 0); + + /* jn (10, x) */ + check_float ("jn (10, NaN) == NaN", FUNC(jn) (10, nan_value), nan_value, 0, 0, 0); + check_float ("jn (10, inf) == 0", FUNC(jn) (10, plus_infty), 0, 0, 0, 0); + + check_float ("jn (10, -1.0) == 0.26306151236874532070e-9", FUNC(jn) (10, -1.0), 0.26306151236874532070e-9L, DELTA1100, 0, 0); + check_float ("jn (10, 0.0) == 0.0", FUNC(jn) (10, 0.0), 0.0, 0, 0, 0); + check_float ("jn (10, 0.1) == 0.26905328954342155795e-19", FUNC(jn) (10, 0.1L), 0.26905328954342155795e-19L, DELTA1102, 0, 0); + check_float ("jn (10, 0.7) == 0.75175911502153953928e-11", FUNC(jn) (10, 0.7L), 0.75175911502153953928e-11L, DELTA1103, 0, 0); + check_float ("jn (10, 1.0) == 0.26306151236874532070e-9", FUNC(jn) (10, 1.0), 0.26306151236874532070e-9L, DELTA1104, 0, 0); + check_float ("jn (10, 2.0) == 0.25153862827167367096e-6", FUNC(jn) (10, 2.0), 0.25153862827167367096e-6L, DELTA1105, 0, 0); + check_float ("jn (10, 10.0) == 0.20748610663335885770", FUNC(jn) (10, 10.0), 0.20748610663335885770L, DELTA1106, 0, 0); + + print_max_error ("jn", DELTAjn, 0); +} + + +static void +ldexp_test (void) +{ + check_float ("ldexp (0, 0) == 0", FUNC(ldexp) (0, 0), 0, 0, 0, 0); + check_float ("ldexp (-0, 0) == -0", FUNC(ldexp) (minus_zero, 0), minus_zero, 0, 0, 0); + + check_float ("ldexp (inf, 1) == inf", FUNC(ldexp) (plus_infty, 1), plus_infty, 0, 0, 0); + check_float ("ldexp (-inf, 1) == -inf", FUNC(ldexp) (minus_infty, 1), minus_infty, 0, 0, 0); + check_float ("ldexp (NaN, 1) == NaN", FUNC(ldexp) (nan_value, 1), nan_value, 0, 0, 0); + + check_float ("ldexp (0.8, 4) == 12.8", FUNC(ldexp) (0.8L, 4), 12.8L, 0, 0, 0); + check_float ("ldexp (-0.854375, 5) == -27.34", FUNC(ldexp) (-0.854375L, 5), -27.34L, 0, 0, 0); + + /* ldexp (x, 0) == x. */ + check_float ("ldexp (1.0, 0) == 1.0", FUNC(ldexp) (1.0L, 0L), 1.0L, 0, 0, 0); +} + +static void +lgamma_test (void) +{ + errno = 0; + FUNC(lgamma) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + feclearexcept (FE_ALL_EXCEPT); + + init_max_error (); + + signgam = 0; + check_float ("lgamma (inf) == inf", FUNC(lgamma) (plus_infty), plus_infty, 0, 0, 0); + signgam = 0; + check_float ("lgamma (0) == inf plus division by zero exception", FUNC(lgamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + signgam = 0; + check_float ("lgamma (NaN) == NaN", FUNC(lgamma) (nan_value), nan_value, 0, 0, 0); + + /* lgamma (x) == +inf plus divide by zero exception for integer x <= 0. */ + signgam = 0; + check_float ("lgamma (-3) == inf plus division by zero exception", FUNC(lgamma) (-3), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + signgam = 0; + check_float ("lgamma (-inf) == inf", FUNC(lgamma) (minus_infty), plus_infty, 0, 0, 0); + + signgam = 0; + check_float ("lgamma (1) == 0", FUNC(lgamma) (1), 0, 0, 0, 0); + check_int ("lgamma (1) sets signgam to 1", signgam, 1, 0, 0, 0); + + signgam = 0; + check_float ("lgamma (3) == M_LN2l", FUNC(lgamma) (3), M_LN2l, 0, 0, 0); + check_int ("lgamma (3) sets signgam to 1", signgam, 1, 0, 0, 0); + + signgam = 0; + check_float ("lgamma (0.5) == log(sqrt(pi))", FUNC(lgamma) (0.5), M_LOG_SQRT_PIl, 0, 0, 0); + check_int ("lgamma (0.5) sets signgam to 1", signgam, 1, 0, 0, 0); + signgam = 0; + check_float ("lgamma (-0.5) == log(2*sqrt(pi))", FUNC(lgamma) (-0.5), M_LOG_2_SQRT_PIl, DELTA1126, 0, 0); + check_int ("lgamma (-0.5) sets signgam to -1", signgam, -1, 0, 0, 0); + signgam = 0; + check_float ("lgamma (0.7) == 0.26086724653166651439", FUNC(lgamma) (0.7L), 0.26086724653166651439L, DELTA1128, 0, 0); + check_int ("lgamma (0.7) sets signgam to 1", signgam, 1, 0, 0, 0); + signgam = 0; + check_float ("lgamma (1.2) == -0.853740900033158497197e-1", FUNC(lgamma) (1.2L), -0.853740900033158497197e-1L, DELTA1130, 0, 0); + check_int ("lgamma (1.2) sets signgam to 1", signgam, 1, 0, 0, 0); + + print_max_error ("lgamma", DELTAlgamma, 0); +} + +static void +lrint_test (void) +{ + /* XXX this test is incomplete. We need to have a way to specifiy + the rounding method and test the critical cases. So far, only + unproblematic numbers are tested. */ + + init_max_error (); + + check_long ("lrint (0.0) == 0", FUNC(lrint) (0.0), 0, 0, 0, 0); + check_long ("lrint (-0) == 0", FUNC(lrint) (minus_zero), 0, 0, 0, 0); + check_long ("lrint (0.2) == 0", FUNC(lrint) (0.2L), 0, 0, 0, 0); + check_long ("lrint (-0.2) == 0", FUNC(lrint) (-0.2L), 0, 0, 0, 0); + + check_long ("lrint (1.4) == 1", FUNC(lrint) (1.4L), 1, 0, 0, 0); + check_long ("lrint (-1.4) == -1", FUNC(lrint) (-1.4L), -1, 0, 0, 0); + + check_long ("lrint (8388600.3) == 8388600", FUNC(lrint) (8388600.3L), 8388600, 0, 0, 0); + check_long ("lrint (-8388600.3) == -8388600", FUNC(lrint) (-8388600.3L), -8388600, 0, 0, 0); + + print_max_error ("lrint", 0, 0); +} + +static void +llrint_test (void) +{ + /* XXX this test is incomplete. We need to have a way to specifiy + the rounding method and test the critical cases. So far, only + unproblematic numbers are tested. */ + + init_max_error (); + + check_longlong ("llrint (0.0) == 0", FUNC(llrint) (0.0), 0, 0, 0, 0); + check_longlong ("llrint (-0) == 0", FUNC(llrint) (minus_zero), 0, 0, 0, 0); + check_longlong ("llrint (0.2) == 0", FUNC(llrint) (0.2L), 0, 0, 0, 0); + check_longlong ("llrint (-0.2) == 0", FUNC(llrint) (-0.2L), 0, 0, 0, 0); + + check_longlong ("llrint (1.4) == 1", FUNC(llrint) (1.4L), 1, 0, 0, 0); + check_longlong ("llrint (-1.4) == -1", FUNC(llrint) (-1.4L), -1, 0, 0, 0); + + check_longlong ("llrint (8388600.3) == 8388600", FUNC(llrint) (8388600.3L), 8388600, 0, 0, 0); + check_longlong ("llrint (-8388600.3) == -8388600", FUNC(llrint) (-8388600.3L), -8388600, 0, 0, 0); + + /* Test boundary conditions. */ + /* 0x1FFFFF */ + check_longlong ("llrint (2097151.0) == 2097151LL", FUNC(llrint) (2097151.0), 2097151LL, 0, 0, 0); + /* 0x800000 */ + check_longlong ("llrint (8388608.0) == 8388608LL", FUNC(llrint) (8388608.0), 8388608LL, 0, 0, 0); + /* 0x1000000 */ + check_longlong ("llrint (16777216.0) == 16777216LL", FUNC(llrint) (16777216.0), 16777216LL, 0, 0, 0); + /* 0x20000000000 */ + check_longlong ("llrint (2199023255552.0) == 2199023255552LL", FUNC(llrint) (2199023255552.0), 2199023255552LL, 0, 0, 0); + /* 0x40000000000 */ + check_longlong ("llrint (4398046511104.0) == 4398046511104LL", FUNC(llrint) (4398046511104.0), 4398046511104LL, 0, 0, 0); + /* 0x10000000000000 */ + check_longlong ("llrint (4503599627370496.0) == 4503599627370496LL", FUNC(llrint) (4503599627370496.0), 4503599627370496LL, 0, 0, 0); + /* 0x10000080000000 */ + check_longlong ("llrint (4503601774854144.0) == 4503601774854144LL", FUNC(llrint) (4503601774854144.0), 4503601774854144LL, 0, 0, 0); + /* 0x20000000000000 */ + check_longlong ("llrint (9007199254740992.0) == 9007199254740992LL", FUNC(llrint) (9007199254740992.0), 9007199254740992LL, 0, 0, 0); + /* 0x80000000000000 */ + check_longlong ("llrint (36028797018963968.0) == 36028797018963968LL", FUNC(llrint) (36028797018963968.0), 36028797018963968LL, 0, 0, 0); + /* 0x100000000000000 */ + check_longlong ("llrint (72057594037927936.0) == 72057594037927936LL", FUNC(llrint) (72057594037927936.0), 72057594037927936LL, 0, 0, 0); + + print_max_error ("llrint", 0, 0); +} + +static void +log_test (void) +{ + errno = 0; + FUNC(log) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + init_max_error (); + + check_float ("log (0) == -inf plus division by zero exception", FUNC(log) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("log (-0) == -inf plus division by zero exception", FUNC(log) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_float ("log (1) == 0", FUNC(log) (1), 0, 0, 0, 0); + + check_float ("log (-1) == NaN plus invalid exception", FUNC(log) (-1), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("log (inf) == inf", FUNC(log) (plus_infty), plus_infty, 0, 0, 0); + + check_float ("log (e) == 1", FUNC(log) (M_El), 1, DELTA1163, 0, 0); + check_float ("log (1.0 / M_El) == -1", FUNC(log) (1.0 / M_El), -1, DELTA1164, 0, 0); + check_float ("log (2) == M_LN2l", FUNC(log) (2), M_LN2l, 0, 0, 0); + check_float ("log (10) == M_LN10l", FUNC(log) (10), M_LN10l, 0, 0, 0); + check_float ("log (0.7) == -0.35667494393873237891263871124118447", FUNC(log) (0.7L), -0.35667494393873237891263871124118447L, DELTA1167, 0, 0); + + print_max_error ("log", DELTAlog, 0); +} + + +static void +log10_test (void) +{ + errno = 0; + FUNC(log10) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("log10 (0) == -inf plus division by zero exception", FUNC(log10) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("log10 (-0) == -inf plus division by zero exception", FUNC(log10) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_float ("log10 (1) == 0", FUNC(log10) (1), 0, 0, 0, 0); + + /* log10 (x) == NaN plus invalid exception if x < 0. */ + check_float ("log10 (-1) == NaN plus invalid exception", FUNC(log10) (-1), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("log10 (inf) == inf", FUNC(log10) (plus_infty), plus_infty, 0, 0, 0); + check_float ("log10 (NaN) == NaN", FUNC(log10) (nan_value), nan_value, 0, 0, 0); + + check_float ("log10 (0.1) == -1", FUNC(log10) (0.1L), -1, 0, 0, 0); + check_float ("log10 (10.0) == 1", FUNC(log10) (10.0), 1, 0, 0, 0); + check_float ("log10 (100.0) == 2", FUNC(log10) (100.0), 2, 0, 0, 0); + check_float ("log10 (10000.0) == 4", FUNC(log10) (10000.0), 4, 0, 0, 0); + check_float ("log10 (e) == log10(e)", FUNC(log10) (M_El), M_LOG10El, DELTA1178, 0, 0); + check_float ("log10 (0.7) == -0.15490195998574316929", FUNC(log10) (0.7L), -0.15490195998574316929L, DELTA1179, 0, 0); + + print_max_error ("log10", DELTAlog10, 0); +} + + +static void +log1p_test (void) +{ + errno = 0; + FUNC(log1p) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("log1p (0) == 0", FUNC(log1p) (0), 0, 0, 0, 0); + check_float ("log1p (-0) == -0", FUNC(log1p) (minus_zero), minus_zero, 0, 0, 0); + + check_float ("log1p (-1) == -inf plus division by zero exception", FUNC(log1p) (-1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("log1p (-2) == NaN plus invalid exception", FUNC(log1p) (-2), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("log1p (inf) == inf", FUNC(log1p) (plus_infty), plus_infty, 0, 0, 0); + check_float ("log1p (NaN) == NaN", FUNC(log1p) (nan_value), nan_value, 0, 0, 0); + + check_float ("log1p (M_El - 1.0) == 1", FUNC(log1p) (M_El - 1.0), 1, DELTA1186, 0, 0); + + check_float ("log1p (-0.3) == -0.35667494393873237891263871124118447", FUNC(log1p) (-0.3L), -0.35667494393873237891263871124118447L, DELTA1187, 0, 0); + + print_max_error ("log1p", DELTAlog1p, 0); +} + + +static void +log2_test (void) +{ + errno = 0; + FUNC(log2) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("log2 (0) == -inf plus division by zero exception", FUNC(log2) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("log2 (-0) == -inf plus division by zero exception", FUNC(log2) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_float ("log2 (1) == 0", FUNC(log2) (1), 0, 0, 0, 0); + + check_float ("log2 (-1) == NaN plus invalid exception", FUNC(log2) (-1), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("log2 (inf) == inf", FUNC(log2) (plus_infty), plus_infty, 0, 0, 0); + check_float ("log2 (NaN) == NaN", FUNC(log2) (nan_value), nan_value, 0, 0, 0); + + check_float ("log2 (e) == M_LOG2El", FUNC(log2) (M_El), M_LOG2El, 0, 0, 0); + check_float ("log2 (2.0) == 1", FUNC(log2) (2.0), 1, 0, 0, 0); + check_float ("log2 (16.0) == 4", FUNC(log2) (16.0), 4, 0, 0, 0); + check_float ("log2 (256.0) == 8", FUNC(log2) (256.0), 8, 0, 0, 0); + check_float ("log2 (0.7) == -0.51457317282975824043", FUNC(log2) (0.7L), -0.51457317282975824043L, DELTA1198, 0, 0); + + print_max_error ("log2", DELTAlog2, 0); +} + + +static void +logb_test (void) +{ + init_max_error (); + + check_float ("logb (inf) == inf", FUNC(logb) (plus_infty), plus_infty, 0, 0, 0); + check_float ("logb (-inf) == inf", FUNC(logb) (minus_infty), plus_infty, 0, 0, 0); + + check_float ("logb (0) == -inf plus division by zero exception", FUNC(logb) (0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_float ("logb (-0) == -inf plus division by zero exception", FUNC(logb) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("logb (NaN) == NaN", FUNC(logb) (nan_value), nan_value, 0, 0, 0); + + check_float ("logb (1) == 0", FUNC(logb) (1), 0, 0, 0, 0); + check_float ("logb (e) == 1", FUNC(logb) (M_El), 1, 0, 0, 0); + check_float ("logb (1024) == 10", FUNC(logb) (1024), 10, 0, 0, 0); + check_float ("logb (-2000) == 10", FUNC(logb) (-2000), 10, 0, 0, 0); + + print_max_error ("logb", 0, 0); +} + +static void +lround_test (void) +{ + init_max_error (); + + check_long ("lround (0) == 0", FUNC(lround) (0), 0, 0, 0, 0); + check_long ("lround (-0) == 0", FUNC(lround) (minus_zero), 0, 0, 0, 0); + check_long ("lround (0.2) == 0.0", FUNC(lround) (0.2L), 0.0, 0, 0, 0); + check_long ("lround (-0.2) == 0", FUNC(lround) (-0.2L), 0, 0, 0, 0); + check_long ("lround (0.5) == 1", FUNC(lround) (0.5), 1, 0, 0, 0); + check_long ("lround (-0.5) == -1", FUNC(lround) (-0.5), -1, 0, 0, 0); + check_long ("lround (0.8) == 1", FUNC(lround) (0.8L), 1, 0, 0, 0); + check_long ("lround (-0.8) == -1", FUNC(lround) (-0.8L), -1, 0, 0, 0); + check_long ("lround (1.5) == 2", FUNC(lround) (1.5), 2, 0, 0, 0); + check_long ("lround (-1.5) == -2", FUNC(lround) (-1.5), -2, 0, 0, 0); + check_long ("lround (22514.5) == 22515", FUNC(lround) (22514.5), 22515, 0, 0, 0); + check_long ("lround (-22514.5) == -22515", FUNC(lround) (-22514.5), -22515, 0, 0, 0); +#ifndef TEST_FLOAT + check_long ("lround (2097152.5) == 2097153", FUNC(lround) (2097152.5), 2097153, 0, 0, 0); + check_long ("lround (-2097152.5) == -2097153", FUNC(lround) (-2097152.5), -2097153, 0, 0, 0); +#endif + print_max_error ("lround", 0, 0); +} + + +static void +llround_test (void) +{ + init_max_error (); + + check_longlong ("llround (0) == 0", FUNC(llround) (0), 0, 0, 0, 0); + check_longlong ("llround (-0) == 0", FUNC(llround) (minus_zero), 0, 0, 0, 0); + check_longlong ("llround (0.2) == 0.0", FUNC(llround) (0.2L), 0.0, 0, 0, 0); + check_longlong ("llround (-0.2) == 0", FUNC(llround) (-0.2L), 0, 0, 0, 0); + check_longlong ("llround (0.5) == 1", FUNC(llround) (0.5), 1, 0, 0, 0); + check_longlong ("llround (-0.5) == -1", FUNC(llround) (-0.5), -1, 0, 0, 0); + check_longlong ("llround (0.8) == 1", FUNC(llround) (0.8L), 1, 0, 0, 0); + check_longlong ("llround (-0.8) == -1", FUNC(llround) (-0.8L), -1, 0, 0, 0); + check_longlong ("llround (1.5) == 2", FUNC(llround) (1.5), 2, 0, 0, 0); + check_longlong ("llround (-1.5) == -2", FUNC(llround) (-1.5), -2, 0, 0, 0); + check_longlong ("llround (22514.5) == 22515", FUNC(llround) (22514.5), 22515, 0, 0, 0); + check_longlong ("llround (-22514.5) == -22515", FUNC(llround) (-22514.5), -22515, 0, 0, 0); +#ifndef TEST_FLOAT + check_longlong ("llround (2097152.5) == 2097153", FUNC(llround) (2097152.5), 2097153, 0, 0, 0); + check_longlong ("llround (-2097152.5) == -2097153", FUNC(llround) (-2097152.5), -2097153, 0, 0, 0); + check_longlong ("llround (34359738368.5) == 34359738369ll", FUNC(llround) (34359738368.5), 34359738369ll, 0, 0, 0); + check_longlong ("llround (-34359738368.5) == -34359738369ll", FUNC(llround) (-34359738368.5), -34359738369ll, 0, 0, 0); +#endif + + /* Test boundary conditions. */ + /* 0x1FFFFF */ + check_longlong ("llround (2097151.0) == 2097151LL", FUNC(llround) (2097151.0), 2097151LL, 0, 0, 0); + /* 0x800000 */ + check_longlong ("llround (8388608.0) == 8388608LL", FUNC(llround) (8388608.0), 8388608LL, 0, 0, 0); + /* 0x1000000 */ + check_longlong ("llround (16777216.0) == 16777216LL", FUNC(llround) (16777216.0), 16777216LL, 0, 0, 0); + /* 0x20000000000 */ + check_longlong ("llround (2199023255552.0) == 2199023255552LL", FUNC(llround) (2199023255552.0), 2199023255552LL, 0, 0, 0); + /* 0x40000000000 */ + check_longlong ("llround (4398046511104.0) == 4398046511104LL", FUNC(llround) (4398046511104.0), 4398046511104LL, 0, 0, 0); + /* 0x10000000000000 */ + check_longlong ("llround (4503599627370496.0) == 4503599627370496LL", FUNC(llround) (4503599627370496.0), 4503599627370496LL, 0, 0, 0); + /* 0x10000080000000 */ + check_longlong ("llrint (4503601774854144.0) == 4503601774854144LL", FUNC(llrint) (4503601774854144.0), 4503601774854144LL, 0, 0, 0); + /* 0x20000000000000 */ + check_longlong ("llround (9007199254740992.0) == 9007199254740992LL", FUNC(llround) (9007199254740992.0), 9007199254740992LL, 0, 0, 0); + /* 0x80000000000000 */ + check_longlong ("llround (36028797018963968.0) == 36028797018963968LL", FUNC(llround) (36028797018963968.0), 36028797018963968LL, 0, 0, 0); + /* 0x100000000000000 */ + check_longlong ("llround (72057594037927936.0) == 72057594037927936LL", FUNC(llround) (72057594037927936.0), 72057594037927936LL, 0, 0, 0); + +#ifndef TEST_FLOAT + /* 0x100000000 */ + check_longlong ("llround (4294967295.5) == 4294967296LL", FUNC(llround) (4294967295.5), 4294967296LL, 0, 0, 0); + /* 0x200000000 */ + check_longlong ("llround (8589934591.5) == 8589934592LL", FUNC(llround) (8589934591.5), 8589934592LL, 0, 0, 0); +#endif + + print_max_error ("llround", 0, 0); +} + +static void +modf_test (void) +{ + FLOAT x; + + init_max_error (); + + check_float ("modf (inf, &x) == 0", FUNC(modf) (plus_infty, &x), 0, 0, 0, 0); + check_float ("modf (inf, &x) sets x to plus_infty", x, plus_infty, 0, 0, 0); + check_float ("modf (-inf, &x) == -0", FUNC(modf) (minus_infty, &x), minus_zero, 0, 0, 0); + check_float ("modf (-inf, &x) sets x to minus_infty", x, minus_infty, 0, 0, 0); + check_float ("modf (NaN, &x) == NaN", FUNC(modf) (nan_value, &x), nan_value, 0, 0, 0); + check_float ("modf (NaN, &x) sets x to nan_value", x, nan_value, 0, 0, 0); + check_float ("modf (0, &x) == 0", FUNC(modf) (0, &x), 0, 0, 0, 0); + check_float ("modf (0, &x) sets x to 0", x, 0, 0, 0, 0); + check_float ("modf (1.5, &x) == 0.5", FUNC(modf) (1.5, &x), 0.5, 0, 0, 0); + check_float ("modf (1.5, &x) sets x to 1", x, 1, 0, 0, 0); + check_float ("modf (2.5, &x) == 0.5", FUNC(modf) (2.5, &x), 0.5, 0, 0, 0); + check_float ("modf (2.5, &x) sets x to 2", x, 2, 0, 0, 0); + check_float ("modf (-2.5, &x) == -0.5", FUNC(modf) (-2.5, &x), -0.5, 0, 0, 0); + check_float ("modf (-2.5, &x) sets x to -2", x, -2, 0, 0, 0); + check_float ("modf (20, &x) == 0", FUNC(modf) (20, &x), 0, 0, 0, 0); + check_float ("modf (20, &x) sets x to 20", x, 20, 0, 0, 0); + check_float ("modf (21, &x) == 0", FUNC(modf) (21, &x), 0, 0, 0, 0); + check_float ("modf (21, &x) sets x to 21", x, 21, 0, 0, 0); + check_float ("modf (89.5, &x) == 0.5", FUNC(modf) (89.5, &x), 0.5, 0, 0, 0); + check_float ("modf (89.5, &x) sets x to 89", x, 89, 0, 0, 0); + + print_max_error ("modf", 0, 0); +} + +static void +nearbyint_test (void) +{ + init_max_error (); + + check_float ("nearbyint (0.0) == 0.0", FUNC(nearbyint) (0.0), 0.0, 0, 0, 0); + check_float ("nearbyint (-0) == -0", FUNC(nearbyint) (minus_zero), minus_zero, 0, 0, 0); + check_float ("nearbyint (inf) == inf", FUNC(nearbyint) (plus_infty), plus_infty, 0, 0, 0); + check_float ("nearbyint (-inf) == -inf", FUNC(nearbyint) (minus_infty), minus_infty, 0, 0, 0); + check_float ("nearbyint (NaN) == NaN", FUNC(nearbyint) (nan_value), nan_value, 0, 0, 0); + + /* Default rounding mode is round to nearest. */ + check_float ("nearbyint (0.5) == 0.0", FUNC(nearbyint) (0.5), 0.0, 0, 0, 0); + check_float ("nearbyint (1.5) == 2.0", FUNC(nearbyint) (1.5), 2.0, 0, 0, 0); + check_float ("nearbyint (-0.5) == -0", FUNC(nearbyint) (-0.5), minus_zero, 0, 0, 0); + check_float ("nearbyint (-1.5) == -2.0", FUNC(nearbyint) (-1.5), -2.0, 0, 0, 0); + + print_max_error ("nearbyint", 0, 0); +} + +static void +nextafter_test (void) +{ + + init_max_error (); + + check_float ("nextafter (0, 0) == 0", FUNC(nextafter) (0, 0), 0, 0, 0, 0); + check_float ("nextafter (-0, 0) == 0", FUNC(nextafter) (minus_zero, 0), 0, 0, 0, 0); + check_float ("nextafter (0, -0) == -0", FUNC(nextafter) (0, minus_zero), minus_zero, 0, 0, 0); + check_float ("nextafter (-0, -0) == -0", FUNC(nextafter) (minus_zero, minus_zero), minus_zero, 0, 0, 0); + + check_float ("nextafter (9, 9) == 9", FUNC(nextafter) (9, 9), 9, 0, 0, 0); + check_float ("nextafter (-9, -9) == -9", FUNC(nextafter) (-9, -9), -9, 0, 0, 0); + check_float ("nextafter (inf, inf) == inf", FUNC(nextafter) (plus_infty, plus_infty), plus_infty, 0, 0, 0); + check_float ("nextafter (-inf, -inf) == -inf", FUNC(nextafter) (minus_infty, minus_infty), minus_infty, 0, 0, 0); + + check_float ("nextafter (NaN, 1.1) == NaN", FUNC(nextafter) (nan_value, 1.1L), nan_value, 0, 0, 0); + check_float ("nextafter (1.1, NaN) == NaN", FUNC(nextafter) (1.1L, nan_value), nan_value, 0, 0, 0); + check_float ("nextafter (NaN, NaN) == NaN", FUNC(nextafter) (nan_value, nan_value), nan_value, 0, 0, 0); + + /* XXX We need the hexadecimal FP number representation here for further + tests. */ + + print_max_error ("nextafter", 0, 0); +} + + +#if 0 /* XXX scp XXX */ +static void +nexttoward_test (void) +{ + init_max_error (); + check_float ("nexttoward (0, 0) == 0", FUNC(nexttoward) (0, 0), 0, 0, 0, 0); + check_float ("nexttoward (-0, 0) == 0", FUNC(nexttoward) (minus_zero, 0), 0, 0, 0, 0); + check_float ("nexttoward (0, -0) == -0", FUNC(nexttoward) (0, minus_zero), minus_zero, 0, 0, 0); + check_float ("nexttoward (-0, -0) == -0", FUNC(nexttoward) (minus_zero, minus_zero), minus_zero, 0, 0, 0); + + check_float ("nexttoward (9, 9) == 9", FUNC(nexttoward) (9, 9), 9, 0, 0, 0); + check_float ("nexttoward (-9, -9) == -9", FUNC(nexttoward) (-9, -9), -9, 0, 0, 0); + check_float ("nexttoward (inf, inf) == inf", FUNC(nexttoward) (plus_infty, plus_infty), plus_infty, 0, 0, 0); + check_float ("nexttoward (-inf, -inf) == -inf", FUNC(nexttoward) (minus_infty, minus_infty), minus_infty, 0, 0, 0); + + check_float ("nexttoward (NaN, 1.1) == NaN", FUNC(nexttoward) (nan_value, 1.1L), nan_value, 0, 0, 0); + check_float ("nexttoward (1.1, NaN) == NaN", FUNC(nexttoward) (1.1L, nan_value), nan_value, 0, 0, 0); + check_float ("nexttoward (NaN, NaN) == NaN", FUNC(nexttoward) (nan_value, nan_value), nan_value, 0, 0, 0); + + /* XXX We need the hexadecimal FP number representation here for further + tests. */ + + print_max_error ("nexttoward", 0, 0); +} +#endif + + +static void +pow_test (void) +{ + + errno = 0; + FUNC(pow) (0, 0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("pow (0, 0) == 1", FUNC(pow) (0, 0), 1, 0, 0, 0); + check_float ("pow (0, -0) == 1", FUNC(pow) (0, minus_zero), 1, 0, 0, 0); + check_float ("pow (-0, 0) == 1", FUNC(pow) (minus_zero, 0), 1, 0, 0, 0); + check_float ("pow (-0, -0) == 1", FUNC(pow) (minus_zero, minus_zero), 1, 0, 0, 0); + + check_float ("pow (10, 0) == 1", FUNC(pow) (10, 0), 1, 0, 0, 0); + check_float ("pow (10, -0) == 1", FUNC(pow) (10, minus_zero), 1, 0, 0, 0); + check_float ("pow (-10, 0) == 1", FUNC(pow) (-10, 0), 1, 0, 0, 0); + check_float ("pow (-10, -0) == 1", FUNC(pow) (-10, minus_zero), 1, 0, 0, 0); + + check_float ("pow (NaN, 0) == 1", FUNC(pow) (nan_value, 0), 1, 0, 0, 0); + check_float ("pow (NaN, -0) == 1", FUNC(pow) (nan_value, minus_zero), 1, 0, 0, 0); + + +#ifndef TEST_INLINE + check_float ("pow (1.1, inf) == inf", FUNC(pow) (1.1L, plus_infty), plus_infty, 0, 0, 0); + check_float ("pow (inf, inf) == inf", FUNC(pow) (plus_infty, plus_infty), plus_infty, 0, 0, 0); + check_float ("pow (-1.1, inf) == inf", FUNC(pow) (-1.1L, plus_infty), plus_infty, 0, 0, 0); + check_float ("pow (-inf, inf) == inf", FUNC(pow) (minus_infty, plus_infty), plus_infty, 0, 0, 0); + + check_float ("pow (0.9, inf) == 0", FUNC(pow) (0.9L, plus_infty), 0, 0, 0, 0); + check_float ("pow (1e-7, inf) == 0", FUNC(pow) (1e-7L, plus_infty), 0, 0, 0, 0); + check_float ("pow (-0.9, inf) == 0", FUNC(pow) (-0.9L, plus_infty), 0, 0, 0, 0); + check_float ("pow (-1e-7, inf) == 0", FUNC(pow) (-1e-7L, plus_infty), 0, 0, 0, 0); + + check_float ("pow (1.1, -inf) == 0", FUNC(pow) (1.1L, minus_infty), 0, 0, 0, 0); + check_float ("pow (inf, -inf) == 0", FUNC(pow) (plus_infty, minus_infty), 0, 0, 0, 0); + check_float ("pow (-1.1, -inf) == 0", FUNC(pow) (-1.1L, minus_infty), 0, 0, 0, 0); + check_float ("pow (-inf, -inf) == 0", FUNC(pow) (minus_infty, minus_infty), 0, 0, 0, 0); + + check_float ("pow (0.9, -inf) == inf", FUNC(pow) (0.9L, minus_infty), plus_infty, 0, 0, 0); + check_float ("pow (1e-7, -inf) == inf", FUNC(pow) (1e-7L, minus_infty), plus_infty, 0, 0, 0); + check_float ("pow (-0.9, -inf) == inf", FUNC(pow) (-0.9L, minus_infty), plus_infty, 0, 0, 0); + check_float ("pow (-1e-7, -inf) == inf", FUNC(pow) (-1e-7L, minus_infty), plus_infty, 0, 0, 0); + + check_float ("pow (inf, 1e-7) == inf", FUNC(pow) (plus_infty, 1e-7L), plus_infty, 0, 0, 0); + check_float ("pow (inf, 1) == inf", FUNC(pow) (plus_infty, 1), plus_infty, 0, 0, 0); + check_float ("pow (inf, 1e7) == inf", FUNC(pow) (plus_infty, 1e7L), plus_infty, 0, 0, 0); + + check_float ("pow (inf, -1e-7) == 0", FUNC(pow) (plus_infty, -1e-7L), 0, 0, 0, 0); + check_float ("pow (inf, -1) == 0", FUNC(pow) (plus_infty, -1), 0, 0, 0, 0); + check_float ("pow (inf, -1e7) == 0", FUNC(pow) (plus_infty, -1e7L), 0, 0, 0, 0); + + check_float ("pow (-inf, 1) == -inf", FUNC(pow) (minus_infty, 1), minus_infty, 0, 0, 0); + check_float ("pow (-inf, 11) == -inf", FUNC(pow) (minus_infty, 11), minus_infty, 0, 0, 0); + check_float ("pow (-inf, 1001) == -inf", FUNC(pow) (minus_infty, 1001), minus_infty, 0, 0, 0); + + check_float ("pow (-inf, 2) == inf", FUNC(pow) (minus_infty, 2), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 12) == inf", FUNC(pow) (minus_infty, 12), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 1002) == inf", FUNC(pow) (minus_infty, 1002), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 0.1) == inf", FUNC(pow) (minus_infty, 0.1L), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 1.1) == inf", FUNC(pow) (minus_infty, 1.1L), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 11.1) == inf", FUNC(pow) (minus_infty, 11.1L), plus_infty, 0, 0, 0); + check_float ("pow (-inf, 1001.1) == inf", FUNC(pow) (minus_infty, 1001.1L), plus_infty, 0, 0, 0); + + check_float ("pow (-inf, -1) == -0", FUNC(pow) (minus_infty, -1), minus_zero, 0, 0, 0); + check_float ("pow (-inf, -11) == -0", FUNC(pow) (minus_infty, -11), minus_zero, 0, 0, 0); + check_float ("pow (-inf, -1001) == -0", FUNC(pow) (minus_infty, -1001), minus_zero, 0, 0, 0); + + check_float ("pow (-inf, -2) == 0", FUNC(pow) (minus_infty, -2), 0, 0, 0, 0); + check_float ("pow (-inf, -12) == 0", FUNC(pow) (minus_infty, -12), 0, 0, 0, 0); + check_float ("pow (-inf, -1002) == 0", FUNC(pow) (minus_infty, -1002), 0, 0, 0, 0); + check_float ("pow (-inf, -0.1) == 0", FUNC(pow) (minus_infty, -0.1L), 0, 0, 0, 0); + check_float ("pow (-inf, -1.1) == 0", FUNC(pow) (minus_infty, -1.1L), 0, 0, 0, 0); + check_float ("pow (-inf, -11.1) == 0", FUNC(pow) (minus_infty, -11.1L), 0, 0, 0, 0); + check_float ("pow (-inf, -1001.1) == 0", FUNC(pow) (minus_infty, -1001.1L), 0, 0, 0, 0); +#endif + + check_float ("pow (NaN, NaN) == NaN", FUNC(pow) (nan_value, nan_value), nan_value, 0, 0, 0); + check_float ("pow (0, NaN) == NaN", FUNC(pow) (0, nan_value), nan_value, 0, 0, 0); + check_float ("pow (1, NaN) == 1", FUNC(pow) (1, nan_value), 1, 0, 0, 0); + check_float ("pow (-1, NaN) == NaN", FUNC(pow) (-1, nan_value), nan_value, 0, 0, 0); + check_float ("pow (NaN, 1) == NaN", FUNC(pow) (nan_value, 1), nan_value, 0, 0, 0); + check_float ("pow (NaN, -1) == NaN", FUNC(pow) (nan_value, -1), nan_value, 0, 0, 0); + + /* pow (x, NaN) == NaN. */ + check_float ("pow (3.0, NaN) == NaN", FUNC(pow) (3.0, nan_value), nan_value, 0, 0, 0); + + check_float ("pow (1, inf) == 1", FUNC(pow) (1, plus_infty), 1, 0, 0, 0); + check_float ("pow (-1, inf) == 1", FUNC(pow) (-1, plus_infty), 1, 0, 0, 0); + check_float ("pow (1, -inf) == 1", FUNC(pow) (1, minus_infty), 1, 0, 0, 0); + check_float ("pow (-1, -inf) == 1", FUNC(pow) (-1, minus_infty), 1, 0, 0, 0); + + check_float ("pow (-0.1, 1.1) == NaN plus invalid exception", FUNC(pow) (-0.1L, 1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("pow (-0.1, -1.1) == NaN plus invalid exception", FUNC(pow) (-0.1L, -1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("pow (-10.1, 1.1) == NaN plus invalid exception", FUNC(pow) (-10.1L, 1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("pow (-10.1, -1.1) == NaN plus invalid exception", FUNC(pow) (-10.1L, -1.1L), nan_value, 0, 0, INVALID_EXCEPTION); + + check_float ("pow (0, -1) == inf plus division by zero exception", FUNC(pow) (0, -1), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (0, -11) == inf plus division by zero exception", FUNC(pow) (0, -11), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (-0, -1) == -inf plus division by zero exception", FUNC(pow) (minus_zero, -1), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (-0, -11) == -inf plus division by zero exception", FUNC(pow) (minus_zero, -11), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + check_float ("pow (0, -2) == inf plus division by zero exception", FUNC(pow) (0, -2), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (0, -11.1) == inf plus division by zero exception", FUNC(pow) (0, -11.1L), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (-0, -2) == inf plus division by zero exception", FUNC(pow) (minus_zero, -2), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("pow (-0, -11.1) == inf plus division by zero exception", FUNC(pow) (minus_zero, -11.1L), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + + + check_float ("pow (0, 1) == 0", FUNC(pow) (0, 1), 0, 0, 0, 0); + check_float ("pow (0, 11) == 0", FUNC(pow) (0, 11), 0, 0, 0, 0); + + check_float ("pow (-0, 1) == -0", FUNC(pow) (minus_zero, 1), minus_zero, 0, 0, 0); + check_float ("pow (-0, 11) == -0", FUNC(pow) (minus_zero, 11), minus_zero, 0, 0, 0); + + + check_float ("pow (0, 2) == 0", FUNC(pow) (0, 2), 0, 0, 0, 0); + check_float ("pow (0, 11.1) == 0", FUNC(pow) (0, 11.1L), 0, 0, 0, 0); + + + check_float ("pow (-0, 2) == 0", FUNC(pow) (minus_zero, 2), 0, 0, 0, 0); + check_float ("pow (-0, 11.1) == 0", FUNC(pow) (minus_zero, 11.1L), 0, 0, 0, 0); + +#ifndef TEST_INLINE + /* pow (x, +inf) == +inf for |x| > 1. */ + check_float ("pow (1.5, inf) == inf", FUNC(pow) (1.5, plus_infty), plus_infty, 0, 0, 0); + + /* pow (x, +inf) == +0 for |x| < 1. */ + check_float ("pow (0.5, inf) == 0.0", FUNC(pow) (0.5, plus_infty), 0.0, 0, 0, 0); + + /* pow (x, -inf) == +0 for |x| > 1. */ + check_float ("pow (1.5, -inf) == 0.0", FUNC(pow) (1.5, minus_infty), 0.0, 0, 0, 0); + + /* pow (x, -inf) == +inf for |x| < 1. */ + check_float ("pow (0.5, -inf) == inf", FUNC(pow) (0.5, minus_infty), plus_infty, 0, 0, 0); +#endif + + /* pow (+inf, y) == +inf for y > 0. */ + check_float ("pow (inf, 2) == inf", FUNC(pow) (plus_infty, 2), plus_infty, 0, 0, 0); + + /* pow (+inf, y) == +0 for y < 0. */ + check_float ("pow (inf, -1) == 0.0", FUNC(pow) (plus_infty, -1), 0.0, 0, 0, 0); + + /* pow (-inf, y) == -inf for y an odd integer > 0. */ + check_float ("pow (-inf, 27) == -inf", FUNC(pow) (minus_infty, 27), minus_infty, 0, 0, 0); + + /* pow (-inf, y) == +inf for y > 0 and not an odd integer. */ + check_float ("pow (-inf, 28) == inf", FUNC(pow) (minus_infty, 28), plus_infty, 0, 0, 0); + + /* pow (-inf, y) == -0 for y an odd integer < 0. */ + check_float ("pow (-inf, -3) == -0", FUNC(pow) (minus_infty, -3), minus_zero, 0, 0, 0); + /* pow (-inf, y) == +0 for y < 0 and not an odd integer. */ + check_float ("pow (-inf, -2.0) == 0.0", FUNC(pow) (minus_infty, -2.0), 0.0, 0, 0, 0); + + /* pow (+0, y) == +0 for y an odd integer > 0. */ + check_float ("pow (0.0, 27) == 0.0", FUNC(pow) (0.0, 27), 0.0, 0, 0, 0); + + /* pow (-0, y) == -0 for y an odd integer > 0. */ + check_float ("pow (-0, 27) == -0", FUNC(pow) (minus_zero, 27), minus_zero, 0, 0, 0); + + /* pow (+0, y) == +0 for y > 0 and not an odd integer. */ + check_float ("pow (0.0, 4) == 0.0", FUNC(pow) (0.0, 4), 0.0, 0, 0, 0); + + /* pow (-0, y) == +0 for y > 0 and not an odd integer. */ + check_float ("pow (-0, 4) == 0.0", FUNC(pow) (minus_zero, 4), 0.0, 0, 0, 0); + + check_float ("pow (0.7, 1.2) == 0.65180494056638638188", FUNC(pow) (0.7L, 1.2L), 0.65180494056638638188L, DELTA1398, 0, 0); + +#if defined TEST_DOUBLE || defined TEST_LDOUBLE + check_float ("pow (-7.49321e+133, -9.80818e+16) == 0", FUNC(pow) (-7.49321e+133, -9.80818e+16), 0, 0, 0, 0); +#endif + + print_max_error ("pow", DELTApow, 0); +} + +static void +remainder_test (void) +{ + errno = 0; + FUNC(remainder) (1.625, 1.0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("remainder (1, 0) == NaN plus invalid exception", FUNC(remainder) (1, 0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remainder (1, -0) == NaN plus invalid exception", FUNC(remainder) (1, minus_zero), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remainder (inf, 1) == NaN plus invalid exception", FUNC(remainder) (plus_infty, 1), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remainder (-inf, 1) == NaN plus invalid exception", FUNC(remainder) (minus_infty, 1), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remainder (NaN, NaN) == NaN", FUNC(remainder) (nan_value, nan_value), nan_value, 0, 0, 0); + + check_float ("remainder (1.625, 1.0) == -0.375", FUNC(remainder) (1.625, 1.0), -0.375, 0, 0, 0); + check_float ("remainder (-1.625, 1.0) == 0.375", FUNC(remainder) (-1.625, 1.0), 0.375, 0, 0, 0); + check_float ("remainder (1.625, -1.0) == -0.375", FUNC(remainder) (1.625, -1.0), -0.375, 0, 0, 0); + check_float ("remainder (-1.625, -1.0) == 0.375", FUNC(remainder) (-1.625, -1.0), 0.375, 0, 0, 0); + check_float ("remainder (5.0, 2.0) == 1.0", FUNC(remainder) (5.0, 2.0), 1.0, 0, 0, 0); + check_float ("remainder (3.0, 2.0) == -1.0", FUNC(remainder) (3.0, 2.0), -1.0, 0, 0, 0); + + print_max_error ("remainder", 0, 0); +} + +static void +remquo_test (void) +{ + /* x is needed. */ + int x; + + errno = 0; + FUNC(remquo) (1.625, 1.0, &x); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("remquo (1, 0, &x) == NaN plus invalid exception", FUNC(remquo) (1, 0, &x), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remquo (1, -0, &x) == NaN plus invalid exception", FUNC(remquo) (1, minus_zero, &x), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remquo (inf, 1, &x) == NaN plus invalid exception", FUNC(remquo) (plus_infty, 1, &x), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remquo (-inf, 1, &x) == NaN plus invalid exception", FUNC(remquo) (minus_infty, 1, &x), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("remquo (NaN, NaN, &x) == NaN", FUNC(remquo) (nan_value, nan_value, &x), nan_value, 0, 0, 0); + + check_float ("remquo (1.625, 1.0, &x) == -0.375", FUNC(remquo) (1.625, 1.0, &x), -0.375, 0, 0, 0); + check_int ("remquo (1.625, 1.0, &x) sets x to 2", x, 2, 0, 0, 0); + check_float ("remquo (-1.625, 1.0, &x) == 0.375", FUNC(remquo) (-1.625, 1.0, &x), 0.375, 0, 0, 0); + check_int ("remquo (-1.625, 1.0, &x) sets x to -2", x, -2, 0, 0, 0); + check_float ("remquo (1.625, -1.0, &x) == -0.375", FUNC(remquo) (1.625, -1.0, &x), -0.375, 0, 0, 0); + check_int ("remquo (1.625, -1.0, &x) sets x to -2", x, -2, 0, 0, 0); + check_float ("remquo (-1.625, -1.0, &x) == 0.375", FUNC(remquo) (-1.625, -1.0, &x), 0.375, 0, 0, 0); + check_int ("remquo (-1.625, -1.0, &x) sets x to 2", x, 2, 0, 0, 0); + + check_float ("remquo (5, 2, &x) == 1", FUNC(remquo) (5, 2, &x), 1, 0, 0, 0); + check_int ("remquo (5, 2, &x) sets x to 2", x, 2, 0, 0, 0); + check_float ("remquo (3, 2, &x) == -1", FUNC(remquo) (3, 2, &x), -1, 0, 0, 0); + check_int ("remquo (3, 2, &x) sets x to 2", x, 2, 0, 0, 0); + + print_max_error ("remquo", 0, 0); +} + +static void +rint_test (void) +{ + init_max_error (); + + check_float ("rint (0.0) == 0.0", FUNC(rint) (0.0), 0.0, 0, 0, 0); + check_float ("rint (-0) == -0", FUNC(rint) (minus_zero), minus_zero, 0, 0, 0); + check_float ("rint (inf) == inf", FUNC(rint) (plus_infty), plus_infty, 0, 0, 0); + check_float ("rint (-inf) == -inf", FUNC(rint) (minus_infty), minus_infty, 0, 0, 0); + + /* Default rounding mode is round to even. */ + check_float ("rint (0.5) == 0.0", FUNC(rint) (0.5), 0.0, 0, 0, 0); + check_float ("rint (1.5) == 2.0", FUNC(rint) (1.5), 2.0, 0, 0, 0); + check_float ("rint (2.5) == 2.0", FUNC(rint) (2.5), 2.0, 0, 0, 0); + check_float ("rint (3.5) == 4.0", FUNC(rint) (3.5), 4.0, 0, 0, 0); + check_float ("rint (4.5) == 4.0", FUNC(rint) (4.5), 4.0, 0, 0, 0); + check_float ("rint (-0.5) == -0.0", FUNC(rint) (-0.5), -0.0, 0, 0, 0); + check_float ("rint (-1.5) == -2.0", FUNC(rint) (-1.5), -2.0, 0, 0, 0); + check_float ("rint (-2.5) == -2.0", FUNC(rint) (-2.5), -2.0, 0, 0, 0); + check_float ("rint (-3.5) == -4.0", FUNC(rint) (-3.5), -4.0, 0, 0, 0); + check_float ("rint (-4.5) == -4.0", FUNC(rint) (-4.5), -4.0, 0, 0, 0); + + print_max_error ("rint", 0, 0); +} + +static void +round_test (void) +{ + init_max_error (); + + check_float ("round (0) == 0", FUNC(round) (0), 0, 0, 0, 0); + check_float ("round (-0) == -0", FUNC(round) (minus_zero), minus_zero, 0, 0, 0); + check_float ("round (0.2) == 0.0", FUNC(round) (0.2L), 0.0, 0, 0, 0); + check_float ("round (-0.2) == -0", FUNC(round) (-0.2L), minus_zero, 0, 0, 0); + check_float ("round (0.5) == 1.0", FUNC(round) (0.5), 1.0, 0, 0, 0); + check_float ("round (-0.5) == -1.0", FUNC(round) (-0.5), -1.0, 0, 0, 0); + check_float ("round (0.8) == 1.0", FUNC(round) (0.8L), 1.0, 0, 0, 0); + check_float ("round (-0.8) == -1.0", FUNC(round) (-0.8L), -1.0, 0, 0, 0); + check_float ("round (1.5) == 2.0", FUNC(round) (1.5), 2.0, 0, 0, 0); + check_float ("round (-1.5) == -2.0", FUNC(round) (-1.5), -2.0, 0, 0, 0); + check_float ("round (2097152.5) == 2097153", FUNC(round) (2097152.5), 2097153, 0, 0, 0); + check_float ("round (-2097152.5) == -2097153", FUNC(round) (-2097152.5), -2097153, 0, 0, 0); + + print_max_error ("round", 0, 0); +} + + +static void +scalbn_test (void) +{ + + init_max_error (); + + check_float ("scalbn (0, 0) == 0", FUNC(scalbn) (0, 0), 0, 0, 0, 0); + check_float ("scalbn (-0, 0) == -0", FUNC(scalbn) (minus_zero, 0), minus_zero, 0, 0, 0); + + check_float ("scalbn (inf, 1) == inf", FUNC(scalbn) (plus_infty, 1), plus_infty, 0, 0, 0); + check_float ("scalbn (-inf, 1) == -inf", FUNC(scalbn) (minus_infty, 1), minus_infty, 0, 0, 0); + check_float ("scalbn (NaN, 1) == NaN", FUNC(scalbn) (nan_value, 1), nan_value, 0, 0, 0); + + check_float ("scalbn (0.8, 4) == 12.8", FUNC(scalbn) (0.8L, 4), 12.8L, 0, 0, 0); + check_float ("scalbn (-0.854375, 5) == -27.34", FUNC(scalbn) (-0.854375L, 5), -27.34L, 0, 0, 0); + + check_float ("scalbn (1, 0) == 1", FUNC(scalbn) (1, 0L), 1, 0, 0, 0); + + print_max_error ("scalbn", 0, 0); +} + +static void +scalbln_test (void) +{ + + init_max_error (); + + check_float ("scalbln (0, 0) == 0", FUNC(scalbln) (0, 0), 0, 0, 0, 0); + check_float ("scalbln (-0, 0) == -0", FUNC(scalbln) (minus_zero, 0), minus_zero, 0, 0, 0); + + check_float ("scalbln (inf, 1) == inf", FUNC(scalbln) (plus_infty, 1), plus_infty, 0, 0, 0); + check_float ("scalbln (-inf, 1) == -inf", FUNC(scalbln) (minus_infty, 1), minus_infty, 0, 0, 0); + check_float ("scalbln (NaN, 1) == NaN", FUNC(scalbln) (nan_value, 1), nan_value, 0, 0, 0); + + check_float ("scalbln (0.8, 4) == 12.8", FUNC(scalbln) (0.8L, 4), 12.8L, 0, 0, 0); + check_float ("scalbln (-0.854375, 5) == -27.34", FUNC(scalbln) (-0.854375L, 5), -27.34L, 0, 0, 0); + + check_float ("scalbln (1, 0) == 1", FUNC(scalbln) (1, 0L), 1, 0, 0, 0); + + print_max_error ("scalbn", 0, 0); +} + +static void +signbit_test (void) +{ + + init_max_error (); + + check_bool ("signbit (0) == false", signbit (0.0), 0, 0, 0, 0); + check_bool ("signbit (-0) == true", signbit (minus_zero), 1, 0, 0, 0); + check_bool ("signbit (inf) == false", signbit (plus_infty), 0, 0, 0, 0); + check_bool ("signbit (-inf) == true", signbit (minus_infty), 1, 0, 0, 0); + + /* signbit (x) != 0 for x < 0. */ + check_bool ("signbit (-1) == true", signbit (-1.0), 1, 0, 0, 0); + /* signbit (x) == 0 for x >= 0. */ + check_bool ("signbit (1) == false", signbit (1.0), 0, 0, 0, 0); + + print_max_error ("signbit", 0, 0); +} + +static void +sin_test (void) +{ + errno = 0; + FUNC(sin) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("sin (0) == 0", FUNC(sin) (0), 0, 0, 0, 0); + check_float ("sin (-0) == -0", FUNC(sin) (minus_zero), minus_zero, 0, 0, 0); + check_float ("sin (inf) == NaN plus invalid exception", FUNC(sin) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sin (-inf) == NaN plus invalid exception", FUNC(sin) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sin (NaN) == NaN", FUNC(sin) (nan_value), nan_value, 0, 0, 0); + + check_float ("sin (pi/6) == 0.5", FUNC(sin) (M_PI_6l), 0.5, 0, 0, 0); + check_float ("sin (-pi/6) == -0.5", FUNC(sin) (-M_PI_6l), -0.5, 0, 0, 0); + check_float ("sin (pi/2) == 1", FUNC(sin) (M_PI_2l), 1, 0, 0, 0); + check_float ("sin (-pi/2) == -1", FUNC(sin) (-M_PI_2l), -1, 0, 0, 0); + check_float ("sin (0.7) == 0.64421768723769105367261435139872014", FUNC(sin) (0.7L), 0.64421768723769105367261435139872014L, DELTA1524, 0, 0); + + print_max_error ("sin", DELTAsin, 0); + +} + + +static void +sincos_test (void) +{ + FLOAT sin_res, cos_res; + + errno = 0; + FUNC(sincos) (0, &sin_res, &cos_res); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + /* sincos is treated differently because it returns void. */ + FUNC (sincos) (0, &sin_res, &cos_res); + check_float ("sincos (0, &sin_res, &cos_res) puts 0 in sin_res", sin_res, 0, 0, 0, 0); + check_float ("sincos (0, &sin_res, &cos_res) puts 1 in cos_res", cos_res, 1, 0, 0, 0); + + FUNC (sincos) (minus_zero, &sin_res, &cos_res); + check_float ("sincos (-0, &sin_res, &cos_res) puts -0 in sin_res", sin_res, minus_zero, 0, 0, 0); + check_float ("sincos (-0, &sin_res, &cos_res) puts 1 in cos_res", cos_res, 1, 0, 0, 0); + FUNC (sincos) (plus_infty, &sin_res, &cos_res); + check_float ("sincos (inf, &sin_res, &cos_res) puts NaN in sin_res plus invalid exception", sin_res, nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sincos (inf, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0); + FUNC (sincos) (minus_infty, &sin_res, &cos_res); + check_float ("sincos (-inf, &sin_res, &cos_res) puts NaN in sin_res plus invalid exception", sin_res, nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sincos (-inf, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0); + FUNC (sincos) (nan_value, &sin_res, &cos_res); + check_float ("sincos (NaN, &sin_res, &cos_res) puts NaN in sin_res", sin_res, nan_value, 0, 0, 0); + check_float ("sincos (NaN, &sin_res, &cos_res) puts NaN in cos_res", cos_res, nan_value, 0, 0, 0); + + FUNC (sincos) (M_PI_2l, &sin_res, &cos_res); + check_float ("sincos (pi/2, &sin_res, &cos_res) puts 1 in sin_res", sin_res, 1, 0, 0, 0); + check_float ("sincos (pi/2, &sin_res, &cos_res) puts 0 in cos_res", cos_res, 0, DELTA1536, 0, 0); + FUNC (sincos) (M_PI_6l, &sin_res, &cos_res); + check_float ("sincos (pi/6, &sin_res, &cos_res) puts 0.5 in sin_res", sin_res, 0.5, 0, 0, 0); + check_float ("sincos (pi/6, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in cos_res", cos_res, 0.86602540378443864676372317075293616L, 0, 0, 0); + FUNC (sincos) (M_PI_6l*2.0, &sin_res, &cos_res); + check_float ("sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.86602540378443864676372317075293616 in sin_res", sin_res, 0.86602540378443864676372317075293616L, DELTA1539, 0, 0); + check_float ("sincos (M_PI_6l*2.0, &sin_res, &cos_res) puts 0.5 in cos_res", cos_res, 0.5, DELTA1540, 0, 0); + FUNC (sincos) (0.7L, &sin_res, &cos_res); + check_float ("sincos (0.7, &sin_res, &cos_res) puts 0.64421768723769105367261435139872014 in sin_res", sin_res, 0.64421768723769105367261435139872014L, DELTA1541, 0, 0); + check_float ("sincos (0.7, &sin_res, &cos_res) puts 0.76484218728448842625585999019186495 in cos_res", cos_res, 0.76484218728448842625585999019186495L, DELTA1542, 0, 0); + + print_max_error ("sincos", DELTAsincos, 0); +} + +static void +sinh_test (void) +{ + errno = 0; + FUNC(sinh) (0.7L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + check_float ("sinh (0) == 0", FUNC(sinh) (0), 0, 0, 0, 0); + check_float ("sinh (-0) == -0", FUNC(sinh) (minus_zero), minus_zero, 0, 0, 0); + +#ifndef TEST_INLINE + check_float ("sinh (inf) == inf", FUNC(sinh) (plus_infty), plus_infty, 0, 0, 0); + check_float ("sinh (-inf) == -inf", FUNC(sinh) (minus_infty), minus_infty, 0, 0, 0); +#endif + check_float ("sinh (NaN) == NaN", FUNC(sinh) (nan_value), nan_value, 0, 0, 0); + + check_float ("sinh (0.7) == 0.75858370183953350346", FUNC(sinh) (0.7L), 0.75858370183953350346L, DELTA1548, 0, 0); +#if 0 /* XXX scp XXX */ + check_float ("sinh (0x8p-32) == 1.86264514923095703232705808926175479e-9", FUNC(sinh) (0x8p-32L), 1.86264514923095703232705808926175479e-9L, 0, 0, 0); +#endif + + print_max_error ("sinh", DELTAsinh, 0); +} + +static void +sqrt_test (void) +{ + errno = 0; + FUNC(sqrt) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("sqrt (0) == 0", FUNC(sqrt) (0), 0, 0, 0, 0); + check_float ("sqrt (NaN) == NaN", FUNC(sqrt) (nan_value), nan_value, 0, 0, 0); + check_float ("sqrt (inf) == inf", FUNC(sqrt) (plus_infty), plus_infty, 0, 0, 0); + + check_float ("sqrt (-0) == -0", FUNC(sqrt) (minus_zero), minus_zero, 0, 0, 0); + + /* sqrt (x) == NaN plus invalid exception for x < 0. */ + check_float ("sqrt (-1) == NaN plus invalid exception", FUNC(sqrt) (-1), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sqrt (-inf) == NaN plus invalid exception", FUNC(sqrt) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("sqrt (NaN) == NaN", FUNC(sqrt) (nan_value), nan_value, 0, 0, 0); + + check_float ("sqrt (2209) == 47", FUNC(sqrt) (2209), 47, 0, 0, 0); + check_float ("sqrt (4) == 2", FUNC(sqrt) (4), 2, 0, 0, 0); + check_float ("sqrt (2) == M_SQRT2l", FUNC(sqrt) (2), M_SQRT2l, 0, 0, 0); + check_float ("sqrt (0.25) == 0.5", FUNC(sqrt) (0.25), 0.5, 0, 0, 0); + check_float ("sqrt (6642.25) == 81.5", FUNC(sqrt) (6642.25), 81.5, 0, 0, 0); + check_float ("sqrt (15239.9025) == 123.45", FUNC(sqrt) (15239.9025L), 123.45L, DELTA1562, 0, 0); + check_float ("sqrt (0.7) == 0.83666002653407554797817202578518747", FUNC(sqrt) (0.7L), 0.83666002653407554797817202578518747L, 0, 0, 0); + + print_max_error ("sqrt", DELTAsqrt, 0); +} + +static void +tan_test (void) +{ + errno = 0; + FUNC(tan) (0); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("tan (0) == 0", FUNC(tan) (0), 0, 0, 0, 0); + check_float ("tan (-0) == -0", FUNC(tan) (minus_zero), minus_zero, 0, 0, 0); + check_float ("tan (inf) == NaN plus invalid exception", FUNC(tan) (plus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("tan (-inf) == NaN plus invalid exception", FUNC(tan) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("tan (NaN) == NaN", FUNC(tan) (nan_value), nan_value, 0, 0, 0); + + check_float ("tan (pi/4) == 1", FUNC(tan) (M_PI_4l), 1, DELTA1569, 0, 0); + check_float ("tan (0.7) == 0.84228838046307944812813500221293775", FUNC(tan) (0.7L), 0.84228838046307944812813500221293775L, DELTA1570, 0, 0); + + print_max_error ("tan", DELTAtan, 0); +} + +static void +tanh_test (void) +{ + errno = 0; + FUNC(tanh) (0.7L); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + init_max_error (); + + check_float ("tanh (0) == 0", FUNC(tanh) (0), 0, 0, 0, 0); + check_float ("tanh (-0) == -0", FUNC(tanh) (minus_zero), minus_zero, 0, 0, 0); + +#ifndef TEST_INLINE + check_float ("tanh (inf) == 1", FUNC(tanh) (plus_infty), 1, 0, 0, 0); + check_float ("tanh (-inf) == -1", FUNC(tanh) (minus_infty), -1, 0, 0, 0); +#endif + check_float ("tanh (NaN) == NaN", FUNC(tanh) (nan_value), nan_value, 0, 0, 0); + + check_float ("tanh (0.7) == 0.60436777711716349631", FUNC(tanh) (0.7L), 0.60436777711716349631L, DELTA1576, 0, 0); + check_float ("tanh (-0.7) == -0.60436777711716349631", FUNC(tanh) (-0.7L), -0.60436777711716349631L, DELTA1577, 0, 0); + + check_float ("tanh (1.0) == 0.7615941559557648881194582826047935904", FUNC(tanh) (1.0L), 0.7615941559557648881194582826047935904L, 0, 0, 0); + check_float ("tanh (-1.0) == -0.7615941559557648881194582826047935904", FUNC(tanh) (-1.0L), -0.7615941559557648881194582826047935904L, 0, 0, 0); + + /* 2^-57 */ + check_float ("tanh (6.938893903907228377647697925567626953125e-18) == 6.938893903907228377647697925567626953125e-18", FUNC(tanh) (6.938893903907228377647697925567626953125e-18L), 6.938893903907228377647697925567626953125e-18L, 0, 0, 0); + + print_max_error ("tanh", DELTAtanh, 0); +} + +static void +tgamma_test (void) +{ + errno = 0; + FUNC(tgamma) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + feclearexcept (FE_ALL_EXCEPT); + + init_max_error (); + + check_float ("tgamma (inf) == inf", FUNC(tgamma) (plus_infty), plus_infty, 0, 0, 0); + check_float ("tgamma (0) == inf plus divide-by-zero", FUNC(tgamma) (0), plus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("tgamma (-0) == inf plus divide-by-zero", FUNC(tgamma) (minus_zero), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + /* tgamma (x) == NaN plus invalid exception for integer x <= 0. */ + check_float ("tgamma (-2) == NaN plus invalid exception", FUNC(tgamma) (-2), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("tgamma (-inf) == NaN plus invalid exception", FUNC(tgamma) (minus_infty), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("tgamma (NaN) == NaN", FUNC(tgamma) (nan_value), nan_value, 0, 0, 0); + + check_float ("tgamma (0.5) == sqrt (pi)", FUNC(tgamma) (0.5), M_SQRT_PIl, DELTA1587, 0, 0); + check_float ("tgamma (-0.5) == -2 sqrt (pi)", FUNC(tgamma) (-0.5), -M_2_SQRT_PIl, DELTA1588, 0, 0); + + check_float ("tgamma (1) == 1", FUNC(tgamma) (1), 1, 0, 0, 0); + check_float ("tgamma (4) == 6", FUNC(tgamma) (4), 6, DELTA1590, 0, 0); + + check_float ("tgamma (0.7) == 1.29805533264755778568", FUNC(tgamma) (0.7L), 1.29805533264755778568L, DELTA1591, 0, 0); + check_float ("tgamma (1.2) == 0.91816874239976061064", FUNC(tgamma) (1.2L), 0.91816874239976061064L, 0, 0, 0); + + print_max_error ("tgamma", DELTAtgamma, 0); +} + +static void +trunc_test (void) +{ + init_max_error (); + + check_float ("trunc (inf) == inf", FUNC(trunc) (plus_infty), plus_infty, 0, 0, 0); + check_float ("trunc (-inf) == -inf", FUNC(trunc) (minus_infty), minus_infty, 0, 0, 0); + check_float ("trunc (NaN) == NaN", FUNC(trunc) (nan_value), nan_value, 0, 0, 0); + + check_float ("trunc (0) == 0", FUNC(trunc) (0), 0, 0, 0, 0); + check_float ("trunc (-0) == -0", FUNC(trunc) (minus_zero), minus_zero, 0, 0, 0); + check_float ("trunc (0.625) == 0", FUNC(trunc) (0.625), 0, 0, 0, 0); + check_float ("trunc (-0.625) == -0", FUNC(trunc) (-0.625), minus_zero, 0, 0, 0); + check_float ("trunc (1) == 1", FUNC(trunc) (1), 1, 0, 0, 0); + check_float ("trunc (-1) == -1", FUNC(trunc) (-1), -1, 0, 0, 0); + check_float ("trunc (1.625) == 1", FUNC(trunc) (1.625), 1, 0, 0, 0); + check_float ("trunc (-1.625) == -1", FUNC(trunc) (-1.625), -1, 0, 0, 0); + + check_float ("trunc (1048580.625) == 1048580", FUNC(trunc) (1048580.625L), 1048580L, 0, 0, 0); + check_float ("trunc (-1048580.625) == -1048580", FUNC(trunc) (-1048580.625L), -1048580L, 0, 0, 0); + + check_float ("trunc (8388610.125) == 8388610.0", FUNC(trunc) (8388610.125L), 8388610.0L, 0, 0, 0); + check_float ("trunc (-8388610.125) == -8388610.0", FUNC(trunc) (-8388610.125L), -8388610.0L, 0, 0, 0); + + check_float ("trunc (4294967296.625) == 4294967296.0", FUNC(trunc) (4294967296.625L), 4294967296.0L, 0, 0, 0); + check_float ("trunc (-4294967296.625) == -4294967296.0", FUNC(trunc) (-4294967296.625L), -4294967296.0L, 0, 0, 0); + + + print_max_error ("trunc", 0, 0); +} + +static void +y0_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(y0) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + /* y0 is the Bessel function of the second kind of order 0 */ + init_max_error (); + + check_float ("y0 (-1.0) == NaN", FUNC(y0) (-1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("y0 (0.0) == -inf", FUNC(y0) (0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("y0 (NaN) == NaN", FUNC(y0) (nan_value), nan_value, 0, 0, 0); + check_float ("y0 (inf) == 0", FUNC(y0) (plus_infty), 0, 0, 0, 0); + + check_float ("y0 (0.1) == -1.5342386513503668441", FUNC(y0) (0.1L), -1.5342386513503668441L, DELTA1614, 0, 0); + check_float ("y0 (0.7) == -0.19066492933739506743", FUNC(y0) (0.7L), -0.19066492933739506743L, DELTA1615, 0, 0); + check_float ("y0 (1.0) == 0.088256964215676957983", FUNC(y0) (1.0), 0.088256964215676957983L, DELTA1616, 0, 0); + check_float ("y0 (1.5) == 0.38244892379775884396", FUNC(y0) (1.5), 0.38244892379775884396L, DELTA1617, 0, 0); + check_float ("y0 (2.0) == 0.51037567264974511960", FUNC(y0) (2.0), 0.51037567264974511960L, DELTA1618, 0, 0); + check_float ("y0 (8.0) == 0.22352148938756622053", FUNC(y0) (8.0), 0.22352148938756622053L, DELTA1619, 0, 0); + check_float ("y0 (10.0) == 0.055671167283599391424", FUNC(y0) (10.0), 0.055671167283599391424L, DELTA1620, 0, 0); + + print_max_error ("y0", DELTAy0, 0); +} + + +static void +y1_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(y1) (1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + /* y1 is the Bessel function of the second kind of order 1 */ + init_max_error (); + + check_float ("y1 (-1.0) == NaN", FUNC(y1) (-1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("y1 (0.0) == -inf", FUNC(y1) (0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("y1 (inf) == 0", FUNC(y1) (plus_infty), 0, 0, 0, 0); + check_float ("y1 (NaN) == NaN", FUNC(y1) (nan_value), nan_value, 0, 0, 0); + + check_float ("y1 (0.1) == -6.4589510947020269877", FUNC(y1) (0.1L), -6.4589510947020269877L, DELTA1625, 0, 0); + check_float ("y1 (0.7) == -1.1032498719076333697", FUNC(y1) (0.7L), -1.1032498719076333697L, DELTA1626, 0, 0); + check_float ("y1 (1.0) == -0.78121282130028871655", FUNC(y1) (1.0), -0.78121282130028871655L, DELTA1627, 0, 0); + check_float ("y1 (1.5) == -0.41230862697391129595", FUNC(y1) (1.5), -0.41230862697391129595L, DELTA1628, 0, 0); + check_float ("y1 (2.0) == -0.10703243154093754689", FUNC(y1) (2.0), -0.10703243154093754689L, DELTA1629, 0, 0); + check_float ("y1 (8.0) == -0.15806046173124749426", FUNC(y1) (8.0), -0.15806046173124749426L, DELTA1630, 0, 0); + check_float ("y1 (10.0) == 0.24901542420695388392", FUNC(y1) (10.0), 0.24901542420695388392L, DELTA1631, 0, 0); + + print_max_error ("y1", DELTAy1, 0); +} + +static void +yn_test (void) +{ + FLOAT s, c; + errno = 0; + FUNC (sincos) (0, &s, &c); + if (errno == ENOSYS) + /* Required function not implemented. */ + return; + FUNC(yn) (1, 1); + if (errno == ENOSYS) + /* Function not implemented. */ + return; + + /* yn is the Bessel function of the second kind of order n */ + init_max_error (); + + /* yn (0, x) == y0 (x) */ + check_float ("yn (0, -1.0) == NaN", FUNC(yn) (0, -1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("yn (0, 0.0) == -inf", FUNC(yn) (0, 0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("yn (0, NaN) == NaN", FUNC(yn) (0, nan_value), nan_value, 0, 0, 0); + check_float ("yn (0, inf) == 0", FUNC(yn) (0, plus_infty), 0, 0, 0, 0); + + check_float ("yn (0, 0.1) == -1.5342386513503668441", FUNC(yn) (0, 0.1L), -1.5342386513503668441L, DELTA1636, 0, 0); + check_float ("yn (0, 0.7) == -0.19066492933739506743", FUNC(yn) (0, 0.7L), -0.19066492933739506743L, DELTA1637, 0, 0); + check_float ("yn (0, 1.0) == 0.088256964215676957983", FUNC(yn) (0, 1.0), 0.088256964215676957983L, DELTA1638, 0, 0); + check_float ("yn (0, 1.5) == 0.38244892379775884396", FUNC(yn) (0, 1.5), 0.38244892379775884396L, DELTA1639, 0, 0); + check_float ("yn (0, 2.0) == 0.51037567264974511960", FUNC(yn) (0, 2.0), 0.51037567264974511960L, DELTA1640, 0, 0); + check_float ("yn (0, 8.0) == 0.22352148938756622053", FUNC(yn) (0, 8.0), 0.22352148938756622053L, DELTA1641, 0, 0); + check_float ("yn (0, 10.0) == 0.055671167283599391424", FUNC(yn) (0, 10.0), 0.055671167283599391424L, DELTA1642, 0, 0); + + /* yn (1, x) == y1 (x) */ + check_float ("yn (1, -1.0) == NaN", FUNC(yn) (1, -1.0), nan_value, 0, 0, INVALID_EXCEPTION); + check_float ("yn (1, 0.0) == -inf", FUNC(yn) (1, 0.0), minus_infty, 0, 0, DIVIDE_BY_ZERO_EXCEPTION); + check_float ("yn (1, inf) == 0", FUNC(yn) (1, plus_infty), 0, 0, 0, 0); + check_float ("yn (1, NaN) == NaN", FUNC(yn) (1, nan_value), nan_value, 0, 0, 0); + + check_float ("yn (1, 0.1) == -6.4589510947020269877", FUNC(yn) (1, 0.1L), -6.4589510947020269877L, DELTA1647, 0, 0); + check_float ("yn (1, 0.7) == -1.1032498719076333697", FUNC(yn) (1, 0.7L), -1.1032498719076333697L, DELTA1648, 0, 0); + check_float ("yn (1, 1.0) == -0.78121282130028871655", FUNC(yn) (1, 1.0), -0.78121282130028871655L, DELTA1649, 0, 0); + check_float ("yn (1, 1.5) == -0.41230862697391129595", FUNC(yn) (1, 1.5), -0.41230862697391129595L, DELTA1650, 0, 0); + check_float ("yn (1, 2.0) == -0.10703243154093754689", FUNC(yn) (1, 2.0), -0.10703243154093754689L, DELTA1651, 0, 0); + check_float ("yn (1, 8.0) == -0.15806046173124749426", FUNC(yn) (1, 8.0), -0.15806046173124749426L, DELTA1652, 0, 0); + check_float ("yn (1, 10.0) == 0.24901542420695388392", FUNC(yn) (1, 10.0), 0.24901542420695388392L, DELTA1653, 0, 0); + + /* yn (3, x) */ + check_float ("yn (3, inf) == 0", FUNC(yn) (3, plus_infty), 0, 0, 0, 0); + check_float ("yn (3, NaN) == NaN", FUNC(yn) (3, nan_value), nan_value, 0, 0, 0); + + check_float ("yn (3, 0.1) == -5099.3323786129048894", FUNC(yn) (3, 0.1L), -5099.3323786129048894L, DELTA1656, 0, 0); + check_float ("yn (3, 0.7) == -15.819479052819633505", FUNC(yn) (3, 0.7L), -15.819479052819633505L, DELTA1657, 0, 0); + check_float ("yn (3, 1.0) == -5.8215176059647288478", FUNC(yn) (3, 1.0), -5.8215176059647288478L, 0, 0, 0); + check_float ("yn (3, 2.0) == -1.1277837768404277861", FUNC(yn) (3, 2.0), -1.1277837768404277861L, DELTA1659, 0, 0); + check_float ("yn (3, 10.0) == -0.25136265718383732978", FUNC(yn) (3, 10.0), -0.25136265718383732978L, DELTA1660, 0, 0); + + /* yn (10, x) */ + check_float ("yn (10, inf) == 0", FUNC(yn) (10, plus_infty), 0, 0, 0, 0); + check_float ("yn (10, NaN) == NaN", FUNC(yn) (10, nan_value), nan_value, 0, 0, 0); + + check_float ("yn (10, 0.1) == -0.11831335132045197885e19", FUNC(yn) (10, 0.1L), -0.11831335132045197885e19L, DELTA1663, 0, 0); + check_float ("yn (10, 0.7) == -0.42447194260703866924e10", FUNC(yn) (10, 0.7L), -0.42447194260703866924e10L, DELTA1664, 0, 0); + check_float ("yn (10, 1.0) == -0.12161801427868918929e9", FUNC(yn) (10, 1.0), -0.12161801427868918929e9L, DELTA1665, 0, 0); + check_float ("yn (10, 2.0) == -129184.54220803928264", FUNC(yn) (10, 2.0), -129184.54220803928264L, DELTA1666, 0, 0); + check_float ("yn (10, 10.0) == -0.35981415218340272205", FUNC(yn) (10, 10.0), -0.35981415218340272205L, DELTA1667, 0, 0); + + print_max_error ("yn", DELTAyn, 0); + +} + + + +static void +initialize (void) +{ + plus_zero = 0.0; + nan_value = plus_zero / plus_zero; /* Suppress GCC warning */ + + minus_zero = FUNC(copysign) (0.0, -1.0); + plus_infty = CHOOSE (HUGE_VALL, HUGE_VAL, HUGE_VALF, + HUGE_VALL, HUGE_VAL, HUGE_VALF); + minus_infty = CHOOSE (-HUGE_VALL, -HUGE_VAL, -HUGE_VALF, + -HUGE_VALL, -HUGE_VAL, -HUGE_VALF); + + (void) &plus_zero; + (void) &nan_value; + (void) &minus_zero; + (void) &plus_infty; + (void) &minus_infty; + + /* Clear all exceptions. From now on we must not get random exceptions. */ + feclearexcept (FE_ALL_EXCEPT); +} + +#if 0 /* XXX scp XXX */ +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "verbose", 'v', "NUMBER", 0, "Level of verbosity (0..3)"}, + { "ulps-file", 'u', NULL, 0, "Output ulps to file ULPs"}, + { "no-max-error", 'f', NULL, 0, + "Don't output maximal errors of functions"}, + { "no-points", 'p', NULL, 0, + "Don't output results of functions invocations"}, + { "ignore-max-ulp", 'i', "yes/no", 0, + "Ignore given maximal errors"}, + { NULL, 0, NULL, 0, NULL } +}; + +/* Short description of program. */ +static const char doc[] = "Math test suite: " TEST_MSG ; + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, NULL, doc, +}; + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'f': + output_max_error = 0; + break; + case 'i': + if (strcmp (arg, "yes") == 0) + ignore_max_ulp = 1; + else if (strcmp (arg, "no") == 0) + ignore_max_ulp = 0; + break; + case 'p': + output_points = 0; + break; + case 'u': + output_ulps = 1; + break; + case 'v': + if (optarg) + verbose = (unsigned int) strtoul (optarg, NULL, 0); + else + verbose = 3; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} +#endif + +#if 0 +/* function to check our ulp calculation. */ +void +check_ulp (void) +{ + int i; + + FLOAT u, diff, ulp; + /* This gives one ulp. */ + u = FUNC(nextafter) (10, 20); + check_equal (10.0, u, 1, &diff, &ulp); + printf ("One ulp: % .4" PRINTF_NEXPR "\n", ulp); + + /* This gives one more ulp. */ + u = FUNC(nextafter) (u, 20); + check_equal (10.0, u, 2, &diff, &ulp); + printf ("two ulp: % .4" PRINTF_NEXPR "\n", ulp); + + /* And now calculate 100 ulp. */ + for (i = 2; i < 100; i++) + u = FUNC(nextafter) (u, 20); + check_equal (10.0, u, 100, &diff, &ulp); + printf ("100 ulp: % .4" PRINTF_NEXPR "\n", ulp); +} +#endif + +int +main (int argc, char **argv) +{ +#if 0 /* XXX scp XXX */ + int remaining; +#endif + + verbose = 1; + output_ulps = 0; + output_max_error = 1; + output_points = 1; + /* XXX set to 0 for releases. */ + ignore_max_ulp = 0; + +#if 0 /* XXX scp XXX */ + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + if (remaining != argc) + { + fprintf (stderr, "wrong number of arguments"); + argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name); + exit (EXIT_FAILURE); + } +#endif + + if (output_ulps) + { + ulps_file = fopen ("ULPs", "a"); + if (ulps_file == NULL) + { + perror ("can't open file `ULPs' for writing: "); + exit (1); + } + } + + + initialize (); + printf (TEST_MSG); + +#if 0 + check_ulp (); +#endif + + /* Keep the tests a wee bit ordered (according to ISO C99). */ + /* Classification macros: */ + fpclassify_test (); + isfinite_test (); + isnormal_test (); + signbit_test (); + + /* Trigonometric functions: */ + acos_test (); + asin_test (); + atan_test (); + atan2_test (); + cos_test (); + sin_test (); + sincos_test (); + tan_test (); + + /* Hyperbolic functions: */ + acosh_test (); + asinh_test (); + atanh_test (); + cosh_test (); + sinh_test (); + tanh_test (); + + /* Exponential and logarithmic functions: */ + exp_test (); +#if 0 /* XXX scp XXX */ + exp10_test (); +#endif + exp2_test (); + expm1_test (); + frexp_test (); + ldexp_test (); + log_test (); + log10_test (); + log1p_test (); + log2_test (); + logb_test (); + modf_test (); + ilogb_test (); + scalbn_test (); + scalbln_test (); + + /* Power and absolute value functions: */ + cbrt_test (); + fabs_test (); + hypot_test (); + pow_test (); + sqrt_test (); + + /* Error and gamma functions: */ + erf_test (); + erfc_test (); + gamma_test (); + lgamma_test (); + tgamma_test (); + + /* Nearest integer functions: */ + ceil_test (); + floor_test (); + nearbyint_test (); + rint_test (); + lrint_test (); + llrint_test (); + round_test (); + lround_test (); + llround_test (); + trunc_test (); + + /* Remainder functions: */ + fmod_test (); + remainder_test (); + remquo_test (); + + /* Manipulation functions: */ + copysign_test (); + nextafter_test (); +#if 0 /* XXX scp XXX */ + nexttoward_test (); +#endif + + /* maximum, minimum and positive difference functions */ + fdim_test (); + fmax_test (); + fmin_test (); + + /* Multiply and add: */ + fma_test (); + +#if 0 /* XXX scp XXX */ + /* Complex functions: */ + cabs_test (); + cacos_test (); + cacosh_test (); + carg_test (); + casin_test (); + casinh_test (); + catan_test (); + catanh_test (); + ccos_test (); + ccosh_test (); + cexp_test (); + cimag_test (); + clog10_test (); + clog_test (); + conj_test (); + cpow_test (); + cproj_test (); + creal_test (); + csin_test (); + csinh_test (); + csqrt_test (); + ctan_test (); + ctanh_test (); +#endif + + /* Bessel functions: */ + j0_test (); + j1_test (); + jn_test (); + y0_test (); + y1_test (); + yn_test (); + + if (output_ulps) + fclose (ulps_file); + + printf ("\nTest suite completed:\n"); + printf (" %d test cases plus %d tests for exception flags executed.\n", + noTests, noExcTests); + if (noXFails) + printf (" %d expected failures occurred.\n", noXFails); + if (noXPasses) + printf (" %d unexpected passes occurred.\n", noXPasses); + if (noErrors) + { + printf (" %d errors occurred.\n", noErrors); + return 1; + } + printf (" All tests passed successfully.\n"); + + return 0; +} + +/* + * Local Variables: + * mode:c + * End: + */ diff --git a/src/openlibm/test/test-211.c b/src/openlibm/test/test-211.c new file mode 100644 index 0000000..8bec4e9 --- /dev/null +++ b/src/openlibm/test/test-211.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int +main() +{ + float x = 0xd.65874p-4f; + float y = 4.0f; + float z = powf (x, y); + assert(z==0x1.f74424p-2); +} diff --git a/src/openlibm/test/test-double.c b/src/openlibm/test/test-double.c new file mode 100644 index 0000000..4d239a7 --- /dev/null +++ b/src/openlibm/test/test-double.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define FUNC(function) function +#define FLOAT double +#define TEST_MSG "testing double (without inline functions)\n" +#define MATHCONST(x) x +#define CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat) Cdouble +#define PRINTF_EXPR "e" +#define PRINTF_XEXPR "a" +#define PRINTF_NEXPR "f" +#define TEST_DOUBLE 1 + +#ifndef __NO_MATH_INLINES +# define __NO_MATH_INLINES +#endif + +#include "libm-test.c" diff --git a/src/openlibm/test/test-float.c b/src/openlibm/test/test-float.c new file mode 100644 index 0000000..26a4213 --- /dev/null +++ b/src/openlibm/test/test-float.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define FUNC(function) function ## f +#define FLOAT float +#define TEST_MSG "testing float (without inline functions)\n" +#define MATHCONST(x) x +#define CHOOSE(Clongdouble,Cdouble,Cfloat,Cinlinelongdouble,Cinlinedouble,Cinlinefloat) Cfloat +#define PRINTF_EXPR "e" +#define PRINTF_XEXPR "a" +#define PRINTF_NEXPR "f" +#define TEST_FLOAT 1 + +#ifndef __NO_MATH_INLINES +# define __NO_MATH_INLINES +#endif + +#include "libm-test.c" diff --git a/src/openlibm/wasm32/Make.files b/src/openlibm/wasm32/Make.files new file mode 100644 index 0000000..e69de29 diff --git a/src/openlibm/wasm32/assert.h b/src/openlibm/wasm32/assert.h new file mode 100644 index 0000000..5c6205b --- /dev/null +++ b/src/openlibm/wasm32/assert.h @@ -0,0 +1 @@ +#define assert(x) ((void)0) diff --git a/src/openlibm/wasm32/float.h b/src/openlibm/wasm32/float.h new file mode 100644 index 0000000..c82ecbd --- /dev/null +++ b/src/openlibm/wasm32/float.h @@ -0,0 +1,33 @@ +#pragma once + +#define FLT_RADIX 2 + +#define FLT_TRUE_MIN 1.40129846432481707092e-45F +#define FLT_MIN 1.17549435082228750797e-38F +#define FLT_MAX 3.40282346638528859812e+38F +#define FLT_EPSILON 1.1920928955078125e-07F + +#define FLT_MANT_DIG 24 +#define FLT_MIN_EXP (-125) +#define FLT_MAX_EXP 128 +#define FLT_HAS_SUBNORM 1 + +#define FLT_DIG 6 +#define FLT_DECIMAL_DIG 9 +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_10_EXP 38 + +#define DBL_TRUE_MIN 4.94065645841246544177e-324 +#define DBL_MIN 2.22507385850720138309e-308 +#define DBL_MAX 1.79769313486231570815e+308 +#define DBL_EPSILON 2.22044604925031308085e-16 + +#define DBL_MANT_DIG 53 +#define DBL_MIN_EXP (-1021) +#define DBL_MAX_EXP 1024 +#define DBL_HAS_SUBNORM 1 + +#define DBL_DIG 15 +#define DBL_DECIMAL_DIG 17 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_10_EXP 308 diff --git a/src/openlibm/wasm32/limits.h b/src/openlibm/wasm32/limits.h new file mode 100644 index 0000000..1f8d124 --- /dev/null +++ b/src/openlibm/wasm32/limits.h @@ -0,0 +1,9 @@ +#include + +#define INT_MIN INT32_MIN +#define INT_MAX INT32_MAX +#define LONG_MIN INT32_MIN +#define LONG_MAX INT32_MAX +#define LLONG_MIN INT64_MIN +#define LLONG_MAX INT64_MAX + diff --git a/src/openlibm/wasm32/stdint.h b/src/openlibm/wasm32/stdint.h new file mode 100644 index 0000000..3996e5b --- /dev/null +++ b/src/openlibm/wasm32/stdint.h @@ -0,0 +1,43 @@ +#pragma once + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned int uintptr_t; +typedef int intptr_t; + +_Static_assert(sizeof (uint8_t) == 1, "invalid size"); +_Static_assert(sizeof (uint16_t) == 2, "invalid size"); +_Static_assert(sizeof (uint32_t) == 4, "invalid size"); +_Static_assert(sizeof (uint64_t) == 8, "invalid size"); + +_Static_assert(sizeof (int8_t) == 1, "invalid size"); +_Static_assert(sizeof (int16_t) == 2, "invalid size"); +_Static_assert(sizeof (int32_t) == 4, "invalid size"); +_Static_assert(sizeof (int64_t) == 8, "invalid size"); + +_Static_assert(sizeof (uintptr_t) == sizeof (intptr_t), "invalid size"); +_Static_assert(sizeof (uintptr_t) == sizeof (void*), "invalid size"); +_Static_assert(sizeof (uintptr_t) == 4, "invalid size"); + +#define UINT8_MAX 0xFF +#define UINT16_MAX 0xFFFF +#define UINT32_MAX 0xFFFFFFFFUL +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL + +#define INT8_MAX 0x7F +#define INT16_MAX 0x7FFF +#define INT32_MAX 0x7FFFFFFF +#define INT64_MAX 0x7FFFFFFFFFFFFFFF + +#define INT8_MIN (-0x80) +#define INT16_MIN (-0x8000) +#define INT32_MIN (-0x80000000L) +#define INT64_MIN (-0x8000000000000000LL)