C++ Incomplete Code about dates, what is the better solution? - c++

Im writing a code that, if you input your birthday date and any other date, it returns the total number of years, months and day that you are alive.
Obs.:including (leap) bissextile years.
Obs.2:for invalid dates, the output must be "data invalida" (invalid date in portuguese).
Inputs/Outputs:
Obs.: The date format is in the brazillian standard, the format is Day / Month / Year.
8 //the first input is the number of inputs that you will test.
Input 1: 29/02/2000
Input 2: 01/03/2001
Output: 1 0 1
Input 1: 29/02/2000
Input 2: 28/02/2001
Output: 1 0 0
Input 1: 29/12/2012
Input 2: 13/01/2013
Output: 0 0 15
Input 1: 27/05/2012
Input 2: 27/05/2013
Output: 1 0 0
Input 1: 01/01/2012
Input 2: 05/01/2013
Output: 1 0 4
Input 1: 13/05/1966
Input 2: 05/02/2015
Output: 48 8 23
Input 1: 29/02/2003
Input 2: 4/05/2012
Output: data invalida
Input 1: 14/13/1995
Input 2: 7/8/1996
Output: data invalida
The Code:
#include <iostream>
#include <cstdio>
using namespace std;
int verificar(int ano)
{
if (((ano % 4 == 0) && (ano % 100 != 0)) || (ano % 400 == 0))
return 1;
else
return 0;
}
int checkdia(int dia, int mes, int ano){
if (dia>0)
if (((mes==1)||(mes==3)||(mes==5)||(mes==7)||(mes==8)||(mes==10)||(mes==12)) && (dia<=31))
return 1;
else{
if (((mes==4)||(mes==6)||(mes==9)||(mes==11)) && (dia<=30))
return 1;
else{
if ((mes==2) && (dia<=28))
return 1;
else{
if ((((verificar(ano))==true)&&(dia<=29))&&(mes==2))
return 1;
else
return 0;
}
}
}
else
return 0;
}
int checkmes(int mes)
{
if ((mes>0) && (mes<=12))
return 1;
else
return 0;
}
int checkano(int ano)
{
if ((ano>0) && (ano<11000))
return 1;
else
return 0;
}
int main(){
int numerodetestes, mes1, mes2, dia1, dia2, ano1, ano2, teste11, teste12, teste13, teste21, teste22, teste23;
cin>>numerodetestes;
for(int c=0;c<=numerodetestes;c++){
scanf("%d/%d/%d", &dia1, &mes1, &ano1);
scanf("%d/%d/%d", &dia2, &mes2, &ano2);
teste11=checkano(ano1);
teste12=checkdia(dia1,mes1,ano1);
teste13=checkmes(mes1);
teste21=checkano(ano2);
teste22=checkdia(dia2,mes2,ano2);
teste23=checkmes(mes2);
if ((dia1==29)&&(mes1==02))
dia1=28;
if ((teste11+teste12+teste13+teste21+teste22+teste23)==6){
total=((365*(ano2-ano1))+sexto);
//... incomplete part ...//
}
else
cout<<"data invalida"<<endl;
}
return 0;
}
Glossary:
dia: day
mes: month
ano: year
numerodetestes: number of tests
verificar: function for bissextile
check(...): function to check "X"
teste"XX": int variable that will receive a 0 or 1 of a check function.
THE PROBLEM IS: I cant figure out how to calculate it in an organized way.

