aboutsummaryrefslogtreecommitdiff
path: root/src/stage1/bigfloat.cpp
blob: 58b0aff54af01bc6dbc1ab8bac778c883aba2edc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * 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 "parse_f128.h"
#include <stdio.h>
#include <math.h>
#include <errno.h>


void bigfloat_init_128(BigFloat *dest, float128_t x) {
    dest->value = x;
}

void bigfloat_init_16(BigFloat *dest, float16_t x) {
    f16_to_f128M(x, &dest->value);
}

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);
    float128_t one_f128;
    ui32_to_f128M(1, &one_f128);
    f128M_add(&base, &one_f128, &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;
    }
}

Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) {
    char *str_begin = (char *)buf_ptr;
    char *str_end;

    errno = 0;
    dest->value = parse_f128(str_begin, &str_end);
    if (errno) {
        return ErrorOverflow;
    }

    assert(str_end <= ((char*)buf_ptr) + buf_len);
    return ErrorNone;
}

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;
    }
}

float16_t bigfloat_to_f16(const BigFloat *bigfloat) {
    return f128M_to_f16(&bigfloat->value);
}

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);
}

void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) {
    f128M_sqrt(&op->value, &dest->value);
}

bool bigfloat_is_nan(const BigFloat *op) {
    return f128M_isSignalingNaN(&op->value);
}