Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/tests/bcl.c
39507 views
1
/*
2
* *****************************************************************************
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2018-2025 Gavin D. Howard and contributors.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions are met:
10
*
11
* * Redistributions of source code must retain the above copyright notice, this
12
* list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright notice,
15
* this list of conditions and the following disclaimer in the documentation
16
* and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
* POSSIBILITY OF SUCH DAMAGE.
29
*
30
* *****************************************************************************
31
*
32
* Tests for bcl(3).
33
*
34
*/
35
36
#include <stdlib.h>
37
#include <stdbool.h>
38
#include <string.h>
39
40
#include <bcl.h>
41
42
/**
43
* Takes an error code and aborts if it actually is an error.
44
* @param e The error code.
45
*/
46
static void
47
err(BclError e)
48
{
49
if (e != BCL_ERROR_NONE) abort();
50
}
51
52
int
53
main(void)
54
{
55
BclError e;
56
BclContext ctxt;
57
size_t scale;
58
BclNumber n, n2, n3, n4, n5, n6, n7;
59
char* res;
60
BclBigDig b = 0;
61
62
e = bcl_start();
63
err(e);
64
65
// We do this twice to test the reference counting code.
66
e = bcl_init();
67
err(e);
68
e = bcl_init();
69
err(e);
70
71
// If bcl is set to abort on fatal error, that is a bug because it should
72
// default to off.
73
if (bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
74
75
bcl_setAbortOnFatalError(true);
76
77
// Now it *should* be set.
78
if (!bcl_abortOnFatalError()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
79
80
// We do this twice to test the context stack.
81
ctxt = bcl_ctxt_create();
82
bcl_pushContext(ctxt);
83
ctxt = bcl_ctxt_create();
84
bcl_pushContext(ctxt);
85
86
// Ensure that the scale is properly set.
87
scale = 10;
88
bcl_ctxt_setScale(ctxt, scale);
89
scale = bcl_ctxt_scale(ctxt);
90
if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
91
92
scale = 16;
93
bcl_ctxt_setIbase(ctxt, scale);
94
scale = bcl_ctxt_ibase(ctxt);
95
if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
96
97
// Now the obase.
98
bcl_ctxt_setObase(ctxt, scale);
99
scale = bcl_ctxt_obase(ctxt);
100
if (scale != 16) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
101
102
// Set the back for the tests
103
bcl_ctxt_setIbase(ctxt, 10);
104
scale = bcl_ctxt_ibase(ctxt);
105
if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
106
bcl_ctxt_setObase(ctxt, 10);
107
scale = bcl_ctxt_obase(ctxt);
108
if (scale != 10) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
109
110
// Ensure that creating, duping, and copying works.
111
n = bcl_num_create();
112
n2 = bcl_dup(n);
113
bcl_copy(n, n2);
114
115
// Ensure that parsing works.
116
n3 = bcl_parse("2938");
117
err(bcl_err(n3));
118
n4 = bcl_parse("-28390.9108273");
119
err(bcl_err(n4));
120
121
// We also want to be sure that negatives work. This is a special case
122
// because bc and dc generate a negative instruction; they don't actually
123
// parse numbers as negative.
124
if (!bcl_num_neg(n4)) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
125
126
// Add them and check the result.
127
n5 = bcl_add_keep(n3, n4);
128
err(bcl_err(n5));
129
res = bcl_string(n5);
130
if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
131
if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
132
133
// We want to ensure all memory gets freed because we run this under
134
// Valgrind.
135
free(res);
136
137
// Add them and check the result.
138
n3 = bcl_add(n3, n4);
139
err(bcl_err(n3));
140
res = bcl_string_keep(n3);
141
if (res == NULL) err(BCL_ERROR_FATAL_ALLOC_ERR);
142
if (strcmp(res, "-25452.9108273")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
143
144
// We want to ensure all memory gets freed because we run this under
145
// Valgrind.
146
free(res);
147
148
// Ensure that divmod, a special case, works.
149
n4 = bcl_parse("8937458902.2890347");
150
err(bcl_err(n4));
151
e = bcl_divmod_keep(n4, n3, &n5, &n6);
152
err(e);
153
154
res = bcl_string(n5);
155
if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
156
free(res);
157
158
res = bcl_string(n6);
159
if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
160
free(res);
161
162
// Ensure that divmod, a special case, works.
163
n4 = bcl_parse("8937458902.2890347");
164
err(bcl_err(n4));
165
e = bcl_divmod(bcl_dup(n4), n3, &n5, &n6);
166
err(e);
167
168
res = bcl_string(n5);
169
if (strcmp(res, "-351137.0060159482")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
170
free(res);
171
172
res = bcl_string(n6);
173
if (strcmp(res, ".00000152374405414")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
174
free(res);
175
176
// Ensure that sqrt works. This is also a special case. The reason is
177
// because it is a one-argument function. Since all binary operators go
178
// through the same code (basically), we can test add and be done. However,
179
// sqrt does not, so we want to specifically test it.
180
n4 = bcl_sqrt(n4);
181
err(bcl_err(n4));
182
183
res = bcl_string(bcl_dup(n4));
184
185
if (strcmp(res, "94538.1346457028")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
186
187
free(res);
188
189
// We want to check that numbers are properly extended...
190
e = bcl_num_setScale(n4, 20);
191
err(e);
192
193
res = bcl_string(bcl_dup(n4));
194
195
if (strcmp(res, "94538.13464570280000000000"))
196
err(BCL_ERROR_FATAL_UNKNOWN_ERR);
197
198
free(res);
199
200
// ...and truncated.
201
e = bcl_num_setScale(n4, 0);
202
err(e);
203
204
res = bcl_string(bcl_dup(n4));
205
206
if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
207
208
free(res);
209
210
// Check conversion to hardware integers...
211
e = bcl_bigdig(n4, &b);
212
err(e);
213
214
if (b != 94538) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
215
216
// ...and back.
217
n4 = bcl_bigdig2num(b);
218
err(bcl_err(n4));
219
220
res = bcl_string(bcl_dup(n4));
221
222
if (strcmp(res, "94538")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
223
224
free(res);
225
226
// Check rand.
227
n4 = bcl_frand(10);
228
err(bcl_err(n4));
229
230
// Check that no asserts fire in shifting.
231
n4 = bcl_lshift(n4, bcl_bigdig2num(10));
232
err(bcl_err(n4));
233
234
// Repeat.
235
n3 = bcl_irand(n4);
236
err(bcl_err(n3));
237
238
// Repeat.
239
n2 = bcl_ifrand_keep(n3, 10);
240
err(bcl_err(n2));
241
242
// Repeat.
243
n2 = bcl_ifrand(bcl_dup(n3), 10);
244
err(bcl_err(n2));
245
246
// Still checking asserts.
247
e = bcl_rand_seedWithNum_keep(n3);
248
err(e);
249
250
// Still checking asserts.
251
e = bcl_rand_seedWithNum(n3);
252
err(e);
253
254
// Still checking asserts.
255
n4 = bcl_rand_seed2num();
256
err(bcl_err(n4));
257
258
// Finally, check modexp, yet another special case.
259
n5 = bcl_parse("10");
260
err(bcl_err(n5));
261
262
n6 = bcl_modexp_keep(n5, n5, n5);
263
err(bcl_err(n6));
264
265
n7 = bcl_modexp(bcl_dup(n5), bcl_dup(n5), bcl_dup(n5));
266
err(bcl_err(n7));
267
268
// Clean up.
269
bcl_num_free(n);
270
271
// Test leading zeroes.
272
if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
273
274
n = bcl_parse("0.01");
275
err(bcl_err(n));
276
277
n2 = bcl_parse("-0.01");
278
err(bcl_err(n2));
279
280
n3 = bcl_parse("1.01");
281
err(bcl_err(n3));
282
283
n4 = bcl_parse("-1.01");
284
err(bcl_err(n4));
285
286
res = bcl_string_keep(n);
287
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
288
289
free(res);
290
291
res = bcl_string(bcl_dup(n));
292
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
293
294
free(res);
295
296
res = bcl_string(bcl_dup(n2));
297
if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
298
299
free(res);
300
301
res = bcl_string(bcl_dup(n3));
302
if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
303
304
free(res);
305
306
res = bcl_string(bcl_dup(n4));
307
if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
308
309
free(res);
310
311
bcl_setLeadingZeroes(true);
312
313
if (!bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
314
315
res = bcl_string(bcl_dup(n));
316
if (strcmp(res, "0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
317
318
free(res);
319
320
res = bcl_string(bcl_dup(n2));
321
if (strcmp(res, "-0.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
322
323
free(res);
324
325
res = bcl_string(bcl_dup(n3));
326
if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
327
328
free(res);
329
330
res = bcl_string(bcl_dup(n4));
331
if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
332
333
free(res);
334
335
bcl_setLeadingZeroes(false);
336
337
if (bcl_leadingZeroes()) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
338
339
res = bcl_string(n);
340
if (strcmp(res, ".01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
341
342
free(res);
343
344
res = bcl_string(n2);
345
if (strcmp(res, "-.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
346
347
free(res);
348
349
res = bcl_string(n3);
350
if (strcmp(res, "1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
351
352
free(res);
353
354
res = bcl_string(n4);
355
if (strcmp(res, "-1.01")) err(BCL_ERROR_FATAL_UNKNOWN_ERR);
356
357
free(res);
358
359
bcl_ctxt_freeNums(ctxt);
360
361
bcl_gc();
362
363
// We need to pop both contexts and free them.
364
bcl_popContext();
365
366
bcl_ctxt_free(ctxt);
367
368
ctxt = bcl_context();
369
370
bcl_popContext();
371
372
bcl_ctxt_free(ctxt);
373
374
// Decrement the reference counter to ensure all is freed.
375
bcl_free();
376
377
bcl_free();
378
379
bcl_end();
380
381
return 0;
382
}
383
384