You should use bool instead of int for your return values :
bool verificar(int ano)
{
return ((ano % 4 == 0) && (ano % 100 != 0)) || (ano % 400 == 0));
}
Also your check functions could be greatly simplified :
bool checkmes(int mes) {
return ( (mes > 0) && (mes <= 12) );
}
bool checkano(int ano) {
return ( (ano > 0) && (ano < 11000) );
}
bool checkdia(int dia, int mes, int ano) {
if(dia < 1 || dia > 31) return false;
if(mes%2 == 0 && dia >30) return false;
if(mes == 2 && dia >28) return verificar(ano);
return true;
}
Then you could write something like :
bool checkdata(int dia, int mes, int ano) {
return ( checkano(ano) && checkmes(mes) && checkdia(dia, mes, ano) );
}
Which would allow you to write :
if( !checkdata(dia1,mes1,ano1) || !checkdata(dia2,mes2,ano2) ) {
cout<< "data invalida" <<endl;
}
Now for the main problem, you could easily get an estimation of the number of day between two dates, but you can't easily get the real number, because dates are nothing but logical. You would have to take into account all calendar modifications across history.
For an easy estimation, I would first add/subtract the dates offset to the first of January, and then add the year difference :
bool isLeap(int year) {
     return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int monthLengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int monthLength(int month, int year) {
int n = monthLengths[month-1];
if(month == 2 && isLeap(year)) n += 1;
return n;
}
int yearLength(int year) {
return isLeap(year) ? 366 : 365;
}
int nDay = 0; /* day counter */
/* subtract data1 offset to 01/01 */
nDay -= dia1;
for(int i = mes1; i > 1; --i) {
nDay -= monthLength(i - 1, ano1);
}
/* add data2 offset to 01/01 */
nDay += dia2;
for(int i = mes2; i > 1; --i) {
nDay += monthLength(i - 1, ano2);
}
/* add year offset */
for(int i = ano2; i > ano1; --i) {
nDay += yearLength(i);
}
cout << "Difference = " << nDay << " days" << endl;

Related

Problem of calculating the days between two dates in c++ using class of Date when the first date is bigger than second date

when the first date is bigger than the second, it doesent calculate.
for example: first date 22/10/2022
second date: 15/10/2022
#include <iostream>
#include <cstdlib>
using namespace std;
class Date {
public:
Date(int d, int m, int y);
void set_date(int d, int m, int y);
void print_date();
void inc_one_day();
bool equals(Date d);
int get_day() { return day; }
int get_month() { return month; }
int get_year() { return year; }
private :
int day;
int month;
int year;
};
bool is_leap_year(int year)
{
int r = year % 33;
return r == 1 || r == 5 || r == 9 || r == 13 || r == 17 || r == 22 || r == 26 || r == 30;
}
int days_of_month(int m, int y){
if (m < 7)
return 31;
else if (m < 12)
return 30;
else if (m == 12)
return is_leap_year(y) ? 30 : 29;
else
abort();
}
void Date::inc_one_day(){
day++;
if (day > days_of_month(month, year)) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
}
bool Date::equals(Date d) {
return day == d.day && month == d.month && year == d.year;
}
int days_between(Date d1, Date d2){
int count = 1;
while (!d1.equals(d2)){
d1.inc_one_day();
count++;
}
return count;
}
Date::Date(int d, int m, int y){
cout << "constructor called \n";
set_date(d, m, y);
}
void Date::set_date(int d, int m, int y){
if (y < 0 || m < 1 || m>12 || d < 1 || d > days_of_month(m, y))
abort();
day = d;
month = m;
year = y;
}
void Date::print_date(){
cout << day << '/' << month << '/' << year<<endl;
}
int main(){
Date bd(22, 12, 1395);
Date be(15, 12, 1395);
cout << '\n';
int i;
i= days_between(bd, be);
cout << i << endl;
}
here's my code.
I've seen many codes that calculate the days between two dates, but they didn't use class Date.
how can i solve this problem? could you guys help me please.I'm sorry i'm new in c++ so, my problem might be so basic.
It is clear why your algorithm does not work - you are incrementing the later date so it will never equal the earlier date. The solution is simply to compare the dates and swap the operands if necessary so that you are always incrementing the earlier date toward the later date.
int days_between(Date d1, Date d2)
{
int count = 0 ;
// Initially assume d2 >= d1
Date* earlier = &d1 ;
Date* later = &d2 ;
// Test if d1 > d2...
int year_diff = d2.get_year() - d1.get_year() ;
int mon_diff = d2.get_month() - d1.get_month() ;
int day_diff = d2.get_day() - d1.get_day() ;
if( year_diff < 0 ||
(year_diff == 0 && (mon_diff < 0 || (mon_diff == 0 &&
day_diff < 0 ))))
{
// d1 > d2, so swap
earlier = &d2 ;
later = &d1 ;
}
while (!earlier->equals(*later))
{
earlier->inc_one_day();
count++;
}
return count;
}
Note that it is not clear why you start with a count of 1. If the dates start equal, surely that should return a zero? That is how I have written it in any case.
If it is required to indicate whether the dates were reversed or not, you might want to return a signed value. In that case:
return earlier == &d2 ? -count : count ;
Which for the dates in your example will return -7.
Your solution is a good candidate for operator overloading so you could simply and more intuitively write:
if( d1 > d2 )
{
earlier = &d2 ;
later = &d1 ;
}
while( *earlier != *later))
{
earlier++ ;
count++ ;
}
return earlier == &d2 ? -count : count ;
and even ultimately:
i = be - bd;
What would be easier is to write a function that calculates the total number of days that have occurred since the year 0000. After that you can simply subtract them from each other and return the total number of days between them.

