Make improvements

This commit is contained in:
Justine Tunney 2020-12-01 03:43:40 -08:00
parent 3e4fd4b0ad
commit e44a0cf6f8
256 changed files with 23100 additions and 2294 deletions

21
third_party/chibicc/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Rui Ueyama
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.

720
third_party/chibicc/chibicc.c vendored Normal file
View file

@ -0,0 +1,720 @@
#include "third_party/chibicc/chibicc.h"
typedef enum {
FILE_NONE,
FILE_C,
FILE_ASM,
FILE_OBJ,
FILE_AR,
FILE_DSO,
} FileType;
StringArray include_paths;
bool opt_fcommon = true;
bool opt_fpic;
static FileType opt_x;
static StringArray opt_include;
static bool opt_E;
static bool opt_M;
static bool opt_MD;
static bool opt_MMD;
static bool opt_MP;
static bool opt_S;
static bool opt_c;
static bool opt_cc1;
static bool opt_hash_hash_hash;
static bool opt_static;
static bool opt_shared;
static char *opt_MF;
static char *opt_MT;
static char *opt_o;
static StringArray ld_extra_args;
static StringArray std_include_paths;
char *base_file;
static char *output_file;
static StringArray input_paths;
static char **tmpfiles;
static void usage(int status) {
fprintf(stderr, "chibicc [ -o <path> ] <file>\n");
exit(status);
}
static bool take_arg(char *arg) {
char *x[] = {
"-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker",
};
for (int i = 0; i < sizeof(x) / sizeof(*x); i++)
if (!strcmp(arg, x[i])) return true;
return false;
}
static void add_default_include_paths(char *argv0) {
// We expect that chibicc-specific include files are installed
// to ./include relative to argv[0].
char *buf = calloc(1, strlen(argv0) + 10);
sprintf(buf, "%s/include", dirname(strdup(argv0)));
strarray_push(&include_paths, buf);
// Add standard include paths.
strarray_push(&include_paths, ".");
// Keep a copy of the standard include paths for -MMD option.
for (int i = 0; i < include_paths.len; i++)
strarray_push(&std_include_paths, include_paths.data[i]);
}
static void define(char *str) {
char *eq = strchr(str, '=');
if (eq)
define_macro(strndup(str, eq - str), eq + 1);
else
define_macro(str, "1");
}
static FileType parse_opt_x(char *s) {
if (!strcmp(s, "c")) return FILE_C;
if (!strcmp(s, "assembler")) return FILE_ASM;
if (!strcmp(s, "none")) return FILE_NONE;
error("<command line>: unknown argument for -x: %s", s);
}
static char *quote_makefile(char *s) {
char *buf = calloc(1, strlen(s) * 2 + 1);
for (int i = 0, j = 0; s[i]; i++) {
switch (s[i]) {
case '$':
buf[j++] = '$';
buf[j++] = '$';
break;
case '#':
buf[j++] = '\\';
buf[j++] = '#';
break;
case ' ':
case '\t':
for (int k = i - 1; k >= 0 && s[k] == '\\'; k--) buf[j++] = '\\';
buf[j++] = '\\';
buf[j++] = s[i];
break;
default:
buf[j++] = s[i];
break;
}
}
return buf;
}
static void parse_args(int argc, char **argv) {
// Make sure that all command line options that take an argument
// have an argument.
for (int i = 1; i < argc; i++)
if (take_arg(argv[i]))
if (!argv[++i]) usage(1);
StringArray idirafter = {};
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-###")) {
opt_hash_hash_hash = true;
continue;
}
if (!strcmp(argv[i], "-cc1")) {
opt_cc1 = true;
continue;
}
if (!strcmp(argv[i], "--help")) usage(0);
if (!strcmp(argv[i], "-o")) {
opt_o = argv[++i];
continue;
}
if (!strncmp(argv[i], "-o", 2)) {
opt_o = argv[i] + 2;
continue;
}
if (!strcmp(argv[i], "-S")) {
opt_S = true;
continue;
}
if (!strcmp(argv[i], "-fcommon")) {
opt_fcommon = true;
continue;
}
if (!strcmp(argv[i], "-fno-common")) {
opt_fcommon = false;
continue;
}
if (!strcmp(argv[i], "-c")) {
opt_c = true;
continue;
}
if (!strcmp(argv[i], "-E")) {
opt_E = true;
continue;
}
if (!strncmp(argv[i], "-I", 2)) {
strarray_push(&include_paths, argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-D")) {
define(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-D", 2)) {
define(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-U")) {
undef_macro(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-U", 2)) {
undef_macro(argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-include")) {
strarray_push(&opt_include, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-x")) {
opt_x = parse_opt_x(argv[++i]);
continue;
}
if (!strncmp(argv[i], "-x", 2)) {
opt_x = parse_opt_x(argv[i] + 2);
continue;
}
if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
strarray_push(&input_paths, argv[i]);
continue;
}
if (!strcmp(argv[i], "-Xlinker")) {
strarray_push(&ld_extra_args, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-s")) {
strarray_push(&ld_extra_args, "-s");
continue;
}
if (!strcmp(argv[i], "-M")) {
opt_M = true;
continue;
}
if (!strcmp(argv[i], "-MF")) {
opt_MF = argv[++i];
continue;
}
if (!strcmp(argv[i], "-MP")) {
opt_MP = true;
continue;
}
if (!strcmp(argv[i], "-MT")) {
if (opt_MT == NULL)
opt_MT = argv[++i];
else
opt_MT = format("%s %s", opt_MT, argv[++i]);
continue;
}
if (!strcmp(argv[i], "-MD")) {
opt_MD = true;
continue;
}
if (!strcmp(argv[i], "-MQ")) {
if (opt_MT == NULL)
opt_MT = quote_makefile(argv[++i]);
else
opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i]));
continue;
}
if (!strcmp(argv[i], "-MMD")) {
opt_MD = opt_MMD = true;
continue;
}
if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) {
opt_fpic = true;
continue;
}
if (!strcmp(argv[i], "-cc1-input")) {
base_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-cc1-output")) {
output_file = argv[++i];
continue;
}
if (!strcmp(argv[i], "-idirafter")) {
strarray_push(&idirafter, argv[i++]);
continue;
}
if (!strcmp(argv[i], "-static")) {
opt_static = true;
strarray_push(&ld_extra_args, "-static");
continue;
}
if (!strcmp(argv[i], "-shared")) {
opt_shared = true;
strarray_push(&ld_extra_args, "-shared");
continue;
}
if (!strcmp(argv[i], "-L")) {
strarray_push(&ld_extra_args, "-L");
strarray_push(&ld_extra_args, argv[++i]);
continue;
}
if (!strncmp(argv[i], "-L", 2)) {
strarray_push(&ld_extra_args, "-L");
strarray_push(&ld_extra_args, argv[i] + 2);
continue;
}
if (!strcmp(argv[i], "-hashmap-test")) {
hashmap_test();
exit(0);
}
// These options are ignored for now.
if (!strncmp(argv[i], "-O", 2) || !strncmp(argv[i], "-W", 2) ||
!strncmp(argv[i], "-g", 2) || !strncmp(argv[i], "-std=", 5) ||
!strcmp(argv[i], "-ffreestanding") ||
!strcmp(argv[i], "-fno-builtin") ||
!strcmp(argv[i], "-fno-omit-frame-pointer") ||
!strcmp(argv[i], "-fno-stack-protector") ||
!strcmp(argv[i], "-fno-strict-aliasing") || !strcmp(argv[i], "-m64") ||
!strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w"))
continue;
if (argv[i][0] == '-' && argv[i][1] != '\0')
error("unknown argument: %s", argv[i]);
strarray_push(&input_paths, argv[i]);
}
for (int i = 0; i < idirafter.len; i++)
strarray_push(&include_paths, idirafter.data[i]);
if (input_paths.len == 0) error("no input files");
// -E implies that the input is the C macro language.
if (opt_E) opt_x = FILE_C;
}
static FILE *open_file(char *path) {
if (!path || strcmp(path, "-") == 0) return stdout;
FILE *out = fopen(path, "w");
if (!out) error("cannot open output file: %s: %s", path, strerror(errno));
return out;
}
static bool ends_with(char *p, char *q) {
int len1 = strlen(p);
int len2 = strlen(q);
return (len1 >= len2) && !strcmp(p + len1 - len2, q);
}
// Replace file extension
static char *replace_extn(char *tmpl, char *extn) {
char *filename = basename(strdup(tmpl));
int len1 = strlen(filename);
int len2 = strlen(extn);
char *buf = calloc(1, len1 + len2 + 2);
char *dot = strrchr(filename, '.');
if (dot) *dot = '\0';
sprintf(buf, "%s%s", filename, extn);
return buf;
}
static void cleanup(void) {
if (tmpfiles)
for (int i = 0; tmpfiles[i]; i++) unlink(tmpfiles[i]);
}
static char *create_tmpfile(void) {
char tmpl[] = "/tmp/chibicc-XXXXXX";
char *path = calloc(1, sizeof(tmpl));
memcpy(path, tmpl, sizeof(tmpl));
int fd = mkstemp(path);
if (fd == -1) error("mkstemp failed: %s", strerror(errno));
close(fd);
static int len = 2;
tmpfiles = realloc(tmpfiles, sizeof(char *) * len);
tmpfiles[len - 2] = path;
tmpfiles[len - 1] = NULL;
len++;
return path;
}
static void run_subprocess(char **argv) {
// If -### is given, dump the subprocess's command line.
if (opt_hash_hash_hash) {
fprintf(stderr, "%s", argv[0]);
for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]);
fprintf(stderr, "\n");
}
if (fork() == 0) {
// Child process. Run a new command.
execvp(argv[0], argv);
fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno));
_exit(1);
}
// Wait for the child process to finish.
int status;
while (wait(&status) > 0)
;
if (status != 0) exit(1);
}
static void run_cc1(int argc, char **argv, char *input, char *output) {
char **args = calloc(argc + 10, sizeof(char *));
memcpy(args, argv, argc * sizeof(char *));
args[argc++] = "-cc1";
if (input) {
args[argc++] = "-cc1-input";
args[argc++] = input;
}
if (output) {
args[argc++] = "-cc1-output";
args[argc++] = output;
}
run_subprocess(args);
}
// Print tokens to stdout. Used for -E.
static void print_tokens(Token *tok) {
FILE *out = open_file(opt_o ? opt_o : "-");
int line = 1;
for (; tok->kind != TK_EOF; tok = tok->next) {
if (line > 1 && tok->at_bol) fprintf(out, "\n");
if (tok->has_space && !tok->at_bol) fprintf(out, " ");
fprintf(out, "%.*s", tok->len, tok->loc);
line++;
}
fprintf(out, "\n");
}
static bool in_std_include_path(char *path) {
for (int i = 0; i < std_include_paths.len; i++) {
char *dir = std_include_paths.data[i];
int len = strlen(dir);
if (strncmp(dir, path, len) == 0 && path[len] == '/') return true;
}
return false;
}
// If -M options is given, the compiler write a list of input files to
// stdout in a format that "make" command can read. This feature is
// used to automate file dependency management.
static void print_dependencies(void) {
char *path;
if (opt_MF)
path = opt_MF;
else if (opt_MD)
path = replace_extn(opt_o ? opt_o : base_file, ".d");
else if (opt_o)
path = opt_o;
else
path = "-";
FILE *out = open_file(path);
if (opt_MT)
fprintf(out, "%s:", opt_MT);
else
fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o")));
File **files = get_input_files();
for (int i = 0; files[i]; i++) {
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
fprintf(out, " \\\n %s", files[i]->name);
}
fprintf(out, "\n\n");
if (opt_MP) {
for (int i = 1; files[i]; i++) {
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
fprintf(out, "%s:\n\n", quote_makefile(files[i]->name));
}
}
}
static Token *must_tokenize_file(char *path) {
Token *tok = tokenize_file(path);
if (!tok) error("%s: %s", path, strerror(errno));
return tok;
}
static Token *append_tokens(Token *tok1, Token *tok2) {
if (!tok1 || tok1->kind == TK_EOF) return tok2;
Token *t = tok1;
while (t->next->kind != TK_EOF) t = t->next;
t->next = tok2;
return tok1;
}
static void cc1(void) {
Token *tok = NULL;
// Process -include option
for (int i = 0; i < opt_include.len; i++) {
char *incl = opt_include.data[i];
char *path;
if (file_exists(incl)) {
path = incl;
} else {
path = search_include_paths(incl);
if (!path) error("-include: %s: %s", incl, strerror(errno));
}
Token *tok2 = must_tokenize_file(path);
tok = append_tokens(tok, tok2);
}
// Tokenize and parse.
Token *tok2 = must_tokenize_file(base_file);
tok = append_tokens(tok, tok2);
tok = preprocess(tok);
// If -M or -MD are given, print file dependencies.
if (opt_M || opt_MD) {
print_dependencies();
if (opt_M) return;
}
// If -E is given, print out preprocessed C code as a result.
if (opt_E) {
print_tokens(tok);
return;
}
Obj *prog = parse(tok);
// Traverse the AST to emit assembly.
FILE *out = open_file(output_file);
codegen(prog, out);
fclose(out);
}
static void assemble(char *input, char *output) {
char *cmd[] = {"as", "-W", "-I.", "-c", input, "-o", output, NULL};
run_subprocess(cmd);
}
static void run_linker(StringArray *inputs, char *output) {
StringArray arr = {};
strarray_push(&arr, "ld");
strarray_push(&arr, "-o");
strarray_push(&arr, output);
strarray_push(&arr, "-m");
strarray_push(&arr, "elf_x86_64");
if (opt_shared) {
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o");
} else {
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crt1.o");
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o");
}
strarray_push(&arr, "-L/usr/lib/gcc/x86_64-linux-gnu/9");
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/usr/lib64");
strarray_push(&arr, "-L/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/lib64");
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
strarray_push(&arr, "-L/usr/lib");
strarray_push(&arr, "-L/lib");
if (!opt_static) {
strarray_push(&arr, "-dynamic-linker");
strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2");
}
for (int i = 0; i < ld_extra_args.len; i++)
strarray_push(&arr, ld_extra_args.data[i]);
for (int i = 0; i < inputs->len; i++) strarray_push(&arr, inputs->data[i]);
if (opt_static) {
strarray_push(&arr, "--start-group");
strarray_push(&arr, "-lgcc");
strarray_push(&arr, "-lgcc_eh");
strarray_push(&arr, "-lc");
strarray_push(&arr, "--end-group");
} else {
strarray_push(&arr, "-lc");
strarray_push(&arr, "-lgcc");
strarray_push(&arr, "--as-needed");
strarray_push(&arr, "-lgcc_s");
strarray_push(&arr, "--no-as-needed");
}
if (opt_shared)
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o");
else
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o");
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crtn.o");
strarray_push(&arr, NULL);
run_subprocess(arr.data);
}
static FileType get_file_type(char *filename) {
if (opt_x != FILE_NONE) return opt_x;
if (ends_with(filename, ".a")) return FILE_AR;
if (ends_with(filename, ".so")) return FILE_DSO;
if (ends_with(filename, ".o")) return FILE_OBJ;
if (ends_with(filename, ".c")) return FILE_C;
if (ends_with(filename, ".s")) return FILE_ASM;
error("<command line>: unknown file extension: %s", filename);
}
int main(int argc, char **argv) {
atexit(cleanup);
init_macros();
parse_args(argc, argv);
if (opt_cc1) {
add_default_include_paths(argv[0]);
cc1();
return 0;
}
if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
StringArray ld_args = {};
for (int i = 0; i < input_paths.len; i++) {
char *input = input_paths.data[i];
if (!strncmp(input, "-l", 2)) {
strarray_push(&ld_args, input);
continue;
}
if (!strncmp(input, "-Wl,", 4)) {
char *s = strdup(input + 4);
char *arg = strtok(s, ",");
while (arg) {
strarray_push(&ld_args, arg);
arg = strtok(NULL, ",");
}
continue;
}
char *output;
if (opt_o)
output = opt_o;
else if (opt_S)
output = replace_extn(input, ".s");
else
output = replace_extn(input, ".o");
FileType type = get_file_type(input);
// Handle .o or .a
if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) {
strarray_push(&ld_args, input);
continue;
}
// Handle .s
if (type == FILE_ASM) {
if (!opt_S) assemble(input, output);
continue;
}
assert(type == FILE_C);
// Just preprocess
if (opt_E || opt_M) {
run_cc1(argc, argv, input, NULL);
continue;
}
// Compile
if (opt_S) {
run_cc1(argc, argv, input, output);
continue;
}
// Compile and assemble
if (opt_c) {
char *tmp = create_tmpfile();
run_cc1(argc, argv, input, tmp);
assemble(tmp, output);
continue;
}
// Compile, assemble and link
char *tmp1 = create_tmpfile();
char *tmp2 = create_tmpfile();
run_cc1(argc, argv, input, tmp1);
assemble(tmp1, tmp2);
strarray_push(&ld_args, tmp2);
continue;
}
if (ld_args.len > 0) run_linker(&ld_args, opt_o ? opt_o : "a.out");
return 0;
}

474
third_party/chibicc/chibicc.h vendored Normal file
View file

@ -0,0 +1,474 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _POSIX_C_SOURCE 200809L
#include "libc/assert.h"
#include "libc/bits/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/weirdtypes.h"
#include "libc/conv/conv.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
#include "libc/unicode/unicode.h"
#include "libc/x/x.h"
#include "third_party/gdtoa/gdtoa.h"
#pragma GCC diagnostic ignored "-Wswitch"
#ifndef __GNUC__
#define __attribute__(x)
#endif
typedef struct Type Type;
typedef struct Node Node;
typedef struct Member Member;
typedef struct Relocation Relocation;
typedef struct Hideset Hideset;
//
// strarray.c
//
typedef struct {
char **data;
int capacity;
int len;
} StringArray;
void strarray_push(StringArray *arr, char *s);
//
// tokenize.c
//
// Token
typedef enum {
TK_RESERVED, // Keywords or punctuators
TK_IDENT, // Identifiers
TK_STR, // String literals
TK_NUM, // Numeric literals
TK_PP_NUM, // Preprocessing numbers
TK_EOF, // End-of-file markers
} TokenKind;
typedef struct {
char *name;
int file_no;
char *contents;
// For #line directive
char *display_name;
int line_delta;
} File;
// Token type
typedef struct Token Token;
struct Token {
TokenKind kind; // Token kind
Token *next; // Next token
int64_t val; // If kind is TK_NUM, its value
long double fval; // If kind is TK_NUM, its value
char *loc; // Token location
int len; // Token length
Type *ty; // Used if TK_NUM or TK_STR
char *str; // String literal contents including terminating '\0'
File *file; // Source location
char *filename; // Filename
int line_no; // Line number
int line_delta; // Line number
bool at_bol; // True if this token is at beginning of line
bool has_space; // True if this token follows a space character
Hideset *hideset; // For macro expansion
Token *origin; // If this is expanded from a macro, the original token
};
noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
noreturn void error_at(char *loc, char *fmt, ...)
__attribute__((format(printf, 2, 3)));
noreturn void error_tok(Token *tok, char *fmt, ...)
__attribute__((format(printf, 2, 3)));
void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
bool equal(Token *tok, char *op);
Token *skip(Token *tok, char *op);
bool consume(Token **rest, Token *tok, char *str);
void convert_pp_tokens(Token *tok);
File **get_input_files(void);
File *new_file(char *name, int file_no, char *contents);
Token *tokenize_string_literal(Token *tok, Type *basety);
Token *tokenize(File *file);
Token *tokenize_file(char *filename);
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
//
// preprocess.c
//
char *format(char *fmt, ...);
char *search_include_paths(char *filename);
bool file_exists(char *path);
void init_macros(void);
void define_macro(char *name, char *buf);
void undef_macro(char *name);
Token *preprocess(Token *tok);
//
// parse.c
//
// Variable or function
typedef struct Obj Obj;
struct Obj {
Obj *next;
char *name; // Variable name
Type *ty; // Type
Token *tok; // representative token
bool is_local; // local or global/function
int align; // alignment
// Local variable
int offset;
// Global variable or function
bool is_function;
bool is_definition;
bool is_static;
// Global variable
bool is_tentative;
bool is_tls;
char *init_data;
Relocation *rel;
// Function
bool is_inline;
Obj *params;
Node *body;
Obj *locals;
Obj *va_area;
Obj *alloca_bottom;
int stack_size;
// Static inline function
bool is_live;
bool is_root;
StringArray refs;
};
// Global variable can be initialized either by a constant expression
// or a pointer to another global variable. This struct represents the
// latter.
typedef struct Relocation Relocation;
struct Relocation {
Relocation *next;
int offset;
char **label;
long addend;
};
// AST node
typedef enum {
ND_NULL_EXPR, // Do nothing
ND_ADD, // +
ND_SUB, // -
ND_MUL, // *
ND_DIV, // /
ND_NEG, // unary -
ND_MOD, // %
ND_BITAND, // &
ND_BITOR, // |
ND_BITXOR, // ^
ND_SHL, // <<
ND_SHR, // >>
ND_EQ, // ==
ND_NE, // !=
ND_LT, // <
ND_LE, // <=
ND_ASSIGN, // =
ND_COND, // ?:
ND_COMMA, // ,
ND_MEMBER, // . (struct member access)
ND_ADDR, // unary &
ND_DEREF, // unary *
ND_NOT, // !
ND_BITNOT, // ~
ND_LOGAND, // &&
ND_LOGOR, // ||
ND_RETURN, // "return"
ND_IF, // "if"
ND_FOR, // "for" or "while"
ND_DO, // "do"
ND_SWITCH, // "switch"
ND_CASE, // "case"
ND_BLOCK, // { ... }
ND_GOTO, // "goto"
ND_GOTO_EXPR, // "goto" labels-as-values
ND_LABEL, // Labeled statement
ND_LABEL_VAL, // [GNU] Labels-as-values
ND_FUNCALL, // Function call
ND_EXPR_STMT, // Expression statement
ND_STMT_EXPR, // Statement expression
ND_VAR, // Variable
ND_VLA_PTR, // VLA designator
ND_NUM, // Integer
ND_CAST, // Type cast
ND_MEMZERO, // Zero-clear a stack variable
ND_ASM, // "asm"
ND_CAS, // Atomic compare-and-swap
ND_EXCH, // Atomic exchange
} NodeKind;
// AST node type
struct Node {
NodeKind kind; // Node kind
Node *next; // Next node
Type *ty; // Type, e.g. int or pointer to int
Token *tok; // Representative token
Node *lhs; // Left-hand side
Node *rhs; // Right-hand side
// "if" or "for" statement
Node *cond;
Node *then;
Node *els;
Node *init;
Node *inc;
// "break" and "continue" labels
char *brk_label;
char *cont_label;
// Block or statement expression
Node *body;
// Struct member access
Member *member;
// Function call
Type *func_ty;
Node *args;
bool pass_by_stack;
Obj *ret_buffer;
// Goto or labeled statement, or labels-as-values
char *label;
char *unique_label;
Node *goto_next;
// Switch
Node *case_next;
Node *default_case;
// Case
long begin;
long end;
// "asm" string literal
char *asm_str;
// Atomic compare-and-swap
Node *cas_addr;
Node *cas_old;
Node *cas_new;
// Atomic op= operators
Obj *atomic_addr;
Node *atomic_expr;
// Variable
Obj *var;
// Numeric literal
int64_t val;
long double fval;
};
Node *new_cast(Node *expr, Type *ty);
int64_t const_expr(Token **rest, Token *tok);
Obj *parse(Token *tok);
//
// type.c
//
typedef enum {
TY_VOID,
TY_BOOL,
TY_CHAR,
TY_SHORT,
TY_INT,
TY_LONG,
TY_FLOAT,
TY_DOUBLE,
TY_LDOUBLE,
TY_ENUM,
TY_PTR,
TY_FUNC,
TY_ARRAY,
TY_VLA, // variable-length array
TY_STRUCT,
TY_UNION,
} TypeKind;
struct Type {
TypeKind kind;
int size; // sizeof() value
int align; // alignment
bool is_unsigned; // unsigned or signed
bool is_atomic; // true if _Atomic
Type *origin; // for type compatibility check
// Pointer-to or array-of type. We intentionally use the same member
// to represent pointer/array duality in C.
//
// In many contexts in which a pointer is expected, we examine this
// member instead of "kind" member to determine whether a type is a
// pointer or not. That means in many contexts "array of T" is
// naturally handled as if it were "pointer to T", as required by
// the C spec.
Type *base;
// Declaration
Token *name;
Token *name_pos;
// Array
int array_len;
// Variable-length array
Node *vla_len; // # of elements
Obj *vla_size; // sizeof() value
// Struct
Member *members;
bool is_flexible;
bool is_packed;
// Function type
Type *return_ty;
Type *params;
bool is_variadic;
Type *next;
};
// Struct member
struct Member {
Member *next;
Type *ty;
Token *tok; // for error message
Token *name;
int idx;
int align;
int offset;
// Bitfield
bool is_bitfield;
int bit_offset;
int bit_width;
};
extern Type *ty_void;
extern Type *ty_bool;
extern Type *ty_char;
extern Type *ty_short;
extern Type *ty_int;
extern Type *ty_long;
extern Type *ty_uchar;
extern Type *ty_ushort;
extern Type *ty_uint;
extern Type *ty_ulong;
extern Type *ty_float;
extern Type *ty_double;
extern Type *ty_ldouble;
bool is_integer(Type *ty);
bool is_flonum(Type *ty);
bool is_numeric(Type *ty);
bool is_compatible(Type *t1, Type *t2);
Type *copy_type(Type *ty);
Type *pointer_to(Type *base);
Type *func_type(Type *return_ty);
Type *array_of(Type *base, int size);
Type *vla_of(Type *base, Node *expr);
Type *enum_type(void);
Type *struct_type(void);
void add_type(Node *node);
//
// codegen.c
//
void codegen(Obj *prog, FILE *out);
int align_to(int n, int align);
//
// unicode.c
//
int encode_utf8(char *buf, uint32_t c);
uint32_t decode_utf8(char **new_pos, char *p);
bool is_ident1(uint32_t c);
bool is_ident2(uint32_t c);
int str_width(char *p, int len);
//
// hashmap.c
//
typedef struct {
char *key;
int keylen;
void *val;
} HashEntry;
typedef struct {
HashEntry *buckets;
int capacity;
int used;
} HashMap;
void *hashmap_get(HashMap *map, char *key);
void *hashmap_get2(HashMap *map, char *key, int keylen);
void hashmap_put(HashMap *map, char *key, void *val);
void hashmap_put2(HashMap *map, char *key, int keylen, void *val);
void hashmap_delete(HashMap *map, char *key);
void hashmap_delete2(HashMap *map, char *key, int keylen);
void hashmap_test(void);
//
// main.c
//
extern StringArray include_paths;
extern bool opt_fpic;
extern bool opt_fcommon;
extern char *base_file;
typedef struct StaticAsm {
struct StaticAsm *next;
Node *body;
} StaticAsm;
extern struct StaticAsm *staticasms;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */

78
third_party/chibicc/chibicc.mk vendored Normal file
View file

