h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

math.h (3958B)


      1 #define SWAP(x, y) do { x ^= y; y ^= x; x ^= y; } while (0)
      2 #define MIN(x, y) ((x) < (y) ? (x) : (y))
      3 #define MAX(x, y) ((x) > (y) ? (x) : (y))
      4 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
      5 
      6 STATIC int64_t factorial(int64_t);
      7 STATIC bool isperm(size_t n, const uint8_t [n]);
      8 STATIC int64_t permtoindex(size_t n, const uint8_t [n]);
      9 STATIC void indextoperm(int64_t, size_t n, uint8_t [n]);
     10 STATIC int permsign(size_t n, const uint8_t [n]);
     11 STATIC int64_t digitstosumzero(size_t n, const uint8_t [n], uint8_t);
     12 STATIC void sumzerotodigits(int64_t, size_t n, uint8_t, uint8_t [n]);
     13 STATIC double intpow(double, uint64_t);
     14 
     15 STATIC int64_t
     16 factorial(int64_t n)
     17 {
     18 	int64_t i, ret;
     19 
     20 	if (n > FACTORIAL_MAX) {
     21 		LOG("Error: won't compute factorial for n=%" PRId64 " because"
     22 		    " it is larger than %" PRId64 "\n", n, FACTORIAL_MAX);
     23 		return -1;
     24 	}
     25 
     26 	if (n < 0)
     27 		return 0;
     28 
     29 	for (i = 1, ret = 1; i <= n; i++)
     30 		ret *= i;
     31 
     32 	return ret;
     33 }
     34 
     35 STATIC bool
     36 isperm(size_t n, const uint8_t a[n])
     37 {
     38 	size_t i;
     39 	bool aux[FACTORIAL_MAX+1];
     40 
     41 	if (n > (size_t)FACTORIAL_MAX) {
     42 		LOG("Error: won't compute 'isperm()' for n=%zu because"
     43 		    " it is larger than %" PRId64 "\n", n, FACTORIAL_MAX);
     44 		return false;
     45 	}
     46 
     47 	memset(aux, false, n);
     48 	
     49 	for (i = 0; i < n; i++) {
     50 		if (a[i] >= n)
     51 			return false;
     52 		else
     53 			aux[a[i]] = true;
     54 	}
     55 
     56 	for (i = 0; i < n; i++)
     57 		if (!aux[i])
     58 			return false;
     59 
     60 	return true;
     61 }
     62 
     63 STATIC int64_t
     64 permtoindex(size_t n, const uint8_t a[n])
     65 {
     66 	size_t i, j;
     67 	int64_t c, ret;
     68 
     69 	if (n > (size_t)FACTORIAL_MAX) {
     70 		LOG("Error: won't compute 'permtoindex()' for n=%zu because "
     71 		    "it is larger than %" PRId64 "\n", n, FACTORIAL_MAX);
     72 		return -1;
     73 	}
     74 
     75 	if (!isperm(n, a))
     76 		return -1;
     77 
     78 	for (i = 0, ret = 0; i < n; i++) {
     79 		for (j = i+1, c = 0; j < n; j++)
     80 			c += (a[i] > a[j]) ? 1 : 0;
     81 		ret += factorial(n-i-1) * c;
     82 	}
     83 
     84 	return ret;
     85 }
     86 
     87 STATIC void
     88 indextoperm(int64_t p, size_t n, uint8_t r[n])
     89 {
     90 	int64_t c;
     91 	size_t i, j;
     92 	uint8_t a[FACTORIAL_MAX+1];
     93 
     94 	if (n > FACTORIAL_MAX) {
     95 		LOG("Error: won't compute 'indextoperm()' for n=%zu because "
     96 		    "it is larger than %" PRId64 "\n", n, FACTORIAL_MAX);
     97 		goto indextoperm_error;
     98 	}
     99 
    100 	memset(a, 0, n);
    101 
    102 	if (p < 0 || p >= factorial(n))
    103 		goto indextoperm_error;
    104 
    105 	for (i = 0; i < n; i++) {
    106 		for (j = 0, c = 0; c <= p / factorial(n-i-1); j++)
    107 			c += a[j] ? 0 : 1;
    108 		r[i] = j-1;
    109 		a[j-1] = 1;
    110 		p %= factorial(n-i-1);
    111 	}
    112 
    113 	if (!isperm(n, r))
    114 		goto indextoperm_error;
    115 
    116 	return;
    117 
    118 indextoperm_error:
    119 	memset(r, UINT8_ERROR, n);
    120 }
    121 
    122 STATIC int
    123 permsign(size_t n, const uint8_t a[n])
    124 {
    125 	size_t i, j, ret;
    126 
    127 	for (i = 0, ret = 0; i < n; i++)
    128 		for (j = i+1; j < n; j++)
    129 			ret += a[i] > a[j] ? 1 : 0;
    130 
    131 	return ret % 2;
    132 }
    133 
    134 STATIC int64_t
    135 digitstosumzero(size_t n, const uint8_t a[n], uint8_t b)
    136 {
    137 	int64_t ret, p;
    138 	size_t i, sum;
    139 
    140 	if (!((n == 8 && b == 3 ) || (n == 12 && b == 2))) {
    141 		LOG("Won't compute 'sumzero' for n=%zu and b=%" PRIu8
    142 		    " (use n=8 b=3 or n=12 b=2)\n", n, b);
    143 		return -1;
    144 	}
    145 
    146 	for (i = 1, ret = 0, p = 1, sum = 0; i < n; i++, p *= (int64_t)b) {
    147 		if (a[i] >= b) {
    148 			LOG("Error: digit %" PRIu8 " larger than maximum"
    149 			    " (b=%" PRIu8 "\n", a[i], b);
    150 			return -1;
    151 		}
    152 		sum += a[i];
    153 		ret += p * (int64_t)a[i];
    154 	}
    155 
    156 	if ((sum + a[0]) % b != 0) {
    157 		LOG("Error: digits do not have sum zero modulo b\n");
    158 		return -1;
    159 	}
    160 
    161 	return ret;
    162 }
    163 
    164 STATIC void
    165 sumzerotodigits(int64_t d, size_t n, uint8_t b, uint8_t a[n])
    166 {
    167 	uint8_t sum;
    168 	size_t i;
    169 
    170 	if (!((n == 8 && b == 3 ) || (n == 12 && b == 2))) {
    171 		LOG("Won't compute 'digits' for n=%" PRIu8 "and b=%" PRIu8
    172 		    " (use n=8 b=3 or n=12 b=2)\n");
    173 		goto sumzerotodigits_error;
    174 	}
    175 
    176 	for (i = 1, sum = 0; i < n; i++, d /= (int64_t)b) {
    177 		a[i] = (uint8_t)(d % (int64_t)b);
    178 		sum += a[i];
    179 	}
    180 	a[0] = (b - (sum % b)) % b;
    181 
    182 	return;
    183 
    184 sumzerotodigits_error:
    185 	memset(a, UINT8_ERROR, n);
    186 }
    187 
    188 STATIC double
    189 intpow(double b, uint64_t e)
    190 {
    191 	double r;
    192 
    193 	if (e == 0)
    194 		return 1;
    195 
    196 	r = intpow(b, e/2);
    197 
    198 	return e % 2 == 0 ? r * r : b * r * r;
    199 }