zig

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

blob 3986efc1 (4073B) - 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 void bigfloat_init_float(BigFloat *dest, long double x) {
     15     dest->value = x;
     16 }
     17 
     18 void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) {
     19     dest->value = x->value;
     20 }
     21 
     22 void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
     23     dest->value = 0.0;
     24     if (op->digit_count == 0)
     25         return;
     26 
     27     long double base = (long double)UINT64_MAX;
     28     const uint64_t *digits = bigint_ptr(op);
     29 
     30     for (size_t i = op->digit_count - 1;;) {
     31         uint64_t digit = digits[i];
     32         dest->value *= base;
     33         dest->value += (long double)digit;
     34 
     35         if (i == 0) {
     36             if (op->is_negative) {
     37                 dest->value = -dest->value;
     38             }
     39             return;
     40         }
     41         i -= 1;
     42     }
     43 }
     44 
     45 int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) {
     46     char *str_begin = (char *)buf_ptr;
     47     char *str_end;
     48     errno = 0;
     49     dest->value = strtold(str_begin, &str_end);
     50     if (errno) {
     51         return ErrorOverflow;
     52     }
     53     assert(str_end <= ((char*)buf_ptr) + buf_len);
     54     return 0;
     55 }
     56 
     57 void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     58     dest->value = op1->value + op2->value;
     59 }
     60 
     61 void bigfloat_negate(BigFloat *dest, const BigFloat *op) {
     62     dest->value = -op->value;
     63 }
     64 
     65 void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     66     dest->value = op1->value - op2->value;
     67 }
     68 
     69 void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     70     dest->value = op1->value * op2->value;
     71 }
     72 
     73 void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     74     dest->value = op1->value / op2->value;
     75 }
     76 
     77 void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     78     dest->value = op1->value / op2->value;
     79     if (dest->value >= 0.0) {
     80         dest->value = floorl(dest->value);
     81     } else {
     82         dest->value = ceill(dest->value);
     83     }
     84 }
     85 
     86 void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     87     dest->value = floorl(op1->value / op2->value);
     88 }
     89 
     90 void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     91     dest->value = fmodl(op1->value, op2->value);
     92 }
     93 
     94 void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
     95     dest->value = fmodl(fmodl(op1->value, op2->value) + op2->value, op2->value);
     96 }
     97 
     98 void bigfloat_write_buf(Buf *buf, const BigFloat *op) {
     99     buf_appendf(buf, "%Lf", op->value);
    100 }
    101 
    102 Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
    103     if (op1->value > op2->value) {
    104         return CmpGT;
    105     } else if (op1->value < op2->value) {
    106         return CmpLT;
    107     } else {
    108         return CmpEQ;
    109     }
    110 }
    111 
    112 // TODO this is wrong when compiler running on big endian systems. caught by tests
    113 void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian) {
    114     if (bit_count == 32) {
    115         float f32 = op->value;
    116         memcpy(buf, &f32, 4);
    117     } else if (bit_count == 64) {
    118         double f64 = op->value;
    119         memcpy(buf, &f64, 8);
    120     } else {
    121         zig_unreachable();
    122     }
    123 }
    124 
    125 // TODO this is wrong when compiler running on big endian systems. caught by tests
    126 void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian) {
    127     if (bit_count == 32) {
    128         float f32;
    129         memcpy(&f32, buf, 4);
    130         dest->value = f32;
    131     } else if (bit_count == 64) {
    132         double f64;
    133         memcpy(&f64, buf, 8);
    134         dest->value = f64;
    135     } else {
    136         zig_unreachable();
    137     }
    138 }
    139 
    140 double bigfloat_to_double(const BigFloat *bigfloat) {
    141     return bigfloat->value;
    142 }
    143 
    144 Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {
    145     if (bigfloat->value < 0.0) {
    146         return CmpLT;
    147     } else if (bigfloat->value > 0.0) {
    148         return CmpGT;
    149     } else {
    150         return CmpEQ;
    151     }
    152 }