@ -0,0 +1,78 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_CHIBICC
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(THIRD_PARTY_CHIBICC_A)
THIRD_PARTY_CHIBICC_A = o/$(MODE)/third_party/chibicc/chibicc.a
THIRD_PARTY_CHIBICC_A_FILES := $(wildcard third_party/chibicc/*)
THIRD_PARTY_CHIBICC_A_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
THIRD_PARTY_CHIBICC_BINS = \
o/$(MODE)/third_party/chibicc/chibicc.com
THIRD_PARTY_CHIBICC_A_SRCS = \
$(THIRD_PARTY_CHIBICC_A_SRCS_S) \
$(THIRD_PARTY_CHIBICC_A_SRCS_C)
THIRD_PARTY_CHIBICC_A_OBJS = \
$(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_CHIBICC_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(THIRD_PARTY_CHIBICC_A_SRCS_C:%.c=o/$(MODE)/%.o)
THIRD_PARTY_CHIBICC_A_CHECKS = \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_FMT \
LIBC_NEXGEN32E \
LIBC_UNICODE \
LIBC_STDIO \
LIBC_MEM \
LIBC_LOG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_TIME \
LIBC_X \
LIBC_CONV \
LIBC_RUNTIME \
THIRD_PARTY_GDTOA
THIRD_PARTY_CHIBICC_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_CHIBICC_A): \
third_party/chibicc/ \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(THIRD_PARTY_CHIBICC_A_OBJS)
$(THIRD_PARTY_CHIBICC_A).pkg: \
$(THIRD_PARTY_CHIBICC_A_OBJS) \
$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/third_party/chibicc/%.com.dbg: \
$(THIRD_PARTY_CHIBICC_A_DEPS) \
$(THIRD_PARTY_CHIBICC_A) \
o/$(MODE)/third_party/chibicc/%.o \
$(THIRD_PARTY_CHIBICC_A).pkg \
$(CRT) \
$(APE)
@$(APELINK)
THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)))
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_CHIBICC_HDRS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_CHIBICC_CHECKS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_CHIBICC_OBJS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_OBJS))
$(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk
.PHONY: o/$(MODE)/third_party/chibicc
o/$(MODE)/third_party/chibicc: \
$(THIRD_PARTY_CHIBICC_BINS) \
$(THIRD_PARTY_CHIBICC_CHECKS)

1590
third_party/chibicc/codegen.c vendored Normal file

File diff suppressed because it is too large Load diff

130
third_party/chibicc/hashmap.c vendored Normal file
View file

@ -0,0 +1,130 @@
// This is an implementation of the open-addressing hash table.
#include "third_party/chibicc/chibicc.h"
#define TOMBSTONE ((void *)-1) // Represents a deleted hash entry
static uint64_t fnv_hash(char *s, int len) {
uint64_t hash = 0xcbf29ce484222325;
for (int i = 0; i < len; i++) {
hash *= 0x100000001b3;
hash ^= (unsigned char)s[i];
}
return hash;
}
// Make room for new entires in a given hashmap by removing
// tombstones and possibly extending the bucket size.
static void rehash(HashMap *map) {
// Compute the size of the new hashmap.
int nkeys = 0;
for (int i = 0; i < map->capacity; i++)
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++;
int cap = map->capacity;
while ((nkeys * 100) / cap >= 50) cap = cap * 2;
// Create a new hashmap and copy all key-values.
HashMap map2 = {};
map2.buckets = calloc(cap, sizeof(HashEntry));
map2.capacity = cap;
for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[i];
if (ent->key && ent->key != TOMBSTONE)
hashmap_put2(&map2, ent->key, ent->keylen, ent->val);
}
assert(map2.used == nkeys);
*map = map2;
}
static bool match(HashEntry *ent, char *key, int keylen) {
return ent->key && ent->key != TOMBSTONE && ent->keylen == keylen &&
memcmp(ent->key, key, keylen) == 0;
}
static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
if (!map->buckets) return NULL;
uint64_t hash = fnv_hash(key, keylen);
for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
if (match(ent, key, keylen)) return ent;
if (ent->key == NULL) return NULL;
}
UNREACHABLE();
}
static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {
if (!map->buckets) {
map->buckets = calloc((map->capacity = 16), sizeof(HashEntry));
}
if ((map->used * 100) / map->capacity >= 70) rehash(map);
uint64_t hash = fnv_hash(key, keylen);
for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
if (match(ent, key, keylen)) return ent;
if (ent->key == TOMBSTONE) {
ent->key = key;
ent->keylen = keylen;
return ent;
}
if (ent->key == NULL) {
ent->key = key;
ent->keylen = keylen;
map->used++;
return ent;
}
}
UNREACHABLE();
}
void *hashmap_get(HashMap *map, char *key) {
return hashmap_get2(map, key, strlen(key));
}
void *hashmap_get2(HashMap *map, char *key, int keylen) {
HashEntry *ent = get_entry(map, key, keylen);
return ent ? ent->val : NULL;
}
void hashmap_put(HashMap *map, char *key, void *val) {
hashmap_put2(map, key, strlen(key), val);
}
void hashmap_put2(HashMap *map, char *key, int keylen, void *val) {
HashEntry *ent = get_or_insert_entry(map, key, keylen);
ent->val = val;
}
void hashmap_delete(HashMap *map, char *key) {
hashmap_delete2(map, key, strlen(key));
}
void hashmap_delete2(HashMap *map, char *key, int keylen) {
HashEntry *ent = get_entry(map, key, keylen);
if (ent) ent->key = TOMBSTONE;
}
void hashmap_test(void) {
HashMap *map = calloc(1, sizeof(HashMap));
for (int i = 0; i < 5000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 1000; i < 2000; i++) hashmap_delete(map, format("key %d", i));
for (int i = 1500; i < 1600; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 0; i < 1000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 1000; i < 1500; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 1500; i < 1600; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 1600; i < 2000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 2000; i < 5000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 5000; i < 6000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
assert(hashmap_get(map, "no such key") == NULL);
printf("OK\n");
}

3301
third_party/chibicc/parse.c vendored Normal file

File diff suppressed because it is too large Load diff

1099
third_party/chibicc/preprocess.c vendored Normal file

File diff suppressed because it is too large Load diff

16
third_party/chibicc/strarray.c vendored Normal file
View file

@ -0,0 +1,16 @@
#include "third_party/chibicc/chibicc.h"
void strarray_push(StringArray *arr, char *s) {
if (!arr->data) {
arr->data = calloc(8, sizeof(char *));
arr->capacity = 8;
}
if (arr->capacity == arr->len) {
arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
arr->capacity *= 2;
for (int i = arr->len; i < arr->capacity; i++) arr->data[i] = NULL;
}
arr->data[arr->len++] = s;
}

785
third_party/chibicc/tokenize.c vendored Normal file
View file

@ -0,0 +1,785 @@
#include "third_party/chibicc/chibicc.h"
// Input file
static File *current_file;
// A list of all input files.
static File **input_files;
// True if the current position is at the beginning of a line
static bool at_bol;
// True if the current position follows a space character
static bool has_space;
// Reports an error and exit.
void error(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
exit(1);
}
// Reports an error message in the following format.
//
// foo.c:10: x = y + 1;
// ^ <error message here>
static void verror_at(char *filename, char *input, int line_no, char *loc,
char *fmt, va_list ap) {
// Find a line containing `loc`.
char *line = loc;
while (input < line && line[-1] != '\n') line--;
char *end = loc;
while (*end && *end != '\n') end++;
// Print out the line.
int indent = fprintf(stderr, "%s:%d: ", filename, line_no);
fprintf(stderr, "%.*s\n", (int)(end - line), line);
// Show the error message.
int pos = str_width(line, loc - line) + indent;
fprintf(stderr, "%*s", pos, ""); // print pos spaces.
fprintf(stderr, "^ ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
void error_at(char *loc, char *fmt, ...) {
int line_no = 1;
for (char *p = current_file->contents; p < loc; p++)
if (*p == '\n') line_no++;
va_list ap;
va_start(ap, fmt);
verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap);
exit(1);
}
void error_tok(Token *tok, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt,
ap);
exit(1);
}
void warn_tok(Token *tok, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt,
ap);
}
// Consumes the current token if it matches `op`.
bool equal(Token *tok, char *op) {
return strlen(op) == tok->len && !strncmp(tok->loc, op, tok->len);
}
// Ensure that the current token is `op`.
Token *skip(Token *tok, char *op) {
if (!equal(tok, op)) error_tok(tok, "expected '%s'", op);
return tok->next;
}
bool consume(Token **rest, Token *tok, char *str) {
if (equal(tok, str)) {
*rest = tok->next;
return true;
}
*rest = tok;
return false;
}
// Create a new token and add it as the next token of `cur`.
static Token *new_token(TokenKind kind, char *start, char *end) {
Token *tok = calloc(1, sizeof(Token));
tok->kind = kind;
tok->loc = start;
tok->len = end - start;
tok->file = current_file;
tok->filename = current_file->display_name;
tok->at_bol = at_bol;
tok->has_space = has_space;
at_bol = has_space = false;
return tok;
}
static bool starts_with(char *p, char *q) {
return strncmp(p, q, strlen(q)) == 0;
}
// Read an identifier and returns a pointer pointing to the end
// of an identifier.
//
// Returns null if p does not point to a valid identifier.
static char *read_ident(char *p) {
uint32_t c = decode_utf8(&p, p);
if (!is_ident1(c)) return NULL;
for (;;) {
char *q;
c = decode_utf8(&q, p);
if (!is_ident2(c)) return p;
p = q;
}
}
static int from_hex(char c) {
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return c - 'a' + 10;
return c - 'A' + 10;
}
static bool is_keyword(Token *tok) {
static HashMap map;
if (map.capacity == 0) {
static char *kw[] = {
"return", "if", "else",
"for", "while", "int",
"sizeof", "char", "struct",
"union", "short", "long",
"void", "typedef", "_Bool",
"enum", "static", "goto",
"break", "continue", "switch",
"case", "default", "extern",
"_Alignof", "_Alignas", "do",
"signed", "unsigned", "const",
"volatile", "auto", "register",
"restrict", "__restrict", "__restrict__",
"_Noreturn", "float", "double",
"typeof", "asm", "_Thread_local",
"__thread", "_Atomic", "__attribute__",
};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
hashmap_put(&map, kw[i], (void *)1);
}
return hashmap_get2(&map, tok->loc, tok->len);
}
static int read_escaped_char(char **new_pos, char *p) {
if ('0' <= *p && *p <= '7') {
// Read an octal number.
int c = *p++ - '0';
if ('0' <= *p && *p <= '7') {
c = (c << 3) + (*p++ - '0');
if ('0' <= *p && *p <= '7') c = (c << 3) + (*p++ - '0');
}
*new_pos = p;
return c;
}
if (*p == 'x') {
// Read a hexadecimal number.
p++;
if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence");
int c = 0;
for (; isxdigit(*p); p++) c = (c << 4) + from_hex(*p);
*new_pos = p;
return c;
}
*new_pos = p + 1;
switch (*p) {
case 'a':
return '\a';
case 'b':
return '\b';
case 't':
return '\t';
case 'n':
return '\n';
case 'v':
return '\v';
case 'f':
return '\f';
case 'r':
return '\r';
// [GNU] \e for the ASCII escape character is a GNU C extension.
case 'e':
return 27;
default:
return *p;
}
}
// Find a closing double-quote.
static char *string_literal_end(char *p) {
char *start = p;
for (; *p != '"'; p++) {
if (*p == '\0') error_at(start, "unclosed string literal");
if (*p == '\\') p++;
}
return p;
}
static Token *read_string_literal(char *start, char *quote) {
char *end = string_literal_end(quote + 1);
char *buf = calloc(1, end - quote);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\')
buf[len++] = read_escaped_char(&p, p + 1);
else
buf[len++] = *p++;
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty_char, len + 1);
tok->str = buf;
return tok;
}
// Read a UTF-8-encoded string literal and transcode it in UTF-16.
//
// UTF-16 is yet another variable-width encoding for Unicode. Code
// points smaller than U+10000 are encoded in 2 bytes. Code points
// equal to or larger than that are encoded in 4 bytes. Each 2 bytes
// in the 4 byte sequence is called "surrogate", and a 4 byte sequence
// is called a "surrogate pair".
static Token *read_utf16_string_literal(char *start, char *quote) {
char *end = string_literal_end(quote + 1);
uint16_t *buf = calloc(2, end - start - 1);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\') {
buf[len++] = read_escaped_char(&p, p + 1);
continue;
}
uint32_t c = decode_utf8(&p, p);
if (c < 0x10000) {
// Encode a code point in 2 bytes.
buf[len++] = c;
} else {
// Encode a code point in 4 bytes.
c -= 0x10000;
buf[len++] = 0xd800 + ((c >> 10) & 0x3ff);
buf[len++] = 0xdc00 + (c & 0x3ff);
}
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty_ushort, len + 1);
tok->str = (char *)buf;
return tok;
}
// Read a UTF-8-encoded string literal and transcode it in UTF-32.
//
// UTF-32 is a fixed-width encoding for Unicode. Each code point is
// encoded in 4 bytes.
static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
char *end = string_literal_end(quote + 1);
uint32_t *buf = calloc(4, end - quote);
int len = 0;
for (char *p = quote + 1; p < end;) {
if (*p == '\\')
buf[len++] = read_escaped_char(&p, p + 1);
else
buf[len++] = decode_utf8(&p, p);
}
Token *tok = new_token(TK_STR, start, end + 1);
tok->ty = array_of(ty, len + 1);
tok->str = (char *)buf;
return tok;
}
static Token *read_char_literal(char *start, char *quote, Type *ty) {
char *p = quote + 1;
if (*p == '\0') error_at(start, "unclosed char literal");
int c;
if (*p == '\\')
c = read_escaped_char(&p, p + 1);
else
c = decode_utf8(&p, p);
char *end = strchr(p, '\'');
if (!end) error_at(p, "unclosed char literal");
Token *tok = new_token(TK_NUM, start, end + 1);
tok->val = c;
tok->ty = ty;
return tok;
}
static bool convert_pp_int(Token *tok) {
char *p = tok->loc;
// Read a binary, octal, decimal or hexadecimal number.
int base = 10;
if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) {
p += 2;
base = 16;
} else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) {
p += 2;
base = 2;
} else if (*p == '0') {
base = 8;
}
int64_t val = strtoul(p, &p, base);
// Read U, L or LL suffixes.
bool l = false;
bool u = false;
if (starts_with(p, "LLU") || starts_with(p, "LLu") || starts_with(p, "llU") ||
starts_with(p, "llu") || starts_with(p, "ULL") || starts_with(p, "Ull") ||
starts_with(p, "uLL") || starts_with(p, "ull")) {
p += 3;
l = u = true;
} else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) {
p += 2;
l = u = true;
} else if (starts_with(p, "LL") || starts_with(p, "ll")) {
p += 2;
l = true;
} else if (*p == 'L' || *p == 'l') {
p++;
l = true;
} else if (*p == 'U' || *p == 'u') {
p++;
u = true;
}
if (p != tok->loc + tok->len) return false;
// Infer a type.
Type *ty;
if (base == 10) {
if (l && u)
ty = ty_ulong;
else if (l)
ty = ty_long;
else if (u)
ty = (val >> 32) ? ty_ulong : ty_uint;
else
ty = (val >> 31) ? ty_long : ty_int;
} else {
if (l && u)
ty = ty_ulong;
else if (l)
ty = (val >> 63) ? ty_ulong : ty_long;
else if (u)
ty = (val >> 32) ? ty_ulong : ty_uint;
else if (val >> 63)
ty = ty_ulong;
else if (val >> 32)
ty = ty_long;
else if (val >> 31)
ty = ty_uint;
else
ty = ty_int;
}
tok->kind = TK_NUM;
tok->val = val;
tok->ty = ty;
return true;
}
// The definition of the numeric literal at the preprocessing stage
// is more relaxed than the definition of that at the later stages.
// In order to handle that, a numeric literal is tokenized as a
// "pp-number" token first and then converted to a regular number
// token after preprocessing.
//
// This function converts a pp-number token to a regular number token.
static void convert_pp_number(Token *tok) {
// Try to parse as an integer constant.
if (convert_pp_int(tok)) return;
// If it's not an integer, it must be a floating point constant.
char *end;
long double val = strtold(tok->loc, &end);
Type *ty;
if (*end == 'f' || *end == 'F') {
ty = ty_float;
end++;
} else if (*end == 'l' || *end == 'L') {
ty = ty_ldouble;
end++;
} else {
ty = ty_double;
}
if (tok->loc + tok->len != end) error_tok(tok, "invalid numeric constant");
tok->kind = TK_NUM;
tok->fval = val;
tok->ty = ty;
}
void convert_pp_tokens(Token *tok) {
for (Token *t = tok; t->kind != TK_EOF; t = t->next) {
if (is_keyword(t))
t->kind = TK_RESERVED;
else if (t->kind == TK_PP_NUM)
convert_pp_number(t);
}
}
// Initialize line info for all tokens.
static void add_line_numbers(Token *tok) {
char *p = current_file->contents;
int n = 1;
do {
if (p == tok->loc) {
tok->line_no = n;
tok = tok->next;
}
if (*p == '\n') n++;
} while (*p++);
}
Token *tokenize_string_literal(Token *tok, Type *basety) {
Token *t;
if (basety->size == 2)
t = read_utf16_string_literal(tok->loc, tok->loc);
else
t = read_utf32_string_literal(tok->loc, tok->loc, basety);
t->next = tok->next;
return t;
}
// Tokenize a given string and returns new tokens.
Token *tokenize(File *file) {
current_file = file;
char *p = file->contents;
Token head = {};
Token *cur = &head;
at_bol = true;
has_space = false;
while (*p) {
// Skip line comments.
if (starts_with(p, "//")) {
p += 2;
while (*p != '\n') p++;
has_space = true;
continue;
}
// Skip block comments.
if (starts_with(p, "/*")) {
char *q = strstr(p + 2, "*/");
if (!q) error_at(p, "unclosed block comment");
p = q + 2;
has_space = true;
continue;
}
// Skip newline.
if (*p == '\n') {
p++;
at_bol = true;
has_space = false;
continue;
}
// Skip whitespace characters.
if (isspace(*p)) {
p++;
has_space = true;
continue;
}
// Numeric literal
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
char *q = p++;
for (;;) {
if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1]))
p += 2;
else if (isalnum(*p) || *p == '.')
p++;
else
break;
}
cur = cur->next = new_token(TK_PP_NUM, q, p);
continue;
}
// String literal
if (*p == '"') {
cur = cur->next = read_string_literal(p, p);
p += cur->len;
continue;
}
// UTF-8 string literal
if (starts_with(p, "u8\"")) {
cur = cur->next = read_string_literal(p, p + 2);
p += cur->len;
continue;
}
// UTF-16 string literal
if (starts_with(p, "u\"")) {
cur = cur->next = read_utf16_string_literal(p, p + 1);
p += cur->len;
continue;
}
// Wide string literal
if (starts_with(p, "L\"")) {
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
p += cur->len;
continue;
}
// UTF-32 string literal
if (starts_with(p, "U\"")) {
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
p += cur->len;
continue;
}
// Character literal
if (*p == '\'') {
cur = cur->next = read_char_literal(p, p, ty_int);
cur->val = (char)cur->val;
p += cur->len;
continue;
}
// UTF-16 character literal
if (starts_with(p, "u'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_ushort);
cur->val &= 0xffff;
p += cur->len;
continue;
}
// Wide character literal
if (starts_with(p, "L'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_int);
p += cur->len;
continue;
}
// UTF-32 character literal
if (starts_with(p, "U'")) {
cur = cur->next = read_char_literal(p, p + 1, ty_uint);
p += cur->len;
continue;
}
// Identifier or keyword
char *q;
if ((q = read_ident(p)) != NULL) {
cur = cur->next = new_token(TK_IDENT, p, q);
p = q;
continue;
}
// Three-letter punctuators
if (starts_with(p, "<<=") || starts_with(p, ">>=") ||
starts_with(p, "...")) {
cur = cur->next = new_token(TK_RESERVED, p, p + 3);
p += 3;
continue;
}
// Two-letter punctuators
if (starts_with(p, "==") || starts_with(p, "!=") || starts_with(p, "<=") ||
starts_with(p, ">=") || starts_with(p, "->") || starts_with(p, "+=") ||
starts_with(p, "-=") || starts_with(p, "*=") || starts_with(p, "/=") ||
starts_with(p, "++") || starts_with(p, "--") || starts_with(p, "%=") ||
starts_with(p, "&=") || starts_with(p, "|=") || starts_with(p, "^=") ||
starts_with(p, "&&") || starts_with(p, "||") || starts_with(p, "<<") ||
starts_with(p, ">>") || starts_with(p, "##")) {
cur = cur->next = new_token(TK_RESERVED, p, p + 2);
p += 2;
continue;
}
// Single-letter punctuators
if (ispunct(*p)) {
cur = cur->next = new_token(TK_RESERVED, p, p + 1);
p++;
continue;
}
error_at(p, "invalid token");
}
cur = cur->next = new_token(TK_EOF, p, p);
add_line_numbers(head.next);
return head.next;
}
// Returns the contents of a given file.
static char *read_file(char *path) {
FILE *fp;
if (strcmp(path, "-") == 0) {
// By convention, read from stdin if a given filename is "-".
fp = stdin;
} else {
fp = fopen(path, "r");
if (!fp) return NULL;
}
int buflen = 4096;
int nread = 0;
char *buf = calloc(1, buflen);
// Read the entire file.
for (;;) {
int end = buflen - 2; // extra 2 bytes for the trailing "\n\0"
int n = fread(buf + nread, 1, end - nread, fp);
if (n == 0) break;
nread += n;
if (nread == end) {
buflen *= 2;
buf = realloc(buf, buflen);
}
}
if (fp != stdin) fclose(fp);
// Make sure that the last logical line is properly terminated with '\n'.
if (nread > 0 && buf[nread - 1] == '\\')
buf[nread - 1] = '\n';
else if (nread == 0 || buf[nread - 1] != '\n')
buf[nread++] = '\n';
buf[nread] = '\0';
return buf;
}
File **get_input_files(void) {
return input_files;
}
File *new_file(char *name, int file_no, char *contents) {
File *file = calloc(1, sizeof(File));
file->name = name;
file->display_name = name;
file->file_no = file_no;
file->contents = contents;
return file;
}
// Replaces \r or \r\n with \n.
static void canonicalize_newline(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '\r' && p[i + 1] == '\n') {
i += 2;
p[j++] = '\n';
} else if (p[i] == '\r') {
i++;
p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
// Removes backslashes followed by a newline.
static void remove_backslash_newline(char *p) {
int i = 0, j = 0;
// We want to keep the number of newline characters so that
// the logical line number matches the physical one.
// This counter maintain the number of newlines we have removed.
int n = 0;
while (p[i]) {
if (p[i] == '\\' && p[i + 1] == '\n') {
i += 2;
n++;
} else if (p[i] == '\n') {
p[j++] = p[i++];
for (; n > 0; n--) p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
static uint32_t read_universal_char(char *p, int len) {
uint32_t c = 0;
for (int i = 0; i < len; i++) {
if (!isxdigit(p[i])) return 0;
c = (c << 4) | from_hex(p[i]);
}
return c;
}
// Replace \u or \U escape sequences with corresponding UTF-8 bytes.
static void convert_universal_chars(char *p) {
char *q = p;
while (*p) {
if (starts_with(p, "\\u")) {
uint32_t c = read_universal_char(p + 2, 4);
if (c) {
p += 6;
q += encode_utf8(q, c);
} else {
*q++ = *p++;
}
} else if (starts_with(p, "\\U")) {
uint32_t c = read_universal_char(p + 2, 8);
if (c) {
p += 10;
q += encode_utf8(q, c);
} else {
*q++ = *p++;
}
} else if (p[0] == '\\') {
*q++ = *p++;
*q++ = *p++;
} else {
*q++ = *p++;
}
}
*q = '\0';
}
Token *tokenize_file(char *path) {
char *p = read_file(path);
if (!p) return NULL;
canonicalize_newline(p);
remove_backslash_newline(p);
convert_universal_chars(p);
// Save the filename for assembler .file directive.
static int file_no;
File *file = new_file(path, file_no + 1, p);
// Save the filename for assembler .file directive.
input_files = realloc(input_files, sizeof(char *) * (file_no + 2));
input_files[file_no] = file;
input_files[file_no + 1] = NULL;
file_no++;
return tokenize(file);
}

286
third_party/chibicc/type.c vendored Normal file
View file

@ -0,0 +1,286 @@
#include "third_party/chibicc/chibicc.h"
Type *ty_void = &(Type){TY_VOID, 1, 1};
Type *ty_bool = &(Type){TY_BOOL, 1, 1};
Type *ty_char = &(Type){TY_CHAR, 1, 1};
Type *ty_short = &(Type){TY_SHORT, 2, 2};
Type *ty_int = &(Type){TY_INT, 4, 4};
Type *ty_long = &(Type){TY_LONG, 8, 8};
Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
Type *ty_uint = &(Type){TY_INT, 4, 4, true};
Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
Type *ty_float = &(Type){TY_FLOAT, 4, 4};
Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
static Type *new_type(TypeKind kind, int size, int align) {
Type *ty = calloc(1, sizeof(Type));
ty->kind = kind;
ty->size = size;
ty->align = align;
return ty;
}
bool is_integer(Type *ty) {
TypeKind k = ty->kind;
return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || k == TY_INT ||
k == TY_LONG || k == TY_ENUM;
}
bool is_flonum(Type *ty) {
return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE ||
ty->kind == TY_LDOUBLE;
}
bool is_numeric(Type *ty) {
return is_integer(ty) || is_flonum(ty);
}
bool is_compatible(Type *t1, Type *t2) {
if (t1 == t2) return true;
if (t1->origin) return is_compatible(t1->origin, t2);
if (t2->origin) return is_compatible(t1, t2->origin);
if (t1->kind != t2->kind) return false;
switch (t1->kind) {
case TY_CHAR:
case TY_SHORT:
case TY_INT:
case TY_LONG:
return t1->is_unsigned == t2->is_unsigned;
case TY_FLOAT:
case TY_DOUBLE:
case TY_LDOUBLE:
return true;
case TY_PTR:
return is_compatible(t1->base, t2->base);
case TY_FUNC: {
if (!is_compatible(t1->return_ty, t2->return_ty)) return false;
if (t1->is_variadic != t2->is_variadic) return false;
Type *p1 = t1->params;
Type *p2 = t2->params;
for (; p1 && p2; p1 = p1->next, p2 = p2->next)
if (!is_compatible(p1, p2)) return false;
return p1 == NULL && p2 == NULL;
}
case TY_ARRAY:
if (!is_compatible(t1->base, t2->base)) return false;
return t1->array_len < 0 && t2->array_len < 0 &&
t1->array_len == t2->array_len;
}
return false;
}
Type *copy_type(Type *ty) {
Type *ret = calloc(1, sizeof(Type));
*ret = *ty;
ret->origin = ty;
return ret;
}
Type *pointer_to(Type *base) {
Type *ty = new_type(TY_PTR, 8, 8);
ty->base = base;
ty->is_unsigned = true;
return ty;
}
Type *func_type(Type *return_ty) {
// The C spec disallows sizeof(<function type>), but
// GCC allows that and the expression is evaluated to 1.
Type *ty = new_type(TY_FUNC, 1, 1);
ty->return_ty = return_ty;
return ty;
}
Type *array_of(Type *base, int len) {
Type *ty = new_type(TY_ARRAY, base->size * len, base->align);
ty->base = base;
ty->array_len = len;
return ty;
}
Type *vla_of(Type *base, Node *len) {
Type *ty = new_type(TY_VLA, 8, 8);
ty->base = base;
ty->vla_len = len;
return ty;
}
Type *enum_type(void) {
return new_type(TY_ENUM, 4, 4);
}
Type *struct_type(void) {
return new_type(TY_STRUCT, 0, 1);
}
static Type *get_common_type(Type *ty1, Type *ty2) {
if (ty1->base) return pointer_to(ty1->base);
if (ty1->kind == TY_FUNC) return pointer_to(ty1);
if (ty2->kind == TY_FUNC) return pointer_to(ty2);
if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE) return ty_ldouble;
if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) return ty_double;
if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) return ty_float;
if (ty1->size < 4) ty1 = ty_int;
if (ty2->size < 4) ty2 = ty_int;
if (ty1->size != ty2->size) return (ty1->size < ty2->size) ? ty2 : ty1;
if (ty2->is_unsigned) return ty2;
return ty1;
}
// For many binary operators, we implicitly promote operands so that
// both operands have the same type. Any integral type smaller than
// int is always promoted to int. If the type of one operand is larger
// than the other's (e.g. "long" vs. "int"), the smaller operand will
// be promoted to match with the other.
//
// This operation is called the "usual arithmetic conversion".
static void usual_arith_conv(Node **lhs, Node **rhs) {
Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty);
*lhs = new_cast(*lhs, ty);
*rhs = new_cast(*rhs, ty);
}
void add_type(Node *node) {
if (!node || node->ty) return;
add_type(node->lhs);
add_type(node->rhs);
add_type(node->cond);
add_type(node->then);
add_type(node->els);
add_type(node->init);
add_type(node->inc);
for (Node *n = node->body; n; n = n->next) add_type(n);
for (Node *n = node->args; n; n = n->next) add_type(n);
switch (node->kind) {
case ND_NUM:
node->ty = ty_int;
return;
case ND_ADD:
case ND_SUB:
case ND_MUL:
case ND_DIV:
case ND_MOD:
case ND_BITAND:
case ND_BITOR:
case ND_BITXOR:
usual_arith_conv(&node->lhs, &node->rhs);
node->ty = node->lhs->ty;
return;
case ND_NEG: {
Type *ty = get_common_type(ty_int, node->lhs->ty);
node->lhs = new_cast(node->lhs, ty);
node->ty = ty;
return;
}
case ND_ASSIGN:
if (node->lhs->ty->kind == TY_ARRAY)
error_tok(node->lhs->tok, "not an lvalue");
if (node->lhs->ty->kind != TY_STRUCT)
node->rhs = new_cast(node->rhs, node->lhs->ty);
node->ty = node->lhs->ty;
return;
case ND_EQ:
case ND_NE:
case ND_LT:
case ND_LE:
usual_arith_conv(&node->lhs, &node->rhs);
node->ty = ty_int;
return;
case ND_FUNCALL:
node->ty = node->func_ty->return_ty;
return;
case ND_NOT:
case ND_LOGOR:
case ND_LOGAND:
node->ty = ty_int;
return;
case ND_BITNOT:
case ND_SHL:
case ND_SHR:
node->ty = node->lhs->ty;
return;
case ND_VAR:
case ND_VLA_PTR:
node->ty = node->var->ty;
return;
case ND_COND:
if (node->then->ty->kind == TY_VOID || node->els->ty->kind == TY_VOID) {
node->ty = ty_void;
} else {
usual_arith_conv(&node->then, &node->els);
node->ty = node->then->ty;
}
return;
case ND_COMMA:
node->ty = node->rhs->ty;
return;
case ND_MEMBER:
node->ty = node->member->ty;
return;
case ND_ADDR: {
Type *ty = node->lhs->ty;
if (ty->kind == TY_ARRAY)
node->ty = pointer_to(ty->base);
else
node->ty = pointer_to(ty);
return;
}
case ND_DEREF:
if (!node->lhs->ty->base)
error_tok(node->tok, "invalid pointer dereference");
if (node->lhs->ty->base->kind == TY_VOID)
error_tok(node->tok, "dereferencing a void pointer");
node->ty = node->lhs->ty->base;
return;
case ND_STMT_EXPR:
if (node->body) {
Node *stmt = node->body;
while (stmt->next) stmt = stmt->next;
if (stmt->kind == ND_EXPR_STMT) {
node->ty = stmt->lhs->ty;
return;
}
}
error_tok(node->tok,
"statement expression returning void is not supported");
return;
case ND_LABEL_VAL:
node->ty = pointer_to(ty_void);
return;
case ND_CAS:
add_type(node->cas_addr);
add_type(node->cas_old);
add_type(node->cas_new);
node->ty = ty_bool;
if (node->cas_addr->ty->kind != TY_PTR)
error_tok(node->cas_addr->tok, "pointer expected");
if (node->cas_old->ty->kind != TY_PTR)
error_tok(node->cas_old->tok, "pointer expected");
return;
case ND_EXCH:
if (node->lhs->ty->kind != TY_PTR)
error_tok(node->cas_addr->tok, "pointer expected");
node->ty = node->lhs->ty->base;
return;
}
}

186
third_party/chibicc/unicode.c vendored Normal file
View file

@ -0,0 +1,186 @@
#include "third_party/chibicc/chibicc.h"
// Encode a given character in UTF-8.
int encode_utf8(char *buf, uint32_t c) {
if (c <= 0x7F) {
buf[0] = c;
return 1;
}
if (c <= 0x7FF) {
buf[0] = 0b11000000 | (c >> 6);
buf[1] = 0b10000000 | (c & 0b00111111);
return 2;
}
if (c <= 0xFFFF) {
buf[0] = 0b11100000 | (c >> 12);
buf[1] = 0b10000000 | ((c >> 6) & 0b00111111);
buf[2] = 0b10000000 | (c & 0b00111111);
return 3;
}
buf[0] = 0b11110000 | (c >> 18);
buf[1] = 0b10000000 | ((c >> 12) & 0b00111111);
buf[2] = 0b10000000 | ((c >> 6) & 0b00111111);
buf[3] = 0b10000000 | (c & 0b00111111);
return 4;
}
// Read a UTF-8-encoded Unicode code point from a source file.
// We assume that source files are always in UTF-8.
//
// UTF-8 is a variable-width encoding in which one code point is
// encoded in one to four bytes. One byte UTF-8 code points are
// identical to ASCII. Non-ASCII characters are encoded using more
// than one byte.
uint32_t decode_utf8(char **new_pos, char *p) {
if ((unsigned char)*p < 128) {
*new_pos = p + 1;
return *p;
}
char *start = p;
int len;
uint32_t c;
if ((unsigned char)*p >= 0b11110000) {
len = 4;
c = *p & 0b111;
} else if ((unsigned char)*p >= 0b11100000) {
len = 3;
c = *p & 0b1111;
} else if ((unsigned char)*p >= 0b11000000) {
len = 2;
c = *p & 0b11111;
} else {
error_at(start, "invalid UTF-8 sequence");
}
for (int i = 1; i < len; i++) {
if ((unsigned char)p[i] >> 6 != 0b10)
error_at(start, "invalid UTF-8 sequence");
c = (c << 6) | (p[i] & 0b111111);
}
*new_pos = p + len;
return c;
}
static bool in_range(uint32_t *range, uint32_t c) {
for (int i = 0; range[i] != -1; i += 2)
if (range[i] <= c && c <= range[i + 1]) return true;
return false;
}
// C11 allows not only ASCII but some multibyte characters in certan
// Unicode ranges to be used in an identifier. See C11 Annex D for the
// details.
//
// This function returns true if a given character is acceptable as
// the first character of an identifier.
//
// For example, ¾ (U+00BE) is a valid identifier because characters in
// 0x00BE-0x00C0 are allowed, while neither ⟘ (U+27D8) nor ' '
// (U+3000, full-width space) are allowed because they are out of range.
bool is_ident1(uint32_t c) {
static uint32_t range[] = {
'_', '_', 'a', 'z', 'A', 'Z', '$', '$',
0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D,
0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F,
0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793,
0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F,
0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF,
0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD, 0x10000, 0x1FFFD,
0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD,
0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD,
0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD,
0xE0000, 0xEFFFD, -1,
};
return in_range(range, c);
}
// Returns true if a given character is acceptable as a non-first
// character of an identifier.
bool is_ident2(uint32_t c) {
static uint32_t range[] = {
'0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0,
0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1,
};
return is_ident1(c) || in_range(range, c);
}
// Returns the number of columns needed to display a given
// character in a fixed-width font.
//
// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
static int char_width(uint32_t c) {
static uint32_t range1[] = {
0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,
0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,
0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,
0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,
0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,
0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,
0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,
0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,
0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,
0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,
0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,
0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,
0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,
0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,
0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,
0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,
0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,
0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,
0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,
0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,
0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,
0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,
0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,
0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,
0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,
0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,
0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,
0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,
0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,
0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,
0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,
0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,
0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,
0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,
0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
-1,
};
if (in_range(range1, c)) return 0;
static uint32_t range2[] = {
0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,
0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1,
};
if (in_range(range2, c)) return 2;
return 1;
}
// Returns the number of columns needed to display a given
// string in a fixed-width font.
int str_width(char *p, int len) {
char *start = p;
int w = 0;
while (p - start < len) {
uint32_t c = decode_utf8(&p, p);
w += char_width(c);
}
return w;
}

