Lucas Lehmer C implementation up to M31 without BIGINT - c

I started learning C yesterday and I've literally just learned the basic data types (char, int, float), while loops, operators and printing.
Before I learn anything more, I wanted to set myself a mathematical challenge as the above should be enough to do elementary arithmetic. These are the constraints I'm working within - I'm well aware there are other ways to do the problem, like I could create an array to store all of the values of the Lucas Lehmer sequence, or I could use BIGINT etc. But I'm trying to use just what I've learned so far.
It just so happens that the largest possible INT value in C is 2^31-1, which is also a Mersenne Prime, M31. So I'd like to write a function which tests all candidate Mersennes up to M31.
This was my initial stab at it:
#include <stdio.h>
#include <stdbool.h>
int main() {
int p = 3;
while (p < 32) {
int e = 0;
int Mp = 1;
while (e < p) {
Mp *= 2;
++e;
}
Mp -= 1;
printf("Testing p=%d: %d\n", p, Mp);
int i = 0;
int Si = 4;
while (i < (p - 2))
{
Si = (Si * Si - 2) % Mp;
++i;
}
if (Si == 0) {
printf("2^%d is prime: %d\n", p, Mp);
}
++p;
++p;
}
return 0;
}
This worked up to p = 13, at which point we get a problem in the generation of the Si numbers, in particular the squaring, which wraps round beyond the limit for a signed INT.
In order to handle the squaring in a way that doesn't involve getting a number bigger than 2^31-1 I turned multiplication into repeated addition:
int main() {
int p = 3;
while (p < 32) {
int e = 0;
int Mp = 1;
while (e < p) {
Mp *= 2;
++e;
}
Mp -= 1;
int i = 0;
int Si = 4;
while (i < (p - 2))
{
int newSi;
newSi = 0;
int multiplications = 0;
while (multiplications < Si) {
newSi = (newSi + Si) % Mp;
++multiplications;
}
Si = newSi - 2;
++i;
}
if (Si == 0) {
printf("2^%d is prime: %d\n", p, Mp);
}
++p;
++p;
}
return 0;
}
But this had a huge effect on the time complexity of the function. It also only detected up to 2^19-1 as prime. Switching all values to unsigned instead of int makes the algorithm work up to 2^31 - 1, as below, but I'm trying to avoid doing so as I'd really like to do this within the bounds of a signed integer, just to see if it's possible.
#include <stdio.h>
int main() {
unsigned p = 3;
while (p < 32) {
unsigned e = 0;
unsigned Mp = 1;
while (e < p) {
Mp *= 2;
++e;
}
Mp -= 1;
unsigned i = 0;
unsigned Si = 4;
while (i < (p - 2))
{
unsigned newSi;
newSi = 0;
unsigned multiplications = 0;
while (multiplications < Si) {
newSi = (newSi + Si) % Mp;
++multiplications;
}
Si = newSi - 2;
++i;
}
if (Si == 0) {
printf("2^%d is prime: %d\n", p, Mp);
}
++p;
++p;
}
return 0;
}
But this has had a huge effect on the time complexity of the function.
Can anyone advise if there's an efficient way to run this function with only the functionality I've learned to date? I'm very particular about this constraint on the functionality I can use - I could easily just follow the next few lessons and learn other features of C, but the challenge here is to do so using these elementary skills only. I have found other questions on StackOverflow relating to an implementation of LL testing, but none that ask about an efficient algorithm that just uses math operators, int, while and printf.

Related

Printing a Count in C Only Printing to 65

