Time duration Calculator with c++ Problems - c++

I'm currently taking a c++ college course, and I'm running into a problem that makes me feel like an idiot. We're making a time duration calculator that calculates the time after and before a certain duration, and the assignment tries to instruct us how to avoid negatives. I'm not sure what I'm doing wrong, but no matter what I do, it won't work. This is his instruction: "Also, when negative operands are used, the remainder operator is not defined the same way that the mathematical modulus operation (Euclidian Division) is defined. For those reasons, it is easier to just make sure we don't end up with negative remainders. This is easily done by adding a day (or two or three) to before when calculating the difference. Go ahead and do that."
and this is my code (all of which has followed his instructions till now)
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int run()
{
int timeHours;
int timeMinutes;
int durationHours;
int durationMinutes;
char discard; // won't keep this character
cout << "Enter current time: " << endl;
cin >> timeHours >> discard >> timeMinutes;
cout << "Enter duration: " << endl;
cin >> durationHours >> discard >> durationMinutes;
// processing section - compute the results
int timeInMin = (timeHours * 60) + timeMinutes;
int durationInMin = (durationHours * 60) + durationMinutes;
int after = timeInMin + durationInMin;
int before = timeInMin - durationInMin;
int afterHours = after / 60%12;
int afterMinutes = after % 60;
int beforeHours = (before / 60);
int beforeMinutes = (before % 60);
// output section: test data inside brackets[]
cout << setfill('0'); // only needed once
cout << endl;
cout << durationHours << ":" << setw(2) << durationMinutes << " hours after, and before, " <<
timeHours << ":" << setw(2) << timeMinutes << " is [" << afterHours << ":" << setw(2) <<
afterMinutes << ", " << beforeHours << ":" << setw(2) << beforeMinutes << "]" << endl;
return 0;
}
for example, if I plug in 2:30 as the time and 13:27 as the duration, expected [3:57, 1:03] but found [3:57, -10:-57]
I've tried adding both 24 and 1440 (number of minutes in a day) to before as well as the calculations that use the int before, but no luck. I've tried reaching out to my class a few days ago, but no one has responded.
Edit: he also says to do this in order to get rid of midnight times that look like 0:32 by doing this: Add 11 to after-hours. Find the remainder of dividing by 12. Add 1 to the result. Does he mean something like:
int afterHours = (((after / 60%12) + 11) / 12) + 1
the %12 was so that the hours wouldn't go over 12 and turn into military time

Instead of this:
// processing section - compute the results
int timeInMin = (timeHours * 60) + timeMinutes;
int durationInMin = (durationHours * 60) + durationMinutes;
int after = timeInMin + durationInMin;
int before = timeInMin - durationInMin;
int afterHours = after / 60%12;
int afterMinutes = after % 60;
int beforeHours = (before / 60);
int beforeMinutes = (before % 60);
This:
int timeInMin = (timeHours * 60) + timeMinutes;
int durationInMin = (durationHours * 60) + durationMinutes;
int after = timeInMin + durationInMin;
int before = (timeInMin % 720) + 720 - durationInMin; // 720 is 12 hours in minutes
int afterHours = (after / 60) % 12;
int afterMinutes = (after - (afterHours * 60)) % 60;
afterHours = afterHours + 12 * (afterHours == 0);
int beforeHours = (before / 60) % 12;
int beforeMinutes = (before - (beforeHours * 60)) % 60;
beforeHours = beforeHours + 12 * (beforeHours == 0);

The trick is to get an integer into the range [1,12] using only +, - and %.
Let's start with the negative numbers:
t = 8;
d = 11;
b = t-d; // -3
So we add 12:
b = t-d + 12; // 9
Ah, but what if the interval is bigger?
d = 100;
b = t-d + 12; // -80
This is why your teacher talked about adding "a day or two or three". But how to know how many? No need, we have modulo:
d = 100;
d = d%12; // 4
b = t-d + 12; // 16
Now we're positive, but we're getting numbers greater than 12. No problem, we use modulo again:
d = 100;
d = d%12; // 4
b = (t-d + 12)%12; // 4
a = (t+d)%12; // 0
Ah, now we're getting [0,11], but we want [1,12]. So we use the trick (x-1)%m +1:
d = 100;
d = d%12; // 4
b = (t-d + 12 - 1)%12 + 1; // 4
a = (t+d - 1)%12 + 1; // 12
There we have it. We still have to deal with minutes (the same way) and with a smart Alec user who enters negative numbers, but it should be clear how to do that and this post is getting long.