419
third_party/gdtoa/README vendored Normal file
View file

@ -0,0 +1,419 @@
This directory contains source for a library of binary -> decimal
and decimal -> binary conversion routines, for single-, double-,
and extended-precision IEEE binary floating-point arithmetic, and
other IEEE-like binary floating-point, including "double double",
as in
T. J. Dekker, "A Floating-Point Technique for Extending the
Available Precision", Numer. Math. 18 (1971), pp. 224-242
and
"Inside Macintosh: PowerPC Numerics", Addison-Wesley, 1994
The conversion routines use double-precision floating-point arithmetic
and, where necessary, high precision integer arithmetic. The routines
are generalizations of the strtod and dtoa routines described in
David M. Gay, "Correctly Rounded Binary-Decimal and
Decimal-Binary Conversions", Numerical Analysis Manuscript
No. 90-10, Bell Labs, Murray Hill, 1990;
http://cm.bell-labs.com/cm/cs/what/ampl/REFS/rounding.ps.gz
(based in part on papers by Clinger and Steele & White: see the
references in the above paper).
The present conversion routines should be able to use any of IEEE binary,
VAX, or IBM-mainframe double-precision arithmetic internally, but I (dmg)
have so far only had a chance to test them with IEEE double precision
arithmetic.
The core conversion routines are strtodg for decimal -> binary conversions
and gdtoa for binary -> decimal conversions. These routines operate
on arrays of unsigned 32-bit integers of type ULong, a signed 32-bit
exponent of type Long, and arithmetic characteristics described in
struct FPI; FPI, Long, and ULong are defined in gdtoa.h. File arith.h
is supposed to provide #defines that cause gdtoa.h to define its
types correctly. File arithchk.c is source for a program that
generates a suitable arith.h on all systems where I've been able to
test it.
The core conversion routines are meant to be called by helper routines
that know details of the particular binary arithmetic of interest and
convert. The present directory provides helper routines for 5 variants
of IEEE binary floating-point arithmetic, each indicated by one or
two letters:
f IEEE single precision
d IEEE double precision
x IEEE extended precision, as on Intel 80x87
and software emulations of Motorola 68xxx chips
that do not pad the way the 68xxx does, but
only store 80 bits
xL IEEE extended precision, as on Motorola 68xxx chips
Q quad precision, as on Sun Sparc chips
dd double double, pairs of IEEE double numbers
whose sum is the desired value
For decimal -> binary conversions, there are three families of
helper routines: one for round-nearest (or the current rounding
mode on IEEE-arithmetic systems that provide the C99 fegetround()
function, if compiled with -DHonor_FLT_ROUNDS):
strtof
strtod
strtodd
strtopd
strtopf
strtopx
strtopxL
strtopQ
one with rounding direction specified:
strtorf
strtord
strtordd
strtorx
strtorxL
strtorQ
and one for computing an interval (at most one bit wide) that contains
the decimal number:
strtoIf
strtoId
strtoIdd
strtoIx
strtoIxL
strtoIQ
The latter call strtoIg, which makes one call on strtodg and adjusts
the result to provide the desired interval. On systems where native
arithmetic can easily make one-ulp adjustments on values in the
desired floating-point format, it might be more efficient to use the
native arithmetic. Routine strtodI is a variant of strtoId that
illustrates one way to do this for IEEE binary double-precision
arithmetic -- but whether this is more efficient remains to be seen.
Functions strtod and strtof have "natural" return types, float and
double -- strtod is specified by the C standard, and strtof appears
in the stdlib.h of some systems, such as (at least some) Linux systems.
The other functions write their results to their final argument(s):
to the final two argument for the strtoI... (interval) functions,
and to the final argument for the others (strtop... and strtor...).
Where possible, these arguments have "natural" return types (double*
or float*), to permit at least some type checking. In reality, they
are viewed as arrays of ULong (or, for the "x" functions, UShort)
values. On systems where long double is the appropriate type, one can
pass long double* final argument(s) to these routines. The int value
that these routines return is the return value from the call they make
on strtodg; see the enum of possible return values in gdtoa.h.
Source files g_ddfmt.c, misc.c, smisc.c, strtod.c, strtodg.c, and ulp.c
should use true IEEE double arithmetic (not, e.g., double extended),
at least for storing (and viewing the bits of) the variables declared
"double" within them.
One detail indicated in struct FPI is whether the target binary
arithmetic departs from the IEEE standard by flushing denormalized
numbers to 0. On systems that do this, the helper routines for
conversion to double-double format (when compiled with
Sudden_Underflow #defined) penalize the bottom of the exponent
range so that they return a nonzero result only when the least
significant bit of the less significant member of the pair of
double values returned can be expressed as a normalized double
value. An alternative would be to drop to 53-bit precision near
the bottom of the exponent range. To get correct rounding, this
would (in general) require two calls on strtodg (one specifying
126-bit arithmetic, then, if necessary, one specifying 53-bit
arithmetic).
By default, the core routine strtodg and strtod set errno to ERANGE
if the result overflows to +Infinity or underflows to 0. Compile
these routines with NO_ERRNO #defined to inhibit errno assignments.
Routine strtod is based on netlib's "dtoa.c from fp", and
(f = strtod(s,se)) is more efficient for some conversions than, say,
strtord(s,se,1,&f). Parts of strtod require true IEEE double
arithmetic with the default rounding mode (round-to-nearest) and, on
systems with IEEE extended-precision registers, double-precision
(53-bit) rounding precision. If the machine uses (the equivalent of)
Intel 80x87 arithmetic, the call
_control87(PC_53, MCW_PC);
does this with many compilers. Whether this or another call is
appropriate depends on the compiler; for this to work, it may be
necessary third_party/gdtoa/to #include "float.h" or another system-dependent header
file.
Source file strtodnrp.c gives a strtod that does not require 53-bit
rounding precision on systems (such as Intel IA32 systems) that may
suffer double rounding due to use of extended-precision registers.
For some conversions this variant of strtod is less efficient than the
one in strtod.c when the latter is run with 53-bit rounding precision.
When float or double are involved, the values that the strto* routines
return for NaNs are determined by gd_qnan.h, which the makefile
generates by running the program whose source is qnan.c. For other
types, default NaN values are specified in g__fmt.c and may need
adjusting. Note that the rules for distinguishing signaling from
quiet NaNs are system-dependent. For cross-compilation, you need to
determine arith.h and gd_qnan.h suitably, e.g., using the arithmetic
of the target machine.
C99's hexadecimal floating-point constants are recognized by the
strto* routines (but this feature has not yet been heavily tested).
Compiling with NO_HEX_FP #defined disables this feature.
When compiled with -DINFNAN_CHECK, the strto* routines recognize C99's
NaN and Infinity syntax. Moreover, unless No_Hex_NaN is #defined, the
strto* routines also recognize C99's NaN(...) syntax: they accept
(case insensitively) strings of the form NaN(x), where x is a string
of hexadecimal digits and spaces; if there is only one string of
hexadecimal digits, it is taken for the fraction bits of the resulting
NaN; if there are two or more strings of hexadecimal digits, each
string is assigned to the next available sequence of 32-bit words of
fractions bits (starting with the most significant), right-aligned in
each sequence. Strings of hexadecimal digits may be preceded by "0x"
or "0X".
For binary -> decimal conversions, I've provided a family of helper
routines:
g_ffmt
g_dfmt
g_ddfmt
g_xfmt
g_xLfmt
g_Qfmt
g_ffmt_p
g_dfmt_p
g_ddfmt_p
g_xfmt_p
g_xLfmt_p
g_Qfmt_p
which do a "%g" style conversion either to a specified number of decimal
places (if their ndig argument is positive), or to the shortest
decimal string that rounds to the given binary floating-point value
(if ndig <= 0). They write into a buffer supplied as an argument
and return either a pointer to the end of the string (a null character)
in the buffer, if the buffer was long enough, or 0. Other forms of
conversion are easily done with the help of gdtoa(), such as %e or %f
style and conversions with direction of rounding specified (so that, if
desired, the decimal value is either >= or <= the binary value).
On IEEE-arithmetic systems that provide the C99 fegetround() function,
if compiled with -DHonor_FLT_ROUNDS, these routines honor the current
rounding mode. For pedants, the ...fmt_p() routines are similar to the
...fmt() routines, but have an additional final int argument, nik,
that for conversions of Infinity or NaN, determines whether upper,
lower, or mixed case is used, whether (...) is added to NaN values,
and whether the sign of a NaN is reported or suppressed:
nik = ic + 6*(nb + 3*ns),
where ic with 0 <= ic < 6 controls the rendering of Infinity and NaN:
0 ==> Infinity or NaN
1 ==> infinity or nan
2 ==> INFINITY or NAN
3 ==> Inf or NaN
4 ==> inf or nan
5 ==> INF or NAN
nb with 0 <= nb < 3 determines whether NaN values are rendered
as NaN(...):
0 ==> no
1 ==> yes
2 ==> no for default NaN values; yes otherwise
ns = 0 or 1 determines whether the sign of NaN values reported:
0 ==> distinguish NaN and -NaN
1 ==> report both as NaN
For an example of more general conversions based on dtoa(), see
netlib's "printf.c from ampl/solvers".
For double-double -> decimal, g_ddfmt() assumes IEEE-like arithmetic
of precision max(126, #bits(input)) bits, where #bits(input) is the
number of mantissa bits needed to represent the sum of the two double
values in the input.
The makefile creates a library, gdtoa.a. To use the helper
routines, a program only needs to include gdtoa.h. All the
source files for gdtoa.a include a more extensive gdtoaimp.h;
among other things, gdtoaimp.h has #defines that make "internal"
names end in _D2A. To make a "system" library, one could modify
these #defines to make the names start with __.
Various comments about possible #defines appear in gdtoaimp.h,
but for most purposes, arith.h should set suitable #defines.
Systems with preemptive scheduling of multiple threads require some
manual intervention. On such systems, it's necessary to compile
dmisc.c, dtoa.c gdota.c, and misc.c with MULTIPLE_THREADS #defined,
and to provide (or suitably #define) two locks, acquired by
ACQUIRE_DTOA_LOCK(n) and freed by FREE_DTOA_LOCK(n) for n = 0 or 1.
(The second lock, accessed in pow5mult, ensures lazy evaluation of
only one copy of high powers of 5; omitting this lock would introduce
a small probability of wasting memory, but would otherwise be harmless.)
Routines that call dtoa or gdtoa directly must also invoke freedtoa(s)
to free the value s returned by dtoa or gdtoa. It's OK to do so whether
or not MULTIPLE_THREADS is #defined, and the helper g_*fmt routines
listed above all do this indirectly (in gfmt_D2A(), which they all call).
When MULTIPLE_THREADS is #defined, source file misc.c provides
void set_max_gdtoa_threads(unsigned int n);
and expects
unsigned int dtoa_get_threadno(void);
to be available (possibly provided by
#define dtoa_get_threadno omp_get_thread_num
if OpenMP is in use or by
#define dtoa_get_threadno pthread_self
if Pthreads is in use), to return the current thread number. If
set_max_gdtoa_threads(n) was called and the current thread number is
k with k < n, then calls on ACQUIRE_DTOA_LOCK(...) and
FREE_DTOA_LOCK(...) are avoided; instead each thread with thread
number < n has a separate copy of relevant data structures. After
set_max_gdtoa_threads(n), a call set_max_gdtoa_threads(m) with m <= n
has has no effect, but a call with m > n is honored. Such a call
invokes REALLOC (assumed to be "realloc" if REALLOC is not #defined)
to extend the size of the relevant array.
By default, there is a private pool of memory of length 2304 bytes
for intermediate quantities, and MALLOC (see gdtoaimp.h) is called only
if the private pool does not suffice. 2304 is large enough that MALLOC
is called only under very unusual circumstances (decimal -> binary
conversion of very long strings) for conversions to and from double
precision. For systems with preemptively scheduled multiple threads
or for conversions to extended or quad, it may be appropriate to
#define PRIVATE_MEM nnnn, where nnnn is a suitable value > 2304.
For extended and quad precisions, -DPRIVATE_MEM=20000 is probably
plenty even for many digits at the ends of the exponent range.
Use of the private pool avoids some overhead. When MULTIPLE_THREADS
is #defined, only thread 0 uses PRIVATE_MEM.
Directory test provides some test routines. See its README.
I've also tested this stuff (except double double conversions)
with Vern Paxson's testbase program: see
V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal
Conversion", manuscript, May 1991,
ftp://ftp.ee.lbl.gov/testbase-report.ps.Z .
(The same ftp directory has source for testbase.)
Some system-dependent additions to CFLAGS in the makefile:
HP-UX: -Aa -Ae
OSF (DEC Unix): -ieee_with_no_inexact
SunOS 4.1x: -DKR_headers -DBad_float_h
If you want to put this stuff into a shared library and your
operating system requires export lists for shared libraries,
the following would be an appropriate export list:
dtoa
freedtoa
g_Qfmt
g_ddfmt
g_dfmt
g_ffmt
g_xLfmt
g_xfmt
gdtoa
strtoIQ
strtoId
strtoIdd
strtoIf
strtoIx
strtoIxL
strtod
strtodI
strtodg
strtof
strtopQ
strtopd
strtopdd
strtopf
strtopx
strtopxL
strtorQ
strtord
strtordd
strtorf
strtorx
strtorxL
When time permits, I (dmg) hope to write in more detail about the
present conversion routines; for now, this README file must suffice.
Meanwhile, if you wish to write helper functions for other kinds of
IEEE-like arithmetic, some explanation of struct FPI and the bits
array may be helpful. Both gdtoa and strtodg operate on a bits array
described by FPI *fpi. The bits array is of type ULong, a 32-bit
unsigned integer type. Floating-point numbers have fpi->nbits bits,
with the least significant 32 bits in bits[0], the next 32 bits in
bits[1], etc. These numbers are regarded as integers multiplied by
2^e (i.e., 2 to the power of the exponent e), where e is the second
argument (be) to gdtoa and is stored in *exp by strtodg. The minimum
and maximum exponent values fpi->emin and fpi->emax for normalized
floating-point numbers reflect this arrangement. For example, the
P754 standard for binary IEEE arithmetic specifies doubles as having
53 bits, with normalized values of the form 1.xxxxx... times 2^(b-1023),
with 52 bits (the x's) and the biased exponent b represented explicitly;
b is an unsigned integer in the range 1 <= b <= 2046 for normalized
finite doubles, b = 0 for denormals, and b = 2047 for Infinities and NaNs.
To turn an IEEE double into the representation used by strtodg and gdtoa,
we multiply 1.xxxx... by 2^52 (to make it an integer) and reduce the
exponent e = (b-1023) by 52:
fpi->emin = 1 - 1023 - 52
fpi->emax = 1046 - 1023 - 52
In various wrappers for IEEE double, we actually write -53 + 1 rather
than -52, to emphasize that there are 53 bits including one implicit bit.
Field fpi->rounding indicates the desired rounding direction, with
possible values
FPI_Round_zero = toward 0,
FPI_Round_near = unbiased rounding -- the IEEE default,
FPI_Round_up = toward +Infinity, and
FPI_Round_down = toward -Infinity
given in gdtoa.h.
Field fpi->sudden_underflow indicates whether strtodg should return
denormals or flush them to zero. Normal floating-point numbers have
bit fpi->nbits in the bits array on. Denormals have it off, with
exponent = fpi->emin. Strtodg provides distinct return values for normals
and denormals; see gdtoa.h.
Compiling g__fmt.c, strtod.c, and strtodg.c with -DUSE_LOCALE causes
the decimal-point character to be taken from the current locale; otherwise
it is '.'.
Source files dtoa.c and strtod.c in this directory are derived from
netlib's "dtoa.c from fp" and are meant to function equivalently.
When compiled with Honor_FLT_ROUNDS #defined (on systems that provide
FLT_ROUNDS and fegetround() as specified in the C99 standard), they
honor the current rounding mode. Because FLT_ROUNDS is buggy on some
(Linux) systems -- not reflecting calls on fesetround(), as the C99
standard says it should -- when Honor_FLT_ROUNDS is #defined, the
current rounding mode is obtained from fegetround() rather than from
FLT_ROUNDS, unless Trust_FLT_ROUNDS is also #defined.
Compile with -DUSE_LOCALE to use the current locale; otherwise
decimal points are assumed to be '.'. With -DUSE_LOCALE, unless
you also compile with -DNO_LOCALE_CACHE, the details about the
current "decimal point" character string are cached and assumed not
to change during the program's execution.
On machines with a 64-bit long double and perhaps a 113-bit "quad"
type, you can invoke "make Printf" to add Printf (and variants, such
as Fprintf) to gdtoa.a. These are analogs, declared in stdio1.h, of
printf and fprintf, etc. in which %La, %Le, %Lf, and %Lg are for long
double and (if appropriate) %Lqa, %Lqe, %Lqf, and %Lqg are for quad
precision printing.
Please send comments to David M. Gay (dmg at acm dot org, with " at "
changed at "@" and " dot " changed to ".").

220
third_party/gdtoa/dmisc.c vendored Normal file
View file

@ -0,0 +1,220 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#ifndef MULTIPLE_THREADS
char *dtoa_result;
#endif
char *
#ifdef KR_headers
rv_alloc(i MTa) int i; MTk
#else
rv_alloc(int i MTd)
#endif
{
int j, k, *r;
j = sizeof(ULong);
for(k = 0;
(int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
j <<= 1)
k++;
r = (int*)Balloc(k MTa);
*r = k;
return
#ifndef MULTIPLE_THREADS
dtoa_result =
#endif
(char *)(r+1);
}
char *
#ifdef KR_headers
nrv_alloc(s, rve, n MTa) char *s, **rve; int n; MTk
#else
nrv_alloc(char *s, char **rve, int n MTd)
#endif
{
char *rv, *t;
t = rv = rv_alloc(n MTa);
while((*t = *s++) !=0)
t++;
if (rve)
*rve = t;
return rv;
}
/* freedtoa(s) must be used to free values s returned by dtoa
* when MULTIPLE_THREADS is #defined. It should be used in all cases,
* but for consistency with earlier versions of dtoa, it is optional
* when MULTIPLE_THREADS is not defined.
*/
void
#ifdef KR_headers
freedtoa(s) char *s;
#else
freedtoa(char *s)
#endif
{
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
Bigint *b = (Bigint *)((int *)s - 1);
b->maxwds = 1 << (b->k = *(int*)b);
Bfree(b MTb);
#ifndef MULTIPLE_THREADS
if (s == dtoa_result)
dtoa_result = 0;
#endif
}
int
quorem
#ifdef KR_headers
(b, S) Bigint *b, *S;
#else
(Bigint *b, Bigint *S)
#endif
{
int n;
ULong *bx, *bxe, q, *sx, *sxe;
#ifdef ULLong
ULLong borrow, carry, y, ys;
#else
ULong borrow, carry, y, ys;
#ifdef Pack_32
ULong si, z, zs;
#endif
#endif
n = S->wds;
#ifdef DEBUG
/*debug*/ if (b->wds > n)
/*debug*/ Bug("oversize b in quorem");
#endif
if (b->wds < n)
return 0;
sx = S->x;
sxe = sx + --n;
bx = b->x;
bxe = bx + n;
q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
#ifdef DEBUG
/*debug*/ if (q > 9)
/*debug*/ Bug("oversized quotient in quorem");
#endif
if (q) {
borrow = 0;
carry = 0;
do {
#ifdef ULLong
ys = *sx++ * (ULLong)q + carry;
carry = ys >> 32;
y = *bx - (ys & 0xffffffffUL) - borrow;
borrow = y >> 32 & 1UL;
*bx++ = y & 0xffffffffUL;
#else
#ifdef Pack_32
si = *sx++;
ys = (si & 0xffff) * q + carry;
zs = (si >> 16) * q + (ys >> 16);
carry = zs >> 16;
y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(bx, z, y);
#else
ys = *sx++ * q + carry;
carry = ys >> 16;
y = *bx - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
*bx++ = y & 0xffff;
#endif
#endif
}
while(sx <= sxe);
if (!*bxe) {
bx = b->x;
while(--bxe > bx && !*bxe)
--n;
b->wds = n;
}
}
if (cmp(b, S) >= 0) {
q++;
borrow = 0;
carry = 0;
bx = b->x;
sx = S->x;
do {
#ifdef ULLong
ys = *sx++ + carry;
carry = ys >> 32;
y = *bx - (ys & 0xffffffffUL) - borrow;
borrow = y >> 32 & 1UL;
*bx++ = y & 0xffffffffUL;
#else
#ifdef Pack_32
si = *sx++;
ys = (si & 0xffff) + carry;
zs = (si >> 16) + (ys >> 16);
carry = zs >> 16;
y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(bx, z, y);
#else
ys = *sx++ + carry;
carry = ys >> 16;
y = *bx - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
*bx++ = y & 0xffff;
#endif
#endif
}
while(sx <= sxe);
bx = b->x;
bxe = bx + n;
if (!*bxe) {
while(--bxe > bx && !*bxe)
--n;
b->wds = n;
}
}
return q;
}

801
third_party/gdtoa/dtoa.c vendored Normal file
View file

@ -0,0 +1,801 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
*
* Inspired by "How to Print Floating-Point Numbers Accurately" by
* Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
*
* Modifications:
* 1. Rather than iterating, we use a simple numeric overestimate
* to determine k = floor(log10(d)). We scale relevant
* quantities using O(log2(k)) rather than O(k) multiplications.
* 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
* try to generate digits strictly left to right. Instead, we
* compute with fewer bits and propagate the carry if necessary
* when rounding the final digit up. This is often faster.
* 3. Under the assumption that input will be rounded nearest,
* mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
* That is, we allow equality in stopping tests when the
* round-nearest rule will give the same floating-point value
* as would satisfaction of the stopping test with strict
* inequality.
* 4. We remove common factors of powers of 2 from relevant
* quantities.
* 5. When converting floating-point integers less than 1e16,
* we use floating-point arithmetic rather than resorting
* to multiple-precision integers.
* 6. When asked to produce fewer than 15 digits, we first try
* to get by with floating-point arithmetic; we resort to
* multiple-precision integer arithmetic only if we cannot
* guarantee that the floating-point calculation has given
* the correctly rounded result. For k requested digits and
* "uniformly" distributed input, the probability is
* something like 10^(k-15) that we must resort to the Long
* calculation.
*/
#ifdef Honor_FLT_ROUNDS
#undef Check_FLT_ROUNDS
#define Check_FLT_ROUNDS
#else
#define Rounding Flt_Rounds
#endif
char *
dtoa
#ifdef KR_headers
(d0, mode, ndigits, decpt, sign, rve)
double d0; int mode, ndigits, *decpt, *sign; char **rve;
#else
(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif
{
/* Arguments ndigits, decpt, sign are similar to those
of ecvt and fcvt; trailing zeros are suppressed from
the returned string. If not null, *rve is set to point
to the end of the return value. If d is +-Infinity or NaN,
then *decpt is set to 9999.
mode:
0 ==> shortest string that yields d when read in
and rounded to nearest.
1 ==> like 0, but with Steele & White stopping rule;
e.g. with IEEE P754 arithmetic , mode 0 gives
1e23 whereas mode 1 gives 9.999999999999999e22.
2 ==> max(1,ndigits) significant digits. This gives a
return value similar to that of ecvt, except
that trailing zeros are suppressed.
3 ==> through ndigits past the decimal point. This
gives a return value similar to that from fcvt,
except that trailing zeros are suppressed, and
ndigits can be negative.
4,5 ==> similar to 2 and 3, respectively, but (in
round-nearest mode) with the tests of mode 0 to
possibly return a shorter string that rounds to d.
With IEEE arithmetic and compilation with
-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
as modes 2 and 3 when FLT_ROUNDS != 1.
6-9 ==> Debugging modes similar to mode - 4: don't try
fast floating-point estimate (if applicable).
Values of mode other than 0-9 are treated as mode 0.
Sufficient space is allocated to the return value
to hold the suppressed trailing zeros.
*/
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
spec_case, try_quick;
Long L;
#ifndef Sudden_Underflow
int denorm;
ULong x;
#endif
Bigint *b, *b1, *delta, *mlo, *mhi, *S;
U d, d2, eps, eps1;
double ds;
char *s, *s0;
#ifdef SET_INEXACT
int inexact, oldinexact;
#endif
#ifdef Honor_FLT_ROUNDS /*{*/
int Rounding;
#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
Rounding = Flt_Rounds;
#else /*}{*/
Rounding = 1;
switch(fegetround()) {
case FE_TOWARDZERO: Rounding = 0; break;
case FE_UPWARD: Rounding = 2; break;
case FE_DOWNWARD: Rounding = 3;
}
#endif /*}}*/
#endif /*}*/
#ifndef MULTIPLE_THREADS
if (dtoa_result) {
freedtoa(dtoa_result);
dtoa_result = 0;
}
#endif
d.d = d0;
if (word0(&d) & Sign_bit) {
/* set sign for everything, including 0's and NaNs */
*sign = 1;
word0(&d) &= ~Sign_bit; /* clear sign bit */
}
else
*sign = 0;
#if defined(IEEE_Arith) + defined(VAX)
#ifdef IEEE_Arith
if ((word0(&d) & Exp_mask) == Exp_mask)
#else
if (word0(&d) == 0x8000)
#endif
{
/* Infinity or NaN */
*decpt = 9999;
#ifdef IEEE_Arith
if (!word1(&d) && !(word0(&d) & 0xfffff))
return nrv_alloc("Infinity", rve, 8 MTb);
#endif
return nrv_alloc("NaN", rve, 3 MTb);
}
#endif
#ifdef IBM
dval(&d) += 0; /* normalize */
#endif
if (!dval(&d)) {
*decpt = 1;
return nrv_alloc("0", rve, 1 MTb);
}
#ifdef SET_INEXACT
try_quick = oldinexact = get_inexact();
inexact = 1;
#endif
#ifdef Honor_FLT_ROUNDS
if (Rounding >= 2) {
if (*sign)
Rounding = Rounding == 2 ? 0 : 2;
else
if (Rounding != 2)
Rounding = 0;
}
#endif
b = d2b(dval(&d), &be, &bbits MTb);
#ifdef Sudden_Underflow
i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
#endif
dval(&d2) = dval(&d);
word0(&d2) &= Frac_mask1;
word0(&d2) |= Exp_11;
#ifdef IBM
if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0)
dval(&d2) /= 1 << j;
#endif
/* log(x) ~=~ log(1.5) + (x-1.5)/1.5
* log10(x) = log(x) / log(10)
* ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
* log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
*
* This suggests computing an approximation k to log10(&d) by
*
* k = (i - Bias)*0.301029995663981
* + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
*
* We want k to be too large rather than too small.
* The error in the first-order Taylor series approximation
* is in our favor, so we just round up the constant enough
* to compensate for any error in the multiplication of
* (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
* and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
* adding 1e-13 to the constant term more than suffices.
* Hence we adjust the constant term to 0.1760912590558.
* (We could get a more accurate k by invoking log10,
* but this is probably not worthwhile.)
*/
i -= Bias;
#ifdef IBM
i <<= 2;
i += j;
#endif
#ifndef Sudden_Underflow
denorm = 0;
}
else {
/* d is denormalized */
i = bbits + be + (Bias + (P-1) - 1);
x = i > 32 ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
: word1(&d) << (32 - i);
dval(&d2) = x;
word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
i -= (Bias + (P-1) - 1) + 1;
denorm = 1;
}
#endif
ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
k = (int)ds;
if (ds < 0. && ds != k)
k--; /* want k = floor(ds) */
k_check = 1;
if (k >= 0 && k <= Ten_pmax) {
if (dval(&d) < tens[k])
k--;
k_check = 0;
}
j = bbits - i - 1;
if (j >= 0) {
b2 = 0;
s2 = j;
}
else {
b2 = -j;
s2 = 0;
}
if (k >= 0) {
b5 = 0;
s5 = k;
s2 += k;
}
else {
b2 -= k;
b5 = -k;
s5 = 0;
}
if (mode < 0 || mode > 9)
mode = 0;
#ifndef SET_INEXACT
#ifdef Check_FLT_ROUNDS
try_quick = Rounding == 1;
#else
try_quick = 1;
#endif
#endif /*SET_INEXACT*/
if (mode > 5) {
mode -= 4;
try_quick = 0;
}
leftright = 1;
ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
/* silence erroneous "gcc -Wall" warning. */
switch(mode) {
case 0:
case 1:
i = 18;
ndigits = 0;
break;
case 2:
leftright = 0;
/* no break */
case 4:
if (ndigits <= 0)
ndigits = 1;
ilim = ilim1 = i = ndigits;
break;
case 3:
leftright = 0;
/* no break */
case 5:
i = ndigits + k + 1;
ilim = i;
ilim1 = i - 1;
if (i <= 0)
i = 1;
}
s = s0 = rv_alloc(i MTb);
#ifdef Honor_FLT_ROUNDS
if (mode > 1 && Rounding != 1)
leftright = 0;
#endif
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
/* Try to get by with floating-point arithmetic. */
i = 0;
j1 = 0;
dval(&d2) = dval(&d);
k0 = k;
ilim0 = ilim;
ieps = 2; /* conservative */
if (k > 0) {
ds = tens[k&0xf];
j = k >> 4;
if (j & Bletch) {
/* prevent overflows */
j &= Bletch - 1;
dval(&d) /= bigtens[n_bigtens-1];
ieps++;
}
for(; j; j >>= 1, i++)
if (j & 1) {
ieps++;
ds *= bigtens[i];
}
dval(&d) /= ds;
}
else if (( j1 = -k )!=0) {
dval(&d) *= tens[j1 & 0xf];
for(j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
ieps++;
dval(&d) *= bigtens[i];
}
}
if (k_check && dval(&d) < 1. && ilim > 0) {
if (ilim1 <= 0)
goto fast_failed;
ilim = ilim1;
k--;
dval(&d) *= 10.;
ieps++;
}
dval(&eps) = ieps*dval(&d) + 7.;
word0(&eps) -= (P-1)*Exp_msk1;
if (ilim == 0) {
S = mhi = 0;
dval(&d) -= 5.;
if (dval(&d) > dval(&eps))
goto one_digit;
if (dval(&d) < -dval(&eps))
goto no_digits;
goto fast_failed;
}
#ifndef No_leftright
if (leftright) {
/* Use Steele & White method of only
* generating digits needed.
*/
dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
if (k0 < 0 && j1 >= 307) {
eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */
word0(&eps1) -= Exp_msk1 * (Bias+P-1);
dval(&eps1) *= tens[j1 & 0xf];
for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++)
if (j & 1)
dval(&eps1) *= bigtens[i];
if (eps.d < eps1.d)
eps.d = eps1.d;
if (10. - d.d < 10.*eps.d && eps.d < 1.) {
/* eps.d < 1. excludes trouble with the tiniest denormal */
*s++ = '1';
++k;
goto ret1;
}
}
for(i = 0;;) {
L = dval(&d);
dval(&d) -= L;
*s++ = '0' + (int)L;
if (dval(&d) < dval(&eps))
goto retc;
if (1. - dval(&d) < dval(&eps))
goto bump_up;
if (++i >= ilim)
break;
dval(&eps) *= 10.;
dval(&d) *= 10.;
}
}
else {
#endif
/* Generate ilim digits, then fix them up. */
dval(&eps) *= tens[ilim-1];
for(i = 1;; i++, dval(&d) *= 10.) {
L = (Long)(dval(&d));
if (!(dval(&d) -= L))
ilim = i;
*s++ = '0' + (int)L;
if (i == ilim) {
if (dval(&d) > 0.5 + dval(&eps))
goto bump_up;
else if (dval(&d) < 0.5 - dval(&eps))
goto retc;
break;
}
}
#ifndef No_leftright
}
#endif
fast_failed:
s = s0;
dval(&d) = dval(&d2);
k = k0;
ilim = ilim0;
}
/* Do we have a "small" integer? */
if (be >= 0 && k <= Int_max) {
/* Yes. */
ds = tens[k];
if (ndigits < 0 && ilim <= 0) {
S = mhi = 0;
if (ilim < 0 || dval(&d) <= 5*ds)
goto no_digits;
goto one_digit;
}
for(i = 1;; i++, dval(&d) *= 10.) {
L = (Long)(dval(&d) / ds);
dval(&d) -= L*ds;
#ifdef Check_FLT_ROUNDS
/* If FLT_ROUNDS == 2, L will usually be high by 1 */
if (dval(&d) < 0) {
L--;
dval(&d) += ds;
}
#endif
*s++ = '0' + (int)L;
if (!dval(&d)) {
#ifdef SET_INEXACT
inexact = 0;
#endif
break;
}
if (i == ilim) {
#ifdef Honor_FLT_ROUNDS
if (mode > 1)
switch(Rounding) {
case 0: goto retc;
case 2: goto bump_up;
}
#endif
dval(&d) += dval(&d);
#ifdef ROUND_BIASED
if (dval(&d) >= ds)
#else
if (dval(&d) > ds || (dval(&d) == ds && L & 1))
#endif
{
bump_up:
while(*--s == '9')
if (s == s0) {
k++;
*s = '0';
break;
}
++*s++;
}
break;
}
}
goto retc;
}
m2 = b2;
m5 = b5;
mhi = mlo = 0;
if (leftright) {
i =
#ifndef Sudden_Underflow
denorm ? be + (Bias + (P-1) - 1 + 1) :
#endif
#ifdef IBM
1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
#else
1 + P - bbits;
#endif
b2 += i;
s2 += i;
mhi = i2b(1 MTb);
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
b2 -= i;
m2 -= i;
s2 -= i;
}
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mhi = pow5mult(mhi, m5 MTb);
b1 = mult(mhi, b MTb);
Bfree(b MTb);
b = b1;
}
if (( j = b5 - m5 )!=0)
b = pow5mult(b, j MTb);
}
else
b = pow5mult(b, b5 MTb);
}
S = i2b(1 MTb);
if (s5 > 0)
S = pow5mult(S, s5 MTb);
/* Check for special case that d is a normalized power of 2. */
spec_case = 0;
if ((mode < 2 || leftright)
#ifdef Honor_FLT_ROUNDS
&& Rounding == 1
#endif
) {
if (!word1(&d) && !(word0(&d) & Bndry_mask)
#ifndef Sudden_Underflow
&& word0(&d) & (Exp_mask & ~Exp_msk1)
#endif
) {
/* The special case */
b2 += Log2P;
s2 += Log2P;
spec_case = 1;
}
}
/* Arrange for convenient computation of quotients:
* shift left if necessary so divisor has 4 leading 0 bits.
*
* Perhaps we should just compute leading 28 bits of S once
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
#ifdef Pack_32
if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
i = 32 - i;
#else
if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
i = 16 - i;
#endif
if (i > 4) {
i -= 4;
b2 += i;
m2 += i;
s2 += i;
}
else if (i < 4) {
i += 28;
b2 += i;
m2 += i;
s2 += i;
}
if (b2 > 0)
b = lshift(b, b2 MTb);
if (s2 > 0)
S = lshift(S, s2 MTb);
if (k_check) {
if (cmp(b,S) < 0) {
k--;
b = multadd(b, 10, 0 MTb); /* we botched the k estimate */
if (leftright)
mhi = multadd(mhi, 10, 0 MTb);
ilim = ilim1;
}
}
if (ilim <= 0 && (mode == 3 || mode == 5)) {
if (ilim < 0 || cmp(b,S = multadd(S,5,0 MTb)) <= 0) {
/* no digits, fcvt style */
no_digits:
k = -1 - ndigits;
goto ret;
}
one_digit:
*s++ = '1';
k++;
goto ret;
}
if (leftright) {
if (m2 > 0)
mhi = lshift(mhi, m2 MTb);
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
*/
mlo = mhi;
if (spec_case) {
mhi = Balloc(mhi->k MTb);
Bcopy(mhi, mlo);
mhi = lshift(mhi, Log2P MTb);
}
for(i = 1;;i++) {
dig = quorem(b,S) + '0';
/* Do we yet have the shortest decimal string
* that will round to d?
*/
j = cmp(b, mlo);
delta = diff(S, mhi MTb);
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta MTb);
#ifndef ROUND_BIASED
if (j1 == 0 && mode != 1 && !(word1(&d) & 1)
#ifdef Honor_FLT_ROUNDS
&& Rounding >= 1
#endif
) {
if (dig == '9')
goto round_9_up;
if (j > 0)
dig++;
#ifdef SET_INEXACT
else if (!b->x[0] && b->wds <= 1)
inexact = 0;
#endif
*s++ = dig;
goto ret;
}
#endif
if (j < 0 || (j == 0 && mode != 1
#ifndef ROUND_BIASED
&& !(word1(&d) & 1)
#endif
)) {
if (!b->x[0] && b->wds <= 1) {
#ifdef SET_INEXACT
inexact = 0;
#endif
goto accept_dig;
}
#ifdef Honor_FLT_ROUNDS
if (mode > 1)
switch(Rounding) {
case 0: goto accept_dig;
case 2: goto keep_dig;
}
#endif /*Honor_FLT_ROUNDS*/
if (j1 > 0) {
b = lshift(b, 1 MTb);
j1 = cmp(b, S);
#ifdef ROUND_BIASED
if (j1 >= 0 /*)*/
#else
if ((j1 > 0 || (j1 == 0 && dig & 1))
#endif
&& dig++ == '9')
goto round_9_up;
}
accept_dig:
*s++ = dig;
goto ret;
}
if (j1 > 0) {
#ifdef Honor_FLT_ROUNDS
if (!Rounding && mode > 1)
goto accept_dig;
#endif
if (dig == '9') { /* possible if i == 1 */
round_9_up:
*s++ = '9';
goto roundoff;
}
*s++ = dig + 1;
goto ret;
}
#ifdef Honor_FLT_ROUNDS
keep_dig:
#endif
*s++ = dig;
if (i == ilim)
break;
b = multadd(b, 10, 0 MTb);
if (mlo == mhi)
mlo = mhi = multadd(mhi, 10, 0 MTb);
else {
mlo = multadd(mlo, 10, 0 MTb);
mhi = multadd(mhi, 10, 0 MTb);
}
}
}
else
for(i = 1;; i++) {
*s++ = dig = quorem(b,S) + '0';
if (!b->x[0] && b->wds <= 1) {
#ifdef SET_INEXACT
inexact = 0;
#endif
goto ret;
}
if (i >= ilim)
break;
b = multadd(b, 10, 0 MTb);
}
/* Round off last digit */
#ifdef Honor_FLT_ROUNDS
switch(Rounding) {
case 0: goto trimzeros;
case 2: goto roundoff;
}
#endif
b = lshift(b, 1 MTb);
j = cmp(b, S);
#ifdef ROUND_BIASED
if (j >= 0)
#else
if (j > 0 || (j == 0 && dig & 1))
#endif
{
roundoff:
while(*--s == '9')
if (s == s0) {
k++;
*s++ = '1';
goto ret;
}
++*s++;
}
else {
#ifdef Honor_FLT_ROUNDS
trimzeros:
#endif
while(*--s == '0');
s++;
}
ret:
Bfree(S MTb);
if (mhi) {
if (mlo && mlo != mhi)
Bfree(mlo MTb);
Bfree(mhi MTb);
}
retc:
while(s > s0 && s[-1] == '0')
--s;
ret1:
#ifdef SET_INEXACT
if (inexact) {
if (!oldinexact) {
word0(&d) = Exp_1 + (70 << Exp_shift);
word1(&d) = 0;
dval(&d) += 1.;
}
}
else if (!oldinexact)
clear_inexact();
#endif
Bfree(b MTb);
*s = 0;
*decpt = k + 1;
if (rve)
*rve = s;
return s0;
}

