File size: 4,940 Bytes
78d2150 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Unity requires these even if empty */
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Helper: find the index of a given small prime in primes_ptab.
Returns -1 if not found (should not happen for small primes we use). */
static int find_prime_index(mp_limb_t prime)
{
for (int i = 0; i < PRIMES_PTAB_ENTRIES; i++)
{
if ((mp_limb_t)primes_ptab[i] == prime)
return i;
}
return -1;
}
/* Helper: compute the base index and offset (ioff) for a given index,
matching the 8-way unrolling the kernel supports. */
static void base_and_offset_for_index(int idx, int *base, int *ioff)
{
int off = idx % 8;
*ioff = off;
*base = idx - off;
}
static void init_factors(struct factors *f)
{
memset(f, 0, sizeof(*f));
}
void test_divblock_divides_once_by_3(void)
{
int idx = find_prime_index(3);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
TEST_ASSERT_EQUAL_INT(idx, base + off);
struct factors f; init_factors(&f);
mp_limb_t t0 = (mp_limb_t)3;
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)1);
TEST_ASSERT(f.nfactors == 1);
TEST_ASSERT(f.p[0] == (mp_limb_t)3);
TEST_ASSERT(f.e[0] == 1);
}
void test_divblock_divides_twice_by_3(void)
{
int idx = find_prime_index(3);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
struct factors f; init_factors(&f);
mp_limb_t t0 = (mp_limb_t)9; /* 3^2 */
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)1);
TEST_ASSERT(f.nfactors == 1);
TEST_ASSERT(f.p[0] == (mp_limb_t)3);
TEST_ASSERT(f.e[0] == 2);
}
void test_divblock_non_divisible_returns_input(void)
{
int idx = find_prime_index(3);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
struct factors f; init_factors(&f);
mp_limb_t t0 = (mp_limb_t)10; /* Not divisible by 3 */
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == t0);
TEST_ASSERT(f.nfactors == 0);
}
void test_divblock_returns_remaining_quotient_after_divisions(void)
{
int idx = find_prime_index(3);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
struct factors f; init_factors(&f);
/* t0 = 3^3 * 10 = 270, should divide out 3 three times and return 10 */
mp_limb_t t0 = (mp_limb_t)27 * (mp_limb_t)10;
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)10);
TEST_ASSERT(f.nfactors == 1);
TEST_ASSERT(f.p[0] == (mp_limb_t)3);
TEST_ASSERT(f.e[0] == 3);
}
void test_divblock_works_with_nonzero_offset_prime_23(void)
{
int idx = find_prime_index(23);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
TEST_ASSERT(off >= 0 && off <= 7);
TEST_ASSERT_EQUAL_INT(idx, base + off);
struct factors f; init_factors(&f);
mp_limb_t t0 = (mp_limb_t)23 * (mp_limb_t)7; /* 161 */
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)7);
TEST_ASSERT(f.nfactors == 1);
TEST_ASSERT(f.p[0] == (mp_limb_t)23);
TEST_ASSERT(f.e[0] == 1);
}
void test_divblock_increments_existing_factor_multiplicity(void)
{
int idx = find_prime_index(5);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
struct factors f; init_factors(&f);
/* Pre-populate factors with prime 5 multiplicity 2 */
f.nfactors = 1;
f.p[0] = (mp_limb_t)5;
f.e[0] = 2;
mp_limb_t t0 = (mp_limb_t)5;
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)1);
TEST_ASSERT(f.nfactors == 1);
TEST_ASSERT(f.p[0] == (mp_limb_t)5);
TEST_ASSERT(f.e[0] == 3);
}
void test_divblock_t0_equal_1_no_change(void)
{
int idx = find_prime_index(7);
TEST_ASSERT_NOT_EQUAL(-1, idx);
int base = 0, off = 0;
base_and_offset_for_index(idx, &base, &off);
struct factors f; init_factors(&f);
mp_limb_t t0 = (mp_limb_t)1;
mp_limb_t r = divblock(&f, t0, &primes_dtab[base], (idx_t)base, off);
TEST_ASSERT(r == (mp_limb_t)1);
TEST_ASSERT(f.nfactors == 0);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_divblock_divides_once_by_3);
RUN_TEST(test_divblock_divides_twice_by_3);
RUN_TEST(test_divblock_non_divisible_returns_input);
RUN_TEST(test_divblock_returns_remaining_quotient_after_divisions);
RUN_TEST(test_divblock_works_with_nonzero_offset_prime_23);
RUN_TEST(test_divblock_increments_existing_factor_multiplicity);
RUN_TEST(test_divblock_t0_equal_1_no_change);
return UNITY_END();
} |