Move array-type va_list handling to build_va_arg
[official-gcc.git] / gcc / sreal.c
blob94b75dd866049346044b7c2c84f6ca48110a3012
1 /* Simple data type for real numbers for the GNU compiler.
2 Copyright (C) 2002-2015 Free Software Foundation, Inc.
4 This file is part of GCC.
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
8 Software Foundation; either version 3, or (at your option) any later
9 version.
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.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* This library supports real numbers;
21 inf and nan are NOT supported.
22 It is written to be simple and fast.
24 Value of sreal is
25 x = sig * 2 ^ exp
26 where
27 sig = significant
28 (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
29 exp = exponent
31 One uint64_t is used for the significant.
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.
34 So the precision is 32-bit.
36 Invariant: The numbers are normalized before and after each call of sreal_*.
38 Normalized sreals:
39 All numbers (except zero) meet following conditions:
40 SREAL_MIN_SIG <= sig && sig <= SREAL_MAX_SIG
41 -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP
43 If the number would be too large, it is set to upper bounds of these
44 conditions.
46 If the number is zero or would be too small it meets following conditions:
47 sig == 0 && exp == -SREAL_MAX_EXP
50 #include "config.h"
51 #include "system.h"
52 #include <math.h>
53 #include "coretypes.h"
54 #include "sreal.h"
56 /* Print the content of struct sreal. */
58 void
59 sreal::dump (FILE *file) const
61 fprintf (file, "(%" PRIi64 " * 2^%d)", m_sig, m_exp);
64 DEBUG_FUNCTION void
65 debug (const sreal &ref)
67 ref.dump (stderr);
70 DEBUG_FUNCTION void
71 debug (const sreal *ptr)
73 if (ptr)
74 debug (*ptr);
75 else
76 fprintf (stderr, "<nil>\n");
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).
83 void
84 sreal::shift_right (int s)
86 gcc_checking_assert (s > 0);
87 gcc_checking_assert (s <= SREAL_BITS);
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. */
91 gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
93 m_exp += s;
95 m_sig += (int64_t) 1 << (s - 1);
96 m_sig >>= s;
99 /* Return integer value of *this. */
101 int64_t
102 sreal::to_int () const
104 int64_t sign = m_sig < 0 ? -1 : 1;
106 if (m_exp <= -SREAL_BITS)
107 return 0;
108 if (m_exp >= SREAL_PART_BITS)
109 return sign * INTTYPE_MAXIMUM (int64_t);
110 if (m_exp > 0)
111 return m_sig << m_exp;
112 if (m_exp < 0)
113 return m_sig >> -m_exp;
114 return m_sig;
117 /* Return value of *this as double.
118 This should be used for debug output only. */
120 double
121 sreal::to_double () const
123 double val = m_sig;
124 if (m_exp)
125 val = ldexp (val, m_exp);
126 return val;
129 /* Return *this + other. */
131 sreal
132 sreal::operator+ (const sreal &other) const
134 int dexp;
135 sreal tmp, r;
137 const sreal *a_p = this, *b_p = &other, *bb;
139 if (a_p->m_exp < b_p->m_exp)
140 std::swap (a_p, b_p);
142 dexp = a_p->m_exp - b_p->m_exp;
143 r.m_exp = a_p->m_exp;
144 if (dexp > SREAL_BITS)
146 r.m_sig = a_p->m_sig;
147 return r;
150 if (dexp == 0)
151 bb = b_p;
152 else
154 tmp = *b_p;
155 tmp.shift_right (dexp);
156 bb = &tmp;
159 r.m_sig = a_p->m_sig + bb->m_sig;
160 r.normalize ();
161 return r;
165 /* Return *this - other. */
167 sreal
168 sreal::operator- (const sreal &other) const
170 int dexp;
171 sreal tmp, r;
172 const sreal *bb;
173 const sreal *a_p = this, *b_p = &other;
175 int64_t sign = 1;
176 if (a_p->m_exp < b_p->m_exp)
178 sign = -1;
179 std::swap (a_p, b_p);
182 dexp = a_p->m_exp - b_p->m_exp;
183 r.m_exp = a_p->m_exp;
184 if (dexp > SREAL_BITS)
186 r.m_sig = sign * a_p->m_sig;
187 return r;
189 if (dexp == 0)
190 bb = b_p;
191 else
193 tmp = *b_p;
194 tmp.shift_right (dexp);
195 bb = &tmp;
198 r.m_sig = sign * (a_p->m_sig - bb->m_sig);
199 r.normalize ();
200 return r;
203 /* Return *this * other. */
205 sreal
206 sreal::operator* (const sreal &other) const
208 sreal r;
209 if (absu_hwi (m_sig) < SREAL_MIN_SIG || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
211 r.m_sig = 0;
212 r.m_exp = -SREAL_MAX_EXP;
214 else
216 r.m_sig = m_sig * other.m_sig;
217 r.m_exp = m_exp + other.m_exp;
218 r.normalize ();
221 return r;
224 /* Return *this / other. */
226 sreal
227 sreal::operator/ (const sreal &other) const
229 gcc_checking_assert (other.m_sig != 0);
230 sreal r;
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 ();
234 return r;