I am trying to make a very simple 64 bit operating system, and so far have done really well, but since I am not very familiar with C I have been having some problems with it, and this one stumped me. The output would count like normal (1 2 3 4 5 6 7 8 9 10 11 12 etc.) but it would stop printing at 65. I know that "print.h" works because I have tested it many times, but I am not so sure on my method of converting the numbers to a character array. Any help at all would be much appreciated. Here's my code:
#include "print.h"
int getLen(int x) {
unsigned int n = x;
int count = 0;
while(n!=0)
{
n=n/10;
count++;
}
return count;
}
char ITC(unsigned int x) {
char ret;
unsigned int n = x;
if(n==0){
ret='0';
}
if(n==1){
ret='1';
}
if(n==2){
ret='2';
}
if(n==3){
ret='3';
}
if(n==4){
ret='4';
}
if(n==5){
ret='5';
}
if(n==6){
ret='6';
}
if(n==7){
ret='7';
}
if(n==8){
ret='8';
}
if(n==9){
ret='9';
}
return ret;
}
void kernel_main(){
print_clear();
print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
char out[512];
int onOut = 0;
for (int i = 0; i < 100; i++)
{
onOut++;
unsigned int n = i;
while (n != 0) {
out[onOut + getLen(n)] = ITC(n%10);
n /= 10;
}
out[onOut + getLen(i) + 1] = '\n';
onOut += getLen(i) + 1;
}
for (int i = 0; i < 512; i++)
{
print_char(out[i]);
}
}
The issue is with the algorithm rather then perhaps familiarity with C. Your indexing into the unitialised out array was leaving gaps so outputting junk that happened to be in the array.
Consider the following - the parts I changed annotated - not all are part of the solution; just good practice:
char out[512] = {0}; // <<< Good idea to initialise
int onOut = 0;
for (int i = 1; i < 100; i++) // Start form 1 not zero
{
int n = i; // <<< Type agreement with i
int numlen = getLen(n) ; // <<< Get the length of the initial number
// Don't unnecessarily calculate in the loop
// when you know it decrements by 1 on each
// iteration
for( int j = onOut + numlen; // <<< Start from the end position
(n!=0) && j >= onOut; // <<< toward the start position
j-- ) // <<< backward
{
out[j - 1] = ITC(n % 10); // <<< Insert digit, starting from index zero
n /= 10;
}
onOut += numlen ; // <<< Move to end of newly inserted number
out[onOut++] = '\n'; // <<< Add the newline
}
Note that you have over-complicated this code somewhat; especially w.r.t. to ITC() if you code like that habitually your "operating system" will run very slowly. ITC() can be reduced to a simple look-up thus:
char ITC(unsigned int x)
{
static const char digits[] = "0123456789" ;
return digits[x] ;
}
Or in any likely character set where digits are contiguous and in order, arithmetically thus:
char ITC(unsigned int x)
{
return '0' + x ;
}
I'd give two pieces of advice for success in this project and programming in general.
Comment your code. If you have to explain it to yourself, you are more likely to find the flaws. But also later maintainers or people assisting you with debugging will have an idea of your intended semantics.
Use a debugger. I used a debugger to figure out were your code was going wrong because it was quicker and more direct that other methods. Certainly quicker than posting questions of StackOverflow!
I don't understand why you make that one function so complicated, what's wrong with this?
char ITC(unsigned int x) {
return (char)((int)'0' + n);
}
Some of the above comments are correct, plus you also need to terminate your string with a null character... and NOT print all 512 characters of a non-initialized array. Something like this should work much better (though you should also include the contents of print.h so we can see if there are any problems there):
#include "print.h"
int getLen(unsigned int x)
{
int count = 0;
while (n != 0) {
n = n / 10;
count++;
}
return count;
}
char ITC(unsigned int x)
{
return (x <= 9) ? x + '0' : '?';
}
void kernel_main()
{
char out[512];
int onOut = 0;
print_clear();
print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
for (int i = 0; i < 100; i++) {
unsigned int len = getLen(i);
unsigned int n = i;
unsigned int offs = len;
while (n != 0) {
out[onOut + offs--] = ITC(n % 10);
n /= 10;
}
out[onOut + len + 1] = '\n';
onOut += len + 1;
}
out[onOut + 1] = 0;
for (int i = 0; out[i] != 0; i++) {
print_char(out[i]);
}
}

