blob: d2431cc927dc1871d02be3f4604190fe636d0ac5 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* mpz_cmpabs_d -- compare absolute values of mpz and double.
2
3Copyright 2001-2003, 2012 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 either:
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14or
15
16 * the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
18 later version.
19
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see https://www.gnu.org/licenses/. */
30
31#include "config.h"
32
33#if HAVE_FLOAT_H
34#include <float.h> /* for DBL_MAX */
35#endif
36
37#include "gmp-impl.h"
38
39
40#define RETURN_CMP(zl, dl) \
41 do { \
42 zlimb = (zl); \
43 dlimb = (dl); \
44 if (zlimb != dlimb) \
45 return (zlimb >= dlimb ? 1 : -1); \
46 } while (0)
47
48#define RETURN_NONZERO(ptr, size, val) \
49 do { \
50 mp_size_t __i; \
51 for (__i = (size)-1; __i >= 0; __i--) \
52 if ((ptr)[__i] != 0) \
53 return val; \
54 return 0; \
55 } while (0)
56
57
58int
59mpz_cmpabs_d (mpz_srcptr z, double d)
60{
61 mp_limb_t darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
62 mp_srcptr zp;
63 mp_size_t zsize;
64 int dexp;
65
66 /* d=NaN is an invalid operation, there's no sensible return value.
67 d=Inf or -Inf is always bigger than z. */
68 DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), return -1);
69
70 /* 1. Check for either operand zero. */
71 zsize = SIZ(z);
72 if (d == 0.0)
73 return (zsize != 0);
74 if (zsize == 0)
75 return -1; /* d != 0 */
76
77 /* 2. Ignore signs. */
78 zsize = ABS(zsize);
79 d = ABS(d);
80
81 /* 3. Small d, knowing abs(z) >= 1. */
82 if (d < 1.0)
83 return 1;
84
85 dexp = __gmp_extract_double (darray, d);
86 ASSERT (dexp >= 1);
87
88 /* 4. Check for different high limb positions. */
89 if (zsize != dexp)
90 return (zsize >= dexp ? 1 : -1);
91
92 /* 5. Limb data. */
93 zp = PTR(z);
94
95#if LIMBS_PER_DOUBLE == 2
96 RETURN_CMP (zp[zsize-1], darray[1]);
97 if (zsize == 1)
98 return (darray[0] != 0 ? -1 : 0);
99
100 RETURN_CMP (zp[zsize-2], darray[0]);
101 RETURN_NONZERO (zp, zsize-2, 1);
102#endif
103
104#if LIMBS_PER_DOUBLE == 3
105 RETURN_CMP (zp[zsize-1], darray[2]);
106 if (zsize == 1)
107 return ((darray[0] | darray[1]) != 0 ? -1 : 0);
108
109 RETURN_CMP (zp[zsize-2], darray[1]);
110 if (zsize == 2)
111 return (darray[0] != 0 ? -1 : 0);
112
113 RETURN_CMP (zp[zsize-3], darray[0]);
114 RETURN_NONZERO (zp, zsize-3, 1);
115#endif
116
117#if LIMBS_PER_DOUBLE >= 4
118 {
119 int i;
120 for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
121 {
122 RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
123 if (i >= zsize)
124 RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -1);
125 }
126 RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, 1);
127 }
128#endif
129}