1 /* Simple data type for real numbers for the GNU compiler.
2 Copyright (C) 2002-2023 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
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
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.
28 (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
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_*.
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
46 If the number is zero or would be too small it meets following conditions:
47 sig == 0 && exp == -SREAL_MAX_EXP
53 #include "coretypes.h"
60 #include "data-streamer.h"
62 /* Print the content of struct sreal. */
65 sreal::dump (FILE *file
) const
67 fprintf (file
, "(%" PRIi64
" * 2^%d)", (int64_t)m_sig
, m_exp
);
71 debug (const sreal
&ref
)
77 debug (const sreal
*ptr
)
82 fprintf (stderr
, "<nil>\n");
85 /* Shift this right by S bits. Needed: 0 < S <= SREAL_BITS.
86 When the most significant bit shifted out is 1, add 1 to this (rounding).
90 sreal::shift_right (int s
)
92 gcc_checking_assert (s
> 0);
93 gcc_checking_assert (s
<= SREAL_BITS
);
94 /* Exponent should never be so large because shift_right is used only by
95 sreal_add and sreal_sub ant thus the number cannot be shifted out from
97 gcc_checking_assert (m_exp
+ s
<= SREAL_MAX_EXP
);
101 m_sig
+= (int64_t) 1 << (s
- 1);
105 /* Return integer value of *this. */
108 sreal::to_int () const
110 int64_t sign
= SREAL_SIGN (m_sig
);
112 if (m_exp
<= -SREAL_BITS
)
114 if (m_exp
>= SREAL_PART_BITS
)
115 return sign
* INTTYPE_MAXIMUM (int64_t);
117 return sign
* (SREAL_ABS ((int64_t)m_sig
) << m_exp
);
119 return m_sig
>> -m_exp
;
123 /* Return value of *this as double.
124 This should be used for debug output only. */
127 sreal::to_double () const
131 val
= ldexp (val
, m_exp
);
135 /* Return *this + other. */
138 sreal::operator+ (const sreal
&other
) const
142 int64_t r_sig
, r_exp
;
144 const sreal
*a_p
= this, *b_p
= &other
, *bb
;
146 if (a_p
->m_exp
< b_p
->m_exp
)
147 std::swap (a_p
, b_p
);
149 dexp
= a_p
->m_exp
- b_p
->m_exp
;
151 if (dexp
> SREAL_BITS
)
166 tmp
.shift_right (dexp
);
170 r_sig
= a_p
->m_sig
+ (int64_t)bb
->m_sig
;
171 sreal
r (r_sig
, r_exp
);
176 /* Return *this - other. */
179 sreal::operator- (const sreal
&other
) const
183 int64_t r_sig
, r_exp
;
185 const sreal
*a_p
= this, *b_p
= &other
;
188 if (a_p
->m_exp
< b_p
->m_exp
)
191 std::swap (a_p
, b_p
);
194 dexp
= a_p
->m_exp
- b_p
->m_exp
;
196 if (dexp
> SREAL_BITS
)
198 r_sig
= sign
* a_p
->m_sig
;
210 tmp
.shift_right (dexp
);
214 r_sig
= sign
* ((int64_t) a_p
->m_sig
- (int64_t)bb
->m_sig
);
215 sreal
r (r_sig
, r_exp
);
219 /* Return *this * other. */
222 sreal::operator* (const sreal
&other
) const
225 if (absu_hwi (m_sig
) < SREAL_MIN_SIG
226 || absu_hwi (other
.m_sig
) < SREAL_MIN_SIG
)
229 r
.m_exp
= -SREAL_MAX_EXP
;
232 r
.normalize (m_sig
* (int64_t) other
.m_sig
, m_exp
+ other
.m_exp
);
237 /* Return *this / other. */
240 sreal::operator/ (const sreal
&other
) const
242 gcc_checking_assert (other
.m_sig
!= 0);
243 sreal
r (SREAL_SIGN (m_sig
)
244 * ((int64_t)SREAL_ABS (m_sig
) << SREAL_PART_BITS
) / other
.m_sig
,
245 m_exp
- other
.m_exp
- SREAL_PART_BITS
);
249 /* Stream sreal value to OB. */
252 sreal::stream_out (struct output_block
*ob
)
254 streamer_write_hwi (ob
, m_sig
);
255 streamer_write_hwi (ob
, m_exp
);
258 /* Read sreal value from IB. */
261 sreal::stream_in (class lto_input_block
*ib
)
264 val
.m_sig
= streamer_read_hwi (ib
);
265 val
.m_exp
= streamer_read_hwi (ib
);
273 /* Selftests for sreals. */
275 /* Verify basic sreal operations. */
278 sreal_verify_basics (void)
280 sreal minimum
= INT_MIN
/2;
281 sreal maximum
= INT_MAX
/2;
284 sreal minus_two
= -2;
285 sreal minus_nine
= -9;
287 ASSERT_EQ (INT_MIN
/2, minimum
.to_int ());
288 ASSERT_EQ (INT_MAX
/2, maximum
.to_int ());
290 ASSERT_FALSE (minus_two
< minus_two
);
291 ASSERT_FALSE (seven
< seven
);
292 ASSERT_TRUE (seven
> minus_two
);
293 ASSERT_TRUE (minus_two
< seven
);
294 ASSERT_TRUE (minus_two
!= seven
);
295 ASSERT_EQ (minus_two
, -2);
296 ASSERT_EQ (seven
, 7);
297 ASSERT_EQ ((seven
<< 10) >> 10, 7);
298 ASSERT_EQ (seven
+ minus_nine
, -2);
301 /* Helper function that performs basic arithmetics and comparison
302 of given arguments A and B. */
305 verify_aritmetics (int64_t a
, int64_t b
)
307 ASSERT_EQ (a
, -(-(sreal (a
))).to_int ());
308 ASSERT_EQ (a
< b
, sreal (a
) < sreal (b
));
309 ASSERT_EQ (a
<= b
, sreal (a
) <= sreal (b
));
310 ASSERT_EQ (a
== b
, sreal (a
) == sreal (b
));
311 ASSERT_EQ (a
!= b
, sreal (a
) != sreal (b
));
312 ASSERT_EQ (a
> b
, sreal (a
) > sreal (b
));
313 ASSERT_EQ (a
>= b
, sreal (a
) >= sreal (b
));
314 ASSERT_EQ (a
+ b
, (sreal (a
) + sreal (b
)).to_int ());
315 ASSERT_EQ (a
- b
, (sreal (a
) - sreal (b
)).to_int ());
316 ASSERT_EQ (b
+ a
, (sreal (b
) + sreal (a
)).to_int ());
317 ASSERT_EQ (b
- a
, (sreal (b
) - sreal (a
)).to_int ());
320 /* Verify arithmetics for interesting numbers. */
323 sreal_verify_arithmetics (void)
325 int values
[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123};
326 unsigned c
= sizeof (values
) / sizeof (int);
328 for (unsigned i
= 0; i
< c
; i
++)
329 for (unsigned j
= 0; j
< c
; j
++)
334 verify_aritmetics (a
, b
);
338 /* Helper function that performs various shifting test of a given
342 verify_shifting (int64_t a
)
346 for (unsigned i
= 0; i
< 16; i
++)
347 ASSERT_EQ (a
<< i
, (v
<< i
).to_int());
352 for (unsigned i
= 0; i
< 16; i
++)
353 ASSERT_EQ (a
>> i
, (v
>> i
).to_int());
356 /* Verify shifting for interesting numbers. */
359 sreal_verify_shifting (void)
361 int values
[] = {0, 17, 32, 139, 1024, 55555, 1234123};
362 unsigned c
= sizeof (values
) / sizeof (int);
364 for (unsigned i
= 0; i
< c
; i
++)
365 verify_shifting (values
[i
]);
368 /* Verify division by (of) a negative value. */
371 sreal_verify_negative_division (void)
373 ASSERT_EQ (sreal (1) / sreal (1), sreal (1));
374 ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1));
375 ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1));
376 ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1));
377 ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
380 /* Run all of the selftests within this file. */
382 void sreal_cc_tests ()
384 sreal_verify_basics ();
385 sreal_verify_arithmetics ();
386 sreal_verify_shifting ();
387 sreal_verify_negative_division ();
390 } // namespace selftest
391 #endif /* CHECKING_P */