C++ Program Builds but not printing output

Having trouble determining the cause of this. Everything builds properly just does not print any type of output. I'm sure it is something minuscule so please be understanding and not chew me out for asking such a simple question. Trying my best to learn on my own. The program is supposed to ask you to enter a date dd/mm/yy. Below I have attached the main.cpp and date.h. Thank you for any assistance.
main.cpp
#ifndef DATE_H_
#define DATE_H_
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
class Date
{
private:
int day, month, year;
char format;
bool isLeapYear() const;
int days_in_month() const;
public:
Date(int month=1, int day=1, int year=2000);
void Input();
void Show();
bool Set(int m, int d, int y);
int GetMonth() const;
int GetDay() const;
int GetYear() const;
bool SetFormat(char f);
void Increment(int numDays=1);
int Compare(const Date& d);
void printJulianDate();
};
#endif
//end of date.h
// date.c
#include "date.h"
// constructor
Date::Date(int month, int day, int year)
{
// set the parameters to default values
this->month = 1;
this->day = 1;
this->year = 2000;
this->format = 'D';
// call the method to set the passed month, day and year
if(!Set(month,day,year))
{
cout<<"Invalid date"<<endl; // display error message if invalid date
}
}
// helper function to return if the year is leap or not
bool Date:: isLeapYear() const
{
return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
}
// helper function to return the number of days in the month
int Date::days_in_month() const
{
if(month == 2)
{
if(isLeapYear())
return 29;
else
return 28;
}else if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month ==10 || month==12)
return 31;
else
return 30;
}
// function to input date from the user
void Date:: Input()
{
int m,d,y;
char sep;
// input of date
cout<<"Enter date:";
cin>>m>>sep>>d>>sep>>y;
// loop that continues till the user enters a valid date
while(!Set(m,d,y))
{
cout<<"Invalid date. Try again: ";
cin>>m>>sep>>d>>sep>>y;
}
}
// function to display the date in the format specified
void Date:: Show()
{
if(format == 'D')
{
cout<<month<<"/"<<day<<"/"<<year;
}else if(format == 'T')
{
cout<<setw(2)<<setfill('0')<<month<<"/"<<setw(2)<<setfill('0')<<day<<"/"<<setw(2)<<setfill('0')<<(year%100);
}else if(format == 'L')
{
switch(month)
{
case 1:
cout<<"Jan";
break;
case 2:
cout<<"Feb";
break;
case 3:
cout<<"Mar";
break;
case 4:
cout<<"Apr";
break;
case 5:
cout<<"May";
break;
case 6:
cout<<"June";
break;
case 7:
cout<<"July";
break;
case 8:
cout<<"Aug";
break;
case 9:
cout<<"Sep";
break;
case 10:
cout<<"Oct";
break;
case 11:
cout<<"Nov";
break;
case 12:
cout<<"Dec";
break;
}
cout<<" "<<day<<", "<<year;
}
}
// method to validate the passed arguments and set the date if the arguments represent a valid date
bool Date:: Set(int m, int d, int y)
{
if(y > 1582)
{
if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
{
if(d < 1 || d > 31)
return false;
else
{
day = d;
month = m;
year = y;
return true;
}
}else if(m == 4 || m == 6 || m == 9 || m == 11)
{
if(d < 1 || d > 30)
return false;
else
{
day = d;
month = m;
year = y;
return true;
}
}else if(m == 2)
{
if((y%400 == 0 ) || ((y%4 == 0) && (y%100) != 0))
{
if(d < 1 || d > 29)
return false;
else
{
day = d;
month = m;
year = y;
return true;
}
}else
{
if(d < 1 || d > 28)
return false;
else{
day = d;
month = m;
year = y;
return true;
}
}
}else
return false;
}else if(y == 1582)
{
if(m >= 10)
{
if(m == 10 || m == 12)
{
if(d < 1 || d > 31)
return false;
else
{
day = d;
month = m;
year = y;
return true;
}
}else if( m == 11)
{
if(d < 1 || d > 30)
return false;
else
{
day = d;
month = m;
year = y;
return true;
}
}else
return false;
}
}
return false;
}
// function to return the month
int Date::GetMonth() const
{
return month;
}
// function to return the day
int Date::GetDay() const
{
return day;
}
// function to return the year
int Date::GetYear() const
{
return year;
}
// function to set the format of the date
bool Date::SetFormat(char f)
{
if(f == 'D' || f == 'T' || f == 'L')
{
format = f;
return true;
}
return false;
}
// function to increment the number of days passed to the date and update the date accordingly
void Date:: Increment(int numDays)
{
day += numDays; // add number of days passed
// loop that continues till the date is valid
while(day > days_in_month())
{
day -= days_in_month();
month++;
if(month > 12) // if month > 12, i.e it represents the first month of next year
{
// increment year and set month to 1
year++;
month = 1;
}
}
}
// function to compare the passed date with this date and return
// -1, if the calling object comes first chronologically
// 0, if the calling object comes first chronologically
// 1, if the objects are the same date
int Date::Compare(const Date& d)
{
if(year < d.year)
return -1;
else if(year > d.year)
return 1;
else
{
if(month < d.month)
return -1;
else if(month > d.month)
return 1;
else
{
if(day < d.day)
return -1;
else if(day > d.day)
return 1;
else
return 0;
}
}
}
// function to print the julian date
void Date:: printJulianDate()
{
int days=0;
// loop to get the day number
for(int i=1;i<month;i++)
{
switch(i)
{
case 1:
days += 31;
break;
case 2:
if(isLeapYear())
days += 29;
else
days += 28;
break;
case 3:
days += 31;
break;
case 4:
days += 30;
break;
case 5:
days += 31;
break;
case 6:
days += 30;
break;
case 7:
days += 31;
break;
case 8:
days += 31;
break;
case 9:
days += 30;
break;
case 10:
days += 31;
break;
case 11:
days += 30;
break;
case 12:
days += 31;
break;
}
}
days += day;
cout<<days<<"-"<<setw(4)<<setfill('0')<<year;
}
Date.h
#ifndef UNTITLED16_DATE_H
#define UNTITLED16_DATE_H
#endif //UNTITLED16_DATE_H
date.cpp
int main(){return 0;}
Since your main function is int main(){return 0;} all your code is doing is: starting up, calling main(), and then returning back to the caller. Of course there is no output involved here...
There are many other details with your code where I am not sure if it will work as you intend. But the minimum change you have to do to see anything is something like this:
#include "Date.h"
#include <iostream>
int main() {
Date theDate;
theDate.Input();
theDate.Show();
// and maybe also
Date theDate2;
theDate2.Input();
if (theDate2.Compare(theDate)) {
std::cout << "true" << std::endl;
}
return 0;
}

