Я беру CS50 Intro в CS. В этом задании нас просят создать программу, которая может определить, какой тип кредитной карты (AMEX, Visa, MasterCard) указан во входных данных (и действителен ли он). Действительность проверяется с помощью алгоритма Луна. Вот как работает алгоритм:
- Умножьте все остальные цифры на 2, начиная с предпоследней цифры номера, а затем сложите цифры этих продуктов вместе. (Мы не добавляем продукты вместе, а точнее цифры продуктов!)
- Добавьте сумму к сумме цифр, которые не были умножены на 2.
- Если последняя цифра суммы равна 0, число действительное!
Затем тип кредитной карты проверяется путем проверки первых нескольких цифр кредитной карты. Т.е. номера American Express начинаются с 34 или 37, VISA — с 4 и т. Д. Вот моя реализация:
#include <stdio.h>
#include <cs50.h>
#include <math.h>
#include <stdlib.h>
bool check_is_card_valid(long card);
int checksum(long card);
bool array_consists(const unsigned int arr[], int val, int arrlen);
string get_card_type(long card);
int get_nth_digit(long card, int digit);
int get_card_length(long card);
const unsigned int accepted_card_length[] =
{
15, // AMEX uses 15 digit numbers
16, // MasterCard and VISA uses 16 digit numbers
13 // VISA uses 13 digit numbers
};
const size_t acc_card_len = sizeof(accepted_card_length) / sizeof(*accepted_card_length);
const unsigned int AMEX_first_digits[] = {34, 37};
const size_t amex_digits_len = sizeof(AMEX_first_digits) / sizeof(*AMEX_first_digits);
const unsigned int MASTERCARD_first_digits[] = {51, 52, 53, 54, 55};
const size_t mc_digits_len = sizeof(MASTERCARD_first_digits) / sizeof(*MASTERCARD_first_digits);
const unsigned int VISA_first_digit = 4;
int main(void)
{
long card_number = get_long("Card number: ");
if (check_is_card_valid(card_number) == true)
{
printf("%sn", get_card_type(card_number));
}
else
{
printf("INVALIDn");
}
}
/*
Luhn's algorithm. Starting from the right, multiply every other digit by 2 and add up the digits
add this sum to the sum of the digits that were not multiplied by 2.
*/
int checksum(long card)
{
int checksum = 0;
for (int i = 0; i < get_card_length(card); i++)
{
if (i % 2 == 0)
{
checksum += get_nth_digit(card, i);
}
else if (i % 2 == 1)
{
int num = get_nth_digit(card, i) * 2;
if (num > 9)
{
num = get_nth_digit(num, 0) + get_nth_digit(num, 1);
}
checksum += num;
}
}
return checksum;
}
bool array_consists(const unsigned int arr[], int val, int arrlen)
{
for (int i = 0; i < arrlen; i++)
{
if (val == arr[i])
{
return true;
}
}
return false;
}
// Luhn's algorithm states that if the last digit of the checksum is 0, it is valid
bool check_is_card_valid(long card)
{
if (array_consists(accepted_card_length, get_card_length(card), acc_card_len) == true)
{
return checksum(card) % 10 == 0;
}
else
{
return false;
}
}
string get_card_type(long card)
{
int card_length = get_card_length(card);
int first_digit = get_nth_digit(card, card_length - 1);
int second_digit = get_nth_digit(card, card_length - 2);
int first_two_digits = (first_digit * 10) + second_digit;
if (first_digit == VISA_first_digit)
{
return "VISA";
}
else if (array_consists(AMEX_first_digits, first_two_digits, amex_digits_len) == true)
{
return "AMEX";
}
else if (array_consists(MASTERCARD_first_digits, first_two_digits, mc_digits_len) == true)
{
return "MASTERCARD";
}
else
{
return "INVALID";
}
}
// gets nth digit from the right, starting with 0, using modulo
int get_nth_digit(long card, int digit)
{
return fmod(floor(card / pow(10, digit)), 10);
}
int get_card_length(long card)
{
return floor(log10(card)) + 1;
}
Я хотел бы получить отзывы о моем коде и о том, как я могу его улучшить; такие вещи, как стиль, читабельность, чистота, эффективность и т. д. Легко ли понятен мой код? Что с комментариями — их мало? Я стараюсь не комментировать свой код, когда функция чего-то кажется очевидной. Как мне улучшить стиль и есть ли какие-либо соглашения о коде, которых я не придерживаюсь? Могу ли я оптимизировать это, чтобы ускорить процесс? Или, может быть, есть лучший способ сделать то же самое? В принципе, как мне улучшить свой код?
1 ответ
Упрощение было бы следующим.
int checksum(long card)
{
int checksum = 0;
for (int i = 0; i < get_card_length(card); i++)
{
int digit = get_nth_digit(card, i);
if (i % 2 == 0)
{
checksum += digit;
}
else
{
int num = digit * 2;
if (num > 9) // 10, 12, 14, 16, 18
{
//num = get_nth_digit(num, 0) + get_nth_digit(num, 1);
//num = 1 + num - 10;
num -= 9;
}
checksum += num;
}
}
return checksum;
}
- Более читаемый, если ввести
digit
. else if
может статьelse
. Поскольку значения операндов% неотрицательны, результат не может быть -1.get_nth_digit
является кладжем, и на самом деле конечный результат, кажется, представляет гораздо более простую семантику.
API для проверки номера кредитной карты использует промежуточный checksum
. Это «последняя цифра», значение% 10, должно быть 0 для действительной контрольной суммы. Итак, функция checksum
может быть локальной «частной» функцией. Не совсем понятно, что вы вставляете в .h, а что в .c.