Recursive function for counting divisible digits in C - c

I need to write a recursive function which accepts a number, and it needs to check whether each number is divisible with the previous number. For example, if the input is 63542, result should be 2, while only 6 is divisible by 3, and 4 is divisible by 2. These are the only numbers that are divisible with the their previous number. I have the following code, but it returns every time one more. For the above example it should return 2 but it returns 3.
#include <stdio.h>
int deliv(int num)
{
int temp = num%100;
int counter = 0;
if(num == 0)
{
return 0;
}
else if((temp/10)%(num%10) == 0)
{
counter++;
return counter + deliv(num/10);
}
else return counter + deliv(num/10);
}
int main()
{
int result = deliv(63542);
printf("%d\n", result);
return 0;
}

You want to change your test condition from if(num == 0) to if(num < 10 ) because if num is a single digit number, temp becomes 0 since temp = num/10, which is divisible by num%10.
Also, add this condition to avoid crashing when two consecutive digits are 0.
if(num < 10)
{
return 0;
}
//To avoid crash due to 2 zeroes
else if(temp==0)
{
return counter + deliv(num/10);
}
else if((temp/10)%(num%10) == 0)
{
counter++;
return counter + deliv(num/10);
}
else return counter + deliv(num/10);

Related

Unusual behavior with Luhn's algorithm in C