120
third_party/gdtoa/g_Qfmt.c vendored Normal file
View file

@ -0,0 +1,120 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#endif
#ifdef IEEE_8087
#define _0 3
#define _1 2
#define _2 1
#define _3 0
#endif
char*
#ifdef KR_headers
g_Qfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize;
#else
g_Qfmt(char *buf, void *V, int ndig, size_t bufsize)
#endif
{
static const FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[4], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)V;
sign = L[_0] & 0x80000000L;
bits[3] = L[_0] & 0xffff;
bits[2] = L[_1];
bits[1] = L[_2];
bits[0] = L[_3];
b = buf;
if ( (ex = (L[_0] & 0x7fff0000L) >> 16) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (bits[0] | bits[1] | bits[2] | bits[3])
b = strcp(b, "NaN");
else {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, "Infinity");
}
return b;
}
i = STRTOG_Normal;
bits[3] |= 0x10000;
}
else if (bits[0] | bits[1] | bits[2] | bits[3]) {
i = STRTOG_Denormal;
ex = 1;
}
else {
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 112;
mode = 2;
if (ndig <= 0) {
if (bufsize < 48)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

133
third_party/gdtoa/g_Qfmt_p.c vendored Normal file
View file

@ -0,0 +1,133 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_Q_D2A[4];
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#endif
#ifdef IEEE_8087
#define _0 3
#define _1 2
#define _2 1
#define _3 0
#endif
char*
#ifdef KR_headers
g_Qfmt_p(buf, V, ndig, bufsize, nik) char *buf; char *V; int ndig; size_t bufsize; int nik;
#else
g_Qfmt_p(char *buf, void *V, int ndig, size_t bufsize, int nik)
#endif
{
static const FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[4], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)V;
sign = L[_0] & 0x80000000L;
bits[3] = L[_0] & 0xffff;
bits[2] = L[_1];
bits[1] = L[_2];
bits[0] = L[_3];
b = buf;
if ( (ex = (L[_0] & 0x7fff0000L) >> 16) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (nik < 0 || nik > 35)
nik = 0;
if (bits[0] | bits[1] | bits[2] | bits[3]) {
if (sign && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| bits[0] != NanDflt_Q_D2A[0]
|| bits[1] != NanDflt_Q_D2A[1]
|| bits[2] != NanDflt_Q_D2A[2]
|| (bits[2] ^ NanDflt_Q_D2A[2]) & 0xffff))
b = add_nanbits(b, bufsize - (b-buf), bits, 4);
}
else {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, InfName[nik%6]);
}
return b;
}
i = STRTOG_Normal;
bits[3] |= 0x10000;
}
else if (bits[0] | bits[1] | bits[2] | bits[3]) {
i = STRTOG_Denormal;
ex = 1;
}
else {
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 112;
mode = 2;
if (ndig <= 0) {
if (bufsize < 48)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

200
third_party/gdtoa/g__fmt.c vendored Normal file
View file

@ -0,0 +1,200 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#ifndef ldus_QNAN0
#define ldus_QNAN0 0x7fff
#endif
#ifndef ldus_QNAN1
#define ldus_QNAN1 0xc000
#endif
#ifndef ldus_QNAN2
#define ldus_QNAN2 0
#endif
#ifndef ldus_QNAN3
#define ldus_QNAN3 0
#endif
#ifndef ldus_QNAN4
#define ldus_QNAN4 0
#endif
const char *const InfName[6] = { "Infinity", "infinity", "INFINITY", "Inf", "inf", "INF" };
const char *const NanName[3] = { "NaN", "nan", "NAN" };
const ULong NanDflt_Q_D2A[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff };
const ULong NanDflt_d_D2A[2] = { d_QNAN1, d_QNAN0 };
const ULong NanDflt_f_D2A[1] = { f_QNAN };
const ULong NanDflt_xL_D2A[3] = { 1, 0x80000000, 0x7fff0000 };
const UShort NanDflt_ldus_D2A[5] = { ldus_QNAN4, ldus_QNAN3, ldus_QNAN2, ldus_QNAN1, ldus_QNAN0 };
char *
#ifdef KR_headers
g__fmt(b, s, se, decpt, sign, blen) char *b; char *s; char *se; int decpt; ULong sign; size_t blen;
#else
g__fmt(char *b, char *s, char *se, int decpt, ULong sign, size_t blen)
#endif
{
int i, j, k;
char *be, *s0;
size_t len;
#ifdef USE_LOCALE
#ifdef NO_LOCALE_CACHE
char *decimalpoint = localeconv()->decimal_point;
size_t dlen = strlen(decimalpoint);
#else
char *decimalpoint;
static char *decimalpoint_cache;
static size_t dlen;
if (!(s0 = decimalpoint_cache)) {
s0 = localeconv()->decimal_point;
dlen = strlen(s0);
if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
strcpy(decimalpoint_cache, s0);
s0 = decimalpoint_cache;
}
}
decimalpoint = s0;
#endif
#else
#define dlen 0
#endif
s0 = s;
len = (se-s) + dlen + 6; /* 6 = sign + e+dd + trailing null */
if (blen < len)
goto ret0;
be = b + blen - 1;
if (sign)
*b++ = '-';
if (decpt <= -4 || decpt > se - s + 5) {
*b++ = *s++;
if (*s) {
#ifdef USE_LOCALE
while((*b = *decimalpoint++))
++b;
#else
*b++ = '.';
#endif
while((*b = *s++) !=0)
b++;
}
*b++ = 'e';
/* sprintf(b, "%+.2d", decpt - 1); */
if (--decpt < 0) {
*b++ = '-';
decpt = -decpt;
}
else
*b++ = '+';
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10){}
for(;;) {
i = decpt / k;
if (b >= be)
goto ret0;
*b++ = i + '0';
if (--j <= 0)
break;
decpt -= i*k;
decpt *= 10;
}
*b = 0;
}
else if (decpt <= 0) {
#ifdef USE_LOCALE
while((*b = *decimalpoint++))
++b;
#else
*b++ = '.';
#endif
if (be < b - decpt + (se - s))
goto ret0;
for(; decpt < 0; decpt++)
*b++ = '0';
while((*b = *s++) != 0)
b++;
}
else {
while((*b = *s++) != 0) {
b++;
if (--decpt == 0 && *s) {
#ifdef USE_LOCALE
while(*b = *decimalpoint++)
++b;
#else
*b++ = '.';
#endif
}
}
if (b + decpt > be) {
ret0:
b = 0;
goto ret;
}
for(; decpt > 0; decpt--)
*b++ = '0';
*b = 0;
}
ret:
freedtoa(s0);
return b;
}
char *
add_nanbits_D2A(char *b, size_t blen, ULong *bits, int nb)
{
ULong t;
char *rv;
int i, j;
size_t L;
static char Hexdig[16] = "0123456789abcdef";
while(!bits[--nb])
if (!nb)
return b;
L = 8*nb + 3;
t = bits[nb];
do ++L; while((t >>= 4));
if (L > blen)
return b;
b += L;
*--b = 0;
rv = b;
*--b = /*(*/ ')';
for(i = 0; i < nb; ++i) {
t = bits[i];
for(j = 0; j < 8; ++j, t >>= 4)
*--b = Hexdig[t & 0xf];
}
t = bits[nb];
do *--b = Hexdig[t & 0xf]; while(t >>= 4);
*--b = '('; /*)*/
return rv;
}

174
third_party/gdtoa/g_ddfmt.c vendored Normal file
View file

@ -0,0 +1,174 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg@acm.org). */
char *
#ifdef KR_headers
g_ddfmt(buf, dd0, ndig, bufsize) char *buf; double *dd0; int ndig; size_t bufsize;
#else
g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
#endif
{
FPI fpi;
char *b, *s, *se;
ULong *L, bits0[4], *bits, *zx;
int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z;
U *dd, ddx[2];
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
#ifdef Honor_FLT_ROUNDS /*{{*/
int Rounding;
#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
Rounding = Flt_Rounds;
#else /*}{*/
Rounding = 1;
switch(fegetround()) {
case FE_TOWARDZERO: Rounding = 0; break;
case FE_UPWARD: Rounding = 2; break;
case FE_DOWNWARD: Rounding = 3;
}
#endif /*}}*/
#else /*}{*/
#define Rounding FPI_Round_near
#endif /*}}*/
if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0;
dd = (U*)dd0;
L = dd->L;
if ((L[_0] & 0x7ff00000L) == 0x7ff00000L) {
/* Infinity or NaN */
if (L[_0] & 0xfffff || L[_1]) {
nanret:
return strcp(buf, "NaN");
}
if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
if (L[2+_0] & 0xfffff || L[2+_1])
goto nanret;
if ((L[_0] ^ L[2+_0]) & 0x80000000L)
goto nanret; /* Infinity - Infinity */
}
infret:
b = buf;
if (L[_0] & 0x80000000L)
*b++ = '-';
return strcp(b, "Infinity");
}
if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
L += 2;
if (L[_0] & 0xfffff || L[_1])
goto nanret;
goto infret;
}
if (dval(&dd[0]) + dval(&dd[1]) == 0.) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (L[_0] & L[2+_0] & 0x80000000L)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
if ((L[_0] & 0x7ff00000L) < (L[2+_0] & 0x7ff00000L)) {
dval(&ddx[1]) = dval(&dd[0]);
dval(&ddx[0]) = dval(&dd[1]);
dd = ddx;
L = dd->L;
}
z = d2b(dval(&dd[0]), &ex, &bx MTb);
if (dval(&dd[1]) == 0.)
goto no_y;
x = z;
y = d2b(dval(&dd[1]), &ey, &by MTb);
if ( (i = ex - ey) !=0) {
if (i > 0) {
x = lshift(x, i MTb);
ex = ey;
}
else
y = lshift(y, -i MTb);
}
if ((L[_0] ^ L[2+_0]) & 0x80000000L) {
z = diff(x, y MTb);
if (L[_0] & 0x80000000L)
z->sign = 1 - z->sign;
}
else {
z = sum(x, y MTb);
if (L[_0] & 0x80000000L)
z->sign = 1;
}
Bfree(x MTb);
Bfree(y MTb);
no_y:
bits = zx = z->x;
for(i = 0; !*zx; zx++)
i += 32;
i += lo0bits(zx);
if (i) {
rshift(z, i);
ex += i;
}
fpi.nbits = z->wds * 32 - hi0bits(z->x[j = z->wds-1]);
if (fpi.nbits < 106) {
fpi.nbits = 106;
if (j < 3) {
for(i = 0; i <= j; i++)
bits0[i] = bits[i];
while(i < 4)
bits0[i++] = 0;
bits = bits0;
}
}
mode = 2;
if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
Bfree(z MTb);
return 0;
}
mode = 0;
}
fpi.emin = 1-1023-53+1;
fpi.emax = 2046-1023-106+1;
fpi.rounding = Rounding;
fpi.sudden_underflow = 0;
fpi.int_max = Int_max;
i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = g__fmt(buf, s, se, decpt, z->sign, bufsize);
Bfree(z MTb);
return b;
}

194
third_party/gdtoa/g_ddfmt_p.c vendored Normal file
View file

@ -0,0 +1,194 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg@acm.org). */
extern ULong NanDflt_d_D2A[2];
char *
#ifdef KR_headers
g_ddfmt_p(buf, dd0, ndig, bufsize, nik) char *buf; double *dd0; int ndig; size_t bufsize; int nik;
#else
g_ddfmt_p(char *buf, double *dd0, int ndig, size_t bufsize, int nik)
#endif
{
FPI fpi;
char *b, *s, *se;
ULong *L, bits0[4], *bits, sign, *zx;
int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z;
U *dd, ddx[2];
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
#ifdef Honor_FLT_ROUNDS /*{{*/
int Rounding;
#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
Rounding = Flt_Rounds;
#else /*}{*/
Rounding = 1;
switch(fegetround()) {
case FE_TOWARDZERO: Rounding = 0; break;
case FE_UPWARD: Rounding = 2; break;
case FE_DOWNWARD: Rounding = 3;
}
#endif /*}}*/
#else /*}{*/
#define Rounding FPI_Round_near
#endif /*}}*/
if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0;
dd = (U*)dd0;
L = dd->L;
sign = L[_0] & L[2+_0] & 0x80000000L;
if (nik < 0 || nik > 35)
nik = 0;
if ((L[_0] & 0x7ff00000L) == 0x7ff00000L) {
/* Infinity or NaN */
if (L[_0] & 0xfffff || L[_1]) {
nanret:
b = buf;
if (sign && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| L[_1] != NanDflt_d_D2A[0]
|| (L[_0] ^ NanDflt_d_D2A[1]) & 0xfffff
|| L[2+_1] != NanDflt_d_D2A[0]
|| (L[2+_0] ^ NanDflt_d_D2A[1]) & 0xfffff)) {
bits0[0] = L[2+_1];
bits0[1] = (L[2+_0] & 0xfffff) | (L[_1] << 20);
bits0[2] = (L[_1] >> 12) | (L[_0] << 20);
bits0[3] = (L[_0] >> 12) & 0xff;
b = add_nanbits(b, bufsize - (b-buf), bits0, 4);
}
return b;
}
if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
if (L[2+_0] & 0xfffff || L[2+_1])
goto nanret;
if ((L[_0] ^ L[2+_0]) & 0x80000000L)
goto nanret; /* Infinity - Infinity */
}
infret:
b = buf;
if (L[_0] & 0x80000000L)
*b++ = '-';
return strcp(b, InfName[nik%6]);
}
if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
L += 2;
if (L[_0] & 0xfffff || L[_1])
goto nanret;
goto infret;
}
if (dval(&dd[0]) + dval(&dd[1]) == 0.) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
if ((L[_0] & 0x7ff00000L) < (L[2+_0] & 0x7ff00000L)) {
dval(&ddx[1]) = dval(&dd[0]);
dval(&ddx[0]) = dval(&dd[1]);
dd = ddx;
L = dd->L;
}
z = d2b(dval(&dd[0]), &ex, &bx MTb);
if (dval(&dd[1]) == 0.)
goto no_y;
x = z;
y = d2b(dval(&dd[1]), &ey, &by MTb);
if ( (i = ex - ey) !=0) {
if (i > 0) {
x = lshift(x, i MTb);
ex = ey;
}
else
y = lshift(y, -i MTb);
}
if ((L[_0] ^ L[2+_0]) & 0x80000000L) {
z = diff(x, y MTb);
if (L[_0] & 0x80000000L)
z->sign = 1 - z->sign;
}
else {
z = sum(x, y MTb);
if (L[_0] & 0x80000000L)
z->sign = 1;
}
Bfree(x MTb);
Bfree(y MTb);
no_y:
bits = zx = z->x;
for(i = 0; !*zx; zx++)
i += 32;
i += lo0bits(zx);
if (i) {
rshift(z, i);
ex += i;
}
fpi.nbits = z->wds * 32 - hi0bits(z->x[j = z->wds-1]);
if (fpi.nbits < 106) {
fpi.nbits = 106;
if (j < 3) {
for(i = 0; i <= j; i++)
bits0[i] = bits[i];
while(i < 4)
bits0[i++] = 0;
bits = bits0;
}
}
mode = 2;
if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
Bfree(z MTb);
return 0;
}
mode = 0;
}
fpi.emin = 1-1023-53+1;
fpi.emax = 2046-1023-106+1;
fpi.rounding = Rounding;
fpi.sudden_underflow = 0;
fpi.int_max = Int_max;
i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = g__fmt(buf, s, se, decpt, z->sign, bufsize);
Bfree(z MTb);
return b;
}

96
third_party/gdtoa/g_dfmt.c vendored Normal file
View file

@ -0,0 +1,96 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
char*
#ifdef KR_headers
g_dfmt(buf, d, ndig, bufsize) char *buf; double *d; int ndig; size_t bufsize;
#else
g_dfmt(char *buf, double *d, int ndig, size_t bufsize)
#endif
{
static const FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)d;
sign = L[_0] & 0x80000000L;
if ((L[_0] & 0x7ff00000) == 0x7ff00000) {
/* Infinity or NaN */
if (bufsize < 10)
return 0;
if (L[_0] & 0xfffff || L[_1]) {
return strcp(buf, "NaN");
}
b = buf;
if (sign)
*b++ = '-';
return strcp(b, "Infinity");
}
if (L[_1] == 0 && (L[_0] ^ sign) == 0 /*d == 0.*/) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (L[_0] & 0x80000000L)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
bits[0] = L[_1];
bits[1] = L[_0] & 0xfffff;
if ( (ex = (L[_0] >> 20) & 0x7ff) !=0)
bits[1] |= 0x100000;
else
ex = 1;
ex -= 0x3ff + 52;
mode = 2;
if (ndig <= 0)
mode = 0;
i = STRTOG_Normal;
if (sign)
i = STRTOG_Normal | STRTOG_Neg;
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

111
third_party/gdtoa/g_dfmt_p.c vendored Normal file
View file

@ -0,0 +1,111 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_d_D2A[2];
char*
#ifdef KR_headers
g_dfmt_p(buf, d, ndig, bufsize, nik) char *buf; double *d; int ndig; size_t bufsize; int nik;
#else
g_dfmt_p(char *buf, double *d, int ndig, size_t bufsize, int nik)
#endif
{
static const FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)d;
sign = L[_0] & 0x80000000L;
if ((L[_0] & 0x7ff00000) == 0x7ff00000) {
/* Infinity or NaN */
if (nik < 0 || nik > 35)
nik = 0;
if (bufsize < 10)
return 0;
if (L[_0] & 0xfffff || L[_1]) {
b = buf;
if (L[_0] & 0x80000000L && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| bits[0] != NanDflt_d_D2A[0]
|| (bits[1] ^ NanDflt_d_D2A[1]) & 0xfffff)) {
bits[0] = L[_1];
bits[1] = L[_0] & 0xfffff;
b = add_nanbits(b, bufsize - (b-buf), bits, 2);
}
return b;
}
b = buf;
if (sign)
*b++ = '-';
return strcp(b, InfName[nik%6]);
}
if (L[_1] == 0 && (L[_0] ^ sign) == 0 /*d == 0.*/) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (L[_0] & 0x80000000L)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
bits[0] = L[_1];
bits[1] = L[_0] & 0xfffff;
if ( (ex = (L[_0] >> 20) & 0x7ff) !=0)
bits[1] |= 0x100000;
else
ex = 1;
ex -= 0x3ff + 52;
mode = 2;
if (ndig <= 0)
mode = 0;
i = STRTOG_Normal;
if (sign)
i = STRTOG_Normal | STRTOG_Neg;
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

94
third_party/gdtoa/g_ffmt.c vendored Normal file
View file

@ -0,0 +1,94 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
char*
#ifdef KR_headers
g_ffmt(buf, f, ndig, bufsize) char *buf; float *f; int ndig; size_t bufsize;
#else
g_ffmt(char *buf, float *f, int ndig, size_t bufsize)
#endif
{
static const FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 6 };
char *b, *s, *se;
ULong bits[1], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)f;
sign = L[0] & 0x80000000L;
if ((L[0] & 0x7f800000) == 0x7f800000) {
/* Infinity or NaN */
if (L[0] & 0x7fffff) {
return strcp(buf, "NaN");
}
b = buf;
if (sign)
*b++ = '-';
return strcp(b, "Infinity");
}
if (*f == 0.) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (L[0] & 0x80000000L)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
bits[0] = L[0] & 0x7fffff;
if ( (ex = (L[0] >> 23) & 0xff) !=0)
bits[0] |= 0x800000;
else
ex = 1;
ex -= 0x7f + 23;
mode = 2;
if (ndig <= 0) {
if (bufsize < 16)
return 0;
mode = 0;
}
i = STRTOG_Normal;
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

105
third_party/gdtoa/g_ffmt_p.c vendored Normal file
View file

@ -0,0 +1,105 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_f_D2A[1];
char*
#ifdef KR_headers
g_ffmt_p(buf, f, ndig, bufsize, nik) char *buf; float *f; int ndig; size_t bufsize; int nik;
#else
g_ffmt_p(char *buf, float *f, int ndig, size_t bufsize, int nik)
#endif
{
static const FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 6 };
char *b, *s, *se;
ULong bits[1], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)f;
sign = L[0] & 0x80000000L;
if ((L[0] & 0x7f800000) == 0x7f800000) {
/* Infinity or NaN */
if (nik < 0 || nik > 35)
nik = 0;
if ((bits[0] = L[0] & 0x7fffff)) {
b = buf;
if (sign && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| (bits[0] ^ NanDflt_f_D2A[0]) & 0x7fffff))
b = add_nanbits(b, bufsize - (b-buf), bits, 1);
return b;
}
b = buf;
if (sign)
*b++ = '-';
return strcp(b, InfName[nik%6]);
}
if (*f == 0.) {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (L[0] & 0x80000000L)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
bits[0] = L[0] & 0x7fffff;
if ( (ex = (L[0] >> 23) & 0xff) !=0)
bits[0] |= 0x800000;
else
ex = 1;
ex -= 0x7f + 23;
mode = 2;
if (ndig <= 0) {
if (bufsize < 16)
return 0;
mode = 0;
}
i = STRTOG_Normal;
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

114
third_party/gdtoa/g_xLfmt.c vendored Normal file
View file

@ -0,0 +1,114 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#endif
#ifdef IEEE_8087
#define _0 2
#define _1 1
#define _2 0
#endif
char*
#ifdef KR_headers
g_xLfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize;
#else
g_xLfmt(char *buf, void *V, int ndig, size_t bufsize)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)V;
sign = L[_0] & 0x80000000L;
bits[1] = L[_1];
bits[0] = L[_2];
if ( (ex = (L[_0] >> 16) & 0x7fff) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (bits[0] | bits[1])
b = strcp(buf, "NaN");
else {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, "Infinity");
}
return b;
}
i = STRTOG_Normal;
}
else if (bits[0] | bits[1]) {
i = STRTOG_Denormal;
}
else {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 63;
mode = 2;
if (ndig <= 0) {
if (bufsize < 32)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

126
third_party/gdtoa/g_xLfmt_p.c vendored Normal file
View file

@ -0,0 +1,126 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_xL_D2A[3];
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#endif
#ifdef IEEE_8087
#define _0 2
#define _1 1
#define _2 0
#endif
char*
#ifdef KR_headers
g_xLfmt_p(buf, V, ndig, bufsize, nik) char *buf; char *V; int ndig; size_t bufsize; int nik;
#else
g_xLfmt_p(char *buf, void *V, int ndig, size_t bufsize, int nik)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], *L, sign;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (ULong*)V;
sign = L[_0] & 0x80000000L;
bits[1] = L[_1];
bits[0] = L[_2];
if ( (ex = (L[_0] >> 16) & 0x7fff) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (nik < 0 || nik > 35)
nik = 0;
if (!bits[0] && bits[1] == 0x80000000) {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, InfName[nik%6]);
}
else {
b = buf;
if (sign && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| bits[0] != NanDflt_xL_D2A[0]
|| bits[1] != NanDflt_xL_D2A[1]))
b = add_nanbits(b, bufsize - (b-buf), bits, 2);
}
return b;
}
i = STRTOG_Normal;
}
else if (bits[0] | bits[1]) {
i = STRTOG_Denormal;
}
else {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 63;
mode = 2;
if (ndig <= 0) {
if (bufsize < 32)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

120
third_party/gdtoa/g_xfmt.c vendored Normal file
View file

@ -0,0 +1,120 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#define _4 4
#endif
#ifdef IEEE_8087
#define _0 4
#define _1 3
#define _2 2
#define _3 1
#define _4 0
#endif
char*
#ifdef KR_headers
g_xfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize;
#else
g_xfmt(char *buf, void *V, int ndig, size_t bufsize)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], sign;
UShort *L;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (UShort *)V;
sign = L[_0] & 0x8000;
bits[1] = (L[_1] << 16) | L[_2];
bits[0] = (L[_3] << 16) | L[_4];
if ( (ex = L[_0] & 0x7fff) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (!bits[0] && bits[1]== 0x80000000) {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, "Infinity");
}
else
b = strcp(buf, "NaN");
return b;
}
i = STRTOG_Normal;
}
else if (bits[0] | bits[1]) {
i = STRTOG_Denormal;
ex = 1;
}
else {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 63;
mode = 2;
if (ndig <= 0) {
if (bufsize < 32)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

136
third_party/gdtoa/g_xfmt_p.c vendored Normal file
View file

@ -0,0 +1,136 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern UShort NanDflt_ldus_D2A[5];
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#define _4 4
#endif
#ifdef IEEE_8087
#define _0 4
#define _1 3
#define _2 2
#define _3 1
#define _4 0
#endif
char*
#ifdef KR_headers
g_xfmt_p(buf, V, ndig, bufsize, nik) char *buf; char *V; int ndig; size_t bufsize; int nik;
#else
g_xfmt_p(char *buf, void *V, int ndig, size_t bufsize, int nik)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max };
char *b, *s, *se;
ULong bits[2], sign;
UShort *L;
int decpt, ex, i, mode;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
if (ndig < 0)
ndig = 0;
if (bufsize < (size_t)(ndig + 10))
return 0;
L = (UShort *)V;
sign = L[_0] & 0x8000;
bits[1] = (L[_1] << 16) | L[_2];
bits[0] = (L[_3] << 16) | L[_4];
if ( (ex = L[_0] & 0x7fff) !=0) {
if (ex == 0x7fff) {
/* Infinity or NaN */
if (nik < 0 || nik > 35)
nik = 0;
if (!bits[0] && bits[1]== 0x80000000) {
b = buf;
if (sign)
*b++ = '-';
b = strcp(b, InfName[nik%6]);
}
else {
b = buf;
if (sign && nik < 18)
*b++ = '-';
b = strcp(b, NanName[nik%3]);
if (nik > 5 && (nik < 12
|| L[_1] != NanDflt_ldus_D2A[3]
|| L[_2] != NanDflt_ldus_D2A[2]
|| L[_3] != NanDflt_ldus_D2A[1]
|| L[_4] != NanDflt_ldus_D2A[0])) {
bits[1] &= 0x7fffffff;
b = add_nanbits(b, bufsize - (b-buf), bits, 2);
}
}
return b;
}
i = STRTOG_Normal;
}
else if (bits[0] | bits[1]) {
i = STRTOG_Denormal;
ex = 1;
}
else {
b = buf;
#ifndef IGNORE_ZERO_SIGN
if (sign)
*b++ = '-';
#endif
*b++ = '0';
*b = 0;
return b;
}
ex -= 0x3fff + 63;
mode = 2;
if (ndig <= 0) {
if (bufsize < 32)
return 0;
mode = 0;
}
s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
return g__fmt(buf, s, se, decpt, sign, bufsize);
}

