blob c1bfcbbb (4792B) - Raw
1 /* 2 * Copyright (c) 2017 Andrew Kelley 3 * 4 * This file is part of zig, which is MIT licensed. 5 * See http://opensource.org/licenses/MIT 6 */ 7 8 #include "bigfloat.hpp" 9 #include "bigint.hpp" 10 #include "buffer.hpp" 11 #include <math.h> 12 #include <errno.h> 13 14 extern "C" { 15 __float128 fmodq(__float128 a, __float128 b); 16 __float128 ceilq(__float128 a); 17 __float128 floorq(__float128 a); 18 __float128 strtoflt128 (const char *s, char **sp); 19 int quadmath_snprintf (char *s, size_t size, const char *format, ...); 20 } 21 22 23 void bigfloat_init_float(BigFloat *dest, __float128 x) { 24 dest->value = x; 25 } 26 27 void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { 28 dest->value = x->value; 29 } 30 31 void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { 32 dest->value = 0.0; 33 if (op->digit_count == 0) 34 return; 35 36 __float128 base = (__float128)UINT64_MAX; 37 const uint64_t *digits = bigint_ptr(op); 38 39 for (size_t i = op->digit_count - 1;;) { 40 uint64_t digit = digits[i]; 41 dest->value *= base; 42 dest->value += (__float128)digit; 43 44 if (i == 0) { 45 if (op->is_negative) { 46 dest->value = -dest->value; 47 } 48 return; 49 } 50 i -= 1; 51 } 52 } 53 54 int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) { 55 char *str_begin = (char *)buf_ptr; 56 char *str_end; 57 errno = 0; 58 dest->value = strtoflt128(str_begin, &str_end); 59 if (errno) { 60 return ErrorOverflow; 61 } 62 assert(str_end <= ((char*)buf_ptr) + buf_len); 63 return 0; 64 } 65 66 void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 67 dest->value = op1->value + op2->value; 68 } 69 70 void bigfloat_negate(BigFloat *dest, const BigFloat *op) { 71 dest->value = -op->value; 72 } 73 74 void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 75 dest->value = op1->value - op2->value; 76 } 77 78 void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 79 dest->value = op1->value * op2->value; 80 } 81 82 void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 83 dest->value = op1->value / op2->value; 84 } 85 86 void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 87 dest->value = op1->value / op2->value; 88 if (dest->value >= 0.0) { 89 dest->value = floorq(dest->value); 90 } else { 91 dest->value = ceilq(dest->value); 92 } 93 } 94 95 void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 96 dest->value = floorq(op1->value / op2->value); 97 } 98 99 void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 100 dest->value = fmodq(op1->value, op2->value); 101 } 102 103 void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { 104 dest->value = fmodq(fmodq(op1->value, op2->value) + op2->value, op2->value); 105 } 106 107 void bigfloat_write_buf(Buf *buf, const BigFloat *op) { 108 buf_resize(buf, 256); 109 int len = quadmath_snprintf(buf_ptr(buf), buf_len(buf), "%Qf", op->value); 110 assert(len > 0); 111 buf_resize(buf, len); 112 } 113 114 Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { 115 if (op1->value > op2->value) { 116 return CmpGT; 117 } else if (op1->value < op2->value) { 118 return CmpLT; 119 } else { 120 return CmpEQ; 121 } 122 } 123 124 // TODO this is wrong when compiler running on big endian systems. caught by tests 125 void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian) { 126 if (bit_count == 32) { 127 float f32 = op->value; 128 memcpy(buf, &f32, 4); 129 } else if (bit_count == 64) { 130 double f64 = op->value; 131 memcpy(buf, &f64, 8); 132 } else if (bit_count == 128) { 133 __float128 f128 = op->value; 134 memcpy(buf, &f128, 16); 135 } else { 136 zig_unreachable(); 137 } 138 } 139 140 // TODO this is wrong when compiler running on big endian systems. caught by tests 141 void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian) { 142 if (bit_count == 32) { 143 float f32; 144 memcpy(&f32, buf, 4); 145 dest->value = f32; 146 } else if (bit_count == 64) { 147 double f64; 148 memcpy(&f64, buf, 8); 149 dest->value = f64; 150 } else if (bit_count == 128) { 151 __float128 f128; 152 memcpy(&f128, buf, 16); 153 dest->value = f128; 154 } else { 155 zig_unreachable(); 156 } 157 } 158 159 double bigfloat_to_double(const BigFloat *bigfloat) { 160 return bigfloat->value; 161 } 162 163 Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { 164 if (bigfloat->value < 0.0) { 165 return CmpLT; 166 } else if (bigfloat->value > 0.0) { 167 return CmpGT; 168 } else { 169 return CmpEQ; 170 } 171 } 172 173 bool bigfloat_has_fraction(const BigFloat *bigfloat) { 174 return floorq(bigfloat->value) != bigfloat->value; 175 }