diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-09-14 01:47:53 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-09-14 01:47:53 -0400 |
| commit | 75b1c71cb300b88625cd93ebf21d41361b65e2c7 (patch) | |
| tree | 9aaa94dece961979989e00d40a36a396fe5ea079 /src/bigfloat.cpp | |
| parent | bb44e4b479c89f029fef44aac11a8202a457c1b2 (diff) | |
| parent | 14cda27b640651829b1d8af996392b650c7835a5 (diff) | |
| download | zig-75b1c71cb300b88625cd93ebf21d41361b65e2c7.tar.gz zig-75b1c71cb300b88625cd93ebf21d41361b65e2c7.zip | |
Merge branch 'soft-float'
Diffstat (limited to 'src/bigfloat.cpp')
| -rw-r--r-- | src/bigfloat.cpp | 111 |
1 files changed, 72 insertions, 39 deletions
diff --git a/src/bigfloat.cpp b/src/bigfloat.cpp index 33cff544cc..2cab9658e8 100644 --- a/src/bigfloat.cpp +++ b/src/bigfloat.cpp @@ -8,42 +8,52 @@ #include "bigfloat.hpp" #include "bigint.hpp" #include "buffer.hpp" -#include "quadmath.hpp" +#include "softfloat.hpp" +#include <stdio.h> #include <math.h> #include <errno.h> -void bigfloat_init_128(BigFloat *dest, __float128 x) { + +void bigfloat_init_128(BigFloat *dest, float128_t x) { dest->value = x; } void bigfloat_init_32(BigFloat *dest, float x) { - dest->value = x; + float32_t f32_val; + memcpy(&f32_val, &x, sizeof(float)); + f32_to_f128M(f32_val, &dest->value); } void bigfloat_init_64(BigFloat *dest, double x) { - dest->value = x; + float64_t f64_val; + memcpy(&f64_val, &x, sizeof(double)); + f64_to_f128M(f64_val, &dest->value); } void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { - dest->value = x->value; + memcpy(&dest->value, &x->value, sizeof(float128_t)); } void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { - dest->value = 0.0; + ui32_to_f128M(0, &dest->value); if (op->digit_count == 0) return; - __float128 base = (__float128)UINT64_MAX; + float128_t base; + ui64_to_f128M(UINT64_MAX, &base); 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 += (__float128)digit; + float128_t digit_f128; + ui64_to_f128M(digits[i], &digit_f128); + + f128M_mulAdd(&dest->value, &base, &digit_f128, &dest->value); if (i == 0) { if (op->is_negative) { - dest->value = -dest->value; + float128_t zero_f128; + ui32_to_f128M(0, &zero_f128); + f128M_sub(&zero_f128, &dest->value, &dest->value); } return; } @@ -54,97 +64,120 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { 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 = strtoflt128(str_begin, &str_end); + double value = strtod(str_begin, &str_end); // TODO actual f128 parsing if (errno) { return ErrorOverflow; } + + float64_t value_f64; + memcpy(&value_f64, &value, sizeof(double)); + f64_to_f128M(value_f64, &dest->value); + 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; + f128M_add(&op1->value, &op2->value, &dest->value); } void bigfloat_negate(BigFloat *dest, const BigFloat *op) { - dest->value = -op->value; + float128_t zero_f128; + ui32_to_f128M(0, &zero_f128); + f128M_sub(&zero_f128, &op->value, &dest->value); } void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = op1->value - op2->value; + f128M_sub(&op1->value, &op2->value, &dest->value); } void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = op1->value * op2->value; + f128M_mul(&op1->value, &op2->value, &dest->value); } void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = op1->value / op2->value; + f128M_div(&op1->value, &op2->value, &dest->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 = floorq(dest->value); - } else { - dest->value = ceilq(dest->value); - } + f128M_div(&op1->value, &op2->value, &dest->value); + f128M_roundToInt(&dest->value, softfloat_round_minMag, false, &dest->value); } void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = floorq(op1->value / op2->value); + f128M_div(&op1->value, &op2->value, &dest->value); + f128M_roundToInt(&dest->value, softfloat_round_min, false, &dest->value); } void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = fmodq(op1->value, op2->value); + f128M_rem(&op1->value, &op2->value, &dest->value); } void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - dest->value = fmodq(fmodq(op1->value, op2->value) + op2->value, op2->value); + f128M_rem(&op1->value, &op2->value, &dest->value); + f128M_add(&dest->value, &op2->value, &dest->value); + f128M_rem(&dest->value, &op2->value, &dest->value); } void bigfloat_append_buf(Buf *buf, const BigFloat *op) { const size_t extra_len = 100; size_t old_len = buf_len(buf); buf_resize(buf, old_len + extra_len); - int len = quadmath_snprintf(buf_ptr(buf) + old_len, extra_len, "%Qf", op->value); + + // TODO actually print f128 + float64_t f64_value = f128M_to_f64(&op->value); + double double_value; + memcpy(&double_value, &f64_value, sizeof(double)); + + int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); assert(len > 0); buf_resize(buf, old_len + len); } Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { - if (op1->value > op2->value) { - return CmpGT; - } else if (op1->value < op2->value) { + if (f128M_lt(&op1->value, &op2->value)) { return CmpLT; - } else { + } else if (f128M_eq(&op1->value, &op2->value)) { return CmpEQ; + } else { + return CmpGT; } } float bigfloat_to_f32(const BigFloat *bigfloat) { - return (float)bigfloat->value; + float32_t f32_value = f128M_to_f32(&bigfloat->value); + float result; + memcpy(&result, &f32_value, sizeof(float)); + return result; } double bigfloat_to_f64(const BigFloat *bigfloat) { - return (double)bigfloat->value; + float64_t f64_value = f128M_to_f64(&bigfloat->value); + double result; + memcpy(&result, &f64_value, sizeof(double)); + return result; } -__float128 bigfloat_to_f128(const BigFloat *bigfloat) { +float128_t bigfloat_to_f128(const BigFloat *bigfloat) { return bigfloat->value; } Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { - if (bigfloat->value < 0.0) { + float128_t zero_float; + ui32_to_f128M(0, &zero_float); + if (f128M_lt(&bigfloat->value, &zero_float)) { return CmpLT; - } else if (bigfloat->value > 0.0) { - return CmpGT; - } else { + } else if (f128M_eq(&bigfloat->value, &zero_float)) { return CmpEQ; + } else { + return CmpGT; } } bool bigfloat_has_fraction(const BigFloat *bigfloat) { - return floorq(bigfloat->value) != bigfloat->value; + float128_t floored; + f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored); + return !f128M_eq(&floored, &bigfloat->value); } |