759
third_party/gdtoa/gdtoa.c vendored Normal file
View file

@ -0,0 +1,759 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
static Bigint *
#ifdef KR_headers
bitstob(bits, nbits, bbits MTa) ULong *bits; int nbits; int *bbits; MTk
#else
bitstob(ULong *bits, int nbits, int *bbits MTd)
#endif
{
int i, k;
Bigint *b;
ULong *be, *x, *x0;
i = ULbits;
k = 0;
while(i < nbits) {
i <<= 1;
k++;
}
#ifndef Pack_32
if (!k)
k = 1;
#endif
b = Balloc(k MTa);
be = bits + ((nbits - 1) >> kshift);
x = x0 = b->x;
do {
*x++ = *bits & ALL_ON;
#ifdef Pack_16
*x++ = (*bits >> 16) & ALL_ON;
#endif
} while(++bits <= be);
i = x - x0;
while(!x0[--i])
if (!i) {
b->wds = 0;
*bbits = 0;
goto ret;
}
b->wds = i + 1;
*bbits = i*ULbits + 32 - hi0bits(b->x[i]);
ret:
return b;
}
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
*
* Inspired by "How to Print Floating-Point Numbers Accurately" by
* Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
*
* Modifications:
* 1. Rather than iterating, we use a simple numeric overestimate
* to determine k = floor(log10(d)). We scale relevant
* quantities using O(log2(k)) rather than O(k) multiplications.
* 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
* try to generate digits strictly left to right. Instead, we
* compute with fewer bits and propagate the carry if necessary
* when rounding the final digit up. This is often faster.
* 3. Under the assumption that input will be rounded nearest,
* mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
* That is, we allow equality in stopping tests when the
* round-nearest rule will give the same floating-point value
* as would satisfaction of the stopping test with strict
* inequality.
* 4. We remove common factors of powers of 2 from relevant
* quantities.
* 5. When converting floating-point integers less than 1e16,
* we use floating-point arithmetic rather than resorting
* to multiple-precision integers.
* 6. When asked to produce fewer than 15 digits, we first try
* to get by with floating-point arithmetic; we resort to
* multiple-precision integer arithmetic only if we cannot
* guarantee that the floating-point calculation has given
* the correctly rounded result. For k requested digits and
* "uniformly" distributed input, the probability is
* something like 10^(k-15) that we must resort to the Long
* calculation.
*/
char *
gdtoa
#ifdef KR_headers
(fpi, be, bits, kindp, mode, ndigits, decpt, rve)
CONST FPI *fpi; int be; ULong *bits;
int *kindp, mode, ndigits, *decpt; char **rve;
#else
(CONST FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve)
#endif
{
/* Arguments ndigits and decpt are similar to the second and third
arguments of ecvt and fcvt; trailing zeros are suppressed from
the returned string. If not null, *rve is set to point
to the end of the return value. If d is +-Infinity or NaN,
then *decpt is set to 9999.
be = exponent: value = (integer represented by bits) * (2 to the power of be).
mode:
0 ==> shortest string that yields d when read in
and rounded to nearest.
1 ==> like 0, but with Steele & White stopping rule;
e.g. with IEEE P754 arithmetic , mode 0 gives
1e23 whereas mode 1 gives 9.999999999999999e22.
2 ==> max(1,ndigits) significant digits. This gives a
return value similar to that of ecvt, except
that trailing zeros are suppressed.
3 ==> through ndigits past the decimal point. This
gives a return value similar to that from fcvt,
except that trailing zeros are suppressed, and
ndigits can be negative.
4-9 should give the same return values as 2-3, i.e.,
4 <= mode <= 9 ==> same return as mode
2 + (mode & 1). These modes are mainly for
debugging; often they run slower but sometimes
faster than modes 2-3.
4,5,8,9 ==> left-to-right digit generation.
6-9 ==> don't try fast floating-point estimate
(if applicable).
Values of mode other than 0-9 are treated as mode 0.
Sufficient space is allocated to the return value
to hold the suppressed trailing zeros.
*/
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
int rdir, s2, s5, spec_case, try_quick;
Long L;
Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
double d2, ds;
char *s, *s0;
U d, eps;
#ifndef MULTIPLE_THREADS
if (dtoa_result) {
freedtoa(dtoa_result);
dtoa_result = 0;
}
#endif
inex = 0;
kind = *kindp &= ~STRTOG_Inexact;
switch(kind & STRTOG_Retmask) {
case STRTOG_Zero:
goto ret_zero;
case STRTOG_Normal:
case STRTOG_Denormal:
break;
case STRTOG_Infinite:
*decpt = -32768;
return nrv_alloc("Infinity", rve, 8 MTb);
case STRTOG_NaN:
*decpt = -32768;
return nrv_alloc("NaN", rve, 3 MTb);
default:
return 0;
}
b = bitstob(bits, nbits = fpi->nbits, &bbits MTb);
be0 = be;
if ( (i = trailz(b)) !=0) {
rshift(b, i);
be += i;
bbits -= i;
}
if (!b->wds) {
Bfree(b MTb);
ret_zero:
*decpt = 1;
return nrv_alloc("0", rve, 1 MTb);
}
dval(&d) = b2d(b, &i);
i = be + bbits - 1;
word0(&d) &= Frac_mask1;
word0(&d) |= Exp_11;
#ifdef IBM
if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
dval(&d) /= 1 << j;
#endif
/* log(x) ~=~ log(1.5) + (x-1.5)/1.5
* log10(x) = log(x) / log(10)
* ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
* log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
*
* This suggests computing an approximation k to log10(&d) by
*
* k = (i - Bias)*0.301029995663981
* + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
*
* We want k to be too large rather than too small.
* The error in the first-order Taylor series approximation
* is in our favor, so we just round up the constant enough
* to compensate for any error in the multiplication of
* (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
* and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
* adding 1e-13 to the constant term more than suffices.
* Hence we adjust the constant term to 0.1760912590558.
* (We could get a more accurate k by invoking log10,
* but this is probably not worthwhile.)
*/
ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
/* correct assumption about exponent range */
if ((j = i) < 0)
j = -j;
if ((j -= 1077) > 0)
ds += j * 7e-17;
k = (int)ds;
if (ds < 0. && ds != k)
k--; /* want k = floor(ds) */
k_check = 1;
#ifdef IBM
j = be + bbits - 1;
if ( (j1 = j & 3) !=0)
dval(&d) *= 1 << j1;
word0(&d) += j << Exp_shift - 2 & Exp_mask;
#else
word0(&d) += (be + bbits - 1) << Exp_shift;
#endif
if (k >= 0 && k <= Ten_pmax) {
if (dval(&d) < tens[k])
k--;
k_check = 0;
}
j = bbits - i - 1;
if (j >= 0) {
b2 = 0;
s2 = j;
}
else {
b2 = -j;
s2 = 0;
}
if (k >= 0) {
b5 = 0;
s5 = k;
s2 += k;
}
else {
b2 -= k;
b5 = -k;
s5 = 0;
}
if (mode < 0 || mode > 9)
mode = 0;
try_quick = 1;
if (mode > 5) {
mode -= 4;
try_quick = 0;
}
else if (i >= -4 - Emin || i < Emin)
try_quick = 0;
leftright = 1;
ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
/* silence erroneous "gcc -Wall" warning. */
switch(mode) {
case 0:
case 1:
i = (int)(nbits * .30103) + 3;
ndigits = 0;
break;
case 2:
leftright = 0;
/* no break */
case 4:
if (ndigits <= 0)
ndigits = 1;
ilim = ilim1 = i = ndigits;
break;
case 3:
leftright = 0;
/* no break */
case 5:
i = ndigits + k + 1;
ilim = i;
ilim1 = i - 1;
if (i <= 0)
i = 1;
}
s = s0 = rv_alloc(i MTb);
if (mode <= 1)
rdir = 0;
else if ( (rdir = fpi->rounding - 1) !=0) {
if (rdir < 0)
rdir = 2;
if (kind & STRTOG_Neg)
rdir = 3 - rdir;
}
/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
#ifndef IMPRECISE_INEXACT
&& k == 0
#endif
) {
/* Try to get by with floating-point arithmetic. */
i = 0;
d2 = dval(&d);
k0 = k;
ilim0 = ilim;
ieps = 2; /* conservative */
if (k > 0) {
ds = tens[k&0xf];
j = k >> 4;
if (j & Bletch) {
/* prevent overflows */
j &= Bletch - 1;
dval(&d) /= bigtens[n_bigtens-1];
ieps++;
}
for(; j; j >>= 1, i++)
if (j & 1) {
ieps++;
ds *= bigtens[i];
}
}
else {
ds = 1.;
if ( (j1 = -k) !=0) {
dval(&d) *= tens[j1 & 0xf];
for(j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
ieps++;
dval(&d) *= bigtens[i];
}
}
}
if (k_check && dval(&d) < 1. && ilim > 0) {
if (ilim1 <= 0)
goto fast_failed;
ilim = ilim1;
k--;
dval(&d) *= 10.;
ieps++;
}
dval(&eps) = ieps*dval(&d) + 7.;
word0(&eps) -= (P-1)*Exp_msk1;
if (ilim == 0) {
S = mhi = 0;
dval(&d) -= 5.;
if (dval(&d) > dval(&eps))
goto one_digit;
if (dval(&d) < -dval(&eps))
goto no_digits;
goto fast_failed;
}
#ifndef No_leftright
if (leftright) {
/* Use Steele & White method of only
* generating digits needed.
*/
dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
for(i = 0;;) {
L = (Long)(dval(&d)/ds);
dval(&d) -= L*ds;
*s++ = '0' + (int)L;
if (dval(&d) < dval(&eps)) {
if (dval(&d))
inex = STRTOG_Inexlo;
goto ret1;
}
if (ds - dval(&d) < dval(&eps))
goto bump_up;
if (++i >= ilim)
break;
dval(&eps) *= 10.;
dval(&d) *= 10.;
}
}
else {
#endif
/* Generate ilim digits, then fix them up. */
dval(&eps) *= tens[ilim-1];
for(i = 1;; i++, dval(&d) *= 10.) {
if ( (L = (Long)(dval(&d)/ds)) !=0)
dval(&d) -= L*ds;
*s++ = '0' + (int)L;
if (i == ilim) {
ds *= 0.5;
if (dval(&d) > ds + dval(&eps))
goto bump_up;
else if (dval(&d) < ds - dval(&eps)) {
if (dval(&d))
inex = STRTOG_Inexlo;
goto ret1;
}
break;
}
}
#ifndef No_leftright
}
#endif
fast_failed:
s = s0;
dval(&d) = d2;
k = k0;
ilim = ilim0;
}
/* Do we have a "small" integer? */
if (be >= 0 && k <= fpi->int_max) {
/* Yes. */
ds = tens[k];
if (ndigits < 0 && ilim <= 0) {
S = mhi = 0;
if (ilim < 0 || dval(&d) <= 5*ds)
goto no_digits;
goto one_digit;
}
for(i = 1;; i++, dval(&d) *= 10.) {
L = dval(&d) / ds;
dval(&d) -= L*ds;
#ifdef Check_FLT_ROUNDS
/* If FLT_ROUNDS == 2, L will usually be high by 1 */
if (dval(&d) < 0) {
L--;
dval(&d) += ds;
}
#endif
*s++ = '0' + (int)L;
if (dval(&d) == 0.)
break;
if (i == ilim) {
if (rdir) {
if (rdir == 1)
goto bump_up;
inex = STRTOG_Inexlo;
goto ret1;
}
dval(&d) += dval(&d);
#ifdef ROUND_BIASED
if (dval(&d) >= ds)
#else
if (dval(&d) > ds || (dval(&d) == ds && L & 1))
#endif
{
bump_up:
inex = STRTOG_Inexhi;
while(*--s == '9')
if (s == s0) {
k++;
*s = '0';
break;
}
++*s++;
}
else
inex = STRTOG_Inexlo;
break;
}
}
goto ret1;
}
m2 = b2;
m5 = b5;
mhi = mlo = 0;
if (leftright) {
i = nbits - bbits;
if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
/* denormal */
i = be - fpi->emin + 1;
if (mode >= 2 && ilim > 0 && ilim < i)
goto small_ilim;
}
else if (mode >= 2) {
small_ilim:
j = ilim - 1;
if (m5 >= j)
m5 -= j;
else {
s5 += j -= m5;
b5 += j;
m5 = 0;
}
if ((i = ilim) < 0) {
m2 -= i;
i = 0;
}
}
b2 += i;
s2 += i;
mhi = i2b(1 MTb);
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
b2 -= i;
m2 -= i;
s2 -= i;
}
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mhi = pow5mult(mhi, m5 MTb);
b1 = mult(mhi, b MTb);
Bfree(b MTb);
b = b1;
}
if ( (j = b5 - m5) !=0)
b = pow5mult(b, j MTb);
}
else
b = pow5mult(b, b5 MTb);
}
S = i2b(1 MTb);
if (s5 > 0)
S = pow5mult(S, s5 MTb);
/* Check for special case that d is a normalized power of 2. */
spec_case = 0;
if (mode < 2) {
if (bbits == 1 && be0 > fpi->emin + 1) {
/* The special case */
b2++;
s2++;
spec_case = 1;
}
}
/* Arrange for convenient computation of quotients:
* shift left if necessary so divisor has 4 leading 0 bits.
*
* Perhaps we should just compute leading 28 bits of S once
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
m2 += i;
if ((b2 += i) > 0)
b = lshift(b, b2 MTb);
if ((s2 += i) > 0)
S = lshift(S, s2 MTb);
if (k_check) {
if (cmp(b,S) < 0) {
k--;
b = multadd(b, 10, 0 MTb); /* we botched the k estimate */
if (leftright)
mhi = multadd(mhi, 10, 0 MTb);
ilim = ilim1;
}
}
if (ilim <= 0 && mode > 2) {
if (ilim < 0 || cmp(b,S = multadd(S,5,0 MTb)) <= 0) {
/* no digits, fcvt style */
no_digits:
k = -1 - ndigits;
inex = STRTOG_Inexlo;
goto ret;
}
one_digit:
inex = STRTOG_Inexhi;
*s++ = '1';
k++;
goto ret;
}
if (leftright) {
if (m2 > 0)
mhi = lshift(mhi, m2 MTb);
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
*/
mlo = mhi;
if (spec_case) {
mhi = Balloc(mhi->k MTb);
Bcopy(mhi, mlo);
mhi = lshift(mhi, 1 MTb);
}
for(i = 1;;i++) {
dig = quorem(b,S) + '0';
/* Do we yet have the shortest decimal string
* that will round to d?
*/
j = cmp(b, mlo);
delta = diff(S, mhi MTb);
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta MTb);
#ifndef ROUND_BIASED
if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
if (dig == '9')
goto round_9_up;
if (j <= 0) {
if (b->wds > 1 || b->x[0])
inex = STRTOG_Inexlo;
}
else {
dig++;
inex = STRTOG_Inexhi;
}
*s++ = dig;
goto ret;
}
#endif
if (j < 0 || (j == 0 && !mode
#ifndef ROUND_BIASED
&& !(bits[0] & 1)
#endif
)) {
if (rdir && (b->wds > 1 || b->x[0])) {
if (rdir == 2) {
inex = STRTOG_Inexlo;
goto accept;
}
while (cmp(S,mhi) > 0) {
*s++ = dig;
mhi1 = multadd(mhi, 10, 0 MTb);
if (mlo == mhi)
mlo = mhi1;
mhi = mhi1;
b = multadd(b, 10, 0 MTb);
dig = quorem(b,S) + '0';
}
if (dig++ == '9')
goto round_9_up;
inex = STRTOG_Inexhi;
goto accept;
}
if (j1 > 0) {
b = lshift(b, 1 MTb);
j1 = cmp(b, S);
#ifdef ROUND_BIASED
if (j1 >= 0 /*)*/
#else
if ((j1 > 0 || (j1 == 0 && dig & 1))
#endif
&& dig++ == '9')
goto round_9_up;
inex = STRTOG_Inexhi;
}
if (b->wds > 1 || b->x[0])
inex = STRTOG_Inexlo;
accept:
*s++ = dig;
goto ret;
}
if (j1 > 0 && rdir != 2) {
if (dig == '9') { /* possible if i == 1 */
round_9_up:
*s++ = '9';
inex = STRTOG_Inexhi;
goto roundoff;
}
inex = STRTOG_Inexhi;
*s++ = dig + 1;
goto ret;
}
*s++ = dig;
if (i == ilim)
break;
b = multadd(b, 10, 0 MTb);
if (mlo == mhi)
mlo = mhi = multadd(mhi, 10, 0 MTb);
else {
mlo = multadd(mlo, 10, 0 MTb);
mhi = multadd(mhi, 10, 0 MTb);
}
}
}
else
for(i = 1;; i++) {
*s++ = dig = quorem(b,S) + '0';
if (i >= ilim)
break;
b = multadd(b, 10, 0 MTb);
}
/* Round off last digit */
if (rdir) {
if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
goto chopzeros;
goto roundoff;
}
b = lshift(b, 1 MTb);
j = cmp(b, S);
#ifdef ROUND_BIASED
if (j >= 0)
#else
if (j > 0 || (j == 0 && dig & 1))
#endif
{
roundoff:
inex = STRTOG_Inexhi;
while(*--s == '9')
if (s == s0) {
k++;
*s++ = '1';
goto ret;
}
++*s++;
}
else {
chopzeros:
if (b->wds > 1 || b->x[0])
inex = STRTOG_Inexlo;
}
ret:
Bfree(S MTb);
if (mhi) {
if (mlo && mlo != mhi)
Bfree(mlo MTb);
Bfree(mhi MTb);
}
ret1:
while(s > s0 && s[-1] == '0')
--s;
Bfree(b MTb);
*s = 0;
*decpt = k + 1;
if (rve)
*rve = s;
*kindp |= inex;
return s0;
}

98
third_party/gdtoa/gdtoa.h vendored Normal file
View file

@ -0,0 +1,98 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_GDTOA_GDTOA_H_
#define COSMOPOLITAN_THIRD_PARTY_GDTOA_GDTOA_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum {
/* return values from strtodg */
STRTOG_Zero = 0,
STRTOG_Normal = 1,
STRTOG_Denormal = 2,
STRTOG_Infinite = 3,
STRTOG_NaN = 4,
STRTOG_NaNbits = 5,
STRTOG_NoNumber = 6,
STRTOG_Retmask = 7,
/* The following may be or-ed into one of the above values. */
STRTOG_Neg = 0x08, /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
STRTOG_Inexlo = 0x10, /* returned result rounded toward zero */
STRTOG_Inexhi = 0x20, /* returned result rounded away from zero */
STRTOG_Inexact = 0x30,
STRTOG_Underflow = 0x40,
STRTOG_Overflow = 0x80
};
typedef struct FPI {
int nbits;
int emin;
int emax;
int rounding;
int sudden_underflow;
int int_max;
} FPI;
enum {
/* FPI.rounding values: same as FLT_ROUNDS */
FPI_Round_zero = 0,
FPI_Round_near = 1,
FPI_Round_up = 2,
FPI_Round_down = 3
};
char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve);
char *gdtoa(const FPI *fpi, int be, unsigned *bits, int *kindp, int mode,
int ndigits, int *decpt, char **rve);
void freedtoa(char *);
float strtof(const char *, char **);
double strtod(const char *, char **);
int strtodg(const char *, char **, const FPI *, int *, unsigned *);
long double strtold(const char *, char **);
char *g_ddfmt(char *, double *, int, size_t);
char *g_ddfmt_p(char *, double *, int, size_t, int);
char *g_dfmt(char *, double *, int, size_t);
char *g_dfmt_p(char *, double *, int, size_t, int);
char *g_ffmt(char *, float *, int, size_t);
char *g_ffmt_p(char *, float *, int, size_t, int);
char *g_Qfmt(char *, void *, int, size_t);
char *g_Qfmt_p(char *, void *, int, size_t, int);
char *g_xfmt(char *, void *, int, size_t);
char *g_xfmt_p(char *, void *, int, size_t, int);
char *g_xLfmt(char *, void *, int, size_t);
char *g_xLfmt_p(char *, void *, int, size_t, int);
int strtoId(const char *, char **, double *, double *);
int strtoIdd(const char *, char **, double *, double *);
int strtoIf(const char *, char **, float *, float *);
int strtoIQ(const char *, char **, void *, void *);
int strtoIx(const char *, char **, void *, void *);
int strtoIxL(const char *, char **, void *, void *);
int strtord(const char *, char **, int, double *);
int strtordd(const char *, char **, int, double *);
int strtorf(const char *, char **, int, float *);
int strtorQ(const char *, char **, int, void *);
int strtorx(const char *, char **, int, void *);
int strtorxL(const char *, char **, int, void *);
#if 1
int strtodI(const char *, char **, double *);
int strtopd(const char *, char **, double *);
int strtopdd(const char *, char **, double *);
int strtopf(const char *, char **, float *);
int strtopQ(const char *, char **, void *);
int strtopx(const char *, char **, void *);
int strtopxL(const char *, char **, void *);
#else
#define strtopd(s, se, x) strtord(s, se, 1, x)
#define strtopdd(s, se, x) strtordd(s, se, 1, x)
#define strtopf(s, se, x) strtorf(s, se, 1, x)
#define strtopQ(s, se, x) strtorQ(s, se, 1, x)
#define strtopx(s, se, x) strtorx(s, se, 1, x)
#define strtopxL(s, se, x) strtorxL(s, se, 1, x)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_GDTOA_GDTOA_H_ */

62
third_party/gdtoa/gdtoa.mk vendored Normal file
View file

