Line data Source code
1 : /* Simple multiprecision - small MP library for testing
2 : * Copyright (C) 2022-2024 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #undef NDEBUG
21 : #include <config.h>
22 :
23 : #include <assert.h>
24 : #include <string.h>
25 :
26 : #include <freetds/utils/smp.h>
27 : #include <freetds/sysdep_private.h>
28 :
29 : #define SMP_NUM_COMPONENTS \
30 : (sizeof(((smp*)0)->comp) / sizeof(((smp*)0)->comp[0]))
31 :
32 : const smp smp_zero = {
33 : { 0, 0, 0, 0, 0, 0, 0, 0 },
34 : };
35 :
36 : const smp smp_one = {
37 : { 1, 0, 0, 0, 0, 0, 0, 0 },
38 : };
39 :
40 : smp
41 6052232 : smp_add(smp a, smp b)
42 : {
43 : int i;
44 6052232 : uint32_t carry = 0;
45 : smp res;
46 :
47 54470088 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i) {
48 48417856 : uint32_t sum = carry + a.comp[i] + b.comp[i];
49 48417856 : res.comp[i] = (uint16_t) (sum & 0xffffu);
50 48417856 : carry = sum >> 16;
51 : }
52 6052232 : assert(smp_is_negative(a) != smp_is_negative(b) || smp_is_negative(a) == smp_is_negative(res));
53 6052232 : return res;
54 : }
55 :
56 : smp
57 771848 : smp_not(smp a)
58 : {
59 : int i;
60 : smp res;
61 6946632 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i)
62 6174784 : res.comp[i] = a.comp[i] ^ 0xffffu;
63 771848 : return res;
64 : }
65 :
66 : smp
67 771848 : smp_negate(smp a)
68 : {
69 771848 : return smp_add(smp_not(a), smp_one);
70 : }
71 :
72 : smp
73 1445104 : smp_from_int(int64_t n)
74 : {
75 : int i;
76 : uint64_t un;
77 : smp res;
78 :
79 1445104 : if (n >= 0) {
80 1160120 : un = (uint64_t) n;
81 : } else {
82 284984 : un = (uint64_t) -n;
83 : }
84 11560832 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i) {
85 11560832 : res.comp[i] = (uint16_t) (un & 0xffffu);
86 11560832 : un = un >> 16;
87 : }
88 1445104 : if (n < 0)
89 284984 : return smp_negate(res);
90 1160120 : return res;
91 : }
92 :
93 : bool
94 23735752 : smp_is_negative(smp a)
95 : {
96 23735752 : return (a.comp[SMP_NUM_COMPONENTS-1] >> 15) != 0;
97 : }
98 :
99 : bool
100 6375480 : smp_is_zero(smp a)
101 : {
102 : int i;
103 6375480 : uint16_t or = 0;
104 :
105 57379320 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i)
106 51003840 : or |= a.comp[i];
107 6375480 : return or == 0;
108 : }
109 :
110 : smp
111 432 : smp_sub(smp a, smp b)
112 : {
113 432 : smp c = smp_negate(b);
114 432 : return smp_add(a, c);
115 : }
116 :
117 : double
118 95200 : smp_to_double(smp a)
119 : {
120 : int i;
121 95200 : double n = 0;
122 95200 : double mult = 1.0;
123 95200 : smp b = a;
124 95200 : if (smp_is_negative(a))
125 47504 : b = smp_negate(b);
126 856800 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i) {
127 761600 : n += b.comp[i] * mult;
128 761600 : mult = mult * 65536.0;
129 : }
130 95200 : if (smp_is_negative(a))
131 47504 : return -n;
132 : return n;
133 : }
134 :
135 : int
136 24 : smp_cmp(smp a, smp b)
137 : {
138 24 : smp diff = smp_sub(a, b);
139 24 : if (smp_is_negative(diff))
140 : return -1;
141 16 : if (smp_is_zero(diff))
142 : return 0;
143 8 : return 1;
144 : }
145 :
146 : // divide and return remainder
147 : static uint16_t
148 : div_small(smp *n, uint16_t div)
149 : {
150 : int i;
151 6349248 : uint32_t remainder = 0;
152 63492480 : for (i = SMP_NUM_COMPONENTS; --i >= 0;) {
153 50793984 : uint32_t comp = remainder * 0x10000u + n->comp[i];
154 50793984 : remainder = comp % div;
155 50793984 : n->comp[i] = (uint16_t) (comp / div);
156 : }
157 : return (uint16_t) remainder;
158 : }
159 :
160 : char *
161 692416 : smp_to_string(smp a)
162 : {
163 : char buf[SMP_NUM_COMPONENTS * 16 * 4 / 10 + 2];
164 692416 : char *p = buf+sizeof(buf);
165 692416 : const bool negative = smp_is_negative(a);
166 692416 : smp n = negative ? smp_negate(a) : a;
167 :
168 692416 : *--p = 0;
169 : do
170 6349248 : *--p = div_small(&n, 10) + '0';
171 6349248 : while (!smp_is_zero(n));
172 692416 : if (negative)
173 345304 : *--p = '-';
174 692416 : return strdup(p);
175 : }
176 :
177 : // multiple a number
178 : static void
179 843920 : mul_small(smp *n, uint16_t factor)
180 : {
181 : int i;
182 843920 : uint32_t carry = 0;
183 7595280 : for (i = 0; i < SMP_NUM_COMPONENTS; ++i) {
184 6751360 : uint32_t comp = (uint32_t) n->comp[i] * factor + carry;
185 6751360 : carry = comp >> 16;
186 6751360 : n->comp[i] = (uint16_t) (comp & 0xffffu);
187 : }
188 843920 : assert(carry == 0);
189 843920 : }
190 :
191 : smp
192 91816 : smp_from_string(const char *s)
193 : {
194 91816 : bool negative = false;
195 91816 : smp n = smp_zero;
196 91816 : uint16_t base = 10;
197 :
198 91816 : switch (*s) {
199 45760 : case '-':
200 45760 : negative = true;
201 45760 : case '+':
202 45760 : ++s;
203 : }
204 91816 : if (*s == '0') {
205 264 : base = 8;
206 264 : ++s;
207 264 : if (*s == 'x' || *s == 'X') {
208 48 : ++s;
209 48 : base = 16;
210 : }
211 : }
212 844008 : for (;*s; ++s) {
213 844008 : int digit = 0;
214 844008 : if (*s == '\'')
215 88 : continue;
216 843920 : mul_small(&n, base);
217 843920 : if (*s >= '0' && *s <= '9')
218 843920 : digit = *s - '0';
219 0 : else if (*s >= 'a' && *s <= 'z')
220 0 : digit = *s - 'a' + 10;
221 0 : else if (*s >= 'A' && *s <= 'Z')
222 0 : digit = *s - 'A' + 10;
223 : else
224 : assert(!!"Invalid digit entered");
225 843920 : n = smp_add(n, smp_from_int(digit));
226 : }
227 91816 : if (negative)
228 45760 : return smp_negate(n);
229 46056 : return n;
230 : }
|