I've been doing a CS50 course and stumbled upon this "Credit" problem. At the moment I'm testing it and due to insufficient cases provided in worksheet, I went to the recommended PayPal testing card numbers: https://developer.paypal.com/api/nvp-soap/payflow/integration-guide/test-transactions/#standard-test-cards
Particularly:
Mastercard 5555555555554444
Mastercard 5105105105105100
Mastercard 5199999999999991
Mastercard 5299999999999990
These refuse to cooperate. My program calculates the Luhn's value for them, and it's not close to being a multiplier of 10; am I missing something, because other providers are working perfectly fine.
Results from code check:
:( identifies 5555555555554444 as MASTERCARD
expected "MASTERCARD\n", not "114\nINVALID\n..."
:( identifies 5105105105105100 as MASTERCARD
expected "MASTERCARD\n", not "47\nINVALID\n"
My code:
#include <stdio.h>
#include <cs50.h>
int get_sum_from_second_to_last(long temp_number);
int get_sum_from_odd_digits(long temp_number);
int length(long temp_number);
int return_first_n_digits(int n, long temp_number, int length);
int main()
{
int final_sum = 0;
long number = 0;
do
{
number = get_long("Number: ");
}
while(number<0);
final_sum = get_sum_from_second_to_last(number) + get_sum_from_odd_digits(number);
printf("%i\n", final_sum);
if(final_sum % 10 == 0)
{
if(length(number) == 15 && (return_first_n_digits(2, number, length(number)) == 34 || return_first_n_digits(2, number, length(number)) == 37))
{
printf("AMEX\n");
}
else
{
if((length(number) == 16 || length(number) == 13) && return_first_n_digits(1, number, length(number)) == 4)
{
printf("VISA\n");
}
else
{
if(length(number) == 16 && (return_first_n_digits(2, number, length(number)) == 51 || return_first_n_digits(2, number, length(number)) == 52 || return_first_n_digits(2, number, length(number)) == 53 || return_first_n_digits(2, number, length(number)) == 54 || return_first_n_digits(2, number, length(number)) == 55))
{
printf("MASTERCARD\n");
}
else
{
printf("This card provider recognition is not supported\n");
}
}
}
}
else
{
printf("INVALID\n");
}
}
int get_sum_from_second_to_last(long temp_number)
{
int digit_current = 0;
int counter = 1;
int sum = 0;
do
{
digit_current = temp_number % 10;
if(counter%2 == 0)
{
if((digit_current*2)%10!=0)
{
sum = sum + (digit_current*2)%10 + (digit_current*2)/10;
}
else
{
sum = sum + digit_current*2;
}
}
temp_number = temp_number/10;
counter += 1;
}
while(temp_number);
return sum;
}
int get_sum_from_odd_digits(long temp_number)
{
int digit_current = 0;
int counter = 1;
int sum = 0;
do
{
digit_current = temp_number % 10;
if(counter%2 != 0)
{
sum = sum + digit_current;
}
temp_number = temp_number/10;
counter += 1;
}
while(temp_number);
return sum;
}
int length(long temp_number)
{
int counter = 0;
do
{
temp_number = temp_number/10;
counter++;
}
while(temp_number);
return counter;
}
int return_first_n_digits(int n, long temp_number, int length)
{
int i;
for(i = 0; i < length - n; i++)
{
temp_number = temp_number/10;
}
return temp_number;
}
The issue appears to be in your function for summing up the even numbered digits in the int get_sum_from_second_to_last function. In that function, the digits are multiplied by a factor of two. Then according to information on how the Luhn's algorithm is supposed to work, if the result is a two-digit number, those digits are then supposed to be added together to derive a single digit. It appears that doesn't always happen with the current testing within that function. Since the value of multiplying one digit by "2" can only result in two-digit numbers from "10" to "18", one can effectively derive the summation of the digits by just subtracting the value of "9" from the calculated result.
With that, I offer up the following code snippet as an alternative summation of the even-numbered digits.
int get_sum_from_second_to_last(long temp_number)
{
int digit_current = 0;
int counter = 1;
int sum = 0;
do
{
digit_current = temp_number % 10;
if(counter%2 == 0)
{
if((digit_current*2) > 9)
{
sum = sum + (digit_current * 2 - 9);
}
else
{
sum = sum + digit_current * 2;
}
}
temp_number = temp_number/10;
counter += 1;
}
while(temp_number);
printf("Even digit sum: %d\n", sum);
return sum;
}
FYI, you can leave out the printf() call. I added that just for some visual clarification.
With that change, I tested out the four sample numbers in your narrative and they all produced a valid MASTERCARD result.
Number: 5299999999999990
Even digit sum: 64
Current digit: 0
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 9
Current digit: 2
Odd digit sum: 56
Final sum: 120
MASTERCARD
As a further test, I actually tested out a number for AMEX and for VISA and those worked as well.
I hope that clarifies things.
Regards.

CS50 Luhn's Algorithm in C. Help much appreciated :)

I need to solve the problem on the link below, using Luhn's algorithm and what we have learned so far in CS50 (no arrays).
My program compiles but it doesn't identify the card type. What am I doing wrong?
Many thanks in advance!
Problem: https://cs50.harvard.edu/x/2020/psets/1/credit/#:~:text=check50%20cs50/problems/2020/x/credit
/* This program checks if a bank card number is syntactically valid, using Luhn's algorithm */
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
long long n, temp;
int digit, last, first, product;
int lenght = 0;
int sumOdd, sumEven;
// Prompt user for input as long as the inputted number is equal or smaller than zero
do
{
n = get_long_long("Enter your credit card number without special characters:\n");
} while (n < 0);
// Count the number of digits
while (n > 0)
{
n = n/10;
lenght++;
}
// Check if the number's length is valid
if (lenght != 13 && lenght != 15 && lenght != 16)
{
printf("INVALID");
}
// Find the last digit and add it to the even sum
while (n > 0)
{
last = n % 10;
temp = n - last;
sumEven = sumEven + last;
}
/* Starting with second-to-last digit, multiply every other digit by 2. Add those
products together and then add the sum to the sum of the digits that weren't multiplied by 2 */
while (n > 0)
{
digit = n % 10;
temp = n/10;
if (lenght % 2 == 0)
{
product = digit * 2;
sumOdd = sumOdd + product;
} else
{
sumEven = sumEven + digit;
}
// If the last digit of the sum of sums is zero print the number. Else print INVALID.
if (sumOdd + sumEven % 10 != 0)
{
printf("INVALID\n");
}
else
{
printf("%lld\n", n);
}
// Identify the user's card type as per CS50 Credit instructions. Cards commencing with 3 are AMEX, with 5 MasterCard and with 4, VISA.
while (first >= 10)
{
first = n;
first = first / 10;
if (first == 3)
{
printf("AMEX\n");
}
if (first == 5)
{
printf("MASTERCARD\n");
}
if (first == 1)
{
printf ("VISA\n");
}
}
}
}
You have several consecutive while blocks
while (n>0){
// some code
}
while (n>0){
// some code
}
Your program will only exit the first loop when n is no longer larger than 0. When it reaches the next while loop n will still not be larger than 0 so the body of the next while loop will never be entered. Large chunks of your code are not getting executed.

Made a script on the Luhn's Alg. Unable to understand how to create and call functions clearly for revised script

I am new to programming. I am currently taking online lectures quite rigorously and completed a task using Luhn's Algorithm. It is just one script that runs straight through, but for my future-self I want to learn to code more efficiently as projects get bigger.
That is where my problem comes in. I cannot seem to understand how to define or call functions correctly and unable to revise my script into something more "efficient".
(Everything is already submitted and my script completes the task perfectly, according to the bot, so I am not trying to half-arse my work here just to be clear.)
This is the completed script with only the main function that runs straight through and took me about 12-15 hours to get it working without error from the beginning. Everything is written in C
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
// this grabs the number and verifies the correct amount of digits
int count;
long number = 0;
do
{
number = get_long("Number: ");
count = (number == 0) ? 1 : (log10(number) + 1);
if (count < 13 || count == 14 || count > 16)
{
printf("INVALID\n"); // This is to satisfy the uni. bot command check. Need a EOF for numbers with the wrong amount of digits.
return (0);
}
}
while (count < 13 || count == 14 || count > 16);
//printf("Digits: %i\n", count); // test print for debugging
//This finds the first two digits of input number
long int two = number;
while (two >= 100)
{
two = two / 10;
}
//printf("First two numbers: %li\n", two); // test print for debugging
// verifies card using mod10 (Luhn's)
long sum = 0;
long bigdigit = 0;
//printf("\nLUHN Number: %li\n\n", number); // test print for debugging
if (count == 13 || count == 15)
{
count += 1;
}
for (int i = count; i > 0; i--)
{
if (i % 2 == 0)
{
sum += (number % 10);
}
else
{
bigdigit = (2 * (number % 10));
sum += (bigdigit / 10 + bigdigit % 10);
}
number = (number / 10);
//printf("\nI : %i\n", i); // test print for debugging
//printf("Sum: %li\n", sum); // test print for debugging
//printf("Number: %li\n", number); // test print for debugging
}
if (sum % 10 == 0)
{
printf("VALID\n");
}
else
{
printf("INVALID\n");
return (0);
}
// checks what type of card
if (two == 34 || two == 37)
{
printf("AMEX\n");
return (0);
}
else if (two >= 51 && two <= 55)
{
printf("MASTERCARD\n");
return (0);
}
else if (two >= 40 && two <= 49)
{
printf("VISA\n");
return (0);
}
else
{
printf("INVALID\n");
return (0);
}
}
I was trying to split it into 3 functions of main to call.
long input_number();
bool luhn_check();
void company_check();
I am stuck with the second function and not sure if the third should be a void or not.
"Revised" Script v2
#include <stdio.h>
#include <cs50.h>
#include <math.h>
long input_number(long CCN);
int counter(long CCN, int count);
bool luhn_check(long CCN, int count);
long firsttwo(long CCN, long two);
void card_type(long two);
int main()
{
long CCN = 0;
int count = 0;
long two = 0;
CCN = input_number(CCN);
count = counter(CCN, count);
//printf("CCN: %li\n", CCN); //debugging purposes
//printf("Digits: %i\n", count); //debugging purposes
luhn_check(CCN, count);
two = firsttwo(CCN, two);
//printf("First Two: %li\n", two); //debugging purposes
card_type(two);
}
// this grabs the number and verifies the correct amount of digits
long input_number(long CCN)
{
int count = 0;
do
{
CCN = get_long("Number: ");
count = (CCN == 0) ? 1 : (log10(CCN) + 1);
if (count < 13 || count == 14 || count > 16)
{
//printf("INVALID\n"); // This is to satisfy the uni. bot command check. Need a EOF
//return (0);
}
}
while (count < 13 || count == 14 || count > 16);
return (CCN);
}
int counter(long CCN, int count)
{
do
{
count = (CCN == 0) ? 1 : (log10(CCN) + 1);
}
while (count < 13 || count == 14 || count > 16);
return (count);
}
// verifies card using mod10 (Luhn's)
bool luhn_check(long CCN, int count)
{
long sum = 0;
long bigdigit = 0;
//printf("\nLUHN Number: %ld\n\n", CCN); // test print for debugging
if (count == 13 || count == 15)
{
count += 1;
}
for (int i = count; i > 0; i--)
{
if (i % 2 == 0)
{
sum += (CCN % 10);
}
else
{
bigdigit = (2 * (CCN % 10));
sum += (bigdigit / 10 + bigdigit % 10);
}
CCN = (CCN / 10);
//printf("\nI : %i\n", i); // test print for debugging
//printf("Sum: %li\n", sum); // test print for debugging
//printf("Number: %li\n", CCN); // test print for debugging
}
if (sum % 10 == 0)
{
printf("VALID\n");
return (true);
}
else
{
printf("INVALID\n");
return (false);
}
}
// grabs the first two numbers
long firsttwo(long CCN, long two)
{
two = CCN;
//printf("TWO CCN: %li\n", two); // debugging purposes
while (two >= 100)
{
two = two / 10;
}
return (two);
}
// finds card type and ends
void card_type(long two)
{
if (two == 34 || two == 37)
{
printf("AMEX\n");
//return (0);
}
else if (two >= 51 && two <= 55)
{
printf("MASTERCARD\n");
//return (0);
}
else if (two >= 40 && two <= 49)
{
printf("VISA\n");
//return (0);
}
else
{
printf("INVALID\n");
//return (0);
}
}
I have completed the second version of the script with your suggestions, bar the str of input, I will try to tackle that method in the next version as I have not handled that type yet.
Besides running the program with a string rather than b, is there anything I could have done more efficiently?
Let me start with a few notes on your function input_number:
long input_number()
{
// this grabs the number and verifies the correct amount of digits
int count;
[ .... ]
while (count < 13 || count == 14 || count > 16);
// Once this while loop starts, it will never terminate!
// if count starts at 10 (which is less than 13), the body says "do nothing".
// so count will continue to be unchanged, and the while-loop will continue to run.
return (0); // Code after a return statement will never be reached
// So your printf-statement below will NEVER happen.
// It also seems unlikely you want to return Zero.
// You probably want to return count, or some other value.
printf("Digits: %i\n", count); // test print for debugging
}

