I have to begin my thanking you guys for the help. I am trying to turn the factorial part of the code into another function and was wondering if I needed to add everything within the
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
int indx;
int arrayIndx;
int accumulator;
int fact;
int individualDigit[50];
int length;
for(indx = 99999; indx > 0; indx--)
{
num = indx;
for (length = 0; num > 0; length++)
{
individualDigit[length] = num % 10;
num /= 10;
}
accumulator = 0;
for (arrayIndx = 0; arrayIndx < length; arrayIndx++)
{
fact = 1;
while(individualDigit[arrayIndx] > 0)
{
fact*= individualDigit[arrayIndx];
individualDigit[arrayIndx]--;
}
accumulator += fact;
}
if(accumulator == indx)
{
printf("%d ", accumulator);
}
}
return 0;
}
You program is badly designed. It is not indented, you are using variable names index, indx and idex which is confusing for the reader and would lead to nightmares for long term maintenance. Also the factorial computation would deserve to be in a function for better modularity.
But apart from that, your program does what you ask, correctly computes factorials and adds them in the accumulator variable. The only problem is that you never print that accumulator except for the last 2 cases (2 and 1) where n = n!.
Simply replace :
if (accumulator == indx)
{
printf("\n%d\n", indx);
}
with
printf("\n%d\n", accumulator);
and you will see your results.
If you want to store the sum of factorials in an array, you just have to declare int sumOfFact[26] = {0}; just before int individualDigit[50]; to define the array and initialize sumOfFact[0] to 1, and then add sumOfFact[indx] = accumulator; just before printing the accumulator.
To put the factorial part in a function, it is quite simple. First declare it above your main:
int ffact(int n);
the define it anywhere in your code (eventually in another compilation unit - a .c file - if you want)
inf ffact(int n) {
fact = 1;
while (n > 1) {
fact *= n--;
/* if (fact < 0) { fprintf(stderr, "Overflow in ffact(%d)\n", n); return 0; } */
}
return fact
}
I commented out the test for overflow, because I assume you use at least 32 bits int and fact(9) will not overflow (but fact(13) would ...)
The loop computing the sum of factorials becomes:
accumulator = 0;
for (arrayIndx = 0; arrayIndx < length; arrayIndx++)
{
accumulator += ffact(individualDigit[arrayIndx]);
}
printf("\n%d\n", accumulator);
Advantages for that modularity: it is simpler to separately test the code for ffact. So when things go wrong, you have not to crawl among one simple piece of code of more than 40 lines (not counting the absent but necessaries comments). And the code no longers clutters the individualDigit array.
Related
I'm currently learning C and have been practicing on codewars recently. I came across this question on prime gaps and was curious on how to improve it. I was initially fooled in thinking this wouldn't be as bad but I realized that finding primes is difficult (especially for large numbers where it can be at least an NP-Hard problem). I know my code right now has multiple for-loops and this is terrible in terms of performance. I also don't fully know the clean ways of writing C so there might be some no-nos I did (e.g. I know it's my responsibility to free up dynamically allocated memory but I tried freeing memory in the main() calling function and by freeing the first element of the allocated memory block--not sure if this is the appropriate way of freeing up a block of memory)
In general, the main function calls the prime_gap function several times. I know this code works because it was submitted successfully but any tips on writing this better (algorithmically in C)?
/* a prime gap of length "n" indicates that n-1 consecutive composite numbers exist between two primes.
* For example, the gap beween (2,3) is 1, the gap between (5,7) is 2 and the gap between (7,11) is 4.
* Our function should return the first pair of primes that satisfies the gap that we're looking for in a search between two numbers. /
There should also be no primes that exist within the gap of the first two primes that are found.
* gap(g, n, m) -> where g = gap length, n = start of search space, m = end of search space
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
long long *gap(int g, int n, int m);
bool check_prime(int, bool);
int main(int argc, const char *argv[]){
long long *check3 = gap(2,100,110);
for (int i = 0; i < 2; i++){
printf("%lld ", check3[i]);
}
free(&check3[0]);
printf("\n");
long long *check = gap(2,3,50);
for (int i = 0; i< 2; i++){
printf("%lld ", check[i]);
}
printf("\n");
free(&check[0]);
long long *check1 = gap(2,5,5);
for (int i = 0; i < 2; i++){
printf("%lld ", check1[i]);
}
free(&check1[0]);
printf("\n");
long long *check2 = gap(4,130,200);
for (int i = 0; i < 2; i++){
printf("%lld ", check2[i]);
}
free(&check2[0]);
printf("\n");
long long *check4 = gap(6,100,110);
for (int i = 0; i < 2; i++){
printf("%lld ", check4[i]);
}
free(&check4[0]);
printf("\n");
long long *gap(int g, int n, int m) {
long long *result = (long long*) malloc(sizeof(long long) *2); // dynamically allocate 2 long longs for the integer array
if (result == NULL){
perror("Not enough memory");
}
int test = 0;
static bool prime;
for (int i = n; i < m; i++) { // traverse search space
prime = true;
prime = check_prime(i, prime);
if (prime == true) { // identifies prime number
test = i + g; // add the gap value to identified prime
prime = false; // set bool to false to now check for any primes that exist between i and i+gap
for (int z = i+1; z < test; z++ ) { // check there is no prime in between the first and second (test) primes
prime = check_prime(z, prime);
if (prime == true) break;
}
if (prime != true) { // found no primes between i and i+gap
prime = true; // set bool to true to then toggle off in the check right below if i+gap is not actually prime
prime = check_prime(test, prime); // now need to check whether i+gap itself is a prime
if (prime == true) {
result[0] = i; result[1] = test;
return result;
}
}
}
}
result[0] = result[1] = 0;
return result;
}
bool check_prime(int i, bool prime){
for (int j = 2; j <= sqrt(i); j++){
if (i % j == 0) {
return false;
}
}
return true;
}
Reading you code, the following comments come to mind:
you are never freeing the space allocated by the malloc
therefore I am wondering if you really need to use malloc, a simple global variable would have been sufficient for what you are doing with it
you check_prime function has a second parameter prime that is never used
in function gap, the variable prime is indicated as static, this is not required, it could also lead to errors
from the algorithmic point of view:
your logic goes like
for i in range to check:
if i is prime
check if all the number between i and i+gap are not prime
if i+gap is prime then return the tuple(i, i+gap)
globally, you are checking several times for the same number if it is prime, since this is by far the most "expensive" operation, you should try not to
specifically, you should start by checking test before iterating over all the numbers in the range i..test.
I could easily print what I wanted in a loop, but I'm new to functions and I need to save or return the sum of the dividers that have no remainder to a number which is an input of the user.
Example:
Input - 6
Output - 1+2+3=6
How I started:
int NumberOfDividers(int number)
{
int i,num, count = 0;
num = number;
for ( i = 0; i < num; i++)
{
if ((num % i) == 0) //so now I know i is one of the dividers i want to save.
}
}
So if i is one of the dividers I want, how can I save it into a variable? Or an array?
To return the sum of the proper divisors, do:
int sum_of_proper_divisors (int number)
{
int sum = 0;
int i;
for (i = 1; i < number; i++)
{
if ((number % i) == 0)
sum += i;
}
return sum;
}
You just need to use the return keyword to return the value.
You can do this way...
//other headers as you need
#include<string.h>//this header is for memset
int dividers[1000];//global array
int currPos;//global variable
int NumberOfDividers(int number)
{
int i,num, count = 0;
num = number;
for ( i = 1; i < num; i++)//you should start counting from 1 otherwise you will get floating point exception
{
if ((num % i) == 0)
{
dividers[currPos]=i;//putting the dividers in the array
currPos++;//updating the pivot where the next dividers will stay
}
}
return 0;
}
int main()
{
memset(dividers,0,sizeof(dividers));//initializing the array
currPos=0;//initializing the variable to point at the start of the array
NumberOfDividers(6);
int i;
int sum=0;
for(i=0;i<currPos;i++)
{
printf("%d",dividers[i]);
sum+=dividers[i];
if(i!=currPos-1)
{
printf("+");
}
}
printf("=%d\n",sum);
return 0;
}
As this task looked fun to do, did not want to take away the coding experience. Instead laid out a sample algorithm that should code in C fairly directly.
Pseudo-code
int *NumberOfDividers(int number)
find isqrt(number) --> sqrt_number
sqrt_number*2 + 2 --> max_array_count
allocate int[] with max_array_count elements
validate allocation
starting at divisor = 1, in a loop ...
quotient = number/divisor
remainder = number%divisor
if (remainder == 0)
add divisor to list
if (divisor != quotient) add quotient to list
if (divisor >= quotient) quit loop
divisor++
append 0 to list to indicate the end
shrink array to needed size if desired
validate shrink result
return array pointer.
Notice the loop does at most sqrt(number) iterations, so a reasonable upper bound of the needed array size can be calculated before using any divisors.
Also see How many positive integers are factors of a given number? for more advanced ideas.
You can see an another way to do this. This will work very fast for a vast amount of data. Here is my way and you can follow this to find this in a fastest way to find the sum of factors of a number. Here is my code:
int number_of_divisor(int n)
{
int sum_of_factors=0;
sum_of_factors+=1;//as 1 is factor of all num
//sum_of_factors+=n;//n will always a factor of n
for(int i = 2; i * i <= n; ++i)
{
if(n % i == 0)
{
sum_of_factors+=i;
if(i * i != n)
sum_of_factors+=(n/i);
}
}
return sum_of_factors;
}
if your input is long then change all int by long.
Thank you.
i got a problem which i can't solve
I want to know all prime numbers below a given limit x. Allowing me to enter x and calculate the prime numbers using the method of Erastosthenes. Displaying the result on the screen and saving it to a text file.
Calculating the primenumbers below the x, printing them and saving them to a text file worked, the only problem i have is that x can't exceed 500000
could you guys help me?
#include <stdio.h>
#include <math.h>
void sieve(long x, int primes[]);
main()
{
long i;
long x=500000;
int v[x];
printf("give a x\n");
scanf("%d",&x);
FILE *fp;
fp = fopen("primes.txt", "w");
sieve(x, v);
for (i=0;i<x;i++)
{
if (v[i] == 1)
{
printf("\n%d",i);
fprintf(fp, "%d\n",i);
}
}
fclose(fp);
}
void sieve(long x, int primes[])
{
int i;
int j;
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
for (i=2;i<sqrt(x);i++) // loop through all the numbers up to the sqrt(n)
{
for (j=i*i;j<x;j+=i) // mark off each factor of i by setting it to 0 (False)
{
primes[j] = 0;
}
}
}
You will be able to handle four times as many values by declaring char v [500000] instead of int v [100000].
You can handle eight times more values by declaring unsigned char v [500000] and using only a single bit for each prime number. This makes the code a bit more complicated.
You can handle twice as many values by having a sieve for odd numbers only. Since 2 is the only even prime number, there is no point keeping them in the sieve.
Since memory for local variables in a function is often quite limited, you can handle many more values by using a static array.
Allocating v as an array of int is wasteful, and making it a local array is risky, stack space being limited. If the array becomes large enough to exceed available stack space, the program will invoke undefined behaviour and likely crash.
While there are ways to improve the efficiency of the sieve by changing the sieve array to an array of bits containing only odd numbers or fewer numbers (6n-1 and 6n+1 is a good trick), you can still improve the efficiency of your simplistic approach by a factor of 10 with easy changes:
fix primes[0] and primes[1] outside the loop,
clear even offsets of prime except the first and only scan odd numbers,
use integer arithmetic for the outer loop limit,
ignore numbers that are already known to be composite,
only check off odd multiples of i.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sieve(long x, unsigned char primes[]) {
long i, j;
for (i = 0; i < x; i++) {
primes[i] = i & 1;
}
primes[1] = 0;
primes[2] = 1;
/* loop through all odd numbers up to the sqrt(x) */
for (i = 3; (j = i * i) < x; i += 2) {
/* skip composite numbers */
if (primes[i] == 0)
continue;
/* mark each odd multiple of i as composite */
for (; j < x; j += i + i) {
primes[j] = 0;
}
}
}
int main(int argc, char *argv[]) {
long i, x, count;
int do_count = 0;
unsigned char *v;
if (argc > 1) {
x = strtol(argv[1], NULL, 0);
} else {
printf("enter x: ");
if (scanf("%ld", &x) != 1)
return 1;
}
if (x < 0) {
x = -x;
do_count = 1;
}
v = malloc(x);
if (v == NULL) {
printf("Not enough memory\n");
return 1;
}
sieve(x, v);
if (do_count) {
for (count = i = 0; i < x; i++) {
count += v[i];
}
printf("%ld\n", count);
} else {
for (i = 0; i < x; i++) {
if (v[i] == 1) {
printf("%ld\n", i);
}
}
}
free(v);
return 0;
}
I believe the problem you are having is allocating an array of int if more than 500000 elements on the stack. This is not an efficient way, to use an array where the element is the number and the value indicates whether it is prime or not. If you want to do this, at least use bool, not int as this should only be 1 byte, not 4.
Also notice this
for (i=0;i<x;i++)
{
primes[i]=1; // we initialize the sieve list to all 1's (True)
primes[0]=0,primes[1]=0; // Set the first two numbers (0 and 1) to 0 (False)
}
You are reassigning the first two elements in each loop. Take it out of the loop.
You are initializing x to be 500000, then creating an array with x elements, thus it will have 500000 elements. You are then reading in x. The array will not change size when the value of x changes - it is fixed at 500000 elements, the value of x when you created the array. You want something like this:
long x=500000;
printf("give a x\n");
scanf("%d",&x);
int *v = new int[x];
This fixes your fixed size array issue, and also gets it off the stack and into the heap which will allow you to allocate more space. It should work up to the limit of the memory you have available.
I've been teaching myself C through various sources. One of exercises I've found is this past year's cs50 problem sets (found here under the heading Bad Credit). Essentially, I've solved the problem but realized that I am performing the same step twice and perhaps could wrap that step inside of a function to be reused.
My problem is that I'm not sure how to define a return to an as yet unspecified array. Or, for that matter, if this is a good idea. I think that reusing the code would be a good thing if I could make it work, but I can't figure out how to do so.
The problem, as shown in the code below is taking a long number, separating each individual digit, and performing a bit of math to do a checksum. This is returned to step1 in the code below. The do/while loop is doing the heavy lifting here, and what I would like to do is to do the same with elements in step1 and return those into step2 or any other variable for that matter.
long long num = 378282246310005;
int step1[10];
int step2[10];
do {
int i = 0;
step1[i] = num % 10; // this returns to one array
num /= 10;
i++;
} while (num != 0);
I realize this isn't that big a deal for this problem. I just decided that it would be good to know how to do it, if possible.
I'll take you through the steps. Here's your code:
do {
int i = 0;
step1[i] = num % 10;
num /= 10;
i++;
} while (num != 0);
First, an error. The i variable should be initialized and declared outside the loop, otherwise i == 0 every single time you go through the loop.
int i = 0;
do {
step1[i] = num % 10;
num /= 10;
i++;
} while (num != 0);
This should be recognizable as the expanded version of a for loop, so:
for (int i = 0; num != 0; i++, num /= 10)
step1[i] = num % 10;
// note: different for case num == 0
Then, if you want to turn it into a function,
void get_digits(int digits[], long long num) {
for (int i = 0; num != 0; i++, num /= 10)
digits[i] = num % 10;
}
A long story short, when you pass an array to a function in C, the array doesn't get copied so you can change the array inside the function and see those changes outside the function. (Long version: when arrays are function parameters they decay into pointers.)
Final note: you will need 19 elements in the array, not 10. So:
long long num = 378282246310005;
int step1[19];
get_digits(step1, num);
You can pass the array by reference, like so:
//Number to checksum is num
//Array to store checksum is arr
//Maximal length of arr is n
void checksum(long long num, int arr[], int n){
int i = 0;
do {
arr[i] = num % 10; // this returns to one array
num /= 10;
i++;
if(i==n) return; //break before we overflow array
} while (num != 0);
}
Note that your code is potentially unsafe because you may end up writing to a part of the array beyond the memory you've allocated for it. That is, you define int step1[10] but may end up writing to step[11].
Also, you stuck your int i=0 inside of the loop. I assumed you wanted it outside.
this is the part of my code I'm having trouble with. I can't understand why its doing it wrong. I have an array where it stores numbers 0 - 25 which are cases. The numbers are to be randomized and overwritten into the array. Only condition is is that no number can be doulbes, there can only be one of that number. I'm not asking you to do my code but do hint me or point me in the write directions. I am trying to learn :)
The problem lies within the second do loop. I can get the numbers to be randomized, but I get doubles. I have created a loop to check and fix this, but it's not working. The code does run, and doubles do still happen and I can't see why. It looks correct to me. Please look, thank you (:
This is what I have done originally (at the very end is where I am at now):
int check_double = 0;
int i = 0;
int counter = 0;
int array_adder = 0;
int random_number = 0;
int cases[] = {
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
};
float money[] = {
0.01,1,5,10,25,50,75,100,200,300,400,500,750,1000,5000,10000,25000,50000,750000,100000,200000,300000,400000,500000,750000,1000000
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
counter += 1;
printf("%d\n", cases[counter]);
}
while (counter <= 25);
//make sure there are no doubles in the array, just 0 - 25 and not a single number repeated twice
do
{
check_double = 0;
for (i = 0; i < counter; i++)
{
if (cases[counter] == cases[i])
{
cases[counter] = rand()% 26;
check_double == 1;
}
}
}
while (check_double != 0);
Currently, what I had achived after that was combing both loops and check for doubles as the array goes. This is what I made, it still has doubles and im not sure why, I only posted the cose with both loops combined:
do
{
cases[counter]= rand() % 26;
if (cases[counter]>=1);
for(i=0;i<=counter;i++)
if (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
printf("%d\n",cases[counter]);
counter+=1;
}
Robsta, you could try the following piece of code, I have run this in Dev-C++, any changes that you require can be made from your side. But, I assure you that this code generates what you intend.
int check_double = 0;
int i = 0;
int counter = 0;
int cases[] = {
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
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
for(i=0;i<counter;i++)
if (cases[counter]==cases[i]){
while (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
i=0;
}
printf("%d\t%d\n",counter,cases[counter]);
counter+=1;
}while (counter <= 25);
If you have any clarifications required, I would love to discuss with you.
-Sandip
You're only ever writing over the last value in the array:
for(i=0;i<counter;i++)
if (cases[counter]==cases[i])
You need to loop through as you are, then have an inner loop, where you compare all the other entries to the current one.
Even easier would be to do the loop where you set each random number, so when you set cases[3] for example, loop from 0 to 2 and check to see if your new value for 3 clashes, if so, wash - rinse - repeat!
You have this line of code:
check_double==1;
That doesn't change check_double because it's ==, not =. == compares; it doesn't assign. Change that line to this:
check_double=1;
A helpful compiler (clang in this example) will give you a warning about this:
test.c:5:14: warning: expression result unused [-Wunused-value]
check_double==1;
~~~~~~~~~~~~^ ~
You can't check for duplicates with a single loop. You need to at least compare every possible pair of elements to be able to see if there's a duplicate. I'm guessing you forgot to loop over counter somewhere inside the second do...while?
Note that your method is not guaranteed to terminate. (Very, very likely but not certain.) Why don't you simply shuffle the cases array? Shuffling is simple but tricky; see Fisher-Yates (or Knuth) Shuffle for a simple algorithm.
If you are asking how to randomly sequence the number 1-25 then you could do something like this. This is a very brute-force way of generating the sequence, but it does work and might give you a starting point for something more optimized.
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <conio.h>
const int LastNumber = 25;
bool HasEmpty(int available[LastNumber][2])
{
bool result = false;
for(int i = 0; i < LastNumber; i++)
{
if (available[i][1] == 0)
{
result = true;
break;
}
}
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int available[LastNumber][2];
int newSequence[LastNumber];
srand((unsigned int)time(NULL));
for(int i = 0; i < LastNumber; i++)
{
available[i][0]=i;
available[i][1]=0;
}
int usedIndex = 0;
while (HasEmpty(available))
{
int temp = rand() % (LastNumber + 1);
if (available[temp][1] == 0)
{
newSequence[usedIndex++] = available[temp][0];
available[temp][1] = 1;
}
}
for(int i = 0; i < LastNumber; i++)
{
printf("%d\n",newSequence[i]);
}
getch();
return 0;
}