I am new to C programming and wrote the following algorithm for the calculation of the Jacobi Symbol. Though there are some faster versions of this algorithm available I am only looking for some feedback on my coding style. I should mention that I was taught to ONLY USE ONE return statement in functions and NOT to use things like break
, continue
or go-to
. This is a "philosophy" I also believe in.
- How could I improve?
- Is anything unclearly formulated?
One point I could think of would be to use "long long" instead of only "long" since this algorithm is used in cryptography and should thus be suited for very large integers.
Any kind of feedback would be welcome.
EDIT: There is still a (commented) print statement in this code that helps to visualize the algorithm.
#include <stdio.h>
#include <stdlib.h>
/*
+*****************************************************************************
* Function Name: jacobi
* Function: Calculate the Jacobi Symbol
* Arguments: a = numerator
n = denominator
* Return: (a|n)
* Notes: This function evaluates the Jacobi Symbol for two integers
a and n. It is based on the same idea as the Euclidean
alogrithm for the gcd. The bit complexity is O(log^2(p)).
-****************************************************************************/
short jacobi(long a, long n)
{
// The two if-conditions below terminate the function in case of wrong inputs, i.e.: n < 3 or 2 | n.
if (n<3) {
printf("Wrong input for the Jacobi Symbol: The denominator has to be greater than 2.\n");
exit(0);
}
if (n%2 == 0) {
printf("Wrong input for the Jacobi Symbol: The denominator has to be coprime to 2.\n");
exit(0);
}
long n_mod8 = 0;
short result = 1;
short condition = 1;
while (condition == 1) {
// printf("(%d|%d) and result = %d \n", a, n, result);
a = a % n;
// The The if-condition below utilises the fact that (0|n) = 0.
if (a == 0) {
condition = 0;
result = 0;
} else {
// The while-loop below utilises the Second Supplement
// to extract the 2’s out of a.
while (a % 2 == 0) {
a = a / 2;
n_mod8 = n % 8;
if (n_mod8 == 3 || n_mod8 == 5) {
result = -result;
}
}
// The if-condition below utilises the fact (1|n) = 1.
if ( a == 1) {
condition = 0;
} else {
// This else-condition utilises the Law of
// Quadratic Reciprocity to transfer (a|n) to (n|a).
long tmp = a;
a = n;
n = tmp;
if (a % 4 == 3 && n % 4 == 3) {
result = -result;
}
}
}
}
return result;
}
int main()
{
printf("%d", jacobi(4852777,12408107));
return 0;
}
```
break
in a loop to...break out of the loop is a curious anti-pattern you've developed, especially considering that you useexit
inside of pre-condition checks to break out of the entire program! I've seen this sort of code before, setting flags to indicate when the loop was done instead of actually just breaking out. It was a horrible spaghetti mess. Fortunately, it wasn't generated by a human; it was generated by a tool. I promptly rewrote it, reduced the number of lines by about half, and made it much more readable in the process. Also easier for compiler to optimize. \$\endgroup\$exits
are error exist you should useexit(EXIT_FAILURE)
instead ofexit(0)
. It may be useful for shell&&
/||
combinations. And thoseprintf
's should go tostderr
:printf(…)
=>fprintf(stderr, …)
. \$\endgroup\$