Related

How do I output two zeros for converting Military Time to standard time?

I'm trying to make a program to convert military time to standard time, am just having a problem outputting two zeroes for times such as 1300/1:00pm, it outputs as 1:0pm
int mtime, mins, hrs;
cout<<"Military to Standard Time"<<endl<<"Enter time: ";
cin>>mtime;
if (mtime >= 0 && mtime <= 2400)
{
if (mtime >= 1200)
{
mtime = mtime - 1200;
hrs = mtime / 100;
mins = mtime % 100;
cout<<hrs<<":"<<mins<<" P.M.";
}
else
hrs = mtime / 100;
mins = mtime % 100;
cout<<hrs<<":"<<mins<<" A.M.";
}
else
cout<<"Error, Please Enter Military Time 0000-2400"<<endl;
First, the data is wrong.
Second, if you want to cout 03 rather than 3, you can use
/*
*setw(2):The out put data with is 2 position
*setfill('0'):If the data is not enough 2 position, such 3 is only 1 position,
* so will fill the output data by zero
*/
cout<<setfill('0')<<setw(2)<<mins;
One solution is to conditionally print a 0 if the minutes is less than 10:
#include <iostream>
int main()
{
int hrs = 1;
int mins = 3;
std::cout << hrs << ":" << (mins<10?"0":"") << mins << " A.M.\n";
mins = 15;
std::cout << hrs << ":" << (mins<10?"0":"") << mins << " A.M.\n";
}
Output:
1:03 A.M.
1:15 A.M.
Add curly braces to both the else blocks. Kindly avoid such basic Syntax errors.
else {
hrs = mtime / 100;
mins = mtime % 100;
cout<<hrs<<":"<<mins<<" A.M.";
}
else {
cout<<"Error, Please Enter Military Time 0000-2400<<endl;"
}

How do I fix the error "Floating point exception (core dumped)"?

I am receiving an error that says "core dumped" when running my program. I'm a beginner, and I'm not sure how to fix it. It prints out correctly up until part 1-4
int main() {
string unshuffledDeck = "AAAA222233334444555566667777888899990000JJJJQQQQKKKK";
string shuffledDeck = "";
srand(time(0));
for ( ; unshuffledDeck.length() != 0 ; ){
// (1-2a) Generate a random number between 0 and the current unshuffled deck size
minus 1 to select the card we are going to move
int randomIndex = rand() % (unshuffledDeck.length() - 1);
shuffledDeck = shuffledDeck + unshuffledDeck[randomIndex];
unshuffledDeck.erase(randomIndex, 1);
} // end for
string playerHand = "";
string dealerHand = "";
// (1-4b) Deal the cards by moving them from the deck to the player and dealer hands
do {
playerHand += shuffledDeck[0];
shuffledDeck.erase(0,1);
} while((playerHand.length() - 1) < 2);
do {
dealerHand += shuffledDeck[0];
shuffledDeck.erase(0,1);
} while((dealerHand.length() - 1) < 2);
// (1-4c) Print out the deck and hands to verify cards moved in the appropriate order
cout << shuffledDeck << endl;
cout << "player: " << playerHand << endl;
cout << "dealer: " << dealerHand << endl;
}
int randomIndex = rand() % (unshuffledDeck.length() - 1); this cuses this core dump when unshuffledDeck.length() equals to 1 division by zero is hapening. So you should cange it to int randomIndex = rand() % unshuffledDeck.length(); because modulo operator a % b returns value from -b exclusive to b exclusive e.g. (-b,b) in your case all numbers are positive so it returns value from zero inclusive to b exclusive e.g. [0,b)

Add a number to itself in C++

