I'm new to C and I'm doing CS50. I can't get my code to work. I'm almost positive the for statement is correct. The sum given by the for statement is correct.
I think it's something to do with the (floor(ccNumber / pow(10,13) == 34)
in the if statements.
Explanation of Luhn's Algorithm: https://cs50.harvard.edu/x/2020/psets/1/credit/
Sample credit card numbers for testing: https://www.freeformatter.com/credit-card-number-generator-validator.html
#include <stdio.h>
#include <cs50.h>
#include <math.h>
void credit(long ccNumber);
int main(void)
{
long ccNumber = 0;
credit(ccNumber);
}
void credit(long ccNumber)
{
do
{
ccNumber = get_long("Enter a credit card number: ");
}
while (ccNumber < 0);
{
int sum = 0;
long ccNumberFormat = ccNumber;
int nDigits = floor(log10(ccNumberFormat)) + 1;
int parity = nDigits % 2; // if parity % 2 == 0 then even number of digits, otherwise odd number of digits
for (int i = nDigits; i >= 0; i--) {
int digit = ccNumberFormat % 10;
if (i % 2 != parity) { // even number credit card digits will be multiplied by 2 every even number (starting from 0)
digit = digit * 2;
// printf("%d\n", sum);
}
if (digit > 9) {
digit = digit - 9;
}
sum = sum + digit;
ccNumberFormat /= 10;
printf("%d\n", sum);
}
if (sum % 10 == 0 && nDigits == 15 && (floor(ccNumber / pow(10,13) == 34) || (floor(ccNumber / pow(10,13) == 37))))
{
printf("%s\n", "AMEX");
}
else if (sum % 10 == 0 && (nDigits == 13 || nDigits == 16) && (floor(ccNumber / pow(10,12) == 4) || floor(ccNumber / pow(10,15) == 4)))
{
printf("%s\n", "VISA");
}
else if (sum % 10 == 0 && nDigits == 16 && ((floor(ccNumber / pow(10,14) >= 51) || (floor(ccNumber / pow(10,14) <= 55)))))
{
printf("%s\n", "MASTERCARD");
}
}
}
Pseudocode I more or less followed on Wikipedia::
function checkLuhn(string purportedCC) {
int sum := integer(purportedCC[length(purportedCC)-1])
int nDigits := length(purportedCC)
int parity := nDigits modulus 2
for i from 0 to nDigits - 2 {
int digit := integer(purportedCC[i])
if i modulus 2 = parity
digit := digit × 2
if digit > 9
digit := digit - 9
sum := sum + digit
}
return (sum modulus 10) = 0
}
A credit card number is a big number, are you sure long
is enough and you do not need long long
Out of that in your expressions like floor(ccNumber / pow(10,13) == 34)
the ')' is wrongly placed and you wanted floor(ccNumber / pow(10,13)) == 34
and of course the same for others :
if (sum % 10 == 0 && nDigits == 15 && ((floor(ccNumber / pow(10,13)) == 34) || (floor(ccNumber / pow(10,13)) == 37)))
{
printf("%s\n", "AMEX");
}
else if (sum % 10 == 0 && (nDigits == 13 || nDigits == 16) &&((floor(ccNumber / pow(10,12)) == 4) || (floor(ccNumber / pow(10,15)) == 4)))
{
printf("%s\n", "VISA");
}
else if (sum % 10 == 0 && nDigits == 16 && ((floor(ccNumber / pow(10,14)) >= 51) || (floor(ccNumber / pow(10,14)) <= 55)))
{
printf("%s\n", "MASTERCARD");
}
but in
else if (sum % 10 == 0 && (nDigits == 13 || nDigits == 16) &&((floor(ccNumber / pow(10,12)) == 4) || (floor(ccNumber / pow(10,15)) == 4)))
you take the risk to have a bad result, you need to check (floor(ccNumber / pow(10,12)) == 4)
only if nDigits == 13
and (floor(ccNumber / pow(10,15)) == 4)
only if nDigits == 16
and you can simplify to have :
else if (sum % 10 == 0 && (nDigits == 13 || nDigits == 16) &&(floor(ccNumber / pow(10,nDigits-1)) == 4))
So finally :
#include <stdio.h>
#include <math.h>
void credit(long long ccNumber);
int main(void)
{
long long cc[] = { 4532057997187363ll, // visa
4485661945778178ll, // visa
2720995573736457ll, // MasterCard
2720998284576493ll, // MasterCard
375137447049450ll, // amex
378572901284556ll, // amex
};
for (int i = 0; i != sizeof(cc)/sizeof(*cc); ++i)
credit(cc[i]);
return 0;
}
void credit(long long ccNumber)
{
int sum = 0;
long long ccNumberFormat = ccNumber;
int nDigits = floor(log10(ccNumberFormat)) + 1;
int parity = nDigits % 2; // if parity % 2 == 0 then even number of digits, otherwise odd number of digits
for (int i = nDigits; i >= 0; i--) {
int digit = ccNumberFormat % 10;
if (i % 2 != parity) { // even number credit card digits will be multiplied by 2 every even number (starting from 0)
digit = digit * 2;
// printf("%d\n", sum);
}
if (digit > 9) {
digit = digit - 9;
}
sum = sum + digit;
ccNumberFormat /= 10;
//printf("%d\n", sum);
}
if (sum % 10 == 0 && nDigits == 15 && ((floor(ccNumber / pow(10,13)) == 34) || (floor(ccNumber / pow(10,13)) == 37))) {
printf("%lld %s\n", ccNumber, "AMEX");
}
else if (sum % 10 == 0 && (nDigits == 13 || nDigits == 16) &&(floor(ccNumber / pow(10,nDigits-1)) == 4)) {
printf("%lld %s\n", ccNumber, "VISA");
}
else if (sum % 10 == 0 && nDigits == 16 && ((floor(ccNumber / pow(10,14)) >= 51) || (floor(ccNumber / pow(10,14)) <= 55))) {
printf("%lld %s\n", ccNumber, "MASTERCARD");
}
}
Compilation and execution:
pi@raspberrypi:/tmp $ gcc -Wall f.c -lm
pi@raspberrypi:/tmp $ ./a.out
4532057997187363 VISA
4485661945778178 VISA
2720995573736457 MASTERCARD
2720998284576493 MASTERCARD
375137447049450 AMEX
378572901284556 AMEX
pi@raspberrypi:/tmp $
note also to do floating point computation is a risk, you can do all only using long long