Recursive function in C to determine if digits of an integer are sorted ascending, descending or neither

I need to write a recursive function that returns 1 if digits of a whole number are ascending (left to right), return -1 if descending or return 0 if neither.
My solution attempt returns 0 every time and I know why but I don't know how to get around it.
Here's my code:
#include <stdio.h>
int check_order(int n)
{
if (n % 10 > n / 10 % 10)
{
return check_order(n / 10);
if (n == 0)
{
return 1;
}
}
else if (n % 10 < n / 10 % 10)
{
return check_order(n / 10);
if (n == 0)
{
return -1;
}
}
else
{
return 0;
}
}
int main()
{
int n;
printf("enter a whole number (n > 9):");
scanf_s("%d", &n);
printf("function returned: %d\n", check_order(n));
}
Here's a simple recursion:
int f(int n){
if (n < 10)
return 0;
int dr = n % 10; // rightmost digit
n = n / 10;
int dl = n % 10; // second digit from the right
int curr = dl < dr ? 1 : -1; // current comparison
if (dl == dr) curr = 0; // keep strict order
if (n < 10)
return curr;
return curr == f(n) ? curr : 0; // are the comparisons consistent?
}
Explain your algorithm?
Suppose you use the following:
You are given a number.
You need to turn that number into a sequence of digits.
If you are given a number, you can convert that number to a sequence of digits.
If you are given a sequence of digits, use
that.
Compare each pair of digits -> ascending, descending, or neither.
Combine the results from each pair, sequentially/recursively.
We can use a string to make the digit comparisons easier, and accept very long sequences of digits.
We can use an enum(erated) type to represent the ordering.
How do you combine the results? Define a function that combines the order of two adjacent, overlapping pairs, then you can combine results.
#include <stdio.h>
#include <string.h>
typedef enum { descending=-1, other=0, ascending=1 } order_t;
order_t pair_order(int a, int b) {
if( a < b ) return ascending;
if( a > b ) return descending;
return other;
}
//strict (increasing/decreasing)
order_t strict_order( order_t x, order_t y ) {
if( x == y ) return x;
return other;
}
//monotone (increasing/decreasing)
order_t monotone_order( order_t x, order_t y ) {
if( x == y ) return x;
if( other == x ) return y;
if( other == y ) return x;
return other;
}
order_t check_order( char* p, int remain ) {
//printf("p:%s\n",p); //uncomment to watch progress
if( remain<2 ) return other;
if( remain==2 ) return pair_order(p[0], p[1]);
return strict_order( pair_order(p[0], p[1]), check_order(p+1, remain-1) );
//return monotone_order( pair_order(p[0], p[1]), check_order(p+1, remain-1) );
}
char* order_name[] = {
"descending",
"other",
"ascending"
""
};
int main()
{
char line[666] = "none";
while ( strlen(line) > 0 ) {
printf("enter a number (at least 2 digits):");
fgets(stdin,line,sizeof(line)-1);
if( strlen(line) > 0 && line[strlen(line)-1] == '\n' )
line[strlen(line)-1] = '\0';
order_t order = check_order(line);
printf("function returned: (%d)%s\n", order, order_name[order+1]);
}
}
I think you were started on the right track but need to flesh out your code more. My solution borrows on that of #ChuckCottrill as I like his enum but I don't like that he doesn't play the ball as it lays (i.e. converts to a string instead of dealing with the int.) I also borrow the nice test examples of #ggorlen but I don't like that solution either as it can take multiple passes through the number to figure out the answer when only one pass should be needed:
#include <stdio.h>
typedef enum { descending=-1, other=0, ascending=1 } order_t; // a la #ChuckCottrill
order_t check_order(int n)
{
if (n > 9) {
int right = n % 10;
int left = n / 10 % 10;
if (right > left) {
n /= 10;
if (n > 9) {
return (ascending == check_order(n)) ? ascending : other;
}
return ascending;
}
if (right < left) {
n /= 10;
if (n > 9) {
return (descending == check_order(n)) ? descending : other;
}
return descending;
}
}
return other;
}
int main() { // a la #ggorlen
printf("12345: %d\n", check_order(12345));
printf("54321: %d\n", check_order(54321));
printf("54323: %d\n", check_order(54323));
printf("454321: %d\n", check_order(454321));
printf("1: %d\n", check_order(1));
printf("12: %d\n", check_order(12));
printf("21: %d\n", check_order(21));
}
OUTPUT
> ./a.out
12345: 1
54321: -1
54323: 0
454321: 0
1: 0
12: 1
21: -1
>
A version that works for any length since it takes the string as parameter.
And feeding the recursive function with previous status (ascending or descending) allows for some shorter code and less functions.
int check_order(char *str, int index, int previous) {
char current = str[index]; // char at index
char next = str[index+1]; // char at index+1
if (current == 0 || next == 0) {
return previous; // End of string
}
// Ascending or descending?
int status = next > current ? 1 : (next < current ? -1 : 0);
if (status == 0 || index > 0 && status != previous) {
// If neither -1/1 nor status == previous (while not initial call)
return 0;
}
return check_order(str, index+1, status); // Check from next index
}
The main function must ensure the string is at least 2 chars
int main(int argc, char **argv) {
char *str = *++argv;
// Some optional checks on str here... (like this is a number)
int status = 0; // Default value if string length < 2
if (strlen(str) >= 2) {
status = check_order(str, 0, 0);
}
printf("Check order for %s is %d\n", str, status);
return 0;
}
Code after a return statement like this is unreachable:
return check_order(n / 10);
if (n == 0)
{
return -1;
}
Beyond this, you're on the right track of checking the current digit against the next digit, but I don't see a clear base case (when n < 10, that is, a single digit).
Trying to check ascending and descending in one recursive function is difficult to manage. In particular, communicating state between stack frames and determining which cases are still valid at a given call suggests that the return value is overworked.
To save having to return a struct or use an enum or magic numbers as flags, I'd write two general helper functions, ascending_digits and descending_digits.
#include <stdbool.h>
#include <stdio.h>
bool ascending_digits(int n) {
if (n < 10) return true;
if (n % 10 < n / 10 % 10) return false;
return ascending_digits(n / 10);
}
bool descending_digits(int n) {
if (n < 10) return true;
if (n % 10 > n / 10 % 10) return false;
return descending_digits(n / 10);
}
int check_order(int n) {
if (ascending_digits(n)) return 1;
if (descending_digits(n)) return -1;
return 0;
}
int main() {
printf("12345: %d\n", check_order(12345));
printf("54321: %d\n", check_order(54321));
printf("54323: %d\n", check_order(54323));
printf("454321: %d\n", check_order(454321));
printf("1: %d\n", check_order(1));
printf("12: %d\n", check_order(12));
printf("21: %d\n", check_order(21));
return 0;
}
Output:
12345: 1
54321: -1
54323: 0
454321: 0
1: 1
12: 1
21: -1
Not only are these functions easier to understand and maintain individually, they're also more reusable than if they were inseparably tied together.
This doesn't handle negative numbers--you could apply abs and go from there if you want. Same goes for handling equal values; this implementation accepts numbers such as 1223 but you could use <= to enforce strict ordering.