@ -0,0 +1,62 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_GDTOA
THIRD_PARTY_GDTOA_ARTIFACTS += THIRD_PARTY_GDTOA_A
THIRD_PARTY_GDTOA = $(THIRD_PARTY_GDTOA_A_DEPS) $(THIRD_PARTY_GDTOA_A)
THIRD_PARTY_GDTOA_A = o/$(MODE)/third_party/gdtoa/gdtoa.a
THIRD_PARTY_GDTOA_A_FILES := $(wildcard third_party/gdtoa/*)
THIRD_PARTY_GDTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_GDTOA_A_FILES))
THIRD_PARTY_GDTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_GDTOA_A_FILES))
THIRD_PARTY_GDTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_GDTOA_A_FILES))
THIRD_PARTY_GDTOA_A_SRCS = \
$(THIRD_PARTY_GDTOA_A_SRCS_S) \
$(THIRD_PARTY_GDTOA_A_SRCS_C)
THIRD_PARTY_GDTOA_A_OBJS = \
$(THIRD_PARTY_GDTOA_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_GDTOA_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(THIRD_PARTY_GDTOA_A_SRCS_C:%.c=o/$(MODE)/%.o)
THIRD_PARTY_GDTOA_A_CHECKS = \
$(THIRD_PARTY_GDTOA_A).pkg \
$(THIRD_PARTY_GDTOA_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_GDTOA_A_DIRECTDEPS = \
LIBC_TINYMATH \
LIBC_STR \
LIBC_STUBS \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_SYSV
THIRD_PARTY_GDTOA_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_GDTOA_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_GDTOA_A): \
third_party/gdtoa/ \
$(THIRD_PARTY_GDTOA_A).pkg \
$(THIRD_PARTY_GDTOA_A_OBJS)
$(THIRD_PARTY_GDTOA_A).pkg: \
$(THIRD_PARTY_GDTOA_A_OBJS) \
$(foreach x,$(THIRD_PARTY_GDTOA_A_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_GDTOA_A_OBJS): \
OVERRIDE_CFLAGS += \
$(OLD_CODE) \
$(IEEE_MATH) \
-ffunction-sections \
-fdata-sections
THIRD_PARTY_GDTOA_LIBS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)))
THIRD_PARTY_GDTOA_SRCS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_GDTOA_HDRS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_GDTOA_CHECKS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_GDTOA_OBJS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_OBJS))
$(THIRD_PARTY_GDTOA_OBJS): $(BUILD_FILES) third_party/gdtoa/gdtoa.mk
.PHONY: o/$(MODE)/third_party/gdtoa
o/$(MODE)/third_party/gdtoa: $(THIRD_PARTY_GDTOA_CHECKS)

18
third_party/gdtoa/gdtoa_fltrnds.inc vendored Normal file
View file

@ -0,0 +1,18 @@
FPI *fpi, fpi1;
int Rounding;
#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
Rounding = Flt_Rounds;
#else /*}{*/
Rounding = 1;
switch(fegetround()) {
case FE_TOWARDZERO: Rounding = 0; break;
case FE_UPWARD: Rounding = 2; break;
case FE_DOWNWARD: Rounding = 3;
}
#endif /*}}*/
fpi = &fpi0;
if (Rounding != 1) {
fpi1 = fpi0;
fpi = &fpi1;
fpi1.rounding = Rounding;
}

715
third_party/gdtoa/gdtoaimp.h vendored Normal file
View file

@ -0,0 +1,715 @@
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/gdtoa/gdtoa.h"
asm(".ident\t\"\\n\\n\
gdtoa (MIT License)\\n\
The author of this software is David M. Gay.\\n\
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\"");
asm(".include \"libc/disclaimer.inc\"");
#define IEEE_8087 1
#define f_QNAN 0x7fc00000
#define d_QNAN0 0x7ff80000
#define d_QNAN1 0x0
#if __NO_MATH_ERRNO__ + 0
#define NO_ERRNO 1
#endif
#if __FINITE_MATH_ONLY__ + 0
#define NO_INFNAN_CHECK 1
#endif
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998-2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* This is a variation on dtoa.c that converts arbitary binary
floating-point formats to and from decimal notation. It uses
double-precision arithmetic internally, so there are still
various #ifdefs that adapt the calculations to the native
double-precision arithmetic (any of IEEE, VAX D_floating,
or IBM mainframe arithmetic).
Please send bug reports to David M. Gay (dmg at acm dot org,
with " at " changed at "@" and " dot " changed to ".").
*/
/* On a machine with IEEE extended-precision registers, it is
* necessary to specify double-precision (53-bit) rounding precision
* before invoking strtod or dtoa. If the machine uses (the equivalent
* of) Intel 80x87 arithmetic, the call
* _control87(PC_53, MCW_PC);
* does this with many compilers. Whether this or another call is
* appropriate depends on the compiler; for this to work, it may be
* necessary third_party/gdtoa/to #include "float.h" or another system-dependent
*header file.
*/
/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
*
* This strtod returns a nearest machine number to the input decimal
* string (or sets errno to ERANGE). With IEEE arithmetic, ties are
* broken by the IEEE round-even rule. Otherwise ties are broken by
* biased rounding (add half and chop).
*
* Inspired loosely by William D. Clinger's paper "How to Read Floating
* Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
*
* Modifications:
*
* 1. We only require IEEE, IBM, or VAX double-precision
* arithmetic (not IEEE double-extended).
* 2. We get by with floating-point arithmetic in a case that
* Clinger missed -- when we're computing d * 10^n
* for a small integer d and the integer n is not too
* much larger than 22 (the maximum integer k for which
* we can represent 10^k exactly), we may be able to
* compute (d*10^k) * 10^(e-k) with just one roundoff.
* 3. Rather than a bit-at-a-time adjustment of the binary
* result in the hard case, we use floating-point
* arithmetic to determine the adjustment to within
* one bit; only in really hard cases do we need to
* compute a second residual.
* 4. Because of 3., we don't need a large table of powers of 10
* for ten-to-e (just some small tables, e.g. of 10^k
* for 0 <= k <= 22).
*/
/*
* #define IEEE_8087 for IEEE-arithmetic machines where the least
* significant byte has the lowest address.
* #define IEEE_MC68k for IEEE-arithmetic machines where the most
* significant byte has the lowest address.
* #define Long int on machines with 32-bit ints and 64-bit longs.
* #define Sudden_Underflow for IEEE-format machines without gradual
* underflow (i.e., that flush to zero on underflow).
* #define IBM for IBM mainframe-style floating-point arithmetic.
* #define VAX for VAX-style floating-point arithmetic (D_floating).
* #define No_leftright to omit left-right logic in fast floating-point
* computation of dtoa and gdtoa. This will cause modes 4 and 5 to be
* treated the same as modes 2 and 3 for some inputs.
* #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
* #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
* that use extended-precision instructions to compute rounded
* products and quotients) with IBM.
* #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
* that rounds toward +Infinity.
* #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
* rounding when the underlying floating-point arithmetic uses
* unbiased rounding. This prevent using ordinary floating-point
* arithmetic when the result could be computed with one rounding error.
* #define Inaccurate_Divide for IEEE-format with correctly rounded
* products but inaccurate quotients, e.g., for Intel i860.
* #define NO_LONG_LONG on machines that do not have a "long long"
* integer type (of >= 64 bits). On such machines, you can
* #define Just_16 to store 16 bits per 32-bit Long when doing
* high-precision integer arithmetic. Whether this speeds things
* up or slows things down depends on the machine and the number
* being converted. If long long is available and the name is
* something other than "long long", #define Llong to be the name,
* and if "unsigned Llong" does not work as an unsigned version of
* Llong, #define #ULLong to be the corresponding unsigned type.
* #define KR_headers for old-style C function headers.
* #define Bad_float_h if your system lacks a float.h or if it does not
* define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
* FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
* #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
* if memory is available and otherwise does something you deem
* appropriate. If MALLOC is undefined, malloc will be invoked
* directly -- and assumed always to succeed. Similarly, if you
* want something other than the system's free() to be called to
* recycle memory acquired from MALLOC, #define FREE to be the
* name of the alternate routine. (FREE or free is only called in
* pathological cases, e.g., in a gdtoa call after a gdtoa return in
* mode 3 with thousands of digits requested.)
* #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
* memory allocations from a private pool of memory when possible.
* When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
* unless #defined to be a different length. This default length
* suffices to get rid of MALLOC calls except for unusual cases,
* such as decimal-to-binary conversion of a very long string of
* digits. When converting IEEE double precision values, the
* longest string gdtoa can return is about 751 bytes long. For
* conversions by strtod of strings of 800 digits and all gdtoa
* conversions of IEEE doubles in single-threaded executions with
* 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
* 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
* #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
* #defined automatically on IEEE systems. On such systems,
* when INFNAN_CHECK is #defined, strtod checks
* for Infinity and NaN (case insensitively).
* When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
* strtodg also accepts (case insensitively) strings of the form
* NaN(x), where x is a string of hexadecimal digits (optionally
* preceded by 0x or 0X) and spaces; if there is only one string
* of hexadecimal digits, it is taken for the fraction bits of the
* resulting NaN; if there are two or more strings of hexadecimal
* digits, each string is assigned to the next available sequence
* of 32-bit words of fractions bits (starting with the most
* significant), right-aligned in each sequence.
* Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
* is consumed even when ... has the wrong form (in which case the
* "(...)" is consumed but ignored).
* #define MULTIPLE_THREADS if the system offers preemptively scheduled
* multiple threads. In this case, you must provide (or suitably
* #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
* by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
* in pow5mult, ensures lazy evaluation of only one copy of high
* powers of 5; omitting this lock would introduce a small
* probability of wasting memory, but would otherwise be harmless.)
* You must also invoke freedtoa(s) to free the value s returned by
* dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
* When MULTIPLE_THREADS is #defined, source file misc.c provides
* void set_max_gdtoa_threads(unsigned int n);
* and expects
* unsigned int dtoa_get_threadno(void);
* to be available (possibly provided by
* #define dtoa_get_threadno omp_get_thread_num
* if OpenMP is in use or by
* #define dtoa_get_threadno pthread_self
* if Pthreads is in use), to return the current thread number.
* If set_max_dtoa_threads(n) was called and the current thread
* number is k with k < n, then calls on ACQUIRE_DTOA_LOCK(...) and
* FREE_DTOA_LOCK(...) are avoided; instead each thread with thread
* number < n has a separate copy of relevant data structures.
* After set_max_dtoa_threads(n), a call set_max_dtoa_threads(m)
* with m <= n has has no effect, but a call with m > n is honored.
* Such a call invokes REALLOC (assumed to be "realloc" if REALLOC
* is not #defined) to extend the size of the relevant array.
* #define IMPRECISE_INEXACT if you do not care about the setting of
* the STRTOG_Inexact bits in the special case of doing IEEE double
* precision conversions (which could also be done by the strtod in
* dtoa.c).
* #define NO_HEX_FP to disable recognition of C9x's hexadecimal
* floating-point constants.
* #define -DNO_ERRNO to suppress setting errno (in strtod.c and
* strtodg.c).
* #define NO_STRING_H to use private versions of memcpy.
* On some K&R systems, it may also be necessary to
* #define DECLARE_SIZE_T in this case.
* #define USE_LOCALE to use the current locale's decimal_point value.
*/
#ifndef ANSI
#ifdef KR_headers
#define ANSI(x) ()
#define Void /*nothing*/
#else
#define ANSI(x) x
#define Void void
#endif
#endif /* ANSI */
#ifndef Long
#define Long int
#endif
#ifndef ULong
typedef unsigned Long ULong;
#endif
#ifndef UShort
typedef unsigned short UShort;
#endif
#ifndef CONST
#ifdef KR_headers
#define CONST /* blank */
#else
#define CONST const
#endif
#endif /* CONST */
#ifdef DEBUG
#define Bug(x) \
{ \
fprintf(stderr, "%s\n", x); \
exit(1); \
}
#endif
#ifdef KR_headers
#define Char char
#else
#define Char void
#endif
#ifdef MALLOC
extern Char *MALLOC ANSI((size_t));
#else
#define MALLOC malloc
#endif
#ifdef REALLOC
extern Char *REALLOC ANSI((Char *, size_t));
#else
#define REALLOC realloc
#endif
#undef IEEE_Arith
#undef Avoid_Underflow
#ifdef IEEE_MC68k
#define IEEE_Arith
#endif
#ifdef IEEE_8087
#define IEEE_Arith
#endif
#ifdef Bad_float_h
#ifdef IEEE_Arith
#define DBL_DIG 15
#define DBL_MAX_10_EXP 308
#define DBL_MAX_EXP 1024
#define FLT_RADIX 2
#define DBL_MAX 1.7976931348623157e+308
#endif
#ifdef IBM
#define DBL_DIG 16
#define DBL_MAX_10_EXP 75
#define DBL_MAX_EXP 63
#define FLT_RADIX 16
#define DBL_MAX 7.2370055773322621e+75
#endif
#ifdef VAX
#define DBL_DIG 16
#define DBL_MAX_10_EXP 38
#define DBL_MAX_EXP 127
#define FLT_RADIX 2
#define DBL_MAX 1.7014118346046923e+38
#define n_bigtens 2
#endif
#ifndef LONG_MAX
#define LONG_MAX 2147483647
#endif
#else /* ifndef Bad_float_h */
#endif /* Bad_float_h */
#ifdef IEEE_Arith
#define Scale_Bit 0x10
#define n_bigtens 5
#endif
#ifdef IBM
#define n_bigtens 3
#endif
#ifdef VAX
#define n_bigtens 2
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
#endif
typedef union {
double d;
ULong L[2];
} U;
#ifdef IEEE_8087
#define word0(x) (x)->L[1]
#define word1(x) (x)->L[0]
#else
#define word0(x) (x)->L[0]
#define word1(x) (x)->L[1]
#endif
#define dval(x) (x)->d
/* The following definition of Storeinc is appropriate for MIPS processors.
* An alternative that might be better on some machines is
* #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
*/
#if defined(IEEE_8087) + defined(VAX)
#define Storeinc(a, b, c) \
(((unsigned short *)a)[1] = (unsigned short)b, \
((unsigned short *)a)[0] = (unsigned short)c, a++)
#else
#define Storeinc(a, b, c) \
(((unsigned short *)a)[0] = (unsigned short)b, \
((unsigned short *)a)[1] = (unsigned short)c, a++)
#endif
/* #define P DBL_MANT_DIG */
/* Ten_pmax = floor(P*log(2)/log(5)) */
/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
#ifdef IEEE_Arith
#define Exp_shift 20
#define Exp_shift1 20
#define Exp_msk1 0x100000
#define Exp_msk11 0x100000
#define Exp_mask 0x7ff00000
#define P 53
#define Bias 1023
#define Emin (-1022)
#define Exp_1 0x3ff00000
#define Exp_11 0x3ff00000
#define Ebits 11
#define Frac_mask 0xfffff
#define Frac_mask1 0xfffff
#define Ten_pmax 22
#define Bletch 0x10
#define Bndry_mask 0xfffff
#define Bndry_mask1 0xfffff
#define LSB 1
#define Sign_bit 0x80000000
#define Log2P 1
#define Tiny0 0
#define Tiny1 1
#define Quick_max 14
#define Int_max 14
#ifndef Flt_Rounds
#ifdef FLT_ROUNDS
#define Flt_Rounds FLT_ROUNDS
#else
#define Flt_Rounds 1
#endif
#endif /*Flt_Rounds*/
#else /* ifndef IEEE_Arith */
#undef Sudden_Underflow
#define Sudden_Underflow
#ifdef IBM
#undef Flt_Rounds
#define Flt_Rounds 0
#define Exp_shift 24
#define Exp_shift1 24
#define Exp_msk1 0x1000000
#define Exp_msk11 0x1000000
#define Exp_mask 0x7f000000
#define P 14
#define Bias 65
#define Exp_1 0x41000000
#define Exp_11 0x41000000
#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
#define Frac_mask 0xffffff
#define Frac_mask1 0xffffff
#define Bletch 4
#define Ten_pmax 22
#define Bndry_mask 0xefffff
#define Bndry_mask1 0xffffff
#define LSB 1
#define Sign_bit 0x80000000
#define Log2P 4
#define Tiny0 0x100000
#define Tiny1 0
#define Quick_max 14
#define Int_max 15
#else /* VAX */
#undef Flt_Rounds
#define Flt_Rounds 1
#define Exp_shift 23
#define Exp_shift1 7
#define Exp_msk1 0x80
#define Exp_msk11 0x800000
#define Exp_mask 0x7f80
#define P 56
#define Bias 129
#define Exp_1 0x40800000
#define Exp_11 0x4080
#define Ebits 8
#define Frac_mask 0x7fffff
#define Frac_mask1 0xffff007f
#define Ten_pmax 24
#define Bletch 2
#define Bndry_mask 0xffff007f
#define Bndry_mask1 0xffff007f
#define LSB 0x10000
#define Sign_bit 0x8000
#define Log2P 1
#define Tiny0 0x80
#define Tiny1 0
#define Quick_max 15
#define Int_max 15
#endif /* IBM, VAX */
#endif /* IEEE_Arith */
#ifndef IEEE_Arith
#define ROUND_BIASED
#else
#ifdef ROUND_BIASED_without_Round_Up
#undef ROUND_BIASED
#define ROUND_BIASED
#endif
#endif
#ifdef RND_PRODQUOT
#define rounded_product(a, b) a = rnd_prod(a, b)
#define rounded_quotient(a, b) a = rnd_quot(a, b)
#ifdef KR_headers
extern double rnd_prod(), rnd_quot();
#else
extern double rnd_prod(double, double), rnd_quot(double, double);
#endif
#else
#define rounded_product(a, b) a *= b
#define rounded_quotient(a, b) a /= b
#endif
#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1))
#define Big1 0xffffffff
#undef Pack_16
#ifndef Pack_32
#define Pack_32
#endif
#ifdef NO_LONG_LONG
#undef ULLong
#ifdef Just_16
#undef Pack_32
#define Pack_16
/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
* This makes some inner loops simpler and sometimes saves work
* during multiplications, but it often seems to make things slightly
* slower. Hence the default is now to store 32 bits per Long.
*/
#endif
#else /* long long available */
#ifndef Llong
#define Llong long long
#endif
#ifndef ULLong
#define ULLong unsigned Llong
#endif
#endif /* NO_LONG_LONG */
#ifdef Pack_32
#define ULbits 32
#define kshift 5
#define kmask 31
#define ALL_ON 0xffffffff
#else
#define ULbits 16
#define kshift 4
#define kmask 15
#define ALL_ON 0xffff
#endif
#ifdef MULTIPLE_THREADS /*{{*/
#define MTa , PTI
#define MTb , &TI
#define MTd , ThInfo **PTI
#define MTk ThInfo **PTI;
extern void ACQUIRE_DTOA_LOCK ANSI((unsigned int));
extern void FREE_DTOA_LOCK ANSI((unsigned int));
extern unsigned int dtoa_get_threadno ANSI((void));
#else /*}{*/
#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
#define FREE_DTOA_LOCK(n) /*nothing*/
#define MTa /*nothing*/
#define MTb /*nothing*/
#define MTd /*nothing*/
#define MTk /*nothing*/
#endif /*}}*/
#define Kmax 9
struct Bigint {
struct Bigint *next;
int k, maxwds, sign, wds;
ULong x[1];
};
typedef struct Bigint Bigint;
typedef struct ThInfo {
Bigint *Freelist[Kmax + 1];
Bigint *P5s;
} ThInfo;
#ifdef NO_STRING_H
#ifdef DECLARE_SIZE_T
typedef unsigned int size_t;
#endif
extern void memcpy_D2A ANSI((void *, const void *, size_t));
#define Bcopy(x, y) \
memcpy_D2A(&x->sign, &y->sign, y->wds * sizeof(ULong) + 2 * sizeof(int))
#else /* !NO_STRING_H */
#define Bcopy(x, y) \
memcpy(&x->sign, &y->sign, y->wds * sizeof(ULong) + 2 * sizeof(int))
#endif /* NO_STRING_H */
#define Balloc Balloc_D2A
#define Bfree Bfree_D2A
#define InfName InfName_D2A
#define NanName NanName_D2A
#define ULtoQ ULtoQ_D2A
#define ULtof ULtof_D2A
#define ULtod ULtod_D2A
#define ULtodd ULtodd_D2A
#define ULtox ULtox_D2A
#define ULtoxL ULtoxL_D2A
#define add_nanbits add_nanbits_D2A
#define any_on any_on_D2A
#define b2d b2d_D2A
#define bigtens bigtens_D2A
#define cmp cmp_D2A
#define copybits copybits_D2A
#define d2b d2b_D2A
#define decrement decrement_D2A
#define diff diff_D2A
#define dtoa_result dtoa_result_D2A
#define g__fmt g__fmt_D2A
#define gethex gethex_D2A
#define hexdig hexdig_D2A
#define hexnan hexnan_D2A
#define hi0bits(x) hi0bits_D2A((ULong)(x))
#define i2b i2b_D2A
#define increment increment_D2A
#define lo0bits lo0bits_D2A
#define lshift lshift_D2A
#define match match_D2A
#define mult mult_D2A
#define multadd multadd_D2A
#define nrv_alloc nrv_alloc_D2A
#define pow5mult pow5mult_D2A
#define quorem quorem_D2A
#define ratio ratio_D2A
#define rshift rshift_D2A
#define rv_alloc rv_alloc_D2A
#define s2b s2b_D2A
#define set_ones set_ones_D2A
#define strcp strcp_D2A
#define strtoIg strtoIg_D2A
#define sum sum_D2A
#define tens tens_D2A
#define tinytens tinytens_D2A
#define tinytens tinytens_D2A
#define trailz trailz_D2A
#define ulp ulp_D2A
extern char *add_nanbits ANSI((char *, size_t, ULong *, int));
extern char *dtoa_result;
extern CONST double bigtens[], tens[], tinytens[];
extern const unsigned char hexdig[];
extern const char *const InfName[6], *const NanName[3];
extern Bigint *Balloc ANSI((int MTd));
extern void Bfree ANSI((Bigint * MTd));
extern void ULtof ANSI((ULong *, ULong *, Long, int));
extern void ULtod ANSI((ULong *, ULong *, Long, int));
extern void ULtodd ANSI((ULong *, ULong *, Long, int));
extern void ULtoQ ANSI((ULong *, ULong *, Long, int));
extern void ULtox ANSI((UShort *, ULong *, Long, int));
extern void ULtoxL ANSI((ULong *, ULong *, Long, int));
extern ULong any_on ANSI((Bigint *, int));
extern double b2d ANSI((Bigint *, int *));
extern int cmp ANSI((Bigint *, Bigint *));
extern void copybits ANSI((ULong *, int, Bigint *));
extern Bigint *d2b ANSI((double, int *, int *MTd));
extern void decrement ANSI((Bigint *));
extern Bigint *diff ANSI((Bigint *, Bigint *MTd));
extern char *g__fmt ANSI((char *, char *, char *, int, ULong, size_t));
extern int gethex ANSI((CONST char **, CONST FPI *, Long *, Bigint **,
int MTd));
extern void hexdig_init_D2A(Void);
extern int hexnan ANSI((CONST char **, CONST FPI *, ULong *));
extern int hi0bits_D2A ANSI((ULong));
extern Bigint *i2b ANSI((int MTd));
extern Bigint *increment ANSI((Bigint * MTd));
extern int lo0bits ANSI((ULong *));
extern Bigint *lshift ANSI((Bigint *, int MTd));
extern int match ANSI((CONST char **, char *));
extern Bigint *mult ANSI((Bigint *, Bigint *MTd));
extern Bigint *multadd ANSI((Bigint *, int, int MTd));
extern char *nrv_alloc ANSI((char *, char **, int MTd));
extern Bigint *pow5mult ANSI((Bigint *, int MTd));
extern int quorem ANSI((Bigint *, Bigint *));
extern double ratio ANSI((Bigint *, Bigint *));
extern void rshift ANSI((Bigint *, int));
extern char *rv_alloc ANSI((int MTd));
extern Bigint *s2b ANSI((CONST char *, int, int, ULong, int MTd));
extern Bigint *set_ones ANSI((Bigint *, int MTd));
extern char *strcp ANSI((char *, const char *));
extern int strtoIg ANSI((CONST char *, char **, CONST FPI *, Long *, Bigint **,
int *));
extern Bigint *sum ANSI((Bigint *, Bigint *MTd));
extern int trailz ANSI((Bigint *));
extern double ulp ANSI((U *));
#ifdef __cplusplus
}
#endif
/*
* NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to
* 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
* respectively), but now are determined by compiling and running
* qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
* Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
* and -DNAN_WORD1=... values if necessary. This should still work.
* (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
*/
#ifdef IEEE_Arith
#ifndef NO_INFNAN_CHECK
#undef INFNAN_CHECK
#define INFNAN_CHECK
#endif
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#ifndef NAN_WORD0
#define NAN_WORD0 d_QNAN0
#endif
#ifndef NAN_WORD1
#define NAN_WORD1 d_QNAN1
#endif
#else
#define _0 1
#define _1 0
#ifndef NAN_WORD0
#define NAN_WORD0 d_QNAN1
#endif
#ifndef NAN_WORD1
#define NAN_WORD1 d_QNAN0
#endif
#endif
#else
#undef INFNAN_CHECK
#endif
#undef SI
#ifdef Sudden_Underflow
#define SI 1
#else
#define SI 0
#endif

357
third_party/gdtoa/gethex.c vendored Normal file
View file

@ -0,0 +1,357 @@
#include "libc/errno.h"
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
gethex(sp, fpi, exp, bp, sign MTa)
CONST char **sp; CONST FPI *fpi; Long *exp; Bigint **bp; int sign; MTk
#else
gethex( CONST char **sp, CONST FPI *fpi, Long *exp, Bigint **bp, int sign MTd)
#endif
{
Bigint *b;
CONST unsigned char *decpt, *s0, *s, *s1;
int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
ULong L, lostbits, *x;
Long e, e1;
#ifdef USE_LOCALE
int i;
#ifdef NO_LOCALE_CACHE
const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
#else
const unsigned char *decimalpoint;
static unsigned char *decimalpoint_cache;
if (!(s0 = decimalpoint_cache)) {
s0 = (unsigned char*)localeconv()->decimal_point;
if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
strcpy(decimalpoint_cache, s0);
s0 = decimalpoint_cache;
}
}
decimalpoint = s0;
#endif
#endif
/**** if (!hexdig['0']) hexdig_init_D2A(); ****/
*bp = 0;
havedig = 0;
s0 = *(CONST unsigned char **)sp + 2;
while(s0[havedig] == '0')
havedig++;
s0 += havedig;
s = s0;
decpt = 0;
zret = 0;
e = 0;
if (hexdig[*s])
havedig++;
else {
zret = 1;
#ifdef USE_LOCALE
for(i = 0; decimalpoint[i]; ++i) {
if (s[i] != decimalpoint[i])
goto pcheck;
}
decpt = s += i;
#else
if (*s != '.')
goto pcheck;
decpt = ++s;
#endif
if (!hexdig[*s])
goto pcheck;
while(*s == '0')
s++;
if (hexdig[*s])
zret = 0;
havedig = 1;
s0 = s;
}
while(hexdig[*s])
s++;
#ifdef USE_LOCALE
if (*s == *decimalpoint && !decpt) {
for(i = 1; decimalpoint[i]; ++i) {
if (s[i] != decimalpoint[i])
goto pcheck;
}
decpt = s += i;
#else
if (*s == '.' && !decpt) {
decpt = ++s;
#endif
while(hexdig[*s])
s++;
}/*}*/
if (decpt)
e = -(((Long)(s-decpt)) << 2);
pcheck:
s1 = s;
big = esign = 0;
switch(*s) {
case 'p':
case 'P':
switch(*++s) {
case '-':
esign = 1;
/* no break */
case '+':
s++;
}
if ((n = hexdig[*s]) == 0 || n > 0x19) {
s = s1;
break;
}
e1 = n - 0x10;
while((n = hexdig[*++s]) !=0 && n <= 0x19) {
if (e1 & 0xf8000000)
big = 1;
e1 = 10*e1 + n - 0x10;
}
if (esign)
e1 = -e1;
e += e1;
}
*sp = (char*)s;
if (!havedig)
*sp = (char*)s0 - 1;
if (zret)
return STRTOG_Zero;
if (big) {
if (esign) {
switch(fpi->rounding) {
case FPI_Round_up:
if (sign)
break;
goto ret_tiny;
case FPI_Round_down:
if (!sign)
break;
goto ret_tiny;
}
goto retz;
ret_tiny:
b = Balloc(0 MTa);
b->wds = 1;
b->x[0] = 1;
goto dret;
}
switch(fpi->rounding) {
case FPI_Round_near:
goto ovfl1;
case FPI_Round_up:
if (!sign)
goto ovfl1;
goto ret_big;
case FPI_Round_down:
if (sign)
goto ovfl1;
}
ret_big:
nbits = fpi->nbits;
n0 = n = nbits >> kshift;
if (nbits & kmask)
++n;
for(j = n, k = 0; j >>= 1; ++k);
*bp = b = Balloc(k MTa);
b->wds = n;
for(j = 0; j < n0; ++j)
b->x[j] = ALL_ON;
if (n > n0)
b->x[j] = ALL_ON >> (ULbits - (nbits & kmask));
*exp = fpi->emax;
return STRTOG_Normal | STRTOG_Inexlo;
}
n = s1 - s0 - 1;
for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
k++;
b = Balloc(k MTa);
x = b->x;
n = 0;
L = 0;
#ifdef USE_LOCALE
for(i = 0; decimalpoint[i+1]; ++i);
#endif
while(s1 > s0) {
#ifdef USE_LOCALE
if (*--s1 == decimalpoint[i]) {
s1 -= i;
continue;
}
#else
if (*--s1 == '.')
continue;
#endif
if (n == ULbits) {
*x++ = L;
L = 0;
n = 0;
}
L |= (hexdig[*s1] & 0x0f) << n;
n += 4;
}
*x++ = L;
b->wds = n = x - b->x;
n = ULbits*n - hi0bits(L);
nbits = fpi->nbits;
lostbits = 0;
x = b->x;
if (n > nbits) {
n -= nbits;
if (any_on(b,n)) {
lostbits = 1;
k = n - 1;
if (x[k>>kshift] & 1 << (k & kmask)) {
lostbits = 2;
if (k > 0 && any_on(b,k))
lostbits = 3;
}
}
rshift(b, n);
e += n;
}
else if (n < nbits) {
n = nbits - n;
b = lshift(b, n MTa);
e -= n;
x = b->x;
}
if (e > fpi->emax) {
ovfl:
Bfree(b MTa);
ovfl1:
#ifndef NO_ERRNO
errno = ERANGE;
#endif
switch (fpi->rounding) {
case FPI_Round_zero:
goto ret_big;
case FPI_Round_down:
if (!sign)
goto ret_big;
break;
case FPI_Round_up:
if (sign)
goto ret_big;
}
return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
}
irv = STRTOG_Normal;
if (e < fpi->emin) {
irv = STRTOG_Denormal;
n = fpi->emin - e;
if (n >= nbits) {
switch (fpi->rounding) {
case FPI_Round_near:
if (n == nbits && (n < 2 || lostbits || any_on(b,n-1)))
goto one_bit;
break;
case FPI_Round_up:
if (!sign)
goto one_bit;
break;
case FPI_Round_down:
if (sign) {
one_bit:
x[0] = b->wds = 1;
dret:
*bp = b;
*exp = fpi->emin;
#ifndef NO_ERRNO
errno = ERANGE;
#endif
return STRTOG_Denormal | STRTOG_Inexhi
| STRTOG_Underflow;
}
}
Bfree(b MTa);
retz:
#ifndef NO_ERRNO
errno = ERANGE;
#endif
return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
}
k = n - 1;
if (lostbits)
lostbits = 1;
else if (k > 0)
lostbits = any_on(b,k);
if (x[k>>kshift] & 1 << (k & kmask))
lostbits |= 2;
nbits -= n;
rshift(b,n);
e = fpi->emin;
}
if (lostbits) {
up = 0;
switch(fpi->rounding) {
case FPI_Round_zero:
break;
case FPI_Round_near:
if (lostbits & 2
&& (lostbits | x[0]) & 1)
up = 1;
break;
case FPI_Round_up:
up = 1 - sign;
break;
case FPI_Round_down:
up = sign;
}
if (up) {
k = b->wds;
b = increment(b MTa);
x = b->x;
if (irv == STRTOG_Denormal) {
if (nbits == fpi->nbits - 1
&& x[nbits >> kshift] & 1 << (nbits & kmask))
irv = STRTOG_Normal;
}
else if (b->wds > k
|| ((n = nbits & kmask) !=0
&& hi0bits(x[k-1]) < 32-n)) {
rshift(b,1);
if (++e > fpi->emax)
goto ovfl;
}
irv |= STRTOG_Inexhi;
}
else
irv |= STRTOG_Inexlo;
}
*bp = b;
*exp = e;
return irv;
}

87
third_party/gdtoa/gmisc.c vendored Normal file
View file

@ -0,0 +1,87 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
void
#ifdef KR_headers
rshift(b, k) Bigint *b; int k;
#else
rshift(Bigint *b, int k)
#endif
{
ULong *x, *x1, *xe, y;
int n;
x = x1 = b->x;
n = k >> kshift;
if (n < b->wds) {
xe = x + b->wds;
x += n;
if (k &= kmask) {
n = ULbits - k;
y = *x++ >> k;
while(x < xe) {
*x1++ = (y | (*x << n)) & ALL_ON;
y = *x++ >> k;
}
if ((*x1 = y) !=0)
x1++;
}
else
while(x < xe)
*x1++ = *x++;
}
if ((b->wds = x1 - b->x) == 0)
b->x[0] = 0;
}
int
#ifdef KR_headers
trailz(b) Bigint *b;
#else
trailz(Bigint *b)
#endif
{
ULong L, *x, *xe;
int n = 0;
x = b->x;
xe = x + b->wds;
for(n = 0; x < xe && !*x; x++)
n += ULbits;
if (x < xe) {
L = *x;
n += lo0bits(&L);
}
return n;
}

78
third_party/gdtoa/hd_init.c vendored Normal file
View file

@ -0,0 +1,78 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#if 0
unsigned char hexdig[256];
static void
#ifdef KR_headers
htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;
#else
htinit(unsigned char *h, unsigned char *s, int inc)
#endif
{
int i, j;
for(i = 0; (j = s[i]) !=0; i++)
h[j] = i + inc;
}
void
hexdig_init_D2A(Void) /* Use of hexdig_init omitted 20121220 to avoid a */
/* race condition when multiple threads are used. */
{
#define USC (unsigned char *)
htinit(hexdig, USC "0123456789", 0x10);
htinit(hexdig, USC "abcdef", 0x10 + 10);
htinit(hexdig, USC "ABCDEF", 0x10 + 10);
}
#else
const unsigned char hexdig[256] = {
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,
16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,
0,26,27,28,29,30,31,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,26,27,28,29,30,31,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,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
};
#endif

160
third_party/gdtoa/hexnan.c vendored Normal file
View file

@ -0,0 +1,160 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
static void
#ifdef KR_headers
L_shift(x, x1, i) ULong *x; ULong *x1; int i;
#else
L_shift(ULong *x, ULong *x1, int i)
#endif
{
int j;
i = 8 - i;
i <<= 2;
j = ULbits - i;
do {
*x |= x[1] << j;
x[1] >>= i;
} while(++x < x1);
}
int
#ifdef KR_headers
hexnan(sp, fpi, x0)
CONST char **sp; CONST FPI *fpi; ULong *x0;
#else
hexnan( CONST char **sp, CONST FPI *fpi, ULong *x0)
#endif
{
ULong c, h, *x, *x1, *xe;
CONST char *s;
int havedig, hd0, i, nbits;
/**** if (!hexdig['0']) hexdig_init_D2A(); ****/
nbits = fpi->nbits;
x = x0 + (nbits >> kshift);
if (nbits & kmask)
x++;
*--x = 0;
x1 = xe = x;
havedig = hd0 = i = 0;
s = *sp;
/* allow optional initial 0x or 0X */
while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') {
if (!c)
goto retnan;
++s;
}
if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')
&& *(CONST unsigned char*)(s+3) > ' ')
s += 2;
while((c = *(CONST unsigned char*)++s)) {
if (!(h = hexdig[c])) {
if (c <= ' ') {
if (hd0 < havedig) {
if (x < x1 && i < 8)
L_shift(x, x1, i);
if (x <= x0) {
i = 8;
continue;
}
hd0 = havedig;
*--x = 0;
x1 = x;
i = 0;
}
while((c = *(CONST unsigned char*)(s+1)) <= ' ') {
if (!c)
goto retnan;
++s;
}
if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')
&& *(CONST unsigned char*)(s+3) > ' ')
s += 2;
continue;
}
if (/*(*/ c == ')' && havedig) {
*sp = s + 1;
break;
}
#ifndef GDTOA_NON_PEDANTIC_NANCHECK
do {
if (/*(*/ c == ')') {
*sp = s + 1;
goto break2;
}
} while((c = *++s));
#endif
retnan:
return STRTOG_NaN;
}
havedig++;
if (++i > 8) {
if (x <= x0)
continue;
i = 1;
*--x = 0;
}
*x = (*x << 4) | (h & 0xf);
}
#ifndef GDTOA_NON_PEDANTIC_NANCHECK
break2:
#endif
if (!havedig)
return STRTOG_NaN;
if (x < x1 && i < 8)
L_shift(x, x1, i);
if (x > x0) {
x1 = x0;
do *x1++ = *x++;
while(x <= xe);
do *x1++ = 0;
while(x1 <= xe);
}
else {
/* truncate high-order word if necessary */
if ( (i = nbits & (ULbits-1)) !=0)
*xe &= ((ULong)0xffffffff) >> (ULbits - i);
}
for(x1 = xe;; --x1) {
if (*x1 != 0)
break;
if (x1 == x0) {
*x1 = 1;
break;
}
}
return STRTOG_NaNbits;
}

969
third_party/gdtoa/misc.c vendored Normal file
View file