C++ 6.0 code ignored after compile (Date Time calculator code)

This project I'm working on is forcing me to use Visual C++-6.0 and it seems like everytime I compile this code it causes errors in not only this segment of code but elsewhere that is unrelated to this portion.
Right now I am trying to calculate an expiration date that is 15 months from the date that would be given.
I've tried researching if this is a common issue after windows updates. I know 6.0 has been unsupported and phased out but its a "requirement" for this program. I swore it was working 2 months ago and since that point about 30 patches have been deployed to my Windows 10 device.
Currently in this snippit of code the date that is passed into the code is carried through unaltered. For example: Nov-01-2019 should become Feb-01-2021
void CalculateDates(int numIndex)
{
int tDay = 0, tMonth = 0, tYear = 0, exp_Months = 15;
char sTemp1[4], sTemp2[4], sTemp3[4], sTemp4[4], sDay[4], sYear[4], *p;
p = Database[numIndexCount].sIdentifier;
strncpy(Database[numIndexCount].sPreparedBy, Database[numIndexCount].sIdentifier, 3);
Database[numIndexCount].sPreparedBy[3] = 0;
strncpy(sTemp1, p + 3, 2);
sTemp1[2] = 0;
strncpy(sTemp2, p + 5, 2);
sTemp2[2] = 0;
strncpy(sTemp3, p + 7, 2);
sTemp3[2] = 0;
strcpy(sTemp4, "20");
SetDateMonth(sTemp1);
sprintf(Database[numIndex].sPreparedDate, "%s-%s-%s%s", sTemp2, sMonth1, sTemp4, sTemp3);
tDay = atoi(sTemp2);
tMonth = atoi(sTemp1);
tYear = atoi(sTemp3);
if (tMonth <= 9) {
if (tMonth == 9) {
tMonth = 12;
tYear++;
// cout << "Is the month printing right? ";
// cout<<tMonth;
// cout << "\n";
}
else {
tMonth = (tMonth + exp_Months) % 12;
tYear++;
//cout << "Is the month printing right? ";
//cout<<tMonth;
//cout << "\n";
}
}
if (tMonth == 4 || tMonth == 6 || tMonth == 9 || tMonth == 11) {
// cout << "This is reached";
// cout << "\n";
// cout << "The day value is: ";
// cout << tDay;
// cout << "\n";
if (tDay == 31)
{
tDay = 30;
}
}
if (tDay >= 29 && tMonth == 2 && tYear % 4 == 0) {
if (tYear % 100 != 0) {
tDay = 29;
}
else if (tYear % 100 == 0 && tYear % 400 == 0) {
tDay = 29;
}
}
else if (tYear % 4 != 0 && tMonth == 2) {
tDay = 28;
}
sprintf(sTemp1, "%i", tMonth);
if (tDay < 10) sprintf(sDay, "0%i", tDay);
else sprintf(sDay, "%i", tDay);
if (tYear < 10) sprintf(sYear, "0%i", tYear);
else sprintf(sYear, "%i", tYear);
SetDateMonth(sTemp1);
sprintf(Database[numIndex].sUseByDate, "%s-%s-%s%s", sDay, sMonth1, sTemp4, sYear);
sprintf(sUseByDate, "%s-%s-%s%s", sDay, sMonth1, sTemp4, sYear);
}
End results for the above for today were Nov-01-19 but should have been Feb-01-19

