xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/trec_sqrt.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* Test file for mpfr_rec_sqrt.
2 
3 Copyright 2008-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 <time.h>
24 #include "mpfr-test.h"
25 
26 #define TEST_FUNCTION mpfr_rec_sqrt
27 #define TEST_RANDOM_POS 8 /* 8/512 = 1/64 of the tested numbers are negative */
28 #include "tgeneric.c"
29 
30 static void
special(void)31 special (void)
32 {
33   mpfr_t x, y;
34   int inex;
35 
36   mpfr_init (x);
37   mpfr_init (y);
38 
39   /* rec_sqrt(NaN) = NaN */
40   mpfr_set_nan (x);
41   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
42   MPFR_ASSERTN(mpfr_nan_p (x) && inex == 0);
43 
44   /* rec_sqrt(+Inf) = +0 */
45   mpfr_set_inf (x, 1);
46   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
47   MPFR_ASSERTN(mpfr_zero_p (x) && MPFR_IS_POS(x) && inex == 0);
48 
49   /* rec_sqrt(-Inf) = NaN */
50   mpfr_set_inf (x, -1);
51   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
52   MPFR_ASSERTN(mpfr_nan_p (x) && inex == 0);
53 
54   /* rec_sqrt(+0) = +Inf */
55   mpfr_set_ui (x, 0, MPFR_RNDN);
56   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
57   MPFR_ASSERTN(mpfr_inf_p (x) && MPFR_IS_POS(x) && inex == 0);
58 
59   /* rec_sqrt(-0) = +Inf */
60   mpfr_set_ui (x, 0, MPFR_RNDN);
61   mpfr_neg (x, x, MPFR_RNDN);
62   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
63   MPFR_ASSERTN(mpfr_inf_p (x) && MPFR_IS_POS(x) && inex == 0);
64 
65   /* rec_sqrt(-1) = NaN */
66   mpfr_set_si (x, -1, MPFR_RNDN);
67   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
68   MPFR_ASSERTN(mpfr_nan_p (x) && inex == 0);
69 
70   /* rec_sqrt(1) = 1 */
71   mpfr_set_ui (x, 1, MPFR_RNDN);
72   inex = mpfr_rec_sqrt (x, x, MPFR_RNDN);
73   MPFR_ASSERTN((mpfr_cmp_ui (x, 1) == 0) && (inex == 0));
74 
75   mpfr_set_prec (x, 23);
76   mpfr_set_prec (y, 33);
77   mpfr_set_str_binary (x, "1.0001110110101001010100e-1");
78   inex = mpfr_rec_sqrt (y, x, MPFR_RNDU);
79   mpfr_set_prec (x, 33);
80   mpfr_set_str_binary (x, "1.01010110101110100100100101011");
81   MPFR_ASSERTN (inex > 0 && mpfr_cmp (x, y) == 0);
82 
83   mpfr_clear (x);
84   mpfr_clear (y);
85 }
86 
87 /* Worst case incorrectly rounded in r5573, found with the bad_cases test */
88 static void
bad_case1(void)89 bad_case1 (void)
90 {
91   mpfr_t x, y, z;
92 
93   mpfr_init2 (x, 72);
94   mpfr_inits2 (6, y, z, (mpfr_ptr) 0);
95   mpfr_set_str (x, "1.08310518720928b30e@-120", 16, MPFR_RNDN);
96   mpfr_set_str (z, "f.8@59", 16, MPFR_RNDN);
97   /* z = rec_sqrt(x) rounded on 6 bits toward 0, the exact value
98      being ~= f.bffffffffffffffffa11@59. */
99   mpfr_rec_sqrt (y, x, MPFR_RNDZ);
100   if (mpfr_cmp0 (y, z) != 0)
101     {
102       printf ("Error in bad_case1\nexpected ");
103       mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
104       printf ("\ngot      ");
105       mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
106       printf ("\n");
107       exit (1);
108     }
109   mpfr_clears (x, y, z, (mpfr_ptr) 0);
110 }
111 
112 static int
pm2(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)113 pm2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
114 {
115   return mpfr_pow_si (y, x, -2, rnd_mode);
116 }
117 
118 /* exercises corner cases with inputs around 1 or 2 */
119 static void
bad_case2(void)120 bad_case2 (void)
121 {
122   mpfr_t r, u;
123   mpfr_prec_t pr, pu;
124   int rnd;
125 
126   for (pr = MPFR_PREC_MIN; pr <= 192; pr++)
127     for (pu = MPFR_PREC_MIN; pu <= 192; pu++)
128       {
129         mpfr_init2 (r, pr);
130         mpfr_init2 (u, pu);
131 
132         mpfr_set_ui (u, 1, MPFR_RNDN);
133         RND_LOOP (rnd)
134           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
135 
136         mpfr_nextbelow (u);
137         RND_LOOP (rnd)
138           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
139 
140         mpfr_nextbelow (u);
141         RND_LOOP (rnd)
142           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
143 
144         mpfr_set_ui (u, 1, MPFR_RNDN);
145         mpfr_nextabove (u);
146         RND_LOOP (rnd)
147           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
148 
149         mpfr_nextabove (u);
150         RND_LOOP (rnd)
151           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
152 
153         mpfr_set_ui (u, 2, MPFR_RNDN);
154         RND_LOOP (rnd)
155           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
156 
157         mpfr_nextbelow (u);
158         RND_LOOP (rnd)
159           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
160 
161         mpfr_nextbelow (u);
162         RND_LOOP (rnd)
163           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
164 
165         mpfr_set_ui (u, 2, MPFR_RNDN);
166         mpfr_nextabove (u);
167         RND_LOOP (rnd)
168           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
169 
170         mpfr_nextabove (u);
171         RND_LOOP (rnd)
172           mpfr_rec_sqrt (r, u, (mpfr_rnd_t) rnd);
173 
174         mpfr_clear (r);
175         mpfr_clear (u);
176       }
177 }
178 
179 /* Before commits 270f4df6b3a49caae1cf564dcdc1c55b1c5989eb (master) and
180    934dd8842b4bdeb919a73123203bc8ce56db38d1 (4.2 branch) on 2023-04-17,
181    this was giving a stack overflow in mpfr_rec_sqrt due to a Ziv loop
182    where the working precision was increased additively instead of the
183    standard Ziv loop using the MPFR_ZIV_* macros.
184 */
185 static void
bad_case3(void)186 bad_case3 (void)
187 {
188   mpfr_t x, y;
189   int inex;
190 
191   mpfr_init2 (x, 123456);
192   mpfr_init2 (y, 4);
193   mpfr_set_ui (y, 9, MPFR_RNDN);
194   mpfr_ui_div (x, 1, y, MPFR_RNDN);
195   inex = mpfr_rec_sqrt (y, x, MPFR_RNDN);
196   /* Let's also check the result, though this is not the real purpose
197      of this test (a stack overflow just makes the program crash).
198      1/9 = 0.111000111000111000111000111000111000...E-3 and since the
199      precision 123456 is divisible by 6, x > 1/9. Thus 1/sqrt(x) < 3. */
200   if (mpfr_cmp_ui0 (y, 3) != 0 || inex <= 0)
201     {
202       printf ("Error in bad_case3: expected 3 with inex > 0, got ");
203       mpfr_out_str (stdout, 10, 0, y, MPFR_RNDN);
204       printf (" with inex=%d\n", inex);
205       exit (1);
206     }
207   mpfr_clear (x);
208   mpfr_clear (y);
209 }
210 
211 /* timing test for n limbs (so that we can compare with GMP speed -s n) */
212 static void
test(unsigned long n)213 test (unsigned long n)
214 {
215   mpfr_prec_t p = n * GMP_NUMB_BITS;
216   mpfr_t x, y, z;
217   gmp_randstate_t state;
218   double t;
219 
220   gmp_randinit_default (state);
221   mpfr_init2 (x, p);
222   mpfr_init2 (y, p);
223   mpfr_init2 (z, p);
224   mpfr_urandom (x, state, MPFR_RNDN);
225   mpfr_urandom (y, state, MPFR_RNDN);
226 
227   /* multiplication */
228   t = clock ();
229   mpfr_mul (z, x, y, MPFR_RNDN);
230   t = clock () - t;
231   printf ("mpfr_mul:      %.3gs\n", t / (double) CLOCKS_PER_SEC);
232 
233   /* squaring */
234   t = clock ();
235   mpfr_sqr (z, x, MPFR_RNDN);
236   t = clock () - t;
237   printf ("mpfr_sqr:      %.3gs\n", t / (double) CLOCKS_PER_SEC);
238 
239   /* square root */
240   t = clock ();
241   mpfr_sqrt (z, x, MPFR_RNDN);
242   t = clock () - t;
243   printf ("mpfr_sqrt:     %.3gs\n", t / (double) CLOCKS_PER_SEC);
244 
245   /* inverse square root */
246   t = clock ();
247   mpfr_rec_sqrt (z, x, MPFR_RNDN);
248   t = clock () - t;
249   printf ("mpfr_rec_sqrt: %.3gs\n", t / (double) CLOCKS_PER_SEC);
250 
251   mpfr_clear (x);
252   mpfr_clear (y);
253   mpfr_clear (z);
254   gmp_randclear (state);
255 }
256 
257 int
main(int argc,char * argv[])258 main (int argc, char *argv[])
259 {
260   tests_start_mpfr ();
261 
262   if (argc == 2) /* trec_sqrt n */
263     {
264       unsigned long n = strtoul (argv[1], NULL, 10);
265       test (n);
266       goto end;
267     }
268 
269   special ();
270   bad_case1 ();
271   bad_case2 ();
272   bad_case3 ();
273   test_generic (MPFR_PREC_MIN, 300, 15);
274 
275   data_check ("data/rec_sqrt", mpfr_rec_sqrt, "mpfr_rec_sqrt");
276   bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 4, 128,
277              800, 50);
278   bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 9999, 9999,
279              120000, 1);
280 
281  end:
282   tests_end_mpfr ();
283   return 0;
284 }
285