xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/sreal.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* Simple data type for real numbers for the GNU compiler.
2    Copyright (C) 2002-2017 Free Software Foundation, Inc.
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
8 Software Foundation; either version 3, or (at your option) any later
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
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 /* This library supports real numbers;
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
26    where
27 	sig = significant
28 	  (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
29 	exp = exponent
30 
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.
35 
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
41 	-SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP
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"
52 #include <math.h>
53 #include "coretypes.h"
54 #include "sreal.h"
55 #include "selftest.h"
56 
57 /* Print the content of struct sreal.  */
58 
59 void
60 sreal::dump (FILE *file) const
61 {
62   fprintf (file, "(%" PRIi64 " * 2^%d)", m_sig, m_exp);
63 }
64 
65 DEBUG_FUNCTION void
66 debug (const sreal &ref)
67 {
68   ref.dump (stderr);
69 }
70 
71 DEBUG_FUNCTION void
72 debug (const sreal *ptr)
73 {
74   if (ptr)
75     debug (*ptr);
76   else
77     fprintf (stderr, "<nil>\n");
78 }
79 
80 /* Shift this right by S bits.  Needed: 0 < S <= SREAL_BITS.
81    When the most significant bit shifted out is 1, add 1 to this (rounding).
82    */
83 
84 void
85 sreal::shift_right (int s)
86 {
87   gcc_checking_assert (s > 0);
88   gcc_checking_assert (s <= SREAL_BITS);
89   /* Exponent should never be so large because shift_right is used only by
90      sreal_add and sreal_sub ant thus the number cannot be shifted out from
91      exponent range.  */
92   gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
93 
94   m_exp += s;
95 
96   m_sig += (int64_t) 1 << (s - 1);
97   m_sig >>= s;
98 }
99 
100 /* Return integer value of *this.  */
101 
102 int64_t
103 sreal::to_int () const
104 {
105   int64_t sign = SREAL_SIGN (m_sig);
106 
107   if (m_exp <= -SREAL_BITS)
108     return 0;
109   if (m_exp >= SREAL_PART_BITS)
110     return sign * INTTYPE_MAXIMUM (int64_t);
111   if (m_exp > 0)
112     return sign * (SREAL_ABS (m_sig) << m_exp);
113   if (m_exp < 0)
114     return m_sig >> -m_exp;
115   return m_sig;
116 }
117 
118 /* Return value of *this as double.
119    This should be used for debug output only.  */
120 
121 double
122 sreal::to_double () const
123 {
124   double val = m_sig;
125   if (m_exp)
126     val = ldexp (val, m_exp);
127   return val;
128 }
129 
130 /* Return *this + other.  */
131 
132 sreal
133 sreal::operator+ (const sreal &other) const
134 {
135   int dexp;
136   sreal tmp, r;
137 
138   const sreal *a_p = this, *b_p = &other, *bb;
139 
140   if (a_p->m_exp < b_p->m_exp)
141     std::swap (a_p, b_p);
142 
143   dexp = a_p->m_exp - b_p->m_exp;
144   r.m_exp = a_p->m_exp;
145   if (dexp > SREAL_BITS)
146     {
147       r.m_sig = a_p->m_sig;
148       return r;
149     }
150 
151   if (dexp == 0)
152     bb = b_p;
153   else
154     {
155       tmp = *b_p;
156       tmp.shift_right (dexp);
157       bb = &tmp;
158     }
159 
160   r.m_sig = a_p->m_sig + bb->m_sig;
161   r.normalize ();
162   return r;
163 }
164 
165 
166 /* Return *this - other.  */
167 
168 sreal
169 sreal::operator- (const sreal &other) const
170 {
171   int dexp;
172   sreal tmp, r;
173   const sreal *bb;
174   const sreal *a_p = this, *b_p = &other;
175 
176   int64_t sign = 1;
177   if (a_p->m_exp < b_p->m_exp)
178     {
179       sign = -1;
180       std::swap (a_p, b_p);
181     }
182 
183   dexp = a_p->m_exp - b_p->m_exp;
184   r.m_exp = a_p->m_exp;
185   if (dexp > SREAL_BITS)
186     {
187       r.m_sig = sign * a_p->m_sig;
188       return r;
189     }
190   if (dexp == 0)
191     bb = b_p;
192   else
193     {
194       tmp = *b_p;
195       tmp.shift_right (dexp);
196       bb = &tmp;
197     }
198 
199   r.m_sig = sign * (a_p->m_sig - bb->m_sig);
200   r.normalize ();
201   return r;
202 }
203 
204 /* Return *this * other.  */
205 
206 sreal
207 sreal::operator* (const sreal &other) const
208 {
209   sreal r;
210   if (absu_hwi (m_sig) < SREAL_MIN_SIG || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
211     {
212       r.m_sig = 0;
213       r.m_exp = -SREAL_MAX_EXP;
214     }
215   else
216     {
217       r.m_sig = m_sig * other.m_sig;
218       r.m_exp = m_exp + other.m_exp;
219       r.normalize ();
220     }
221 
222   return r;
223 }
224 
225 /* Return *this / other.  */
226 
227 sreal
228 sreal::operator/ (const sreal &other) const
229 {
230   gcc_checking_assert (other.m_sig != 0);
231   sreal r;
232   r.m_sig
233     = SREAL_SIGN (m_sig) * (SREAL_ABS (m_sig) << SREAL_PART_BITS) / other.m_sig;
234   r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS;
235   r.normalize ();
236   return r;
237 }
238 
239 #if CHECKING_P
240 
241 namespace selftest {
242 
243 /* Selftests for sreals.  */
244 
245 /* Verify basic sreal operations.  */
246 
247 static void
248 sreal_verify_basics (void)
249 {
250   sreal minimum = INT_MIN;
251   sreal maximum = INT_MAX;
252 
253   sreal seven = 7;
254   sreal minus_two = -2;
255   sreal minus_nine = -9;
256 
257   ASSERT_EQ (INT_MIN, minimum.to_int ());
258   ASSERT_EQ (INT_MAX, maximum.to_int ());
259 
260   ASSERT_FALSE (minus_two < minus_two);
261   ASSERT_FALSE (seven < seven);
262   ASSERT_TRUE (seven > minus_two);
263   ASSERT_TRUE (minus_two < seven);
264   ASSERT_TRUE (minus_two != seven);
265   ASSERT_EQ (minus_two, -2);
266   ASSERT_EQ (seven, 7);
267   ASSERT_EQ ((seven << 10) >> 10, 7);
268   ASSERT_EQ (seven + minus_nine, -2);
269 }
270 
271 /* Helper function that performs basic arithmetics and comparison
272    of given arguments A and B.  */
273 
274 static void
275 verify_aritmetics (int64_t a, int64_t b)
276 {
277   ASSERT_EQ (a, -(-(sreal (a))).to_int ());
278   ASSERT_EQ (a < b, sreal (a) < sreal (b));
279   ASSERT_EQ (a <= b, sreal (a) <= sreal (b));
280   ASSERT_EQ (a == b, sreal (a) == sreal (b));
281   ASSERT_EQ (a != b, sreal (a) != sreal (b));
282   ASSERT_EQ (a > b, sreal (a) > sreal (b));
283   ASSERT_EQ (a >= b, sreal (a) >= sreal (b));
284   ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_int ());
285   ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ());
286   ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ());
287   ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ());
288 }
289 
290 /* Verify arithmetics for interesting numbers.  */
291 
292 static void
293 sreal_verify_arithmetics (void)
294 {
295   int values[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123};
296   unsigned c = sizeof (values) / sizeof (int);
297 
298   for (unsigned i = 0; i < c; i++)
299     for (unsigned j = 0; j < c; j++)
300       {
301 	int a = values[i];
302 	int b = values[j];
303 
304 	verify_aritmetics (a, b);
305       }
306 }
307 
308 /* Helper function that performs various shifting test of a given
309    argument A.  */
310 
311 static void
312 verify_shifting (int64_t a)
313 {
314   sreal v = a;
315 
316   for (unsigned i = 0; i < 16; i++)
317     ASSERT_EQ (a << i, (v << i).to_int());
318 
319   a = a << 16;
320   v = v << 16;
321 
322   for (unsigned i = 0; i < 16; i++)
323     ASSERT_EQ (a >> i, (v >> i).to_int());
324 }
325 
326 /* Verify shifting for interesting numbers.  */
327 
328 static void
329 sreal_verify_shifting (void)
330 {
331   int values[] = {0, 17, 32, 139, 1024, 55555, 1234123};
332   unsigned c = sizeof (values) / sizeof (int);
333 
334   for (unsigned i = 0; i < c; i++)
335     verify_shifting (values[i]);
336 }
337 
338 /* Verify division by (of) a negative value.  */
339 
340 static void
341 sreal_verify_negative_division (void)
342 {
343   ASSERT_EQ (sreal (1) / sreal (1), sreal (1));
344   ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1));
345   ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1));
346   ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1));
347   ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
348 }
349 
350 /* Run all of the selftests within this file.  */
351 
352 void sreal_c_tests ()
353 {
354   sreal_verify_basics ();
355   sreal_verify_arithmetics ();
356   sreal_verify_shifting ();
357   sreal_verify_negative_division ();
358 }
359 
360 } // namespace selftest
361 #endif /* CHECKING_P */
362