Which is the simplest way to add a number to itself incrementally until some condition is reached? In the code bellow, we can calculate when an event will occur by simply adding event_occurence to itself until we reach max_events. I know it can be done with std::IOTA and vectors, but I want it to keep it to the simplest math possible.
My idea was to use: i=1, i * number to be multiplied, for i<=some value, i++. But only the first value gets incremented correctly.
int main()
{
int curent_year = 2021;
int input_year;
int event_occurence = 4;
std::cout << "When did you watch your first World Cup?" << std::endl;
std::cin >> input_year;
int max_events = (curent_year - input_year) / event_occurence;
int last_event = input_year + (max_events * event_occurence);
int next_first_event = input_year + event_occurence;
std::cout << "Next world cup was held in " << next_first_event << "... Meanwhile, another " << max_events << " world cups took place. The last world cup took place in " << last_event <<"." << std::endl;
int i=1;
int inbetween_events = input_year + i * event_occurence;
for (int i = 1; i <= max_events; i++)
std::cout << "The were also these worlds cups held in the following years: " <<inbetween_events <<std::endl;
}
code above compiled
int i=1;
int inbetween_events = input_year + i * event_occurence;
for (int i = 1; i <= max_events; i++)
std::cout << "The were also these worlds cups held in the following years: " <<inbetween_events <<std::endl;
}
Problem 1:
You're using a local variable (counted in CPU registers) with the same name function variable that is the parent of function for (...). You declare it in there by saying "int i = 1", what means "make new temp variable name i, value = 1)
Move the "calc"
int inbetween_events = input_year + i * event_occurence;
inside the function if you want to print out series of numbers (print inbetween_events = input_year + i * event_occurence;) , or make it
for (; i <= max_events; i++)
or
for (i = 1; i <= max_events; i++)
That could work, but I can't test it :P
You could change variables' names, but then it's still pretty ineffective, because you would increment one variable inside a loop, making 2 operations instead of one.
Problem 2:
You also don't increment the "inbetween_events" in the "for" loop.
You ask it to print out that variable "i" times. You initialized that variable as output of arithmetic operation, it wont change its value unless you order it to change it.
C++ doesn't store instructions and run them later when needed. It runs them right away. So, if you want to compute the in-between events at multiple dates, you need to code it this way:
for (int i = 1; i <= max_events; i++)
// compute inbetween_events for each value of i
int inbetween_events = input_year + i * event_occurence;
std::cout << "The were also these worlds cups held in the following years: " <<inbetween_events <<std::endl;
}
You'll probably want to fix the output with something like:
// output header first
std::cout << "The were also these worlds cups held in the following years: ";
for (int i = 1; i <= max_events; i++)
// compute inbetween_events for each value of i
int inbetween_events = input_year + i * event_occurence;
// output each year with a comma and space
std::cout << inbetween_events << ", ";
}
// end the line
std::cout << std::endl;

Convert milliseconds to hours:minutes:seconds:milliseconds in C++

