1/* Test mpz_set_d and mpz_init_set_d.
2
3Copyright 2000-2003, 2006 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include "gmp-impl.h"
23#include "tests.h"
24
25
26void
27check_data (void)
28{
29  static const struct {
30    double     d;
31    mp_size_t  want_size;
32    mp_limb_t  want_data[2];
33  } data[] = {
34
35    {  0.0,  0 },
36    {  1.0,  1, { 1 } },
37    { -1.0, -1, { 1 } },
38
39    {  123.0,  1, { 123 } },
40    { -123.0, -1, { 123 } },
41
42    { 1e-1, 0, { 0 } },
43    { -1e-1, 0, { 0 } },
44    { 2.328306436538696e-10, 0, { 0 } },
45    { -2.328306436538696e-10, 0, { 0 } },
46    { 5.421010862427522e-20, 0, { 0 } },
47    { -5.421010862427522e-20, 0, { 0 } },
48    { 2.938735877055719e-39, 0, { 0 } },
49    { -2.938735877055719e-39, 0, { 0 } },
50  };
51
52  mpz_t  z;
53  int    i;
54
55  for (i = 0; i < numberof (data); i++)
56    {
57      mpz_init (z);
58      mpz_set_d (z, data[i].d);
59      MPZ_CHECK_FORMAT (z);
60      if (z->_mp_size != data[i].want_size
61          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
62                                   ABS (data[i].want_size)) != 0)
63        {
64          printf ("mpz_set_d wrong on data[%d]\n", i);
65        bad:
66          d_trace   ("  d  ", data[i].d);
67          printf    ("  got  size %ld\n", (long) z->_mp_size);
68          printf    ("  want size %ld\n", (long) data[i].want_size);
69          mpn_trace ("  got  z", z->_mp_d, z->_mp_size);
70          mpn_trace ("  want z", data[i].want_data, data[i].want_size);
71          abort();
72        }
73      mpz_clear (z);
74
75      mpz_init_set_d (z, data[i].d);
76      MPZ_CHECK_FORMAT (z);
77      if (z->_mp_size != data[i].want_size
78          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
79                                   ABS (data[i].want_size)) != 0)
80        {
81          printf ("mpz_init_set_d wrong on data[%d]\n", i);
82          goto bad;
83        }
84      mpz_clear (z);
85    }
86}
87
88/* Try mpz_set_d on values 2^i+1, while such a value fits a double. */
89void
90check_2n_plus_1 (void)
91{
92  volatile double  p, d, diff;
93  mpz_t  want, got;
94  int    i;
95
96  mpz_init (want);
97  mpz_init (got);
98
99  p = 1.0;
100  mpz_set_ui (want, 2L);  /* gives 3 on first step */
101
102  for (i = 1; i < 500; i++)
103    {
104      mpz_mul_2exp (want, want, 1L);
105      mpz_sub_ui (want, want, 1L);   /* want = 2^i+1 */
106
107      p *= 2.0;  /* p = 2^i */
108      d = p + 1.0;
109      diff = d - p;
110      if (diff != 1.0)
111        break;   /* rounding occurred, stop now */
112
113      mpz_set_d (got, d);
114      MPZ_CHECK_FORMAT (got);
115      if (mpz_cmp (got, want) != 0)
116        {
117          printf ("mpz_set_d wrong on 2^%d+1\n", i);
118          d_trace   ("  d ", d);
119          mpz_trace ("  got  ", got);
120          mpz_trace ("  want ", want);
121          abort ();
122        }
123    }
124
125  mpz_clear (want);
126  mpz_clear (got);
127}
128
129int
130main (void)
131{
132  tests_start ();
133
134  check_data ();
135  check_2n_plus_1 ();
136
137  tests_end ();
138  exit (0);
139}
140