@ -0,0 +1,969 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#ifndef Omit_Private_Memory
#ifndef PRIVATE_MEM
#define PRIVATE_MEM 2304
#endif
#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
static double private_mem[PRIVATE_mem], *pmem_next;
#endif
static ThInfo TI0;
#ifdef MULTIPLE_THREADS /*{{*/
static unsigned int maxthreads = 0;
static ThInfo *TI1;
static int TI0_used;
void
set_max_gdtoa_threads(unsigned int n)
{
size_t L;
if (n > maxthreads) {
L = n*sizeof(ThInfo);
if (TI1) {
TI1 = (ThInfo*)REALLOC(TI1, L);
memset(TI1 + maxthreads, 0, (n-maxthreads)*sizeof(ThInfo));
}
else {
TI1 = (ThInfo*)MALLOC(L);
if (TI0_used) {
memcpy(TI1, &TI0, sizeof(ThInfo));
if (n > 1)
memset(TI1 + 1, 0, L - sizeof(ThInfo));
memset(&TI0, 0, sizeof(ThInfo));
}
else
memset(TI1, 0, L);
}
maxthreads = n;
}
}
static ThInfo*
get_TI(void)
{
unsigned int thno = dtoa_get_threadno();
if (thno < maxthreads)
return TI1 + thno;
if (thno == 0)
TI0_used = 1;
return &TI0;
}
#define freelist TI->Freelist
#define p5s TI->P5s
#else /*}{*/
#define freelist TI0.Freelist
#define p5s TI0.P5s
#endif /*}}*/
Bigint *
Balloc
#ifdef KR_headers
(k MTa) int k; MTk
#else
(int k MTd)
#endif
{
int x;
Bigint *rv;
#ifndef Omit_Private_Memory
unsigned int len;
#endif
static bool once;
if (!once) {
pmem_next = private_mem;
once = true;
}
#ifdef MULTIPLE_THREADS
ThInfo *TI;
if (!(TI = *PTI))
*PTI = TI = get_TI();
if (TI == &TI0)
ACQUIRE_DTOA_LOCK(0);
#endif
/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
/* but this case seems very unlikely. */
if (k <= Kmax && (rv = freelist[k]) !=0) {
freelist[k] = rv->next;
}
else {
x = 1 << k;
#ifdef Omit_Private_Memory
rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
#else
len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
/sizeof(double);
if (k <= Kmax && pmem_next - private_mem + len - PRIVATE_mem <= 0
#ifdef MULTIPLE_THREADS
&& TI == TI1
#endif
) {
rv = (Bigint*)pmem_next;
pmem_next += len;
}
else
rv = (Bigint*)MALLOC(len*sizeof(double));
#endif
rv->k = k;
rv->maxwds = x;
}
#ifdef MULTIPLE_THREADS
if (TI == &TI0)
FREE_DTOA_LOCK(0);
#endif
rv->sign = rv->wds = 0;
return rv;
}
void
Bfree
#ifdef KR_headers
(v MTa) Bigint *v; MTk
#else
(Bigint *v MTd)
#endif
{
#ifdef MULTIPLE_THREADS
ThInfo *TI;
#endif
if (v) {
if (v->k > Kmax)
#ifdef FREE
FREE((void*)v);
#else
free((void*)v);
#endif
else {
#ifdef MULTIPLE_THREADS
if (!(TI = *PTI))
*PTI = TI = get_TI();
if (TI == &TI0)
ACQUIRE_DTOA_LOCK(0);
#endif
v->next = freelist[v->k];
freelist[v->k] = v;
#ifdef MULTIPLE_THREADS
if (TI == &TI0)
FREE_DTOA_LOCK(0);
#endif
}
}
}
int
lo0bits
#ifdef KR_headers
(y) ULong *y;
#else
(ULong *y)
#endif
{
int k;
ULong x = *y;
if (x & 7) {
if (x & 1)
return 0;
if (x & 2) {
*y = x >> 1;
return 1;
}
*y = x >> 2;
return 2;
}
k = 0;
if (!(x & 0xffff)) {
k = 16;
x >>= 16;
}
if (!(x & 0xff)) {
k += 8;
x >>= 8;
}
if (!(x & 0xf)) {
k += 4;
x >>= 4;
}
if (!(x & 0x3)) {
k += 2;
x >>= 2;
}
if (!(x & 1)) {
k++;
x >>= 1;
if (!x)
return 32;
}
*y = x;
return k;
}
Bigint *
multadd
#ifdef KR_headers
(b, m, a MTa) Bigint *b; int m, a; MTk
#else
(Bigint *b, int m, int a MTd) /* multiply by m and add a */
#endif
{
int i, wds;
#ifdef ULLong
ULong *x;
ULLong carry, y;
#else
ULong carry, *x, y;
#ifdef Pack_32
ULong xi, z;
#endif
#endif
Bigint *b1;
wds = b->wds;
x = b->x;
i = 0;
carry = a;
do {
#ifdef ULLong
y = *x * (ULLong)m + carry;
carry = y >> 32;
*x++ = y & 0xffffffffUL;
#else
#ifdef Pack_32
xi = *x;
y = (xi & 0xffff) * m + carry;
z = (xi >> 16) * m + (y >> 16);
carry = z >> 16;
*x++ = (z << 16) + (y & 0xffff);
#else
y = *x * m + carry;
carry = y >> 16;
*x++ = y & 0xffff;
#endif
#endif
}
while(++i < wds);
if (carry) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1 MTa);
Bcopy(b1, b);
Bfree(b MTa);
b = b1;
}
b->x[wds++] = carry;
b->wds = wds;
}
return b;
}
int
hi0bits_D2A
#ifdef KR_headers
(x) ULong x;
#else
(ULong x)
#endif
{
int k = 0;
if (!(x & 0xffff0000)) {
k = 16;
x <<= 16;
}
if (!(x & 0xff000000)) {
k += 8;
x <<= 8;
}
if (!(x & 0xf0000000)) {
k += 4;
x <<= 4;
}
if (!(x & 0xc0000000)) {
k += 2;
x <<= 2;
}
if (!(x & 0x80000000)) {
k++;
if (!(x & 0x40000000))
return 32;
}
return k;
}
Bigint *
i2b
#ifdef KR_headers
(i MTa) int i; MTk
#else
(int i MTd)
#endif
{
Bigint *b;
b = Balloc(1 MTa);
b->x[0] = i;
b->wds = 1;
return b;
}
Bigint *
mult
#ifdef KR_headers
(a, b MTa) Bigint *a, *b; MTk
#else
(Bigint *a, Bigint *b MTd)
#endif
{
Bigint *c;
int k, wa, wb, wc;
ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
ULong y;
#ifdef ULLong
ULLong carry, z;
#else
ULong carry, z;
#ifdef Pack_32
ULong z2;
#endif
#endif
if (a->wds < b->wds) {
c = a;
a = b;
b = c;
}
k = a->k;
wa = a->wds;
wb = b->wds;
wc = wa + wb;
if (wc > a->maxwds)
k++;
c = Balloc(k MTa);
for(x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
xae = xa + wa;
xb = b->x;
xbe = xb + wb;
xc0 = c->x;
#ifdef ULLong
for(; xb < xbe; xc0++) {
if ( (y = *xb++) !=0) {
x = xa;
xc = xc0;
carry = 0;
do {
z = *x++ * (ULLong)y + *xc + carry;
carry = z >> 32;
*xc++ = z & 0xffffffffUL;
}
while(x < xae);
*xc = carry;
}
}
#else
#ifdef Pack_32
for(; xb < xbe; xb++, xc0++) {
if ( (y = *xb & 0xffff) !=0) {
x = xa;
xc = xc0;
carry = 0;
do {
z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
carry = z >> 16;
z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
carry = z2 >> 16;
Storeinc(xc, z2, z);
}
while(x < xae);
*xc = carry;
}
if ( (y = *xb >> 16) !=0) {
x = xa;
xc = xc0;
carry = 0;
z2 = *xc;
do {
z = (*x & 0xffff) * y + (*xc >> 16) + carry;
carry = z >> 16;
Storeinc(xc, z, z2);
z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
carry = z2 >> 16;
}
while(x < xae);
*xc = z2;
}
}
#else
for(; xb < xbe; xc0++) {
if ( (y = *xb++) !=0) {
x = xa;
xc = xc0;
carry = 0;
do {
z = *x++ * y + *xc + carry;
carry = z >> 16;
*xc++ = z & 0xffff;
}
while(x < xae);
*xc = carry;
}
}
#endif
#endif
for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
c->wds = wc;
return c;
}
Bigint *
pow5mult
#ifdef KR_headers
(b, k MTa) Bigint *b; int k; MTk
#else
(Bigint *b, int k MTd)
#endif
{
Bigint *b1, *p5, *p51;
#ifdef MULTIPLE_THREADS
ThInfo *TI;
#endif
int i;
static const int p05[3] = { 5, 25, 125 };
if ( (i = k & 3) !=0)
b = multadd(b, p05[i-1], 0 MTa);
if (!(k >>= 2))
return b;
#ifdef MULTIPLE_THREADS
if (!(TI = *PTI))
*PTI = TI = get_TI();
#endif
if ((p5 = p5s) == 0) {
/* first time */
#ifdef MULTIPLE_THREADS
if (!(TI = *PTI))
*PTI = TI = get_TI();
if (TI == &TI0)
ACQUIRE_DTOA_LOCK(1);
if (!(p5 = p5s)) {
p5 = p5s = i2b(625 MTa);
p5->next = 0;
}
if (TI == &TI0)
FREE_DTOA_LOCK(1);
#else
p5 = p5s = i2b(625);
p5->next = 0;
#endif
}
for(;;) {
if (k & 1) {
b1 = mult(b, p5 MTa);
Bfree(b MTa);
b = b1;
}
if (!(k >>= 1))
break;
if ((p51 = p5->next) == 0) {
#ifdef MULTIPLE_THREADS
if (!TI && !(TI = *PTI))
*PTI = TI = get_TI();
if (TI == &TI0)
ACQUIRE_DTOA_LOCK(1);
if (!(p51 = p5->next)) {
p51 = p5->next = mult(p5,p5 MTa);
p51->next = 0;
}
if (TI == &TI0)
FREE_DTOA_LOCK(1);
#else
p51 = p5->next = mult(p5,p5 MTa);
p51->next = 0;
#endif
}
p5 = p51;
}
return b;
}
Bigint *
lshift
#ifdef KR_headers
(b, k MTa) Bigint *b; int k; MTk
#else
(Bigint *b, int k MTd)
#endif
{
int i, k1, n, n1;
Bigint *b1;
ULong *x, *x1, *xe, z;
n = k >> kshift;
k1 = b->k;
n1 = n + b->wds + 1;
for(i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = Balloc(k1 MTa);
x1 = b1->x;
for(i = 0; i < n; i++)
*x1++ = 0;
x = b->x;
xe = x + b->wds;
if (k &= kmask) {
#ifdef Pack_32
k1 = 32 - k;
z = 0;
do {
*x1++ = *x << k | z;
z = *x++ >> k1;
}
while(x < xe);
if ((*x1 = z) !=0)
++n1;
#else
k1 = 16 - k;
z = 0;
do {
*x1++ = *x << k & 0xffff | z;
z = *x++ >> k1;
}
while(x < xe);
if (*x1 = z)
++n1;
#endif
}
else do
*x1++ = *x++;
while(x < xe);
b1->wds = n1 - 1;
Bfree(b MTa);
return b1;
}
int
cmp
#ifdef KR_headers
(a, b) Bigint *a, *b;
#else
(Bigint *a, Bigint *b)
#endif
{
ULong *xa, *xa0, *xb, *xb0;
int i, j;
i = a->wds;
j = b->wds;
#ifdef DEBUG
if (i > 1 && !a->x[i-1])
Bug("cmp called with a->x[a->wds-1] == 0");
if (j > 1 && !b->x[j-1])
Bug("cmp called with b->x[b->wds-1] == 0");
#endif
if (i -= j)
return i;
xa0 = a->x;
xa = xa0 + j;
xb0 = b->x;
xb = xb0 + j;
for(;;) {
if (*--xa != *--xb)
return *xa < *xb ? -1 : 1;
if (xa <= xa0)
break;
}
return 0;
}
Bigint *
diff
#ifdef KR_headers
(a, b MTa) Bigint *a, *b; MTk
#else
(Bigint *a, Bigint *b MTd)
#endif
{
Bigint *c;
int i, wa, wb;
ULong *xa, *xae, *xb, *xbe, *xc;
#ifdef ULLong
ULLong borrow, y;
#else
ULong borrow, y;
#ifdef Pack_32
ULong z;
#endif
#endif
i = cmp(a,b);
if (!i) {
c = Balloc(0 MTa);
c->wds = 1;
c->x[0] = 0;
return c;
}
if (i < 0) {
c = a;
a = b;
b = c;
i = 1;
}
else
i = 0;
c = Balloc(a->k MTa);
c->sign = i;
wa = a->wds;
xa = a->x;
xae = xa + wa;
wb = b->wds;
xb = b->x;
xbe = xb + wb;
xc = c->x;
borrow = 0;
#ifdef ULLong
do {
y = (ULLong)*xa++ - *xb++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = y & 0xffffffffUL;
}
while(xb < xbe);
while(xa < xae) {
y = *xa++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = y & 0xffffffffUL;
}
#else
#ifdef Pack_32
do {
y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
while(xb < xbe);
while(xa < xae) {
y = (*xa & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*xa++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
#else
do {
y = *xa++ - *xb++ - borrow;
borrow = (y & 0x10000) >> 16;
*xc++ = y & 0xffff;
}
while(xb < xbe);
while(xa < xae) {
y = *xa++ - borrow;
borrow = (y & 0x10000) >> 16;
*xc++ = y & 0xffff;
}
#endif
#endif
while(!*--xc)
wa--;
c->wds = wa;
return c;
}
double
b2d
#ifdef KR_headers
(a, e) Bigint *a; int *e;
#else
(Bigint *a, int *e)
#endif
{
ULong *xa, *xa0, w, y, z;
int k;
U d;
#ifdef VAX
ULong d0, d1;
#else
#define d0 word0(&d)
#define d1 word1(&d)
#endif
xa0 = a->x;
xa = xa0 + a->wds;
y = *--xa;
#ifdef DEBUG
if (!y) Bug("zero y in b2d");
#endif
k = hi0bits(y);
*e = 32 - k;
#ifdef Pack_32
if (k < Ebits) {
d0 = Exp_1 | y >> (Ebits - k);
w = xa > xa0 ? *--xa : 0;
d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
goto ret_d;
}
z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) {
d0 = Exp_1 | y << k | z >> (32 - k);
y = xa > xa0 ? *--xa : 0;
d1 = z << k | y >> (32 - k);
}
else {
d0 = Exp_1 | y;
d1 = z;
}
#else
if (k < Ebits + 16) {
z = xa > xa0 ? *--xa : 0;
d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
w = xa > xa0 ? *--xa : 0;
y = xa > xa0 ? *--xa : 0;
d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
goto ret_d;
}
z = xa > xa0 ? *--xa : 0;
w = xa > xa0 ? *--xa : 0;
k -= Ebits + 16;
d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
y = xa > xa0 ? *--xa : 0;
d1 = w << k + 16 | y << k;
#endif
ret_d:
#ifdef VAX
word0(&d) = d0 >> 16 | d0 << 16;
word1(&d) = d1 >> 16 | d1 << 16;
#endif
return dval(&d);
}
#undef d0
#undef d1
Bigint *
d2b
#ifdef KR_headers
(dd, e, bits MTa) double dd; int *e, *bits; MTk
#else
(double dd, int *e, int *bits MTd)
#endif
{
Bigint *b;
U d;
#ifndef Sudden_Underflow
int i;
#endif
int de, k;
ULong *x, y, z;
#ifdef VAX
ULong d0, d1;
#else
#define d0 word0(&d)
#define d1 word1(&d)
#endif
d.d = dd;
#ifdef VAX
d0 = word0(&d) >> 16 | word0(&d) << 16;
d1 = word1(&d) >> 16 | word1(&d) << 16;
#endif
#ifdef Pack_32
b = Balloc(1 MTa);
#else
b = Balloc(2 MTa);
#endif
x = b->x;
z = d0 & Frac_mask;
d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
#ifdef Sudden_Underflow
de = (int)(d0 >> Exp_shift);
#ifndef IBM
z |= Exp_msk11;
#endif
#else
if ( (de = (int)(d0 >> Exp_shift)) !=0)
z |= Exp_msk1;
#endif
#ifdef Pack_32
if ( (y = d1) !=0) {
if ( (k = lo0bits(&y)) !=0) {
x[0] = y | z << (32 - k);
z >>= k;
}
else
x[0] = y;
#ifndef Sudden_Underflow
i =
#endif
b->wds = (x[1] = z) !=0 ? 2 : 1;
}
else {
k = lo0bits(&z);
x[0] = z;
#ifndef Sudden_Underflow
i =
#endif
b->wds = 1;
k += 32;
}
#else
if ( (y = d1) !=0) {
if ( (k = lo0bits(&y)) !=0)
if (k >= 16) {
x[0] = y | z << 32 - k & 0xffff;
x[1] = z >> k - 16 & 0xffff;
x[2] = z >> k;
i = 2;
}
else {
x[0] = y & 0xffff;
x[1] = y >> 16 | z << 16 - k & 0xffff;
x[2] = z >> k & 0xffff;
x[3] = z >> k+16;
i = 3;
}
else {
x[0] = y & 0xffff;
x[1] = y >> 16;
x[2] = z & 0xffff;
x[3] = z >> 16;
i = 3;
}
}
else {
#ifdef DEBUG
if (!z)
Bug("Zero passed to d2b");
#endif
k = lo0bits(&z);
if (k >= 16) {
x[0] = z;
i = 0;
}
else {
x[0] = z & 0xffff;
x[1] = z >> 16;
i = 1;
}
k += 32;
}
while(!x[i])
--i;
b->wds = i + 1;
#endif
#ifndef Sudden_Underflow
if (de) {
#endif
#ifdef IBM
*e = (de - Bias - (P-1) << 2) + k;
*bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask);
#else
*e = de - Bias - (P-1) + k;
*bits = P - k;
#endif
#ifndef Sudden_Underflow
}
else {
*e = de - Bias - (P-1) + 1 + k;
#ifdef Pack_32
*bits = 32*i - hi0bits(x[i-1]);
#else
*bits = (i+2)*16 - hi0bits(x[i]);
#endif
}
#endif
return b;
}
#undef d0
#undef d1
CONST double
#ifdef IEEE_Arith
bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256
};
#else
#ifdef IBM
bigtens[] = { 1e16, 1e32, 1e64 };
CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
#else
bigtens[] = { 1e16, 1e32 };
CONST double tinytens[] = { 1e-16, 1e-32 };
#endif
#endif
CONST double
tens[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
#ifdef VAX
, 1e23, 1e24
#endif
};
char *
#ifdef KR_headers
strcp_D2A(a, b) char *a; char *b;
#else
strcp_D2A(char *a, CONST char *b)
#endif
{
while((*a = *b++))
a++;
return a;
}
#ifdef NO_STRING_H
Char *
#ifdef KR_headers
memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
#else
memcpy_D2A(void *a1, void *b1, size_t len)
#endif
{
char *a = (char*)a1, *ae = a + len;
char *b = (char*)b1, *a0 = a;
while(a < ae)
*a++ = *b++;
return a0;
}
#endif /* NO_STRING_H */

10
third_party/gdtoa/printf.c.txt vendored Normal file
View file

@ -0,0 +1,10 @@
/* clang-format off */
#ifdef __sun
#define Use_GDTOA_Qtype
#else
#if defined(__i386) || defined(__x86_64)
#define Use_GDTOA_for_i386_long_double
#endif
#endif
#include "third_party/gdtoa/printf.c0"

1635
third_party/gdtoa/printf.c0 vendored Normal file

File diff suppressed because it is too large Load diff

192
third_party/gdtoa/smisc.c vendored Normal file
View file

@ -0,0 +1,192 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
Bigint *
s2b
#ifdef KR_headers
(s, nd0, nd, y9, dplen MTa) CONST char *s; int dplen, nd0, nd; ULong y9; MTk
#else
(CONST char *s, int nd0, int nd, ULong y9, int dplen MTd)
#endif
{
Bigint *b;
int i, k;
Long x, y;
x = (nd + 8) / 9;
for(k = 0, y = 1; x > y; y <<= 1, k++) ;
#ifdef Pack_32
b = Balloc(k MTa);
b->x[0] = y9;
b->wds = 1;
#else
b = Balloc(k+1 MTa);
b->x[0] = y9 & 0xffff;
b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
i = 9;
if (9 < nd0) {
s += 9;
do b = multadd(b, 10, *s++ - '0' MTa);
while(++i < nd0);
s += dplen;
}
else
s += dplen + 9;
for(; i < nd; i++)
b = multadd(b, 10, *s++ - '0' MTa);
return b;
}
double
ratio
#ifdef KR_headers
(a, b) Bigint *a, *b;
#else
(Bigint *a, Bigint *b)
#endif
{
U da, db;
int k, ka, kb;
dval(&da) = b2d(a, &ka);
dval(&db) = b2d(b, &kb);
k = ka - kb + ULbits*(a->wds - b->wds);
#ifdef IBM
if (k > 0) {
word0(&da) += (k >> 2)*Exp_msk1;
if (k &= 3)
dval(&da) *= 1 << k;
}
else {
k = -k;
word0(&db) += (k >> 2)*Exp_msk1;
if (k &= 3)
dval(&db) *= 1 << k;
}
#else
if (k > 0)
word0(&da) += k*Exp_msk1;
else {
k = -k;
word0(&db) += k*Exp_msk1;
}
#endif
return dval(&da) / dval(&db);
}
#ifdef INFNAN_CHECK
int
match
#ifdef KR_headers
(sp, t) char **sp, *t;
#else
(CONST char **sp, char *t)
#endif
{
int c, d;
CONST char *s = *sp;
while( (d = *t++) !=0) {
if ((c = *++s) >= 'A' && c <= 'Z')
c += 'a' - 'A';
if (c != d)
return 0;
}
*sp = s + 1;
return 1;
}
#endif /* INFNAN_CHECK */
void
#ifdef KR_headers
copybits(c, n, b) ULong *c; int n; Bigint *b;
#else
copybits(ULong *c, int n, Bigint *b)
#endif
{
ULong *ce, *x, *xe;
#ifdef Pack_16
int nw, nw1;
#endif
ce = c + ((n-1) >> kshift) + 1;
x = b->x;
#ifdef Pack_32
xe = x + b->wds;
while(x < xe)
*c++ = *x++;
#else
nw = b->wds;
nw1 = nw & 1;
for(xe = x + (nw - nw1); x < xe; x += 2)
Storeinc(c, x[1], x[0]);
if (nw1)
*c++ = *x;
#endif
while(c < ce)
*c++ = 0;
}
ULong
#ifdef KR_headers
any_on(b, k) Bigint *b; int k;
#else
any_on(Bigint *b, int k)
#endif
{
int n, nwds;
ULong *x, *x0, x1, x2;
x = b->x;
nwds = b->wds;
n = k >> kshift;
if (n > nwds)
n = nwds;
else if (n < nwds && (k &= kmask)) {
x1 = x2 = x[n];
x1 >>= k;
x1 <<= k;
if (x1 != x2)
return 1;
}
x0 = x;
x += n;
while(x > x0)
if (*--x)
return 1;
return 0;
}

106
third_party/gdtoa/stdio1.h.txt vendored Normal file
View file

@ -0,0 +1,106 @@
#include "libc/stdio/stdio.h"
/****************************************************************
Copyright (C) 1997-1999 Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* stdio1.h -- for using Printf, Fprintf, Sprintf while
* retaining the system-supplied printf, fprintf, sprintf.
*/
#ifndef STDIO1_H_included
#define STDIO1_H_included
#ifndef STDIO_H_included /* allow suppressing stdio.h */
#endif /* e.g., by cplex.h */
#ifdef KR_headers
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned int size_t;
#endif
#define ANSI(x) ()
#ifndef Char
#define Char char
#endif
#else
#define ANSI(x) x
#ifndef Char
#define Char void
#endif
#endif
#ifndef NO_STDIO1
#ifdef _WIN32
/* Avoid Microsoft bug that perrror may appear in stdlib.h. */
/* It should only be declared in stdio.h. */
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern int Fprintf ANSI((FILE *, const char *, ...));
extern int Printf ANSI((const char *, ...));
extern int Sprintf ANSI((char *, const char *, ...));
extern int Snprintf ANSI((char *, size_t, const char *, ...));
extern void Perror ANSI((const char *));
extern int Vfprintf ANSI((FILE *, const char *, va_list));
extern int Vsprintf ANSI((char *, const char *, va_list));
extern int Vsnprintf ANSI((char *, size_t, const char *, va_list));
#ifdef PF_BUF
extern FILE *stderr_ASL;
extern void(*pfbuf_print_ASL) ANSI((char *));
extern char *pfbuf_ASL;
extern void fflush_ASL ANSI((FILE *));
#ifdef fflush
#define old_fflush_ASL fflush
#undef fflush
#endif
#define fflush fflush_ASL
#endif
#ifdef __cplusplus
}
#endif
#undef printf
#undef fprintf
#undef sprintf
#undef perror
#undef vfprintf
#undef vsprintf
#define printf Printf
#define fprintf Fprintf
#undef snprintf /* for MacOSX */
#undef vsnprintf /* for MacOSX */
#define snprintf Snprintf
#define sprintf Sprintf
#define perror Perror
#define vfprintf Vfprintf
#define vsnprintf Vsnprintf
#define vsprintf Vsprintf
#endif /* NO_STDIO1 */
#endif /* STDIO1_H_included */

67
third_party/gdtoa/strtoIQ.c vendored Normal file
View file

@ -0,0 +1,67 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIQ(s, sp, a, b) CONST char *s; char **sp; void *a; void *b;
#else
strtoIQ(CONST char *s, char **sp, void *a, void *b)
#endif
{
static const FPI fpi = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI, 0 /*unused*/ };
Long exp[2];
Bigint *B[2];
int k, rv[2];
ULong *L = (ULong *)a, *M = (ULong *)b;
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(2 MTb);
B[0]->wds = 4;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtoQ(L, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtoQ(M, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else {
M[0] = L[0];
M[1] = L[1];
M[2] = L[2];
M[3] = L[3];
}
return k;
}

64
third_party/gdtoa/strtoId.c vendored Normal file
View file

@ -0,0 +1,64 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoId(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1;
#else
strtoId(CONST char *s, char **sp, double *f0, double *f1)
#endif
{
static const FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI, 0 /*unused*/ };
Long exp[2];
Bigint *B[2];
int k, rv[2];
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(1 MTb);
B[0]->wds = 2;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else {
((ULong*)f1)[0] = ((ULong*)f0)[0];
((ULong*)f1)[1] = ((ULong*)f0)[1];
}
return k;
}

70
third_party/gdtoa/strtoIdd.c vendored Normal file
View file

@ -0,0 +1,70 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIdd(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1;
#else
strtoIdd(CONST char *s, char **sp, double *f0, double *f1)
#endif
{
#ifdef Sudden_Underflow
static const FPI fpi = { 106, 1-1023, 2046-1023-106+1, 1, 1, 0 /*unused*/ };
#else
static const FPI fpi = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0, 0 /*unused*/ };
#endif
Long exp[2];
Bigint *B[2];
int k, rv[2];
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(2 MTb);
B[0]->wds = 4;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else {
((ULong*)f1)[0] = ((ULong*)f0)[0];
((ULong*)f1)[1] = ((ULong*)f0)[1];
((ULong*)f1)[2] = ((ULong*)f0)[2];
((ULong*)f1)[3] = ((ULong*)f0)[3];
}
return k;
}

62
third_party/gdtoa/strtoIf.c vendored Normal file
View file

@ -0,0 +1,62 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIf(s, sp, f0, f1) CONST char *s; char **sp; float *f0, *f1;
#else
strtoIf(CONST char *s, char **sp, float *f0, float *f1)
#endif
{
static const FPI fpi = { 24, 1-127-24+1, 254-127-24+1, 1, SI, 0 /*unused*/ };
Long exp[2];
Bigint *B[2];
int k, rv[2];
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(0 MTb);
B[0]->wds = 1;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else
*(ULong*)f1 = *(ULong*)f0;
return k;
}

141
third_party/gdtoa/strtoIg.c vendored Normal file
View file

@ -0,0 +1,141 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIg(s00, se, fpi, exp, B, rvp) CONST char *s00; char **se; CONST FPI *fpi; Long *exp; Bigint **B; int *rvp;
#else
strtoIg(CONST char *s00, char **se, CONST FPI *fpi, Long *exp, Bigint **B, int *rvp)
#endif
{
Bigint *b, *b1;
int i, nb, nw, nw1, rv, rv1, swap;
unsigned int nb1, nb11;
Long e1;
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
b = *B;
rv = strtodg(s00, se, fpi, exp, b->x);
if (!(rv & STRTOG_Inexact)) {
B[1] = 0;
return *rvp = rv;
}
e1 = exp[0];
rv1 = rv ^ STRTOG_Inexact;
b1 = Balloc(b->k MTb);
Bcopy(b1, b);
nb = fpi->nbits;
nb1 = nb & 31;
nb11 = (nb1 - 1) & 31;
nw = b->wds;
nw1 = nw - 1;
if (rv & STRTOG_Inexlo) {
swap = 0;
b1 = increment(b1 MTb);
if ((rv & STRTOG_Retmask) == STRTOG_Zero) {
if (fpi->sudden_underflow) {
b1->x[0] = 0;
b1->x[nw1] = 1L << nb11;
rv1 += STRTOG_Normal - STRTOG_Zero;
rv1 &= ~STRTOG_Underflow;
goto swapcheck;
}
rv1 &= STRTOG_Inexlo | STRTOG_Underflow | STRTOG_Zero | STRTOG_Neg;
rv1 |= STRTOG_Inexhi | STRTOG_Denormal;
goto swapcheck;
}
if (b1->wds > nw
|| (nb1 && b1->x[nw1] & 1L << nb1)) {
if (++e1 > fpi->emax)
rv1 = STRTOG_Infinite | STRTOG_Inexhi;
rshift(b1, 1);
}
else if ((rv & STRTOG_Retmask) == STRTOG_Denormal) {
if (b1->x[nw1] & 1L << nb11) {
rv1 += STRTOG_Normal - STRTOG_Denormal;
rv1 &= ~STRTOG_Underflow;
}
}
}
else {
swap = STRTOG_Neg;
if ((rv & STRTOG_Retmask) == STRTOG_Infinite) {
b1 = set_ones(b1, nb MTb);
e1 = fpi->emax;
rv1 = STRTOG_Normal | STRTOG_Inexlo | (rv & STRTOG_Neg);
goto swapcheck;
}
decrement(b1);
if ((rv & STRTOG_Retmask) == STRTOG_Denormal) {
for(i = nw1; !b1->x[i]; --i)
if (!i) {
rv1 = STRTOG_Zero | STRTOG_Inexlo | (rv & STRTOG_Neg);
break;
}
goto swapcheck;
}
if (!(b1->x[nw1] & 1L << nb11)) {
if (e1 == fpi->emin) {
if (fpi->sudden_underflow)
rv1 += STRTOG_Zero - STRTOG_Normal;
else
rv1 += STRTOG_Denormal - STRTOG_Normal;
rv1 |= STRTOG_Underflow;
}
else {
b1 = lshift(b1, 1 MTb);
b1->x[0] |= 1;
--e1;
}
}
}
swapcheck:
if (swap ^ (rv & STRTOG_Neg)) {
rvp[0] = rv1;
rvp[1] = rv;
B[0] = b1;
B[1] = b;
exp[1] = exp[0];
exp[0] = e1;
}
else {
rvp[0] = rv;
rvp[1] = rv1;
B[1] = b1;
exp[1] = e1;
}
return rv;
}

68
third_party/gdtoa/strtoIx.c vendored Normal file
View file

@ -0,0 +1,68 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIx(s, sp, a, b) CONST char *s; char **sp; void *a; void *b;
#else
strtoIx(CONST char *s, char **sp, void *a, void *b)
#endif
{
static const FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
Long exp[2];
Bigint *B[2];
int k, rv[2];
UShort *L = (UShort *)a, *M = (UShort *)b;
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(1 MTb);
B[0]->wds = 2;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtox(L, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtox(M, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else {
M[0] = L[0];
M[1] = L[1];
M[2] = L[2];
M[3] = L[3];
M[4] = L[4];
}
return k;
}

66
third_party/gdtoa/strtoIxL.c vendored Normal file
View file

@ -0,0 +1,66 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtoIxL(s, sp, a, b) CONST char *s; char **sp; void *a; void *b;
#else
strtoIxL(CONST char *s, char **sp, void *a, void *b)
#endif
{
static const FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
Long exp[2];
Bigint *B[2];
int k, rv[2];
ULong *L = (ULong *)a, *M = (ULong *)b;
#ifdef MULTIPLE_THREADS
ThInfo *TI = 0;
#endif
B[0] = Balloc(1 MTb);
B[0]->wds = 2;
k = strtoIg(s, sp, &fpi, exp, B, rv);
ULtoxL(L, B[0]->x, exp[0], rv[0]);
Bfree(B[0] MTb);
if (B[1]) {
ULtoxL(M, B[1]->x, exp[1], rv[1]);
Bfree(B[1] MTb);
}
else {
M[0] = L[0];
M[1] = L[1];
M[2] = L[2];
}
return k;
}

1073
third_party/gdtoa/strtod.c vendored Normal file

File diff suppressed because it is too large Load diff

164
third_party/gdtoa/strtodI.c vendored Normal file
View file

@ -0,0 +1,164 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
static double
#ifdef KR_headers
ulpdown(d) U *d;
#else
ulpdown(U *d)
#endif
{
double u;
ULong *L = d->L;
u = ulp(d);
if (!(L[_1] | (L[_0] & 0xfffff))
&& (L[_0] & 0x7ff00000) > 0x00100000)
u *= 0.5;
return u;
}
int
#ifdef KR_headers
strtodI(s, sp, dd) CONST char *s; char **sp; double *dd;
#else
strtodI(CONST char *s, char **sp, double *dd)
#endif
{
static const FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI, 0 /*unused*/ };
ULong bits[2], sign;
Long exp;
int j, k;
U *u;
k = strtodg(s, sp, &fpi, &exp, bits);
u = (U*)dd;
sign = k & STRTOG_Neg ? 0x80000000L : 0;
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
dval(&u[0]) = dval(&u[1]) = 0.;
break;
case STRTOG_Zero:
dval(&u[0]) = dval(&u[1]) = 0.;
#ifdef Sudden_Underflow
if (k & STRTOG_Inexact) {
if (sign)
word0(&u[0]) = 0x80100000L;
else
word0(&u[1]) = 0x100000L;
}
break;
#else
goto contain;
#endif
case STRTOG_Denormal:
word1(&u[0]) = bits[0];
word0(&u[0]) = bits[1];
goto contain;
case STRTOG_Normal:
word1(&u[0]) = bits[0];
word0(&u[0]) = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20);
contain:
j = k & STRTOG_Inexact;
if (sign) {
word0(&u[0]) |= sign;
j = STRTOG_Inexact - j;
}
switch(j) {
case STRTOG_Inexlo:
#ifdef Sudden_Underflow
if ((u->L[_0] & 0x7ff00000) < 0x3500000) {
word0(&u[1]) = word0(&u[0]) + 0x3500000;
word1(&u[1]) = word1(&u[0]);
dval(&u[1]) += ulp(&u[1]);
word0(&u[1]) -= 0x3500000;
if (!(word0(&u[1]) & 0x7ff00000)) {
word0(&u[1]) = sign;
word1(&u[1]) = 0;
}
}
else
#endif
dval(&u[1]) = dval(&u[0]) + ulp(&u[0]);
break;
case STRTOG_Inexhi:
dval(&u[1]) = dval(&u[0]);
#ifdef Sudden_Underflow
if ((word0(&u[0]) & 0x7ff00000) < 0x3500000) {
word0(&u[0]) += 0x3500000;
dval(&u[0]) -= ulpdown(u);
word0(&u[0]) -= 0x3500000;
if (!(word0(&u[0]) & 0x7ff00000)) {
word0(&u[0]) = sign;
word1(&u[0]) = 0;
}
}
else
#endif
dval(&u[0]) -= ulpdown(u);
break;
default:
dval(&u[1]) = dval(&u[0]);
}
break;
case STRTOG_Infinite:
word0(&u[0]) = word0(&u[1]) = sign | 0x7ff00000;
word1(&u[0]) = word1(&u[1]) = 0;
if (k & STRTOG_Inexact) {
if (sign) {
word0(&u[1]) = 0xffefffffL;
word1(&u[1]) = 0xffffffffL;
}
else {
word0(&u[0]) = 0x7fefffffL;
word1(&u[0]) = 0xffffffffL;
}
}
break;
case STRTOG_NaN:
u->L[0] = (u+1)->L[0] = d_QNAN0;
u->L[1] = (u+1)->L[1] = d_QNAN1;
break;
case STRTOG_NaNbits:
word0(&u[0]) = word0(&u[1]) = 0x7ff00000 | sign | bits[1];
word1(&u[0]) = word1(&u[1]) = bits[0];
}
return k;
}

1085
third_party/gdtoa/strtodg.c vendored Normal file

File diff suppressed because it is too large Load diff

88
third_party/gdtoa/strtodnrp.c vendored Normal file
View file

@ -0,0 +1,88 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 2004 by David M. Gay.
All Rights Reserved
Based on material in the rest of /netlib/fp/gdota.tar.gz,
which is copyright (C) 1998, 2000 by Lucent Technologies.
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* This is a variant of strtod that works on Intel ia32 systems */
/* with the default extended-precision arithmetic -- it does not */
/* require setting the precision control to 53 bits. */
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
double
#ifdef KR_headers
strtod(s, sp) CONST char *s; char **sp;
#else
strtod(CONST char *s, char **sp)
#endif
{
static const FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI, 0 /*unused*/ };
ULong bits[2];
Long exp;
int k;
union { ULong L[2]; double d; } u;
k = strtodg(s, sp, &fpi, &exp, bits);
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
u.L[0] = u.L[1] = 0;
break;
case STRTOG_Normal:
u.L[_1] = bits[0];
u.L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20);
break;
case STRTOG_Denormal:
u.L[_1] = bits[0];
u.L[_0] = bits[1];
break;
case STRTOG_Infinite:
u.L[_0] = 0x7ff00000;
u.L[_1] = 0;
break;
case STRTOG_NaN:
u.L[0] = d_QNAN0;
u.L[1] = d_QNAN1;
break;
case STRTOG_NaNbits:
u.L[_0] = 0x7ff00000 | bits[1];
u.L[_1] = bits[0];
}
if (k & STRTOG_Neg)
u.L[_0] |= 0x80000000L;
return u.d;
}

