14cda27b64
See #302 See #467
184 lines
5.2 KiB
C++
184 lines
5.2 KiB
C++
/*
|
|
* 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 "softfloat.hpp"
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
|
|
|
|
void bigfloat_init_128(BigFloat *dest, float128_t x) {
|
|
dest->value = x;
|
|
}
|
|
|
|
void bigfloat_init_32(BigFloat *dest, float 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) {
|
|
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) {
|
|
memcpy(&dest->value, &x->value, sizeof(float128_t));
|
|
}
|
|
|
|
void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
|
|
ui32_to_f128M(0, &dest->value);
|
|
if (op->digit_count == 0)
|
|
return;
|
|
|
|
float128_t base;
|
|
ui64_to_f128M(UINT64_MAX, &base);
|
|
const uint64_t *digits = bigint_ptr(op);
|
|
|
|
for (size_t i = op->digit_count - 1;;) {
|
|
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) {
|
|
float128_t zero_f128;
|
|
ui32_to_f128M(0, &zero_f128);
|
|
f128M_sub(&zero_f128, &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;
|
|
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) {
|
|
f128M_add(&op1->value, &op2->value, &dest->value);
|
|
}
|
|
|
|
void bigfloat_negate(BigFloat *dest, const BigFloat *op) {
|
|
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) {
|
|
f128M_sub(&op1->value, &op2->value, &dest->value);
|
|
}
|
|
|
|
void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
|
f128M_mul(&op1->value, &op2->value, &dest->value);
|
|
}
|
|
|
|
void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
|
f128M_div(&op1->value, &op2->value, &dest->value);
|
|
}
|
|
|
|
void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
|
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) {
|
|
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) {
|
|
f128M_rem(&op1->value, &op2->value, &dest->value);
|
|
}
|
|
|
|
void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
|
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);
|
|
|
|
// 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 (f128M_lt(&op1->value, &op2->value)) {
|
|
return CmpLT;
|
|
} else if (f128M_eq(&op1->value, &op2->value)) {
|
|
return CmpEQ;
|
|
} else {
|
|
return CmpGT;
|
|
}
|
|
}
|
|
|
|
float bigfloat_to_f32(const BigFloat *bigfloat) {
|
|
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) {
|
|
float64_t f64_value = f128M_to_f64(&bigfloat->value);
|
|
double result;
|
|
memcpy(&result, &f64_value, sizeof(double));
|
|
return result;
|
|
}
|
|
|
|
float128_t bigfloat_to_f128(const BigFloat *bigfloat) {
|
|
return bigfloat->value;
|
|
}
|
|
|
|
Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {
|
|
float128_t zero_float;
|
|
ui32_to_f128M(0, &zero_float);
|
|
if (f128M_lt(&bigfloat->value, &zero_float)) {
|
|
return CmpLT;
|
|
} else if (f128M_eq(&bigfloat->value, &zero_float)) {
|
|
return CmpEQ;
|
|
} else {
|
|
return CmpGT;
|
|
}
|
|
}
|
|
|
|
bool bigfloat_has_fraction(const BigFloat *bigfloat) {
|
|
float128_t floored;
|
|
f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored);
|
|
return !f128M_eq(&floored, &bigfloat->value);
|
|
}
|