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