leapc
Loading...
Searching...
No Matches
quo_mod_test.c
1#include "quo_mod.h"
2
3#include <limits.h>
4/* Keep assert-based tests enabled in Release builds. */
5#ifdef NDEBUG
6#undef NDEBUG
7#endif
8#include <assert.h>
9#include <math.h>
10#include <stdlib.h>
11
12/*
13 * Cross-check modulo results against Lua-style floor-based modulo:
14 *
15 * #define luai_nummod(a, b) ((a) - floor((double)(a) / (b)) * (b))
16 *
17 * A nonzero result has the divisor's sign. Use this floating-point reference
18 * only for the small integer range below, where rounding does not affect it.
19 */
20#define luai_nummod(a, b) ((a) - floor((double)(a) / (b)) * (b))
21
22static double nummod(double x, double y) { return luai_nummod(x, y); }
23
24static void check_quo_mod(int x, int y) {
25 const long long trunc_quo = (long long)x / y;
26 const long long trunc_mod = (long long)x % y;
27 long long expected_quo = trunc_quo;
28 long long expected_mod = trunc_mod;
29
30 if (expected_mod != 0 && (expected_mod < 0) != (y < 0)) {
31 expected_mod += y;
32 expected_quo--;
33 }
34
35 const struct quo_mod qm = quo_mod(x, y);
36 assert(qm.quo == expected_quo);
37 assert(qm.mod == expected_mod);
38 assert((long long)x == (long long)y * qm.quo + qm.mod);
39 if (y > 0)
40 assert(0 <= qm.mod && qm.mod < y);
41 else
42 assert(y < qm.mod && qm.mod <= 0);
43}
44
45int quo_mod_test(int argc, char **argv) {
46 static const int boundary_values[] = {
47 INT_MIN, INT_MIN + 1, -2, -1, 0, 1, 2, INT_MAX - 1, INT_MAX,
48 };
49 static const struct {
50 int x, y, quo, mod;
51 } cases[] = {
52 {7, 3, 2, 1},
53 {-7, 3, -3, 2},
54 {7, -3, -3, -2},
55 {-7, -3, 2, -1},
56 {6, -3, -2, 0},
57 {0, INT_MIN, 0, 0},
58 {INT_MIN, 3, INT_MIN / 3 - (INT_MIN % 3 != 0), INT_MIN % 3 + (INT_MIN % 3 != 0 ? 3 : 0)},
59 {INT_MIN, -3, INT_MIN / -3, INT_MIN % -3},
60 {INT_MAX, -3, INT_MAX / -3 - (INT_MAX % -3 != 0), INT_MAX % -3 - (INT_MAX % -3 != 0 ? 3 : 0)},
61 {INT_MAX, INT_MIN, -1, -1},
62 {INT_MIN, INT_MIN, 1, 0},
63 {INT_MIN, INT_MAX, INT_MIN / INT_MAX - (INT_MIN % INT_MAX != 0),
64 INT_MIN % INT_MAX + (INT_MIN % INT_MAX != 0 ? INT_MAX : 0)},
65 };
66
67 for (size_t i = 0; i < sizeof cases / sizeof cases[0]; i++) {
68 const int x = cases[i].x;
69 const int y = cases[i].y;
70 const struct quo_mod qm = quo_mod(x, y);
71 assert(qm.quo == cases[i].quo);
72 assert(qm.mod == cases[i].mod);
73 assert((long long)x == (long long)y * qm.quo + qm.mod);
74 if (y > 0)
75 assert(0 <= qm.mod && qm.mod < y);
76 else
77 assert(y < qm.mod && qm.mod <= 0);
78 }
79
80 /*
81 * Exercise every valid pairing of the listed boundary values, excluding zero
82 * denominators and INT_MIN / -1. Compute expected results in long long to avoid
83 * overflowing intermediate int arithmetic.
84 */
85 for (size_t i = 0; i < sizeof boundary_values / sizeof boundary_values[0]; i++)
86 for (size_t j = 0; j < sizeof boundary_values / sizeof boundary_values[0]; j++) {
87 const int x = boundary_values[i];
88 const int y = boundary_values[j];
89 if (y == 0 || (x == INT_MIN && y == -1))
90 continue;
91 check_quo_mod(x, y);
92 }
93
94 /*
95 * Exhaustively check every pair in [-333, 333], excluding zero denominators.
96 * Verify the quotient, remainder, x = y * quo + mod invariant, and remainder
97 * bounds against the integer oracle; cross-check Lua-style modulo as well.
98 */
99 for (int x = -333; x <= 333; x++)
100 for (int y = -333; y <= 333; y++) {
101 if (y == 0)
102 continue;
103 check_quo_mod(x, y);
104 assert(nummod(x, y) == quo_mod(x, y).mod);
105 }
106
107 return EXIT_SUCCESS;
108}
Quotient and modulus prototypes.
struct quo_mod quo_mod(int x, int y)
Compute the integer quotient and modulus.
Definition quo_mod.c:12
Quotient and remainder in integer space.
Definition quo_mod.h:22
int mod
Integer modulus.
Definition quo_mod.h:30
int quo
Integer quotient.
Definition quo_mod.h:26