Finding proper descendants of an integer [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm stuck on an basic algorithmic issue and I can't figure out how to solve it.
Basically I wanna list all numbers that are proper descendants of an integer. That is to say, if my number is 21, I want to use its binary representation (10101) and list all numbers which have at least one common bit of value 1 with 21 and are lower than 21. The result here should be 10100, 10001, 10000, 101, 100, 1.
The mathematical definition of proper descendants is as follows:
Let h be a nonnegative number less than 2^m. h = d0 + d1*2^1 + ... + dm-1*2^(m-1) where di = 0 or 1.
Let h' be another nonnegative such as h' = d0' + d1'*2^1 + ... + dm-1'*2^(m-1) where di' = 0 or 1.
h' is a descendant of h if di'<=di for 0<=i<m
I've tried many implementations in both Python and C and tried the old pen and paper technique, but all of them failed. I know it's rather simple but I can't seem to figure it out. I'm coding in C so if you find a solution that works in C that would be ideal, but I'd take anything right now.
Here is a very simple approach: enumerate all integers between n-1 and 1 and print those that are strictly included in n, ie: (i & n) == i.
void list_descendants(int n) {
printf("descendants of %d:", n);
for (int i = n; i --> 1;) {
if ((i & n) == i)
printf(" %d", i);
}
printf("\n");
}
Ok so I finally came up with a code in C that is far from good looking and probably horribly optimised but still works as intended. There are probably much simpler solutions but here is mine for knowledge purposes :
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
unsigned int pui(unsigned int a, unsigned int b)
{
if (b == 0)
return 1;
if (b == 1)
return a;
if (b % 2 == 0)
return pui(a * a, b / 2);
else
return pui(a * a, (b - 1) / 2);
}
unsigned int testBit(unsigned int h, unsigned int offset)
{
unsigned int mask = 1 << offset;
return (h & mask);
}
bool isInList(unsigned int x, unsigned int *output_size, unsigned int **output)
{
for (int i = 0; i < *output_size; i++)
{
if (*(*output + i) == x)
{
return true;
}
}
return false;
}
void listDescendants(unsigned int h, unsigned int *output_size, unsigned int **output, int *currently_processing)
{
unsigned int max_offset = 0;
unsigned int temp_h = h;
unsigned int initial_output_size = *output_size;
while (temp_h > 0)
{
max_offset++;
temp_h /= 2;
}
unsigned int h_radix2[max_offset];
for (int i = 0; i < max_offset; i++)
{
if (testBit(h, i))
{
if (h > pui(2, i) && !isInList(h - pui(2, i), output_size, output))
{
*(*output + *output_size) = h - pui(2, i);
*output_size += 1;
}
}
}
if (*currently_processing < (int)*output_size)
{
*currently_processing += 1;
listDescendants(*(*output + *currently_processing), output_size, output, currently_processing);
}
}
int main()
{
int currently_processing = -1;
unsigned int size = 0;
unsigned int *output = malloc(300 * sizeof(unsigned int));
listDescendants(21, &size, &output, &currently_processing);
printf("size = %u\n", size);
for (int i = 0; i < size; i++)
{
printf("%u ", output[i]);
}
printf("\n");
return 0;
}
You can use a recursive solution, such as the following one.
I'm a bit lazy, so I didn't put the numbers in a list but simply printed them, and I also printed 0 and the given number.
I believe you can easily adjust the code so it will do what you desire.
#include <stdio.h>
#define CHAR_BIT 8
void ProperDescendantsRecursive(unsigned int num, unsigned int bit_index)
{
if (CHAR_BIT * sizeof(unsigned int) - 1 == bit_index)
{
printf("%u\n", num);
}
else
{
unsigned int mask = 1U << bit_index;
if (num & mask)
{
/* with the bit at index bit_index is off */
ProperDescendantsRecursive(num ^ mask, bit_index + 1);
/* with the bit at index bit_index is on */
ProperDescendantsRecursive(num, bit_index + 1);
}
else
{
ProperDescendantsRecursive(num, bit_index + 1);
}
}
}
void ProperDescendants(unsigned int num)
{
ProperDescendantsRecursive(num, 0);
}
int main(void)
{
ProperDescendants(21);
return 0;
}
compiling and running results this output:
0
16
4
20
1
17
5
21

Printf outputting a bunch of zeros

I'm new to C, so I apologize if the answer to this is painfully obvious! I mean to loop through two 2D arrays, passing correspondingly indexed members as arguments to my chineseRemainder routine, i.e. for each iteration, array1[i] and array2[i] should be passed to the routine, where i = i. I am expecting the output of a call to printf to be a certain set of numbers -- instead I am getting all zeros. Here is the main routine, where I call the CR function. **edit I gave xp and xq arbitrary int values, since they do not seem to be the problem, and giving them such values gives the same output.
int main(){
int xp, xq, p = 61, q = 3;
int i, j;
reverseInteger();
for(i = 0; i < 32; ++i){
for(j = 0; j < 10; ++j){
xq = 4;
xp = 1;
printf("%i\n", chineseRemainder(xq, xp, p, q));
}
}
return 0;
}
For troubleshooting's sake, I dumped the contents of xq and xp to make sure those assignments were going through: they are. The problem must be with the CR routine, because it is printing zero even when I pass any set of integers to it. So, here is that function, and its dependencies:
float power(int base, int exp) {
int i;
float result = 1;
if (exp == 0)
result = 1;
else if (exp == 1)
result = base;
else if(exp > 1){
for (i = 0; i < exp; ++i)
result *= base;
}
else
result = 1/power(base, -exp);
return result;
}
float powerMod(int q, int e, int p){
float result;
result = (int)power(q, e) % p;
return result;
}
typedef struct arrayInside{
int array[30][10];
} arrayInside;
arrayInside codesInside;
struct arrayInside reverseInteger(){
int i, j, number;
for(i = 0; i < 30; ++i){
j = 10;
number = (aryConversion(q3[i], 3));
do {
codesInside.array[i][j-1] = number % 10;
--j;
number = number / 10;
}
while (number);
codesInside.array[i][0] = 0;
};
return codesInside;
}
int chineseRemainder(int xq, int xp, int p, int q){
int tp;
int ceiling = (p*q-1)/2;
tp = ((int)(q * (powerMod(q, -1, p))*xp + p * powerMod(p, -1, q) * xq) % (p*q));
if(tp > ceiling)
tp-=p*q;
return tp;
}
Your chineseRemainder actually returns 0 every time. Look at this -
((int)(q * (powerMod(q, -1, p))*xp + p * powerMod(p, -1, q) * xq) % (p*q));
powerMod(q, -1, p) is zero. So multiplying and adding it also going to give zero. Your function actually returns zero. There is nothing wrong. You probably need to check the logic or change the data types.

Finding the Nth prime number in C language

The code runs just fine but instead of using "for loop" to iterate upto 200000 , I think there can be a better alternative and I am having trouble finding it. I need help to optimise this solution.The time taken by this solution currently is 56ms.
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
int isPrime(long long int number)
{
int i;
for (i=2; i*i<=number; i++) {
if (number % i == 0) return 0;
}
return 1;
}
int returnNPrime(int N)
{
int counter = 0;
int i ;
if(N == 1) return 2;
for(i=3;i<200000;i+=2)
{
if(isPrime(i))
{
counter++;
if(counter == (N-1))
return i;
}
}
return 0;
}
int main(int argc, char *argv[])
{
printf("%d",returnNPrime(10001));
return 0;
}
Don't put an arbitrary stop condition. You know that the list of primes is infinite and that the loop will eventually stop. Write it like this:
int returnNPrime (int N)
{
int counter = 0;
int i;
if (N == 1) return 2;
for (i = 3; ; i += 2)
{
if (isPrime(i))
{
counter++;
if (counter == (N - 1))
return i;
}
}
}
That being said, this solution is inefficient because you don't store previously found primes.
Try something like this:
#include <stdio.h>
#include <stdbool.h>
#define N 10001
int primes[N] = { 2, 3 };
int main ()
{
for (int n = 2; n < N; n++) {
for (int x = primes[n - 1] + 2; ; x += 2) {
bool prime = true;
for (int i = 0; i < n; i++) {
int p = primes[i];
if (p * p > x) {
break;
}
if (x % p == 0) {
prime = false;
break;
}
}
if (prime) {
primes[n] = x;
break;
}
}
}
printf ("%d\n", primes[N - 1]);
}
Read this paper http://cr.yp.to/bib/1996/deleglise.pdf which describes how to count the number of primes <= N in O (n^(2/3)) or so and implement the algorithm. It's substantially faster than the Eratosthenes sieve, because it doesn't actually find any primes but just counts how many there are.
Make an educated guess how large the n-th prime would be. Say the guess is x. Use the algorithm above to find out how many primes <= x there are, then use a sieve if you are close enough, or use a better guess with the information you just found and try again. Total time O (n^(2/3)).
With some decent hardware and a lot of patience this will let you find solutions up to n = 10^22 or so.
OP's method consumes a lot of time with as it does not take advantage that there is no need to determine the remainder if i is not a prime.
for (i=2; i*i<=number; i++) {
if (number % i == 0) return 0;
The Sieve_of_Eratosthenes is likely faster yet is a dramatic change from OP's code.
Suspect this code is still too slow for OP.
The follows adjust OP's code by only attempting to test against previously found primes. Also it uses pcandidate / plist[index] as part of a terminating condition. Optimized compilers often can provide this at a small cost once pcandidate % plist[index] is computed.
bool prime_test(const unsigned long *plist, unsigned long long pcandidate) {
if (pcandidate <= 2) return pcandidate == 2;
for (size_t index = 0; ; index++) {
unsigned long long remainder = pcandidate % plist[index];
if (remainder == 0) return false;
unsigned long long quotient = pcandidate / plist[index];
if (quotient < plist[index]) return true;
}
assert(0);
return true;
}
unsigned long long prime_nth(size_t n) {
unsigned long plist[n+1];
plist[0] = 2;
unsigned long long pcandidate = plist[0];
for (size_t index = 0; index <= n; index++) {
while (!prime_test(plist, pcandidate)) pcandidate++;
plist[index] = (unsigned long) pcandidate;
pcandidate++;
}
return plist[n];
}
A classic simplification involves only seeking new primes amongst odd numbers. Also change all math to unsigned. Left for OP.

To find factorial of 500 and store it in a variable...and perform calculations...How to store such a huge number?

how do i store a huge number in a variable (i) and wont need to change much of the program ?
Is there a available datatype to store factorial of 100 for example ?
#include<stdio.h>
#include<conio.h>
void main()
{
long long int i = 1;
long long int sum = 0;
long long int j = 0;
long long int digit = 0;
for(j = 500; j >= 1; j--)
{
i = i * j;
}
printf("%lld", i);
while(i > 0)
{
digit = i%10;
i = i/10;
sum = sum + digit;
}
printf("\n%lld", sum);
getch();
}
There is no built-in language support for such large numbers. You have two options:
if you can, use existing library, like GMP
implement you own solution
If you decide to take the second path, you might want to consider storing digits (not necesserily decimal) in an array, and perform arithmetic operations using well known school algorithms. Keep in mind it will be (probably considerably) less efficient than heavily optimized library code.
#Marcin Łoś is on the money, no C solution without using a library or rolling your own functions.
Follows is a fun, but not imaginative solution where the large number is stored as a array of char (in reverse order).
#include <stdio.h>
#include <string.h>
#include <math.h>
void Mult(char *BigNum, unsigned Factor) {
unsigned Accumulator = 0;
char Digit;
while ((Digit = *BigNum) != '\0') {
Accumulator += ((unsigned)(Digit - '0')) * Factor;
*BigNum++ = Accumulator%10 + '0';
Accumulator /= 10;
}
while (Accumulator > 0) {
*BigNum++ = Accumulator%10 + '0';
Accumulator /= 10;
}
*BigNum = '\0';
}
int main(){
unsigned N = 500;
unsigned Factor;
char BigNum[(size_t) (N*log(N) + 2)]; // Form answer, in reverse order, as a string
strcpy(BigNum, "1");
for (Factor = 1; Factor <= N; Factor++) {
Mult(BigNum, Factor);
}
printf("%u! Length:%zu Reverse:\"%s\"\n", Factor - 1, strlen(BigNum), BigNum);
unsigned long Sum = 0;
size_t i;
for (i=0; BigNum[i]; i++) {
Sum += BigNum[i] - '0';
}
printf("Sum of digits:%lu\n", Sum);
return 0;
}
500! Length:1135 Reverse:"000...221"
Sum of digits:4599

Resources