diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-06-26 14:41:47 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-07-08 17:59:10 -0400 |
| commit | d1e68c3ca84844a96d4897c857861b40751965cc (patch) | |
| tree | 8866451296719e1c1c0850bb31a213d081c22352 /src/bigfloat.cpp | |
| parent | 3e8af78895d313f0706389da2ad7e5c60df95964 (diff) | |
| download | zig-d1e68c3ca84844a96d4897c857861b40751965cc.tar.gz zig-d1e68c3ca84844a96d4897c857861b40751965cc.zip | |
better bigint/bigfloat implementation
Diffstat (limited to 'src/bigfloat.cpp')
| -rw-r--r-- | src/bigfloat.cpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/bigfloat.cpp b/src/bigfloat.cpp new file mode 100644 index 0000000000..3986efc19d --- /dev/null +++ b/src/bigfloat.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "bigfloat.hpp" +#include "bigint.hpp" +#include "buffer.hpp" +#include <math.h> +#include <errno.h> + +void bigfloat_init_float(BigFloat *dest, long double x) { + dest->value = x; +} + +void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { + dest->value = x->value; +} + +void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { + dest->value = 0.0; + if (op->digit_count == 0) + return; + + long double base = (long double)UINT64_MAX; + const uint64_t *digits = bigint_ptr(op); + + for (size_t i = op->digit_count - 1;;) { + uint64_t digit = digits[i]; + dest->value *= base; + dest->value += (long double)digit; + + if (i == 0) { + if (op->is_negative) { + dest->value = -dest->value; + } + return; + } + i -= 1; + } +} + +int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) { + char *str_begin = (char *)buf_ptr; + char *str_end; + errno = 0; + dest->value = strtold(str_begin, &str_end); + if (errno) { + return ErrorOverflow; + } + assert(str_end <= ((char*)buf_ptr) + buf_len); + return 0; +} + +void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = op1->value + op2->value; +} + +void bigfloat_negate(BigFloat *dest, const BigFloat *op) { + dest->value = -op->value; +} + +void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = op1->value - op2->value; +} + +void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = op1->value * op2->value; +} + +void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = op1->value / op2->value; +} + +void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = op1->value / op2->value; + if (dest->value >= 0.0) { + dest->value = floorl(dest->value); + } else { + dest->value = ceill(dest->value); + } +} + +void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = floorl(op1->value / op2->value); +} + +void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = fmodl(op1->value, op2->value); +} + +void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { + dest->value = fmodl(fmodl(op1->value, op2->value) + op2->value, op2->value); +} + +void bigfloat_write_buf(Buf *buf, const BigFloat *op) { + buf_appendf(buf, "%Lf", op->value); +} + +Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { + if (op1->value > op2->value) { + return CmpGT; + } else if (op1->value < op2->value) { + return CmpLT; + } else { + return CmpEQ; + } +} + +// TODO this is wrong when compiler running on big endian systems. caught by tests +void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian) { + if (bit_count == 32) { + float f32 = op->value; + memcpy(buf, &f32, 4); + } else if (bit_count == 64) { + double f64 = op->value; + memcpy(buf, &f64, 8); + } else { + zig_unreachable(); + } +} + +// TODO this is wrong when compiler running on big endian systems. caught by tests +void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian) { + if (bit_count == 32) { + float f32; + memcpy(&f32, buf, 4); + dest->value = f32; + } else if (bit_count == 64) { + double f64; + memcpy(&f64, buf, 8); + dest->value = f64; + } else { + zig_unreachable(); + } +} + +double bigfloat_to_double(const BigFloat *bigfloat) { + return bigfloat->value; +} + +Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { + if (bigfloat->value < 0.0) { + return CmpLT; + } else if (bigfloat->value > 0.0) { + return CmpGT; + } else { + return CmpEQ; + } +} |