80
third_party/gdtoa/strtof.c vendored Normal file
View file

@ -0,0 +1,80 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
float
#ifdef KR_headers
strtof(s, sp) CONST char *s; char **sp;
#else
strtof(CONST char *s, char **sp)
#endif
{
static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI, 0 /*unused*/ };
ULong bits[1];
Long exp;
int k;
union { ULong L[1]; float f; } u;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
switch(k & STRTOG_Retmask) {
default: /* unused */
case STRTOG_NoNumber:
case STRTOG_Zero:
u.L[0] = 0;
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
u.L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23);
break;
case STRTOG_Denormal:
u.L[0] = bits[0];
break;
case STRTOG_Infinite:
u.L[0] = 0x7f800000;
break;
case STRTOG_NaN:
u.L[0] = f_QNAN;
}
if (k & STRTOG_Neg)
u.L[0] |= 0x80000000L;
return u.f;
}

26
third_party/gdtoa/strtold.c vendored Normal file
View file

@ -0,0 +1,26 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "third_party/gdtoa/gdtoa.h"
long double strtold(const char *s, char **endptr) {
long double result;
strtorQ(s, endptr, FPI_Round_near, &result);
return result;
}

110
third_party/gdtoa/strtopQ.c vendored Normal file
View file

@ -0,0 +1,110 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#endif
#ifdef IEEE_8087
#define _0 3
#define _1 2
#define _2 1
#define _3 0
#endif
extern ULong NanDflt_Q_D2A[4];
int
#ifdef KR_headers
strtopQ(s, sp, V) CONST char *s; char **sp; void *V;
#else
strtopQ(CONST char *s, char **sp, void *V)
#endif
{
static const FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI, 0 /*unused*/ };
ULong bits[4];
Long exp;
int k;
ULong *L = (ULong*)V;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = L[3] = 0;
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[_3] = bits[0];
L[_2] = bits[1];
L[_1] = bits[2];
L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16);
break;
case STRTOG_Denormal:
L[_3] = bits[0];
L[_2] = bits[1];
L[_1] = bits[2];
L[_0] = bits[3];
break;
case STRTOG_Infinite:
L[_0] = 0x7fff0000;
L[_1] = L[_2] = L[_3] = 0;
break;
case STRTOG_NaN:
L[_0] = NanDflt_Q_D2A[3];
L[_1] = NanDflt_Q_D2A[2];
L[_2] = NanDflt_Q_D2A[1];
L[_3] = NanDflt_Q_D2A[0];
}
if (k & STRTOG_Neg)
L[_0] |= 0x80000000L;
return k;
}

55
third_party/gdtoa/strtopd.c vendored Normal file
View file

@ -0,0 +1,55 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtopd(s, sp, d) char *s; char **sp; double *d;
#else
strtopd(CONST char *s, char **sp, double *d)
#endif
{
static const FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI, 0 /*unused*/ };
ULong bits[2];
Long exp;
int k;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
ULtod((ULong*)d, bits, exp, k);
return k;
}

184
third_party/gdtoa/strtopdd.c vendored Normal file
View file

@ -0,0 +1,184 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtopdd(s, sp, dd) CONST char *s; char **sp; double *dd;
#else
strtopdd(CONST char *s, char **sp, double *dd)
#endif
{
#ifdef Sudden_Underflow
static const FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1, 0 /*unused*/ };
#else
static const FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0, 0 /*unused*/ };
#endif
ULong bits[4];
Long exp;
int i, j, rv;
typedef union {
double d[2];
ULong L[4];
} U;
U *u;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
rv = strtodg(s, sp, fpi, &exp, bits);
u = (U*)dd;
switch(rv & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
u->d[0] = u->d[1] = 0.;
break;
case STRTOG_Normal:
u->L[_1] = (bits[1] >> 21 | bits[2] << 11) & 0xffffffffL;
u->L[_0] = (bits[2] >> 21) | ((bits[3] << 11) & 0xfffff)
| ((exp + 0x3ff + 105) << 20);
exp += 0x3ff + 52;
if (bits[1] &= 0x1fffff) {
i = hi0bits(bits[1]) - 11;
if (i >= exp) {
i = exp - 1;
exp = 0;
}
else
exp -= i;
if (i > 0) {
bits[1] = bits[1] << i | bits[0] >> (32-i);
bits[0] = bits[0] << i & 0xffffffffL;
}
}
else if (bits[0]) {
i = hi0bits(bits[0]) + 21;
if (i >= exp) {
i = exp - 1;
exp = 0;
}
else
exp -= i;
if (i < 32) {
bits[1] = bits[0] >> (32 - i);
bits[0] = bits[0] << i & 0xffffffffL;
}
else {
bits[1] = bits[0] << (i - 32);
bits[0] = 0;
}
}
else {
u->L[2] = u->L[3] = 0;
break;
}
u->L[2+_1] = bits[0];
u->L[2+_0] = (bits[1] & 0xfffff) | (exp << 20);
break;
case STRTOG_Denormal:
if (bits[3])
goto nearly_normal;
if (bits[2])
goto partly_normal;
if (bits[1] & 0xffe00000)
goto hardly_normal;
/* completely denormal */
u->L[2] = u->L[3] = 0;
u->L[_1] = bits[0];
u->L[_0] = bits[1];
break;
nearly_normal:
i = hi0bits(bits[3]) - 11; /* i >= 12 */
j = 32 - i;
u->L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff)
| ((65 - i) << 20);
u->L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL;
u->L[2+_0] = bits[1] & ((1L << j) - 1);
u->L[2+_1] = bits[0];
break;
partly_normal:
i = hi0bits(bits[2]) - 11;
if (i < 0) {
j = -i;
i += 32;
u->L[_0] = (bits[2] >> j & 0xfffff) | (33 + j) << 20;
u->L[_1] = ((bits[2] << i) | (bits[1] >> j)) & 0xffffffffL;
u->L[2+_0] = bits[1] & ((1L << j) - 1);
u->L[2+_1] = bits[0];
break;
}
if (i == 0) {
u->L[_0] = (bits[2] & 0xfffff) | (33 << 20);
u->L[_1] = bits[1];
u->L[2+_0] = 0;
u->L[2+_1] = bits[0];
break;
}
j = 32 - i;
u->L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff)
| ((j + 1) << 20);
u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL;
u->L[2+_0] = 0;
u->L[2+_1] = bits[0] & ((1L << j) - 1);
break;
hardly_normal:
j = 11 - hi0bits(bits[1]);
i = 32 - j;
u->L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20);
u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL;
u->L[2+_0] = 0;
u->L[2+_1] = bits[0] & ((1L << j) - 1);
break;
case STRTOG_Infinite:
u->L[_0] = u->L[2+_0] = 0x7ff00000;
u->L[_1] = u->L[2+_1] = 0;
break;
case STRTOG_NaN:
u->L[0] = u->L[2] = d_QNAN0;
u->L[1] = u->L[3] = d_QNAN1;
}
if (rv & STRTOG_Neg) {
u->L[ _0] |= 0x80000000L;
u->L[2+_0] |= 0x80000000L;
}
return rv;
}

79
third_party/gdtoa/strtopf.c vendored Normal file
View file

@ -0,0 +1,79 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
int
#ifdef KR_headers
strtopf(s, sp, f) CONST char *s; char **sp; float *f;
#else
strtopf(CONST char *s, char **sp, float *f)
#endif
{
static const FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI, 0 /*unused*/ };
ULong bits[1], *L;
Long exp;
int k;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
L = (ULong*)f;
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = 0;
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23);
break;
case STRTOG_Denormal:
L[0] = bits[0];
break;
case STRTOG_Infinite:
L[0] = 0x7f800000;
break;
case STRTOG_NaN:
L[0] = f_QNAN;
}
if (k & STRTOG_Neg)
L[0] |= 0x80000000L;
return k;
}

112
third_party/gdtoa/strtopx.c vendored Normal file
View file

@ -0,0 +1,112 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern UShort NanDflt_ldus_D2A[5];
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#define _4 4
#endif
#ifdef IEEE_8087
#define _0 4
#define _1 3
#define _2 2
#define _3 1
#define _4 0
#endif
int
#ifdef KR_headers
strtopx(s, sp, V) CONST char *s; char **sp; void *V;
#else
strtopx(CONST char *s, char **sp, void *V)
#endif
{
const static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
ULong bits[2];
Long exp;
int k;
UShort *L = (UShort*)V;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = L[3] = L[4] = 0;
break;
case STRTOG_Denormal:
L[_0] = 0;
goto normal_bits;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[_0] = exp + 0x3fff + 63;
normal_bits:
L[_4] = (UShort)bits[0];
L[_3] = (UShort)(bits[0] >> 16);
L[_2] = (UShort)bits[1];
L[_1] = (UShort)(bits[1] >> 16);
break;
case STRTOG_Infinite:
L[_0] = 0x7fff;
L[_1] = 0x8000;
L[_2] = L[_3] = L[_4] = 0;
break;
case STRTOG_NaN:
L[_4] = NanDflt_ldus_D2A[0];
L[_3] = NanDflt_ldus_D2A[1];
L[_2] = NanDflt_ldus_D2A[2];
L[_1] = NanDflt_ldus_D2A[3];
L[_0] = NanDflt_ldus_D2A[4];
}
if (k & STRTOG_Neg)
L[_0] |= 0x8000;
return k;
}

100
third_party/gdtoa/strtopxL.c vendored Normal file
View file

@ -0,0 +1,100 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_xL_D2A[3];
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#endif
#ifdef IEEE_8087
#define _0 2
#define _1 1
#define _2 0
#endif
int
#ifdef KR_headers
strtopxL(s, sp, V) CONST char *s; char **sp; void *V;
#else
strtopxL(CONST char *s, char **sp, void *V)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
ULong bits[2];
Long exp;
int k;
ULong *L = (ULong*)V;
#ifdef Honor_FLT_ROUNDS
#include "third_party/gdtoa/gdtoa_fltrnds.inc"
#else
#define fpi &fpi0
#endif
k = strtodg(s, sp, fpi, &exp, bits);
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = 0;
break;
case STRTOG_Normal:
case STRTOG_Denormal:
case STRTOG_NaNbits:
L[_2] = bits[0];
L[_1] = bits[1];
L[_0] = (exp + 0x3fff + 63) << 16;
break;
case STRTOG_Infinite:
L[_0] = 0x7fff << 16;
L[_1] = 0x80000000;
L[_2] = 0;
break;
case STRTOG_NaN:
L[_0] = NanDflt_xL_D2A[2];
L[_1] = NanDflt_xL_D2A[1];
L[_2] = NanDflt_xL_D2A[0];
}
if (k & STRTOG_Neg)
L[_0] |= 0x80000000L;
return k;
}

120
third_party/gdtoa/strtorQ.c vendored Normal file
View file

@ -0,0 +1,120 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#endif
#ifdef IEEE_8087
#define _0 3
#define _1 2
#define _2 1
#define _3 0
#endif
extern ULong NanDflt_Q_D2A[4];
void
#ifdef KR_headers
ULtoQ(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k;
#else
ULtoQ(ULong *L, ULong *bits, Long exp, int k)
#endif
{
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = L[3] = 0;
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[_3] = bits[0];
L[_2] = bits[1];
L[_1] = bits[2];
L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16);
break;
case STRTOG_Denormal:
L[_3] = bits[0];
L[_2] = bits[1];
L[_1] = bits[2];
L[_0] = bits[3];
break;
case STRTOG_Infinite:
L[_0] = 0x7fff0000;
L[_1] = L[_2] = L[_3] = 0;
break;
case STRTOG_NaN:
L[_0] = NanDflt_Q_D2A[3];
L[_1] = NanDflt_Q_D2A[2];
L[_2] = NanDflt_Q_D2A[1];
L[_3] = NanDflt_Q_D2A[0];
}
if (k & STRTOG_Neg)
L[_0] |= 0x80000000L;
}
int
#ifdef KR_headers
strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
#else
strtorQ(CONST char *s, char **sp, int rounding, void *L)
#endif
{
static const FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI, 0 /*unused*/ };
FPI *fpi, fpi1;
ULong bits[4];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtoQ((ULong*)L, bits, exp, k);
return k;
}

96
third_party/gdtoa/strtord.c vendored Normal file
View file

@ -0,0 +1,96 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_d_D2A[2];
void
#ifdef KR_headers
ULtod(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k;
#else
ULtod(ULong *L, ULong *bits, Long exp, int k)
#endif
{
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = 0;
break;
case STRTOG_Denormal:
L[_1] = bits[0];
L[_0] = bits[1];
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[_1] = bits[0];
L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20);
break;
case STRTOG_Infinite:
L[_0] = 0x7ff00000;
L[_1] = 0;
break;
case STRTOG_NaN:
L[_0] = NanDflt_d_D2A[1];
L[_1] = NanDflt_d_D2A[0];
}
if (k & STRTOG_Neg)
L[_0] |= 0x80000000L;
}
int
#ifdef KR_headers
strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d;
#else
strtord(CONST char *s, char **sp, int rounding, double *d)
#endif
{
static const FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI, 0 /*unused*/ };
FPI *fpi, fpi1;
ULong bits[2];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtod((ULong*)d, bits, exp, k);
return k;
}

203
third_party/gdtoa/strtordd.c vendored Normal file
View file

@ -0,0 +1,203 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_d_D2A[2];
void
#ifdef KR_headers
ULtodd(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k;
#else
ULtodd(ULong *L, ULong *bits, Long exp, int k)
#endif
{
int i, j;
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = L[3] = 0;
break;
case STRTOG_Normal:
L[_1] = (bits[1] >> 21 | bits[2] << 11) & (ULong)0xffffffffL;
L[_0] = (bits[2] >> 21) | (bits[3] << 11 & 0xfffff)
| ((exp + 0x3ff + 105) << 20);
exp += 0x3ff + 52;
if (bits[1] &= 0x1fffff) {
i = hi0bits(bits[1]) - 11;
if (i >= exp) {
i = exp - 1;
exp = 0;
}
else
exp -= i;
if (i > 0) {
bits[1] = bits[1] << i | bits[0] >> (32-i);
bits[0] = bits[0] << i & (ULong)0xffffffffL;
}
}
else if (bits[0]) {
i = hi0bits(bits[0]) + 21;
if (i >= exp) {
i = exp - 1;
exp = 0;
}
else
exp -= i;
if (i < 32) {
bits[1] = bits[0] >> (32 - i);
bits[0] = bits[0] << i & (ULong)0xffffffffL;
}
else {
bits[1] = bits[0] << (i - 32);
bits[0] = 0;
}
}
else {
L[2] = L[3] = 0;
break;
}
L[2+_1] = bits[0];
L[2+_0] = (bits[1] & 0xfffff) | (exp << 20);
break;
case STRTOG_Denormal:
if (bits[3])
goto nearly_normal;
if (bits[2])
goto partly_normal;
if (bits[1] & 0xffe00000)
goto hardly_normal;
/* completely denormal */
L[2] = L[3] = 0;
L[_1] = bits[0];
L[_0] = bits[1];
break;
nearly_normal:
i = hi0bits(bits[3]) - 11; /* i >= 12 */
j = 32 - i;
L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff)
| ((65 - i) << 20);
L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL;
L[2+_0] = bits[1] & (((ULong)1L << j) - 1);
L[2+_1] = bits[0];
break;
partly_normal:
i = hi0bits(bits[2]) - 11;
if (i < 0) {
j = -i;
i += 32;
L[_0] = (bits[2] >> j & 0xfffff) | ((33 + j) << 20);
L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL;
L[2+_0] = bits[1] & (((ULong)1L << j) - 1);
L[2+_1] = bits[0];
break;
}
if (i == 0) {
L[_0] = (bits[2] & 0xfffff) | (33 << 20);
L[_1] = bits[1];
L[2+_0] = 0;
L[2+_1] = bits[0];
break;
}
j = 32 - i;
L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff)
| ((j + 1) << 20);
L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL;
L[2+_0] = 0;
L[2+_1] = bits[0] & ((1L << j) - 1);
break;
hardly_normal:
j = 11 - hi0bits(bits[1]);
i = 32 - j;
L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20);
L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL;
L[2+_0] = 0;
L[2+_1] = bits[0] & (((ULong)1L << j) - 1);
break;
case STRTOG_Infinite:
L[_0] = L[2+_0] = 0x7ff00000;
L[_1] = L[2+_1] = 0;
break;
case STRTOG_NaN:
L[_0] = L[_0+2] = NanDflt_d_D2A[1];
L[_1] = L[_1+2] = NanDflt_d_D2A[0];
break;
case STRTOG_NaNbits:
L[_1] = (bits[1] >> 20 | bits[2] << 12) & (ULong)0xffffffffL;
L[_0] = bits[2] >> 20 | bits[3] << 12;
L[_0] |= (L[_1] | L[_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L;
L[2+_1] = bits[0] & (ULong)0xffffffffL;
L[2+_0] = bits[1] & 0xfffffL;
L[2+_0] |= (L[2+_1] | L[2+_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L;
}
if (k & STRTOG_Neg) {
L[_0] |= 0x80000000L;
L[2+_0] |= 0x80000000L;
}
}
int
#ifdef KR_headers
strtordd(s, sp, rounding, dd) CONST char *s; char **sp; int rounding; double *dd;
#else
strtordd(CONST char *s, char **sp, int rounding, double *dd)
#endif
{
#ifdef Sudden_Underflow
static const FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1, 0 /*unused*/ };
#else
static const FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0, 0 /*unused*/ };
#endif
FPI *fpi, fpi1;
ULong bits[4];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtodd((ULong*)dd, bits, exp, k);
return k;
}

92
third_party/gdtoa/strtorf.c vendored Normal file
View file

@ -0,0 +1,92 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
extern ULong NanDflt_f_D2A[1];
void
#ifdef KR_headers
ULtof(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k;
#else
ULtof(ULong *L, ULong *bits, Long exp, int k)
#endif
{
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
*L = 0;
break;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23);
break;
case STRTOG_Denormal:
L[0] = bits[0];
break;
case STRTOG_Infinite:
L[0] = 0x7f800000;
break;
case STRTOG_NaN:
L[0] = NanDflt_f_D2A[0];
}
if (k & STRTOG_Neg)
L[0] |= 0x80000000L;
}
int
#ifdef KR_headers
strtorf(s, sp, rounding, f) CONST char *s; char **sp; int rounding; float *f;
#else
strtorf(CONST char *s, char **sp, int rounding, float *f)
#endif
{
static const FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI, 0 /*unused*/ };
FPI *fpi, fpi1;
ULong bits[1];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtof((ULong*)f, bits, exp, k);
return k;
}

123
third_party/gdtoa/strtorx.c vendored Normal file
View file

@ -0,0 +1,123 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#define _3 3
#define _4 4
#endif
#ifdef IEEE_8087
#define _0 4
#define _1 3
#define _2 2
#define _3 1
#define _4 0
#endif
extern UShort NanDflt_ldus_D2A[5];
void
#ifdef KR_headers
ULtox(L, bits, exp, k) UShort *L; ULong *bits; Long exp; int k;
#else
ULtox(UShort *L, ULong *bits, Long exp, int k)
#endif
{
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = L[3] = L[4] = 0;
break;
case STRTOG_Denormal:
L[_0] = 0;
goto normal_bits;
case STRTOG_Normal:
case STRTOG_NaNbits:
L[_0] = exp + 0x3fff + 63;
normal_bits:
L[_4] = (UShort)bits[0];
L[_3] = (UShort)(bits[0] >> 16);
L[_2] = (UShort)bits[1];
L[_1] = (UShort)(bits[1] >> 16);
break;
case STRTOG_Infinite:
L[_0] = 0x7fff;
L[_1] = 0x8000;
L[_2] = L[_3] = L[_4] = 0;
break;
case STRTOG_NaN:
L[_4] = NanDflt_ldus_D2A[0];
L[_3] = NanDflt_ldus_D2A[1];
L[_2] = NanDflt_ldus_D2A[2];
L[_1] = NanDflt_ldus_D2A[3];
L[_0] = NanDflt_ldus_D2A[4];
}
if (k & STRTOG_Neg)
L[_0] |= 0x8000;
}
int
#ifdef KR_headers
strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
#else
strtorx(CONST char *s, char **sp, int rounding, void *L)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
FPI *fpi, fpi1;
ULong bits[2];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtox((UShort*)L, bits, exp, k);
return k;
}

111
third_party/gdtoa/strtorxL.c vendored Normal file
View file

@ -0,0 +1,111 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 2000 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
#undef _0
#undef _1
/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
#ifdef IEEE_MC68k
#define _0 0
#define _1 1
#define _2 2
#endif
#ifdef IEEE_8087
#define _0 2
#define _1 1
#define _2 0
#endif
extern ULong NanDflt_xL_D2A[3];
void
#ifdef KR_headers
ULtoxL(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k;
#else
ULtoxL(ULong *L, ULong *bits, Long exp, int k)
#endif
{
switch(k & STRTOG_Retmask) {
case STRTOG_NoNumber:
case STRTOG_Zero:
L[0] = L[1] = L[2] = 0;
break;
case STRTOG_Normal:
case STRTOG_Denormal:
case STRTOG_NaNbits:
L[_0] = (exp + 0x3fff + 63) << 16;
L[_1] = bits[1];
L[_2] = bits[0];
break;
case STRTOG_Infinite:
L[_0] = 0x7fff0000;
L[_1] = 0x80000000;
L[_2] = 0;
break;
case STRTOG_NaN:
L[_0] = NanDflt_xL_D2A[2];
L[_1] = NanDflt_xL_D2A[1];
L[_2] = NanDflt_xL_D2A[0];
}
if (k & STRTOG_Neg)
L[_0] |= 0x80000000L;
}
int
#ifdef KR_headers
strtorxL(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
#else
strtorxL(CONST char *s, char **sp, int rounding, void *L)
#endif
{
static const FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, 0 /*unused*/ };
FPI *fpi, fpi1;
ULong bits[2];
Long exp;
int k;
fpi = &fpi0;
if (rounding != FPI_Round_near) {
fpi1 = fpi0;
fpi1.rounding = rounding;
fpi = &fpi1;
}
k = strtodg(s, sp, fpi, &exp, bits);
ULtoxL((ULong*)L, bits, exp, k);
return k;
}

99
third_party/gdtoa/sum.c vendored Normal file
View file

@ -0,0 +1,99 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
Bigint *
#ifdef KR_headers
sum(a, b MTa) Bigint *a; Bigint *b; MTk
#else
sum(Bigint *a, Bigint *b MTd)
#endif
{
Bigint *c;
ULong carry, *xc, *xa, *xb, *xe, y;
#ifdef Pack_32
ULong z;
#endif
if (a->wds < b->wds) {
c = b; b = a; a = c;
}
c = Balloc(a->k MTa);
c->wds = a->wds;
carry = 0;
xa = a->x;
xb = b->x;
xc = c->x;
xe = xc + b->wds;
#ifdef Pack_32
do {
y = (*xa & 0xffff) + (*xb & 0xffff) + carry;
carry = (y & 0x10000) >> 16;
z = (*xa++ >> 16) + (*xb++ >> 16) + carry;
carry = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
while(xc < xe);
xe += a->wds - b->wds;
while(xc < xe) {
y = (*xa & 0xffff) + carry;
carry = (y & 0x10000) >> 16;
z = (*xa++ >> 16) + carry;
carry = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
#else
do {
y = *xa++ + *xb++ + carry;
carry = (y & 0x10000) >> 16;
*xc++ = y & 0xffff;
}
while(xc < xe);
xe += a->wds - b->wds;
while(xc < xe) {
y = *xa++ + carry;
carry = (y & 0x10000) >> 16;
*xc++ = y & 0xffff;
}
#endif
if (carry) {
if (c->wds == c->maxwds) {
b = Balloc(c->k + 1 MTa);
Bcopy(b, c);
Bfree(c MTa);
c = b;
}
c->x[c->wds++] = 1;
}
return c;
}

71
third_party/gdtoa/ulp.c vendored Normal file
View file

@ -0,0 +1,71 @@
#include "third_party/gdtoa/gdtoaimp.h"
/* clang-format off */
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
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 and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, 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.
****************************************************************/
/* Please send bug reports to David M. Gay (dmg at acm dot org,
* with " at " changed at "@" and " dot " changed to "."). */
double
ulp
#ifdef KR_headers
(x) U *x;
#else
(U *x)
#endif
{
Long L;
U a;
L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
#ifndef Sudden_Underflow
if (L > 0) {
#endif
#ifdef IBM
L |= Exp_msk1 >> 4;
#endif
word0(&a) = L;
word1(&a) = 0;
#ifndef Sudden_Underflow
}
else {
L = -L >> Exp_shift;
if (L < Exp_shift) {
word0(&a) = 0x80000 >> L;
word1(&a) = 0;
}
else {
word0(&a) = 0;
L -= Exp_shift;
word1(&a) = L >= 31 ? 1 : 1 << (31 - L);
}
}
#endif
return dval(&a);
}

View file

@ -6,10 +6,12 @@ o/$(MODE)/third_party: \
o/$(MODE)/third_party/avir \
o/$(MODE)/third_party/blas \
o/$(MODE)/third_party/bzip2 \
o/$(MODE)/third_party/chibicc \
o/$(MODE)/third_party/compiler_rt \
o/$(MODE)/third_party/ctags \
o/$(MODE)/third_party/dlmalloc \
o/$(MODE)/third_party/dtoa \
o/$(MODE)/third_party/gdtoa \
o/$(MODE)/third_party/duktape \
o/$(MODE)/third_party/editline \
o/$(MODE)/third_party/f2c \