1 /* Test file for mpfr_sqr.
2
3 Copyright 2004-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5
6 This file is part of the GNU MPFR Library.
7
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23 #include "mpfr-test.h"
24
25 #define TEST_FUNCTION mpfr_sqr
26 #include "tgeneric.c"
27
28 static int
inexact_sign(int x)29 inexact_sign (int x)
30 {
31 return (x < 0) ? -1 : (x > 0);
32 }
33
34 static void
error1(mpfr_rnd_t rnd,mpfr_prec_t prec,mpfr_t in,mpfr_ptr outmul,mpfr_ptr outsqr)35 error1 (mpfr_rnd_t rnd, mpfr_prec_t prec,
36 mpfr_t in, mpfr_ptr outmul, mpfr_ptr outsqr)
37 {
38 printf("ERROR: for %s and prec=%lu\nINPUT=", mpfr_print_rnd_mode(rnd),
39 (unsigned long) prec);
40 mpfr_dump(in);
41 printf("OutputMul="); mpfr_dump(outmul);
42 printf("OutputSqr="); mpfr_dump(outsqr);
43 exit(1);
44 }
45
46 static void
error2(mpfr_rnd_t rnd,mpfr_prec_t prec,mpfr_ptr in,mpfr_ptr out,int inexactmul,int inexactsqr)47 error2 (mpfr_rnd_t rnd, mpfr_prec_t prec, mpfr_ptr in, mpfr_ptr out,
48 int inexactmul, int inexactsqr)
49 {
50 printf("ERROR: for %s and prec=%lu\nINPUT=", mpfr_print_rnd_mode(rnd),
51 (unsigned long) prec);
52 mpfr_dump(in);
53 printf("Output="); mpfr_dump(out);
54 printf("InexactMul= %d InexactSqr= %d\n", inexactmul, inexactsqr);
55 exit(1);
56 }
57
58 static void
check_random(mpfr_prec_t p)59 check_random (mpfr_prec_t p)
60 {
61 mpfr_t x,y,z;
62 int r;
63 int i, inexact1, inexact2;
64
65 mpfr_inits2 (p, x, y, z, (mpfr_ptr) 0);
66 for(i = 0 ; i < 500 ; i++)
67 {
68 mpfr_urandomb (x, RANDS);
69 if (MPFR_IS_PURE_FP(x))
70 RND_LOOP_NO_RNDF (r)
71 {
72 /* the following call to mpfr_mul with identical arguments is
73 intentional (to compare with mpfr_sqr) */
74 inexact1 = mpfr_mul (y, x, x, (mpfr_rnd_t) r);
75 inexact2 = mpfr_sqr (z, x, (mpfr_rnd_t) r);
76 if (mpfr_cmp (y, z))
77 error1 ((mpfr_rnd_t) r,p,x,y,z);
78 if (inexact_sign (inexact1) != inexact_sign (inexact2))
79 error2 ((mpfr_rnd_t) r,p,x,y,inexact1,inexact2);
80 }
81 }
82 mpfr_clears (x, y, z, (mpfr_ptr) 0);
83 }
84
85 static void
check_special(void)86 check_special (void)
87 {
88 mpfr_t x, y;
89 mpfr_exp_t emin;
90
91 mpfr_init (x);
92 mpfr_init (y);
93
94 mpfr_set_nan (x);
95 mpfr_sqr (y, x, MPFR_RNDN);
96 MPFR_ASSERTN (mpfr_nan_p (y));
97
98 mpfr_set_inf (x, 1);
99 mpfr_sqr (y, x, MPFR_RNDN);
100 MPFR_ASSERTN (mpfr_inf_p (y) && mpfr_sgn (y) > 0);
101
102 mpfr_set_inf (x, -1);
103 mpfr_sqr (y, x, MPFR_RNDN);
104 MPFR_ASSERTN (mpfr_inf_p (y) && mpfr_sgn (y) > 0);
105
106 mpfr_set_ui (x, 0, MPFR_RNDN);
107 mpfr_sqr (y, x, MPFR_RNDN);
108 MPFR_ASSERTN (mpfr_zero_p (y));
109
110 emin = mpfr_get_emin ();
111 set_emin (0);
112 mpfr_set_ui (x, 1, MPFR_RNDN);
113 mpfr_div_2ui (x, x, 1, MPFR_RNDN);
114 MPFR_ASSERTN (!mpfr_zero_p (x));
115 mpfr_sqr (y, x, MPFR_RNDN);
116 MPFR_ASSERTN (mpfr_zero_p (y));
117 set_emin (emin);
118
119 mpfr_clear (y);
120 mpfr_clear (x);
121 }
122
123 /* check ax < __gmpfr_emin with rnd_mode == MPFR_RNDN, rb = 0 and sb <> 0 */
124 static void
test_underflow(void)125 test_underflow (void)
126 {
127 mpfr_t x, y;
128 mpfr_exp_t emin;
129
130 emin = mpfr_get_emin ();
131 set_emin (0);
132
133 mpfr_init2 (x, 24);
134 mpfr_init2 (y, 24);
135
136 mpfr_set_ui_2exp (x, 11863283, -24, MPFR_RNDN);
137 /* x^2 = 0.011111111111111111111111101101100111111010101001*2^(-48)
138 thus we have an underflow */
139 mpfr_clear_underflow ();
140 mpfr_sqr (y, x, MPFR_RNDN);
141 MPFR_ASSERTN(mpfr_cmp_ui_2exp (y, 1, -1) == 0);
142 MPFR_ASSERTN(mpfr_underflow_p ());
143
144 mpfr_set_prec (x, 69);
145 mpfr_set_prec (y, 69);
146 mpfr_set_str_binary (x, "0.101101010000010011110011001100111111100111011110011001001000010001011");
147 mpfr_clear_underflow ();
148 mpfr_sqr (y, x, MPFR_RNDN);
149 MPFR_ASSERTN(mpfr_cmp_ui_2exp (y, 1, -1) == 0);
150 MPFR_ASSERTN(mpfr_underflow_p ());
151
152 mpfr_clear (y);
153 mpfr_clear (x);
154
155 set_emin (emin);
156 }
157
158 /* Test of a bug seen with GCC 4.5.2 and GMP 5.0.1 on m68k (m68000 target).
159 https://sympa.inria.fr/sympa/arc/mpfr/2011-05/msg00003.html
160 https://sympa.inria.fr/sympa/arc/mpfr/2011-05/msg00041.html
161 */
162 static void
check_mpn_sqr(void)163 check_mpn_sqr (void)
164 {
165 #if GMP_NUMB_BITS == 32 && __GNU_MP_VERSION >= 5
166 /* Note: since we test a low-level bug, src is initialized
167 without using a GMP function, just in case. */
168 mp_limb_t src[5] =
169 { 0x90000000, 0xbaa55f4f, 0x2cbec4d9, 0xfcef3242, 0xda827999 };
170 mp_limb_t exd[10] =
171 { 0x00000000, 0x31000000, 0xbd4bc59a, 0x41fbe2b5, 0x33471e7e,
172 0x90e826a7, 0xbaa55f4f, 0x2cbec4d9, 0xfcef3242, 0xba827999 };
173 mp_limb_t dst[10];
174 int i;
175
176 mpn_sqr (dst, src, 5); /* new in GMP 5 */
177 for (i = 0; i < 10; i++)
178 {
179 if (dst[i] != exd[i])
180 {
181 printf ("Error in check_mpn_sqr\n");
182 printf ("exd[%d] = 0x%08lx\n", i, (unsigned long) exd[i]);
183 printf ("dst[%d] = 0x%08lx\n", i, (unsigned long) dst[i]);
184 printf ("Note: This is not a bug in MPFR, but a bug in"
185 " either GMP or, more\nprobably, in the compiler."
186 " It may cause other tests to fail.\n");
187 exit (1);
188 }
189 }
190 #endif
191 }
192
193 static void
coverage(mpfr_prec_t pmax)194 coverage (mpfr_prec_t pmax)
195 {
196 mpfr_prec_t p;
197
198 for (p = MPFR_PREC_MIN; p <= pmax; p++)
199 {
200 mpfr_t a, b, c;
201 int inex;
202 mpfr_exp_t emin;
203
204 mpfr_init2 (a, p);
205 mpfr_init2 (b, p);
206 mpfr_init2 (c, p);
207
208 /* exercise carry in most significant bits of a, with overflow */
209 mpfr_set_ui_2exp (b, 1, mpfr_get_emax (), MPFR_RNDZ);
210 mpfr_sqrt (b, b, MPFR_RNDU);
211 mpfr_div_2ui (c, b, 1, MPFR_RNDN);
212 mpfr_sqr (c, c, MPFR_RNDN);
213 mpfr_clear_flags ();
214 inex = mpfr_sqr (a, b, MPFR_RNDN);
215 /* if EXP(c) > emax-2, there is overflow */
216 if (mpfr_get_exp (c) > mpfr_get_emax () - 2)
217 {
218 MPFR_ASSERTN(inex > 0);
219 MPFR_ASSERTN(mpfr_inf_p (a) && mpfr_sgn (a) > 0);
220 MPFR_ASSERTN(mpfr_overflow_p ());
221 }
222 else /* no overflow */
223 {
224 /* 2^p-1 is a square only for p=1 */
225 MPFR_ASSERTN((p == 1 && inex == 0) || (p > 1 && inex < 0));
226 MPFR_ASSERTN(!mpfr_overflow_p ());
227 mpfr_set_ui_2exp (c, 1, mpfr_get_emax (), MPFR_RNDZ);
228 MPFR_ASSERTN(mpfr_equal_p (a, c));
229 }
230
231 /* same as above, with RNDU */
232 mpfr_set_ui_2exp (b, 1, mpfr_get_emax (), MPFR_RNDZ);
233 mpfr_sqrt (b, b, MPFR_RNDU);
234 mpfr_div_2ui (c, b, 1, MPFR_RNDN);
235 mpfr_sqr (c, c, MPFR_RNDU);
236 mpfr_clear_flags ();
237 inex = mpfr_sqr (a, b, MPFR_RNDU);
238 /* if EXP(c) > emax-2, there is overflow */
239 if (mpfr_get_exp (c) > mpfr_get_emax () - 2)
240 {
241 MPFR_ASSERTN(inex > 0);
242 MPFR_ASSERTN(mpfr_inf_p (a) && mpfr_sgn (a) > 0);
243 MPFR_ASSERTN(mpfr_overflow_p ());
244 }
245 else /* no overflow */
246 {
247 /* 2^p-1 is a square only for p=1 */
248 MPFR_ASSERTN((p == 1 && inex == 0) || (p > 1 && inex < 0));
249 MPFR_ASSERTN(!mpfr_overflow_p ());
250 mpfr_set_ui_2exp (c, 1, mpfr_get_emax (), MPFR_RNDZ);
251 MPFR_ASSERTN(mpfr_equal_p (a, c));
252 }
253
254 /* exercise trivial overflow */
255 mpfr_set_ui_2exp (b, 1, mpfr_get_emax (), MPFR_RNDZ);
256 mpfr_sqrt (b, b, MPFR_RNDU);
257 mpfr_mul_2ui (b, b, 1, MPFR_RNDN);
258 mpfr_clear_flags ();
259 inex = mpfr_sqr (a, b, MPFR_RNDN);
260 MPFR_ASSERTN(inex > 0);
261 MPFR_ASSERTN(mpfr_inf_p (a) && mpfr_sgn (a) > 0);
262 MPFR_ASSERTN(mpfr_overflow_p ());
263
264 /* exercise trivial underflow */
265 mpfr_set_ui_2exp (b, 1, mpfr_get_emin () - 1, MPFR_RNDZ);
266 mpfr_sqrt (b, b, MPFR_RNDU);
267 mpfr_div_2ui (b, b, 1, MPFR_RNDN);
268 mpfr_clear_flags ();
269 inex = mpfr_sqr (a, b, MPFR_RNDN);
270 MPFR_ASSERTN(inex < 0);
271 MPFR_ASSERTN(mpfr_zero_p (a) && mpfr_signbit (a) == 0);
272 MPFR_ASSERTN(mpfr_underflow_p ());
273
274 /* exercise square between 0.5*2^emin and its predecessor (emin even) */
275 emin = mpfr_get_emin ();
276 set_emin (emin + (emin & 1)); /* now emin is even */
277 mpfr_set_ui_2exp (b, 1, mpfr_get_emin () - 1, MPFR_RNDN);
278 inex = mpfr_sqrt (b, b, MPFR_RNDZ);
279 MPFR_ASSERTN(inex != 0); /* sqrt(2) is not exact */
280 mpfr_mul_2ui (c, b, 1, MPFR_RNDN);
281 mpfr_sqr (c, c, MPFR_RNDN);
282 mpfr_clear_flags ();
283 inex = mpfr_sqr (a, b, MPFR_RNDN);
284 if (mpfr_get_exp (c) < mpfr_get_emin () + 2) /* underflow */
285 {
286 /* if c > 0.5*2^(emin+1), we should round to 0.5*2^emin */
287 if (mpfr_cmp_ui_2exp (c, 1, mpfr_get_emin ()) > 0)
288 {
289 MPFR_ASSERTN(inex > 0);
290 MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 1, mpfr_get_emin () - 1) == 0);
291 MPFR_ASSERTN(mpfr_underflow_p ());
292 }
293 else /* we should round to 0 */
294 {
295 MPFR_ASSERTN(inex < 0);
296 MPFR_ASSERTN(mpfr_zero_p (a) && mpfr_signbit (a) == 0);
297 MPFR_ASSERTN(mpfr_underflow_p ());
298 }
299 }
300 else
301 {
302 MPFR_ASSERTN(inex > 0);
303 MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 1, mpfr_get_emin () - 1) == 0);
304 MPFR_ASSERTN(!mpfr_underflow_p ());
305 }
306 set_emin (emin);
307
308 /* exercise exact square root 2^(emin-2) for emin even */
309 emin = mpfr_get_emin ();
310 set_emin (emin + (emin & 1)); /* now emin is even */
311 mpfr_set_ui_2exp (b, 1, (mpfr_get_emin () - 2) / 2, MPFR_RNDN);
312 inex = mpfr_sqr (a, b, MPFR_RNDN);
313 MPFR_ASSERTN(inex < 0);
314 MPFR_ASSERTN(mpfr_zero_p (a) && mpfr_signbit (a) == 0);
315 MPFR_ASSERTN(mpfr_underflow_p ());
316 set_emin (emin);
317
318 /* same as above, for RNDU */
319 emin = mpfr_get_emin ();
320 set_emin (emin + (emin & 1)); /* now emin is even */
321 mpfr_set_ui_2exp (b, 1, mpfr_get_emin () - 1, MPFR_RNDN);
322 inex = mpfr_sqrt (b, b, MPFR_RNDZ);
323 MPFR_ASSERTN(inex != 0); /* sqrt(2) is not exact */
324 mpfr_mul_2ui (c, b, 1, MPFR_RNDN);
325 mpfr_sqr (c, c, MPFR_RNDU);
326 mpfr_clear_flags ();
327 inex = mpfr_sqr (a, b, MPFR_RNDU);
328 MPFR_ASSERTN(inex > 0);
329 MPFR_ASSERTN(mpfr_cmp_ui_2exp (a, 1, mpfr_get_emin () - 1) == 0);
330 /* we have underflow if c < 2^(emin+1) */
331 if (mpfr_cmp_ui_2exp (c, 1, mpfr_get_emin () + 1) < 0)
332 MPFR_ASSERTN(mpfr_underflow_p ());
333 else
334 MPFR_ASSERTN(!mpfr_underflow_p ());
335 set_emin (emin);
336
337 mpfr_clear (a);
338 mpfr_clear (b);
339 mpfr_clear (c);
340 }
341 }
342
343 int
main(void)344 main (void)
345 {
346 mpfr_prec_t p;
347
348 tests_start_mpfr ();
349
350 coverage (1024);
351 check_mpn_sqr ();
352 check_special ();
353 test_underflow ();
354
355 for (p = MPFR_PREC_MIN; p < 200; p++)
356 check_random (p);
357
358 test_generic (MPFR_PREC_MIN, 200, 15);
359 data_check ("data/sqr", mpfr_sqr, "mpfr_sqr");
360 bad_cases (mpfr_sqr, mpfr_sqrt, "mpfr_sqr", 8, -256, 255, 4, 128, 800, 50);
361
362 tests_end_mpfr ();
363 return 0;
364 }
365