how to make loop in this case?

I need compute the first 100 prime numbers, but in the output i got "9" and other in my numbers....................... i want compute the first 100 prime numbers
{
bool prime; int start, new, kor,k, i,gg;
start=1;
k=1 ;
gg=0;
do
{
if (start < 2) {new = 2;}
if (start == 2) {new = 3;}
if (start > 2) {
if ((new % 2) == 0)
new--;
do {
prime = true;
kor=sqrt(new);
new+=2;
for (i=3;prime&& (i<=kor); i+=2) {
if (new % i == 0)
prime=false;}
} while (!prime) ;
}
gg++;
printf("%d->%d\n",gg, new);
k++;
start++;
continue;
}
while (k<101);
}
With
if (start < 2) {new = 2;}
if (start == 2) {new = 3;}
you have special cases the first and second numbers.
Next time round the do...while loop we skip the for loop because kor is 1, thereby printing 5. Which we didn't check, so perhaps we just got lucky. Smells like we don't check far enough.
Next time, after
kor=sqrt(new1); new1+=2;
kor is 2, so again we don't do the for loop, and print 7. Next time we have the same situation. kor is still 2 so you get 9.
I think if you switch the new+=2 to before the kor=sqrt(1); it will work.
Once you are in this part, you don't need to check if something is even, since you always add 2 to an odd number.
BTW Why does it say continue as the last thing in the loop?
This might be better (I took the liberty of putting it in a function):
void find_primes()
{
bool prime; int start, new, kor,k, i,gg;
start=1; k=1 ;gg=0;
do
{
if (start < 2) {new = 2;}
if (start == 2) {new = 3;}
if (start > 2) {
do {
prime = true;
new+=2;
kor=sqrt(new);
for (i=3;prime&& (i<=kor); i+=2) {
if (new % i == 0)
prime=false;
}
}
while (!prime) ;
}
gg++; printf("%d->%d\n",gg, new);
k++;
start++;
}
while (k<101);
}
I don't know what language you're programming in, so I'm taking a guess at this (I can't comment yet)-
Are you getting all odd numbers as output in your answer? 9, 11, 13, 15...
It seems that you are printing out all values of 'new', regardless of whether prime is true or not. Maybe you should put a
if (prime) {
printf("%d->%d\n",gg, new);
}
there
here is an example program from:
http://www.programmingsimplified.com/c/source-code/c-program-for-prime-number
note: 1 is not a prime number, see:
http://primes.utm.edu/notes/faq/one.html
#include<stdio.h>
int main()
{
int n, i = 3, count, c;
printf("Enter the number of prime numbers required\n");
scanf("%d",&n);
if ( n >= 1 )
{
printf("First %d prime numbers are :\n",n);
printf("2\n");
}
for ( count = 2 ; count <= n ; )
{
for ( c = 2 ; c <= (i - 1) ; c++ )
{
if ( i%c == 0 ) break;
}
if ( c == i )
{
printf("%d\n",i);
count++;
}
i++;
}
return 0;
}

Resources