Need to split an integer and add it with itself - c

So, my basic problem is that I'm trying to write a program for a small project I'm working on for fun.
Basically, my issue is this: I need to take user input, as an int, say 15, then manipulate the number so that it returns the result of 1 + 5, being 6. Or for another example say the number is 29, will give you 2 + 9 = 11, which would then need to be reduced down again to 1 + 1 = 2. That could probably be handled easily, but I'm stuck on how to actually split the int apart without having to take the numbers in one by one. I guess it's possible to with RegEx, but I was looking for a more efficient method.

This is not a particularly good job for a regex. The usual way would be to get individual digits as the remainder after dividing by 10.

A sample code is here:
int sum_of_digits(int n)
{
if(n < 10)
{
return n;
}
int sum = 0;
while( n > 0)
{
sum += n % 10;
n /= 10;
}
return sum_of_digits(sum);
}
int main()
{
int n1 = sum_of_digits(29);
int n2 = sum_of_digits(15);
}

In C, this would do the trick for two digits:
digit_sum = my_int%10 + my_int/10

I think the quickest way here is to use / (divide) and % (modulus) operators to traverse your integer.
int base = 15;
int acum = 0;
while (base > 0) {
acum = acum + (base % 10);
base = base / 10;
};
// At this point, base = 0 and acum = 6
// if acum > 10, then assign it to base and start again.

Related

Failed to reuse variable in C

