]>
Commit | Line | Data |
---|---|---|
fd27ffab | 1 | /* Simple data type for real numbers for the GNU compiler. |
5624e564 | 2 | Copyright (C) 2002-2015 Free Software Foundation, Inc. |
ac5e69da JZ |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it under | |
7 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 8 | Software Foundation; either version 3, or (at your option) any later |
ac5e69da JZ |
9 | version. |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
ac5e69da | 19 | |
fd27ffab | 20 | /* This library supports real numbers; |
ac5e69da JZ |
21 | inf and nan are NOT supported. |
22 | It is written to be simple and fast. | |
23 | ||
24 | Value of sreal is | |
25 | x = sig * 2 ^ exp | |
46c5ad27 | 26 | where |
ac5e69da JZ |
27 | sig = significant |
28 | (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS) | |
29 | exp = exponent | |
30 | ||
618b7f29 | 31 | One uint64_t is used for the significant. |
ac5e69da JZ |
32 | Only a half of significant bits is used (in normalized sreals) so that we do |
33 | not have problems with overflow, for example when c->sig = a->sig * b->sig. | |
618b7f29 | 34 | So the precision is 32-bit. |
46c5ad27 | 35 | |
ac5e69da JZ |
36 | Invariant: The numbers are normalized before and after each call of sreal_*. |
37 | ||
38 | Normalized sreals: | |
39 | All numbers (except zero) meet following conditions: | |
40 | SREAL_MIN_SIG <= sig && sig <= SREAL_MAX_SIG | |
46c5ad27 | 41 | -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP |
ac5e69da JZ |
42 | |
43 | If the number would be too large, it is set to upper bounds of these | |
44 | conditions. | |
45 | ||
46 | If the number is zero or would be too small it meets following conditions: | |
47 | sig == 0 && exp == -SREAL_MAX_EXP | |
48 | */ | |
49 | ||
50 | #include "config.h" | |
51 | #include "system.h" | |
bc1c9c22 | 52 | #include <math.h> |
ac5e69da | 53 | #include "coretypes.h" |
ac5e69da JZ |
54 | #include "sreal.h" |
55 | ||
ac5e69da JZ |
56 | /* Print the content of struct sreal. */ |
57 | ||
58 | void | |
618b7f29 | 59 | sreal::dump (FILE *file) const |
ac5e69da | 60 | { |
618b7f29 | 61 | fprintf (file, "(%" PRIu64 " * 2^%d)", m_sig, m_exp); |
ac5e69da JZ |
62 | } |
63 | ||
7b3b6ae4 | 64 | DEBUG_FUNCTION void |
d1704358 | 65 | debug (const sreal &ref) |
7b3b6ae4 | 66 | { |
618b7f29 | 67 | ref.dump (stderr); |
7b3b6ae4 LC |
68 | } |
69 | ||
70 | DEBUG_FUNCTION void | |
d1704358 | 71 | debug (const sreal *ptr) |
7b3b6ae4 LC |
72 | { |
73 | if (ptr) | |
74 | debug (*ptr); | |
75 | else | |
76 | fprintf (stderr, "<nil>\n"); | |
77 | } | |
78 | ||
618b7f29 TS |
79 | /* Shift this right by S bits. Needed: 0 < S <= SREAL_BITS. |
80 | When the most significant bit shifted out is 1, add 1 to this (rounding). | |
81 | */ | |
7b3b6ae4 | 82 | |
618b7f29 TS |
83 | void |
84 | sreal::shift_right (int s) | |
ac5e69da | 85 | { |
fd27ffab ML |
86 | gcc_checking_assert (s > 0); |
87 | gcc_checking_assert (s <= SREAL_BITS); | |
41374e13 NS |
88 | /* Exponent should never be so large because shift_right is used only by |
89 | sreal_add and sreal_sub ant thus the number cannot be shifted out from | |
90 | exponent range. */ | |
fd27ffab | 91 | gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP); |
ac5e69da | 92 | |
618b7f29 | 93 | m_exp += s; |
ac5e69da | 94 | |
d1704358 | 95 | m_sig += (int64_t) 1 << (s - 1); |
618b7f29 | 96 | m_sig >>= s; |
ac5e69da JZ |
97 | } |
98 | ||
618b7f29 | 99 | /* Return integer value of *this. */ |
ac5e69da | 100 | |
618b7f29 TS |
101 | int64_t |
102 | sreal::to_int () const | |
ac5e69da | 103 | { |
d1704358 | 104 | int64_t sign = m_sig < 0 ? -1 : 1; |
fd27ffab | 105 | |
618b7f29 | 106 | if (m_exp <= -SREAL_BITS) |
ac5e69da | 107 | return 0; |
618b7f29 | 108 | if (m_exp >= SREAL_PART_BITS) |
fd27ffab | 109 | return sign * INTTYPE_MAXIMUM (int64_t); |
618b7f29 | 110 | if (m_exp > 0) |
d1704358 | 111 | return m_sig << m_exp; |
618b7f29 | 112 | if (m_exp < 0) |
d1704358 ML |
113 | return m_sig >> -m_exp; |
114 | return m_sig; | |
ac5e69da JZ |
115 | } |
116 | ||
2bef63e1 JH |
117 | /* Return value of *this as double. |
118 | This should be used for debug output only. */ | |
119 | ||
120 | double | |
121 | sreal::to_double () const | |
122 | { | |
123 | double val = m_sig; | |
124 | if (m_exp) | |
125 | val *= exp2 (m_exp); | |
126 | return val; | |
127 | } | |
128 | ||
618b7f29 | 129 | /* Return *this + other. */ |
ac5e69da | 130 | |
618b7f29 TS |
131 | sreal |
132 | sreal::operator+ (const sreal &other) const | |
ac5e69da | 133 | { |
fd27ffab | 134 | int dexp; |
d1704358 ML |
135 | sreal tmp, r; |
136 | ||
137 | const sreal *a_p = this, *b_p = &other, *bb; | |
fd27ffab | 138 | |
8301b194 | 139 | if (a_p->m_exp < b_p->m_exp) |
fd27ffab ML |
140 | std::swap (a_p, b_p); |
141 | ||
618b7f29 TS |
142 | dexp = a_p->m_exp - b_p->m_exp; |
143 | r.m_exp = a_p->m_exp; | |
ac5e69da JZ |
144 | if (dexp > SREAL_BITS) |
145 | { | |
618b7f29 | 146 | r.m_sig = a_p->m_sig; |
ac5e69da JZ |
147 | return r; |
148 | } | |
149 | ||
150 | if (dexp == 0) | |
618b7f29 | 151 | bb = b_p; |
ac5e69da JZ |
152 | else |
153 | { | |
618b7f29 TS |
154 | tmp = *b_p; |
155 | tmp.shift_right (dexp); | |
ac5e69da JZ |
156 | bb = &tmp; |
157 | } | |
158 | ||
618b7f29 TS |
159 | r.m_sig = a_p->m_sig + bb->m_sig; |
160 | r.normalize (); | |
ac5e69da JZ |
161 | return r; |
162 | } | |
163 | ||
d1704358 | 164 | |
618b7f29 | 165 | /* Return *this - other. */ |
ac5e69da | 166 | |
618b7f29 TS |
167 | sreal |
168 | sreal::operator- (const sreal &other) const | |
ac5e69da JZ |
169 | { |
170 | int dexp; | |
618b7f29 TS |
171 | sreal tmp, r; |
172 | const sreal *bb; | |
d1704358 | 173 | const sreal *a_p = this, *b_p = &other; |
ac5e69da | 174 | |
d1704358 ML |
175 | int64_t sign = 1; |
176 | if (a_p->m_exp < b_p->m_exp) | |
177 | { | |
178 | sign = -1; | |
179 | std::swap (a_p, b_p); | |
180 | } | |
ac5e69da | 181 | |
d1704358 | 182 | dexp = a_p->m_exp - b_p->m_exp; |
fd27ffab | 183 | r.m_exp = a_p->m_exp; |
ac5e69da JZ |
184 | if (dexp > SREAL_BITS) |
185 | { | |
d1704358 | 186 | r.m_sig = sign * a_p->m_sig; |
ac5e69da JZ |
187 | return r; |
188 | } | |
189 | if (dexp == 0) | |
fd27ffab | 190 | bb = b_p; |
ac5e69da JZ |
191 | else |
192 | { | |
fd27ffab | 193 | tmp = *b_p; |
618b7f29 | 194 | tmp.shift_right (dexp); |
ac5e69da JZ |
195 | bb = &tmp; |
196 | } | |
197 | ||
d1704358 | 198 | r.m_sig = sign * (a_p->m_sig - bb->m_sig); |
618b7f29 | 199 | r.normalize (); |
ac5e69da JZ |
200 | return r; |
201 | } | |
202 | ||
618b7f29 | 203 | /* Return *this * other. */ |
ac5e69da | 204 | |
618b7f29 TS |
205 | sreal |
206 | sreal::operator* (const sreal &other) const | |
ac5e69da | 207 | { |
fd27ffab | 208 | sreal r; |
5007f798 | 209 | if (absu_hwi (m_sig) < SREAL_MIN_SIG || absu_hwi (other.m_sig) < SREAL_MIN_SIG) |
ac5e69da | 210 | { |
618b7f29 TS |
211 | r.m_sig = 0; |
212 | r.m_exp = -SREAL_MAX_EXP; | |
ac5e69da JZ |
213 | } |
214 | else | |
215 | { | |
618b7f29 TS |
216 | r.m_sig = m_sig * other.m_sig; |
217 | r.m_exp = m_exp + other.m_exp; | |
218 | r.normalize (); | |
ac5e69da | 219 | } |
fd27ffab | 220 | |
ac5e69da JZ |
221 | return r; |
222 | } | |
223 | ||
618b7f29 | 224 | /* Return *this / other. */ |
ac5e69da | 225 | |
618b7f29 TS |
226 | sreal |
227 | sreal::operator/ (const sreal &other) const | |
ac5e69da | 228 | { |
fd27ffab ML |
229 | gcc_checking_assert (other.m_sig != 0); |
230 | sreal r; | |
618b7f29 TS |
231 | r.m_sig = (m_sig << SREAL_PART_BITS) / other.m_sig; |
232 | r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS; | |
233 | r.normalize (); | |
ac5e69da JZ |
234 | return r; |
235 | } |