zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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 }