spoj samer08e getting wrong answer

Here is my solution for the spoj problem:
http://www.spoj.com/problems/SAMER08E/
This is my logic:
I check if the given dates are adjacent to each other. If they are, then add the difference of the cost. Else skip.
//header files omitted
#define REP(i,n) for(int i=0; i<n; i++)
#define FOR(i,st,end) for(int i=st;i<end;i++)
int monthDates[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool isLeap( int y ){//check if year is leap
if(y%4 == 0 && y%100 != 0 || y%400 == 0)
return true;
return false;
}
bool checkAdjacent( int prev[], int curr[] ){//check if the dates are adjacent to each other
if( prev[0] == 31 && prev[1] == 12 && curr[0] == 1 && curr[1] == 1 && (curr[2] - prev[2]) == 1 )//last and first days of the year
return true;
if( prev[2] == curr[2]){//same year
if( prev[1] == curr[1]){//same month
if((curr[0]-prev[0]) == 1)//same adjacent dates
return true;
}else if( curr[1] - prev[1] == 1){//adjacent months
if( isLeap(prev[2]) && prev[1] == 2 && curr[1] == 3 && prev[0] == 29 && curr[0] == 1)//for leap year february
return true;
else if( !isLeap(prev[2]) && monthDates[prev[1]] == prev[0] && curr[0] == 1)
return true;
}
}
return false;
}
int main(){
int n;
while( scanf("%d", &n) && n){
int prev[4], curr[4], count = 0;
ll totalCost = 0;
REP(i,4)
scanf("%d", &prev[i]);
FOR( i, 1, n){
REP(j,4)
scanf("%d", &curr[j]);
if( checkAdjacent( prev, curr) ){
totalCost += curr[3] - prev[3];
count++;
}
prev[0] = curr[0];
prev[1] = curr[1];
prev[2] = curr[2];
prev[3] = curr[3];
}
printf("%d %lld\n", count, totalCost);
}
return 0;
}
The program works for the test cases, but i keep getting wrong answer. What is the error?
Since there are two people recording the measurements, it might be possible for the same day to be recorded twice, which could throw off your consumption computation.
Your program does not check the condition when the year is leap and the month is not February. Add this condition and you will get AC. I hope this helps.

How should I approach a credit card number validation algorithm?

I'm writing a program to validate credit card numbers and I have to use Luhn's Algorithm. Let me say beforehand, that I have just started to learn to program (we covered loops like last week), so there a lot of things I am unfamiliar with. I am having trouble with one of my functions that checks the arithmetic. Basically, it has to double every second digit from right to left and add everything together. But if you double a number, like 5, and you get 10, then you will have to add 1+0=1 to the total sum instead of 10. That's the part I'm stuck on. How can I put that in a program?
Sample code so far:
int
doubleEvenSum(string creditCardNumber) {
int evenSum;
int countPosition;
int doublePosition;
int length;
length = creditCardNumber.length ();
countPosition = creditCardNumber.at(length - 2);
evenSum = 0;
while(countPosition>0) {
if ((2 * countPosition) < 10) {
doublePosition = 2 * countPosition;
}
else if ((2 * countPosition) > 9) {
???
}
evenSum = evenSum + doublePosition;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/*
return the Luhn (MOD10) checksum for a sequence of digits.
-1 is returned on error (a non-digit was in the sequence
*/
int mod10( char const* s)
{
int len = strlen(s);
int sum = 0;
int dbl = 0;
while (len) {
char digit;
int val;
--len;
digit = s[len];
if (!isdigit( (unsigned char) digit)) return -1; // non digit in the sequence
val = digit - '0'; // convert character to numeric value
if (dbl) {
// double the value
val *= 2;
// if the result is double-digits, add the digits together
if (val > 9) {
val = val - 10;
val = val + 1;
}
}
dbl = !dbl; // only double value every other time
sum += val;
}
return sum % 10;
}
Here is a different algorithm. I cut/pasted from a C# example; the second link discusses a number of optimization for Luhn.
Please study this example, and please run it through the debugger to study how the code behaves as it's executing. Understanding how code actually runs (as opposed to how you think it will run when you write it) is an essential skill. IMHO....
/*
* Validate credit card with Luhn Algorithm
*
* REFERENCES:
* - http://jlcoady.net/c-sharp/credit-card-validation-in-c-sharp
* - http://orb-of-knowledge.blogspot.com/2009/08/extremely-fast-luhn-function-for-c.html
*/
#include <stdio.h> // printf(), scanf(), etc
#include <string.h> // strlen (), etc
#include <ctype.h> // isdigit(), etc
#if !defined(FALSE)
#define FALSE 0
#define TRUE ~FALSE
#endif
/*
* type definitions (should go in separate header)
*/
enum CardType {
MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7
};
/*
* function prototypes (should also go in header)
*/
int luhn (int number[], int len);
bool validate (CardType cardType, char *cardNumber);
/*
* program main
*/
int
main (int argc, char *argv[])
{
char cc_number[80];
int cc_type;
for ( ;; ) {
printf ("Enter a credit card number and type (1, 2, 3, 4, 5. 6 or 7):\n");
printf (" MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7\n");
int iret = scanf ("%s %d", cc_number, &cc_type);
if (iret == 2)
break;
else
printf ("Incorrect input: please enter a valid CC# and CC type\n");
}
if (validate ((CardType)cc_type, cc_number))
printf ("Valid\n");
else
printf ("Invalid card type/number\n");
return 0;
}
/*
* validate card#
*/
bool
validate (CardType cardType, char *cardNumber)
{
// 16 or fewer digits?
int len = strlen(cardNumber);
if (strlen (cardNumber) > 16)
return false;
// number to validate
int number[16];
for(int i = 0; i < (int)strlen (cardNumber); i++) {
if(!isdigit(cardNumber[i]))
return FALSE;
number[i] = cardNumber[i] - '0';
}
// Validate based on card type, first if tests length, second tests prefix
switch(cardType) {
case MASTERCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] == 0 || number[1] > 5)
return FALSE;
break;
case BANKCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] != 6 || number[2] > 1)
return FALSE;
break;
case VISA:
if(len != 16 && len != 13)
return FALSE;
if(number[0] != 4)
return FALSE;
break;
case AMEX:
if(len != 15)
return FALSE;
if(number[0] != 3 || (number[1] != 4 && number[1] != 7))
return FALSE;
break;
case DISCOVER:
if(len != 16)
return FALSE;
if(number[0] != 6 || number[1] != 0 || number[2] != 1 || number[3] != 1)
return FALSE;
break;
case DINERS:
if(len != 14)
return FALSE;
if(number[0] != 3 || (number[1] != 0 && number[1] != 6 && number[1] != 8) || number[1] == 0 && number[2] > 5)
return FALSE;
break;
case JCB:
if(len != 16 && len != 15)
return FALSE;
if(number[0] != 3 || number[1] != 5)
return FALSE;
break;
default:
return FALSE;
}
int sum = luhn (number, len);
return (sum % 10 == 0);
}
// Use Luhn Algorithm to validate
int luhn (int number[], int len)
{
int sum = 0;
for(int i = len - 1; i >= 0; i--)
{
if(i % 2 == len % 2)
{
int n = number[i] * 2;
sum += (n / 10) + (n % 10);
}
else
sum += number[i];
}
return sum;
}
int luhnCardValidator(char cardNumbers[]) {
int sum = 0, nxtDigit, i;
for (i = 0; cardNumbers[i] != NULL_TERMINATOR ; i++) {
nxtDigit = cardNumbers[i] - START_OF_ASCII_NUMERIC;
if (i % 2 == 0)
nxtDigit = (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : nxtDigit * 2;
sum += nxtDigit;
}
return (sum % 10);
}
This:
... (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : ...
is the clever bit. If the digit is greater than 4, then the doubling will be 10 or more. In that case, you take the doubled number and subtract 10 which will give you the ones-digit then you add 1 (the tens-digit).
Just subtract 9 from the double of the number then you will equivalent of the sum of the digits.
For ex.
7= 7*2 = 14 = 1+4 = 5 OR 14-9 = 5
This is more efficient than writing code for adding both digits.