I'm trying to code a program that can tell apart real and fake credit card numbers using Luhn's algorithm in C, which is
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
Then I coded something like this (I already declared all the functions at the top and included all the necessary libraries)
//Luhn's Algorithm
int luhn(long z)
{
int c;
return c = (sumall(z)-sumodd(z)) * 2 + sumaodd(z);
}
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
But somehow it always gives out the wrong answer even though there's no error or bug detected. I came to notice that it works fine when my variable z stands alone, but when it's used multiple times in the same line of code with different functions, their values get messed up (in function luhn). I'm writing this to ask for any fix I can make to make my code run correctly as I intended.
I'd appreciate any help as I'm very new to this, and I'm not a native English speaker so I may have messed up some technical terms, but I hope you'd be able to understand my concerns.
sumall is wrong.
It should be sumeven from:
Add the sum to the sum of the digits that weren’t multiplied by 2.
Your sumall is summing all digits instead of the non-odd (i.e. even) digits.
You should do the * 2 inside sumodd as it should not be applied to the other [even] sum. And, it should be applied to the individual digits [vs the total sum].
Let's start with a proper definition from https://en.wikipedia.org/wiki/Luhn_algorithm
The check digit is computed as follows:
If the number already contains the check digit, drop that digit to form the "payload." The check digit is most often the last digit.
With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).
Sum the digits of the resulting value in each position (using the original value where a digit did not get doubled in the previous step).
The check digit is calculated by 10 − ( s mod ⁡ 10 )
Note that if we have a credit card of 9x where x is the check digit, then the payload is 9.
The correct [odd] sum for that digit is: 9 * 2 --> 18 --> 1 + 8 --> 9
But, sumodd(9x) * 2 --> 9 * 2 --> 18
Here's what I came up with:
// digsum -- calculate sum of digits
static inline int
digsum(int digcur)
{
int sum = 0;
for (; digcur != 0; digcur /= 10)
sum += digcur % 10;
return sum;
}
// luhn -- luhn's algorithm using digits array
int
luhn(long z)
{
char digits[16] = { 0 };
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
// split into digits (we use little-endian)
int digcnt = 0;
for (digcnt = 0; z != 0; ++digcnt, z /= 10)
digits[digcnt] = z % 10;
int sum = 0;
for (int digidx = 0; digidx < digcnt; ++digidx) {
int digcur = digits[digidx];
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
// luhn -- luhn's algorithm using long directly
int
luhn2(long z)
{
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
int sum = 0;
for (int digidx = 0; z != 0; ++digidx, z /= 10) {
int digcur = z % 10;
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
You've invoked undefined behavior by not initializing a few local variables in your functions, for instance you can remove your undefined behaviour in sumodd() by initializing a to zero like so:
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a = 0; //Initialize
while(x)
{
a += x % 10; //You can "a += b" instead of "a = a + b"
x /= 100;
}
return a;
}
It's also important to note that long is only required to be a minimum of 4-bytes wide, so it is not guaranteed to be wide enough to represent a decimal-16-digit-integer. Using long long solves this problem.
Alternatively you may find this problem much easier to solve by treating your credit card number as a char[] instead of an integer type altogether, for instance if we assume a 16-digit credit card number:
int luhn(long long z){
char number[16]; //Convert CC number to array of digits and store them here
for(int c = 0; c < 16; ++c){
number[c] = z % 10; //Last digit is at number[0], first digit is at number[15]
z /= 10;
}
int sum = 0;
for(int c = 0; c < 16; c += 2){
sum += number[c] + number[c + 1] * 2; //Sum the even digits and the doubled odd digits
}
return sum;
}
...and you could skip the long long to char[] translation part altogether if you treat the credit card number as an array of digits in the whole program
This expression:
(sumall(z)-sumodd(z)) * 2 + sumall(z);
Should be:
((sumall(z)-sumodd(z)) * 2 + sumodd(z))%10;
Based on your own definition.
But how about:
(sumall(z) * 2 - sumodd(z))%10
If you're trying to be smart and base off sumall(). You don't need to call anything twice.
Also you don't initialise your local variables. You must assign variables values before using them in C.
Also you don't need the local variable c in the luhn() function. It's harmless but unnecessary.
As others mention in a real-world application we can't recommend enough that such 'codes' are held in a character array. The amount of grief caused by people using integer types to represent digit sequence 'codes' and identifiers is vast. Unless a variable represents a numerical quantity of something, don't represent it as an arithmetic type. More issue has been caused in my career by that error than people trying to use double to represent monetary amounts.
#include <stdio.h>
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a=0;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b=0;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
//Luhn's Algorithm
int luhn(long z)
{
return (sumall(z)*2-sumodd(z))%10;
}
int check_luhn(long y,int expect){
int result=luhn(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumodd(long y,int expect){
int result=sumodd(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumall(long y,int expect){
int result=sumall(y);
if(result==expect){
return 0;
}
return 1;
}
int main(void) {
int errors=0;
errors+=check_sumall(1,1);
errors+=check_sumall(12,3);
errors+=check_sumall(123456789L,45);
errors+=check_sumall(4273391,4+2+7+3+3+9+1);
errors+=check_sumodd(1,1);
errors+=check_sumodd(91,1);
errors+=check_sumodd(791,8);
errors+=check_sumodd(1213191,1+1+1+1);
errors+=check_sumodd(4273391,15);
errors+=check_luhn(1234567890,((9+7+5+3+1)*2+(0+8+6+4+2))%10);
errors+=check_luhn(9264567897,((9+7+5+6+9)*2+(7+8+6+4+2))%10);
if(errors!=0){
printf("*ERRORS*\n");
}else{
printf("Success\n");
}
return 0;
}

Binary decimal conversion with arrays

Do you have a simple idea of how we go from a binary number to a decimal number in C without doing any divisions (because I can have very big numbers), maybe only with masks (&, |, << or >>) .
I have a table like this:
tab[20] = {1,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1,0,1};
and I would like this :
tab[6] = {5,9,6,2,5,3};
Is this something that can be done ? Thank you for your help
idea of how we go from a binary number to a decimal number (can have very big numbers)
For each binary digit, scale the decimal destination by 2 and add the digit.
Pseudo code
some_integer_type tab2[] = {1,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1,0,1};
some_integer_type tab10[big_enough];
zero fill tab10[]
for (each i element in tab2[] starting with index 0) {
// scale tab10[] by 2 and add tab2[]
carry = tab2[i]
for (each j element in tab10[] starting with the last index) {
sum = (tab10[j] << 1) | carry;
if (sum >= 10) {
sum -= 10;
carry = 1;
} else {
carry = 0;
}
tab10[i] = sum;
}
}
print tab10[]
To do >=, -= 10 with only &, |, << or >>, create helper functions: divide and conquer.
No division and up to 64 bit. This is "big". The bin-to-dec is done with sprintf(). That digit-string can then be converted to an array of integers like your tab[6]
char bittab[64] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0};
long num = 0, dupl = 1;
int i;
for (i = 0; i < sizeof bittab; i++) {
num += dupl * bittab[i];
dupl *= 2;
}
char decstring[30];
sprintf(decstring, "%ld\n", num);
for (i = 0; i < strlen(decstring); i++)
printf("%d\n", decstring[i] - '0');
The output is:
3
2
7
6
7
-38
This can be written into a dectab[] array, excluding the null terminator byte.
(I made the bits ascending to leave the size open.)

Is it possible to increment the modulo operator in later loop iterations?

I am trying to construct a simple program which adds together the digits of a long number. I attempted to do this by using a loop employing the modulo operator and some basic arithmetic. I want to increment the modulo operator by multiplying it by ten on each iteration of the loop in order to reach the next digit. I want to check if my code is correct, however, I receive errors pertaining to the lines involving the modulo operations and I'm not quite sure why.
This was my attempted construction:
{
long i = 0;
long b;
int m = 1;
do
{
long number = get_long("Number?\n");
long a = number % m;
b = number - a;
long c = b % m x 10;
long d = c / m;
{
i = i + d;
}
{
m = m x 10
}
}
while (b > 0);
printf("%ld\n", i);
}
Edit:
I made the basic error of writing "x" instead of "*". However, having fixed this, I no longer receive errors, but the program simply returns "0". Any diagnosis would be appreciated.
int main(void)
{
long i = 0;
long b;
int m = 10;
long number = get_long("Number?\n");
do
{
long a = number % m;
b = number - a;
long c = b % m * 10;
long d = c / m;
{
i = i + d;
}
{
m = m * 10;
}
}
while (b > 0);
printf("%ld\n", i);
}
For your revised code:
long c = b % m * 10;
this line will evaluate (b % m) and then multiply it by 10 because of the order of operations.
I presume what you actually want is:
long c = b % (m * 10);
Secondly, the following line determines which digit you start at:
int m = 10;
and this line determines how many digits between the ones you include in your total:
m = m * 10;
So for this configuration, it will start at the 2nd digit from the right and add every digit.
So for the number 1234, you'd get 3 + 2 + 1 = 6.
If you want to add every digit, you could set:
int m = 10;
and you'd get 4 + 3 + 2 + 1 = 10.
Alternatively, if you had used:
m = m * 10;
you'd have 3 + 1 = 4.
First, you're likely getting errors due to these lines:
long c = b % m x 10;
m = m x 10
This is because x is not a valid operator.
The multiplication operator is *:
long c = b % m * 10;
m = m * 10;
As for your approach, I would suggest, instead of changing the modulo operand, you simply divide the original number by 10 to shift it one digit each operation.
For example:
#include <stdio.h>
int main()
{
int sumofdigits = 0;
int num = 12345;
while(num > 0) {
sumofdigits += num % 10;
num /= 10;
}
printf("%d", sumofdigits);
return 0;
}
The reduced-sum of the digits of a number is the same as that number modulo 9.
Example:
#include <stdio.h>
int main(void) {
int number = 57283;
printf("%d \n", number%9);
// 5 + 7 + 2 + 8 + 3 == 25 ==> 2 + 5 == 7
// 57283 % 9 == 7
return 0;
}
If you want to use loops to get the reduced sum:
int sum_of_digits(int num)
{
int sum;
do
{
sum = 0;
while(num)
{
sum += num%10;
num /= 10;
}
num = sum;
} while (sum >9);
return sum;
}
But if you only want the simple sum of digits (one pass only):
int sum_of_digits(int num)
{
int sum = 0;
while(num)
{
sum += num%10;
num /= 10;
}
return sum;
}
You have to find the sum of the digits of a variable of type long by the two operators modulo (%) and division (/), you start with the operator modulo to find the remainder of the division (the digits) then, you add this degit to the sum, then you do the division / 10 to overwrite (the summed digit) until the number is equal to 0 like this:
int main()
{
long number=0,m=0;
printf("Give a number :");
scanf("%ld",&number);
long s=0,temp=number;
while(number != 0)
{
m=number%10;
s+=m;
number/=10;
}
printf("\n%The sum of the digits of the Number %ld is : %ld\n",temp,s);
}

How to generate random long int in C where every digit is non-zero? Moreover the random numbers are repeating

I am making a library management in C for practice. Now, in studentEntry I need to generate a long int studentID in which every digit is non-zero. So, I am using this function:
long int generateStudentID(){
srand(time(NULL));
long int n = 0;
do
{
n = rand() % 10;
}while(n == 0);
int i;
for(i = 1; i < 10; i++)
{
n *= 10;
n += rand() % 10;
}
if(n < 0)
n = n * (-1); //StudentID will be positive
return n;
}
output
Name : khushit
phone No. : 987546321
active : 1
login : 0
StudentID : 2038393052
Wanted to add another student?(y/n)
I wanted to remove all zeros from it. Moreover, when I run the program the first time the random number will be the same as above, and second time random number is same as past runs like e.g:-
program run 1
StudentID : 2038393052
StudentID : 3436731238
program run 2
StudentID : 2038393052
StudentID : 3436731238
What do I need to fix these problems?
You can either do as gchen suggested and run a small loop that continues until the result is not zero (just like you did for the first digit) or accept a small bias and use rand() % 9 + 1.
The problem with the similar sequences has its reason with the coarse resolution of time(). If you run the second call of the function to fast after the first you get the same seed. You might read this description as proposed by user3386109 in the comments.
A nine-digit student ID with no zeros in the number can be generated by:
long generateStudentID(void)
{
long n = 0;
for (int i = 0; i < 9; i++)
n = n * 10 + (rand() % 9) + 1;
return n;
}
This generates a random digit between 1 and 9 by generating a digit between 0 and 8 with (rand() % 9) and adding 1. There's no need to for loops to avoid zeros.
Note that this does not call srand() — you should only call srand() once in a given program (under normal circumstances). Since a long must be at least 32 bits and a 9-digit number only requires 30 bits, there cannot be overflow to worry about.
It's possible to argue that the result is slightly biassed in favour of smaller digits. You could use a function call to eliminate that bias:
int unbiassed_random_int(int max)
{
int limit = RAND_MAX - RAND_MAX % max;
int value;
while ((value = rand()) >= limit)
;
return value % max;
}
If RAND_MAX is 32767 and max is 9, RAND_MAX % 9 is 7. If you don't ignore the values from 32760 upwards, you are more likely to get a digit in the range 0..7 than you are to get an 8 — there are 3642 ways to each of 0..7 and only 3641 ways to get 8. The difference is not large; it is smaller if RAND_MAX is bigger. For the purposes on hand, such refinement is not necessary.
Slightly modify the order of your original function should perform the trick. Instead of removing 0s, just do not add 0s.
long int generateStudentID(){
srand(time(NULL));
long int n = 0;
for(int i = 0; i < 10; i++)
{
long int m = 0;
do
{
m = rand() % 10;
}while(m == 0);
n *= 10;
n += m;
}
//Not needed as n won't be negative
//if(n < 0)
//n = n * (-1); //StudentID will be positive
return n;
}

increment digits of natural number recursively

I wanna make a funcion that will take a natural number and make a new number so every digit in the old number will be incremented and if the digit is 9 it will become zero, but not to check specificly if the digit is 9.
example:
930 will return 41
9999 will return 0
879021 will return 980132.
This is what i got so far:
int newNumber(int n)
{
int dig;
if (n < 9)
return n + 1;
dig = n % 10;
dig++;
n = n / 10;
n = n * 10 + dig;
return newNumber(n/10);
}
There are a couple of issues with your code:
It doesn't handle a single digit of 9 (which cause a stack overflow).
Adding 1 to 9 makes 10 not 0.
I've run it through the sample data you supplied and it seems to work (in C#) and it has a hard core recursive line at the end.
int newNumber(int n)
{
if (n == 9)
return 0;
if (n < 9)
return n + 1;
return (newNumber(n / 10) * 10) + newNumber(n % 10);
}
Here's to avoid the check for n == 9:
int newNumber(int n)
{
static int table[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
return (n <= 9) ? table[n] : (newNumber(n / 10) * 10) + newNumber(n % 10);
}
A lookup table seems the most appropriate and does exactly what the requirements describe. Trying to use the non-compatible arithmetic operators results in side effects (as we see in Bathsheba's answer for example), that then need to be corrected.
unsigned newNumber(unsigned n, unsigned c = 0)
{
return n ? (n + 1) % 10 + 10 * newNumber(n / 10, 1 + c) : !c;
}
is one way, and it will treat 0 as 1, via the !c branch where c counts the number of recursions. Note the tail recursion in the ternary conditional branch - some compilers will optimise a tail recursion out to a simple loop, see What is tail recursion?
Bathsheba's solution posted above is very elegant by using the ternary operator, but it will give you a wrong result if the input is zero. To avoid that you may use a stub function:
#include <stdio.h>
int incDigits(int n)
{
return n ? (n + 1) % 10 + incDigits(n / 10) * 10 : 0;
}
int newNumber(int n)
{
return n ? incDigits(n) : 1;
}
int main()
{
for(int i = 0; i <= 100; ++i)
{
int n = newNumber(i);
printf("%d -> %d\n", i, n);
}
}
EDIT: user meaning-matters also posted a way to fix the input value problem using a lookup table, but he still has to check if n equals 9, which is something you don't want. So I believe using a stub function still is the best way.
Two ternary operator has been used to take care of the two cases:
i) number equal to 9
ii) number not equal to 9 => Another ternary operator is used to take care of further two possible cases:
a) number greater than 9( return sum of num(n/10)*10 and num(n%10) ); this can be further elaborated based on the argument fed to the num function.
b)number smaller than 9(return number plus one(n+1))
Once this function is called from the main function with argument equal to the number to be transformed in the manner asked in the question, each call in line4 will undergo recursion until they pass the argument to the subsequent iteration less than or equal to 9(which leads to termination of the recursion). With basic understanding of recursion, the above para can easily be understood in context to the subroutine below.
Blockquote
int num(int n)//line1
{//line2
int t;//line3
t=(n==9?0:(n>9?num(n/10)*10+num(n%10):n+1));//line4
return t;/line5
}//line6
Blockquote

Resources