I'm looking for a way to print out milliseconds in this format using C++:
cout << hours << " Hours : " << minutes << " Minutes : " << seconds << " Seconds : " << milliseconds << " Milliseconds" << endl;
I know there are a ton of duplicate questions about this. But none of them really handle how to get the remainder in milliseconds. There are a few that do this using Java, but I want a solution in C++.
Edit:
I wanted to clarify the question. I'm looking to take a time value that I get for the time it takes a program to run and print out that time in a legible format for the user. Getting the standard hr:min:sec was straight forward. But including any remaining milliseconds was tripping me up.
std::string format_duration( std::chrono::milliseconds ms ) {
using namespace std::chrono;
auto secs = duration_cast<seconds>(ms);
ms -= duration_cast<milliseconds>(secs);
auto mins = duration_cast<minutes>(secs);
secs -= duration_cast<seconds>(mins);
auto hour = duration_cast<hours>(mins);
mins -= duration_cast<minutes>(hour);
std::stringstream ss;
ss << hour.count() << " Hours : " << mins.count() << " Minutes : " << secs.count() << " Seconds : " << ms.count() << " Milliseconds";
return ss.str();
}
live example.
Extending this to days/years/etc should be easy (there isn't a predefined std::chrono duration type for days/years/etc prior to c++20 however).
But I can do better.
template<class Duration>
struct split_duration {
Duration d;
std::chrono::milliseconds leftover;
split_duration( std::chrono::milliseconds ms ):
d( std::chrono::duration_cast<Duration>(ms) ),
leftover( ms - std::chrono::duration_cast<std::chrono::milliseconds>(d) )
{}
};
template<class...Durations>
std::tuple<Durations...> durations( std::chrono::milliseconds ms ) {
std::tuple<std::optional<split_duration<Durations>>...> tmp;
( (void)(
(void)std::get<std::optional<split_duration<Durations>>>(tmp).emplace( ms ),
ms = std::get<std::optional<split_duration<Durations>>>(tmp)->leftover
), ...
);
return std::make_tuple( std::get<std::optional<split_duration<Durations>>>( tmp )->d... );
}
template<class T>
struct tag_t {};
template<class T>
constexpr tag_t<T> tag = {};
inline std::string duration_name( tag_t<std::chrono::milliseconds> ) { return "ms"; }
inline std::string duration_name( tag_t<std::chrono::seconds> ) { return "Seconds"; }
inline std::string duration_name( tag_t<std::chrono::minutes> ) { return "Minutes"; }
inline std::string duration_name( tag_t<std::chrono::hours> ) { return "Hours"; }
// inline std::string duration_name( tag_t<std::chrono::days> ) { return "Days"; }
// inline std::string duration_name( tag_t<std::chrono::years> ) { return "Years"; }
template<class...Durations>
std::string format_duration( std::chrono::milliseconds ms ) {
auto split = durations<Durations...>(ms);
std::stringstream ss;
(
(void)( ss << duration_name(tag<Durations>) << ": " << std::get<Durations>(split).count() << " " ), ...
);
return ss.str();
}
Days/Years requires c++20, everything else is c++17.
You just call format_durations<Durations...>( some_ms ) and out comes a formatted string based off the Durations.... You do have to do it from most-to-least significant.
durations<Durations...> gives you a tuple breakdown of the time that has to be most-to-least; you could then reorder that before formatting if you chose.
Duplicate duration types leads to compile time errors, as std::get dies a horrible ambiguous death.
Live example.
Maybe you're looking for something like this:
#include <iostream>
using namespace std;
int main() {
//Value chosen to be 1 hour, 1 minute, 1 second, and 1 millisecond
long milli = 3661001;
//3600000 milliseconds in an hour
long hr = milli / 3600000;
milli = milli - 3600000 * hr;
//60000 milliseconds in a minute
long min = milli / 60000;
milli = milli - 60000 * min;
//1000 milliseconds in a second
long sec = milli / 1000;
milli = milli - 1000 * sec;
cout << hr << " hours and " << min << " minutes and " << sec << " seconds and " << milli << " milliseconds." << endl;
}
int milliseconds = ...;
int seconds = milliseconds / 1000;
milliseconds %= 1000;
int minutes = seconds / 60;
seconds %= 60;
int hours = minutes / 60;
minutes %= 60;
cout << hours << " Hours : " << minutes << " Minutes : " << seconds << " Seconds : " << milliseconds << " Milliseconds" << endl;
Not exactly what you're looking for, but if you're only accessing the current time, this will work:
#include <chrono>
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch());
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ms);
ms -= seconds;
You can then add ms.count() to your cout, even if it isn't the actual remainder of the time you originally look at.
Edit: This method should be faster than using a modulus.
// Online IDE - Code Editor, Compiler, Interpreter
#include <stdio.h>
#include <stdint.h>
uint32_t DAYS_IN_MILLISECONDS = 86400000;
uint32_t HOURS_IN_MILLISECONDS = 3600000;
uint16_t MINUTES_IN_MILLISECONDS = 60000;
uint16_t SECONDS_IN_MILLISECONDS = 1000;
int main()
{
uint32_t total_milliseconds = 23*60*60000 + 100 + 1000;
uint8_t days = total_milliseconds / DAYS_IN_MILLISECONDS;
uint8_t hours = (total_milliseconds - days*DAYS_IN_MILLISECONDS) / HOURS_IN_MILLISECONDS;
uint8_t minutes = (total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS) / MINUTES_IN_MILLISECONDS;
uint8_t seconds = (total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS - minutes*MINUTES_IN_MILLISECONDS) / SECONDS_IN_MILLISECONDS;
uint8_t milliseconds = total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS - minutes*MINUTES_IN_MILLISECONDS - seconds*SECONDS_IN_MILLISECONDS;
printf("%i:days %i:hours %i:minutes %i:seconds %i:milliseconds", days, hours, minutes, seconds, milliseconds);
return 0;
}
#ifndef DATETIME_H_
#define DATETIME_H_
/* Useful Constants */
#define SECS_PER_MIN (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY (SECS_PER_HOUR * 24L)
#define DAYS_PER_WEEK (7L)
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
#define SECS_PER_YEAR (SECS_PER_WEEK * 52L)
#define SECS_YR_2000 (946681200UL)
/* Useful Macros for getting elapsed time */
/** Get just seconds part of given Unix time */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
/** Get just minutes part of given Unix time */
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
/** Get just hours part of given Unix time */
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
/** Get day of week from given Unix time */
#define dayOfWeek(_time_) (( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK) // 0 = Sunday
/** Get elapsed days since 1970-01-01 from given Unix time */
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970
/** Get quantity of seconds since midnight from given Unix time */
#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight
/** Get Unix time of midnight at start of day from given Unix time */
#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day
/** Get Unix time of midnight at end of day from given just Unix time */
#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day
/** Get quantity of seconds since midnight at start of previous Sunday from given Unix time */
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + (dayOfWeek(_time_) * SECS_PER_DAY) )
#endif /* DATETIME_H_ */
Sample Code :
unsigned long long s = 1 * 10 ;
unsigned long long m = 1 * 60 * 20;
unsigned long long h = 1 * 60 * 60 * 3;
unsigned long long d = 1 * 60 * 60 * 24 * 60;
unsigned long long M = 1 * 60 * 60 * 24 * 30 * 5;
unsigned long long y = 1 * 60 * 60 * 24 * 30 * 12 * 6;
//unsigned long long timeInSec = s + m + h + d + M + y;
unsigned long long timeInSec = s + m + h + d;
long long seconds = numberOfSeconds(timeInSec);
long long minutes = numberOfMinutes(timeInSec);
long long hours = numberOfHours(timeInSec);
long long day = dayOfWeek(timeInSec);
long long _elapsedDays = elapsedDays(timeInSec);
long long _elapsedSecsToday = elapsedSecsToday(timeInSec);
Not that I do not find interesting the other solutions, and it is my humble monkey way of working... always very near of the assembly code ... in the previous solutions, there is way too many variables created to achieve the goal.. in my exemple, only 2 variables are created, a string: result, an int8_t: n, plus a parameter in the function declaration, so the milliseconds are passed to the function using a INT: value
#include <string>
using namespace std;
// milliseconds to DDD HH:MM:SS.mmm , days are displayed if > 0
string ToDDHHMMSSmmm(int value)
{
string result=""; uint8_t n=value/86400000;
if (n>0) {result=to_string(n)+' ';}
value-=86400000*n; n=value/3600000; if(n<10) result+='0';
result+=to_string(n); value-=3600000*n;
n=value/60000; result+=':'; if(n<10) result+='0';
result+=to_string(n); value-=60000*n;
n=value/1000; result+=':'; if(n<10) result+='0';
result+=to_string(n); value-=1000*n;
result+='.'; if(value<100) result+='0';
if(value<10) result+='0';
result+=to_string(value);
return result;
}
1- a string result is created empty
2- a byte (8 bit int) is created(n) as the milliseconds passed to the
int parameter named value is divided by 86400000 (representing
the quantity of millisec per day)
3- if n is greater than 0, the numbers of days(max 255 days !) is added
to the string result.
4- using the same variables, n(the previously calculated days) will be
multiplied by the same number, and the result is subtracted from the
variable value. now n is set to the value divided by 3600000.
5- if n<10, we have only one digit for the hours, so add a char '0' to
the string result.
6- and convert + add to the string the value of n.
7- same principle for the minutes, the seconds, and the last part
the 3 digit milliseconds.
8- the string is built as the calculation are done, and the return
string is always in the perfect format (DDD) HH:MM:SS.mmm
The bytes used are as follow int32 for the value 4
int8 for the work 1
String 13 to 16 max (if days > 0)
...for a total of 21 Bytes, the large numbers are never stored in variables, they remain in the code and are calculated in the register of the cpu or mcu only. To be even nearer of ASSEMBLY, I should not used std::string and std::to_string, instead, pointers and using 0x20 for spaces, 0x3a for semi colons, and adding 0x30 to any digit values to create the ASCII directly in memory.
Two types of output
#include <iostream>
using namespace std;
int main() {
//Value chosen to be 1 hour, 1 minute, 1 second, and 1 millisecond
long milli = 3661001;
// hours
int hr = (milli / (1000 * 60 * 60)) % 24;
// minutes
int min = (milli / (1000 * 60)) % 60;
// seconds
int sec = (milli / 1000) % 60;
// milliseconds
int mill = milli % 1000;
char msg[10];
sprintf(
msg,
"%02d hours and %02d minutes and %02d seconds and %02d milliseconds.\n",
hr,
min,
sec,
mill
);
printf(msg);
cout << hr << " hours and " << min << " minutes and " << sec << " seconds and " << mill << " milliseconds." << endl;
}

Using CheckSum with C++ for 13 Digit ISBN

I am trying to calculate the final digit of a 13 digit ISBN using the first 12 digits using C++. I feel like my code should be correct but I have a feeling the formula I'm using may be wrong.
The formula is:
10 - (d0 + d1 * 3 + d2 + d3 * 3 + d4 + d5 * 3 + d6 + d7 * 3 + d8 + d9 * 3 + d10 + d11 * 3) % 10
Here's what I have:
#include <cstring>
#include <iostream>
int main() {
int weightedSum = 0;
int checksum = 0;
int i; //for loop decrement
int mul = 3;
const int LENGTH = 12;
char ISBNinput[LENGTH];
std::cout << "Enter first 12 digits of ISBN: "; //ask user for input
std::cin >> ISBNinput; //stores input into ISBNinput
std::cout << std::endl;
for (i = 0; i < strlen(ISBNinput); i++) {
weightedSum += (ISBNinput[i] % 12) * mul;
if (mul == 3) {
mul = 1;
} else {
mul = 3;
}
}//close for loop
checksum = weightedSum % 10; //calculates checksum from weightedSum
std::cout << checksum << std::endl; //prints checksum with new line for format
return 0;
}
For example:
978007063546 should return 3
and
978032133487 should return 9
Thank you for any help.
Here's how I go about this.
First, let's decide how we're going to test this. I'll assume that we've written the function, and that it gives the correct output. So I pick up a couple of books off my desk, and test that it works for them:
#include <iostream>
int main()
{
std::cout << "Book 1 - expect 3, got " << checksum("978032114653") << std::endl;
std::cout << "Book 2 - expect 0, got " << checksum("978020163361") << std::endl;
}
Of course, when we try to compile that, we get an error. So create the function, before main():
char checksum(const char *s)
{
return '1';
}
Now it compiles, but the result is always 1, but now we can start to fill in the body. Let's start with some smaller examples, that we can calculate by hand; add these at the beginning of main():
std::cout << "1 digit - expect 4, got " << checksum("6") << std::endl;
Now let's get this one working - this gives us conversion from character to digit and back, at least:
char checksum(const char *s)
{
int digit = *s - '0';
return '0' + 10 - digit;
}
Let's try 2 digits:
std::cout << "1 digit - expect 6, got " << checksum("11") << std::endl;
And now our test fails again. So add some more processing, to make this pass (and not break the single-digit test):
char checksum(const char *s)
{
int sum = 0;
int digit = *s - '0';
sum += digit;
++s;
if (*s) {
digit = *s - '0';
sum += 3 * digit;
}
return '0' + (10 - sum)%10;
}
We're probably ready to make this into a loop now. Once that's passed, we no longer need the short tests, and I have:
#include <iostream>
char checksum(const char *s)
{
int sum = 0;
for (int mul = 1; *s; ++s) {
int digit = *s - '0';
sum += mul * digit;
mul = 4 - mul;
}
return '0' + (1000 - sum)%10;
}
int test(const char *name, char expected, const char *input)
{
char actual = checksum(input);
if (actual == expected) {
std::cout << "PASS: " << name << ": "
<< input << " => " << actual
<< std::endl;
return 0;
} else {
std::cout << "FAIL: " << name << ": "
<< input << " => " << actual
<< " - expected " << expected
<< std::endl;
return 1;
}
}
int main()
{
int failures = 0;
failures += test("Book 1", '3', "978032114653");
failures += test("Book 2", '0', "978020163361");
return failures > 0;
}
I factored out the actual checking into a function here, so we can keep count of failures, and exit with the appropriate status, but everything else is as I described above.
You'll want to add a few more test cases - in particular, make sure the function correctly returns the extreme values 0 and 9 when it should.
There is one clear bug in your code: you are not allocating enough space in for ISBNinput. You should make it one character longer:
const int LENGTH = 13;
The reason for this is that that character-array strings are terminated with an extra null character. You might be lucky and the next byte in memory could sometimes happen to be a null byte, in which case the program would still work sometimes.
If you run the program with valgrind or a similar memory checker you are likely to see an error as the program access memory beyond what was allocated on the stack.
Also I think there is another bug. I think that mul should be initialized to 1.
By the way, this code is very fragile, depending on you entering no more than 12 characters, all of which are assumed to be digits. It might be OK as a quick hack for a proof-of-concept, but should not be used in any real program.