Skip to content

Instantly share code, notes, and snippets.

@maxdeliso
Last active December 15, 2015 03:59
Show Gist options
  • Select an option

  • Save maxdeliso/5198856 to your computer and use it in GitHub Desktop.

Select an option

Save maxdeliso/5198856 to your computer and use it in GitHub Desktop.
non-negative integer recognizer in C++
/*
* A practical implementation of a 'bulletproof' non-negative integer
* recognizer with overflow detection. Results are written to stdout,
* and diagnostics are written to stderr. Using redirection, you can
* easily retrieve just the recognized values separated by newlines
* like this: nnIntRecognizer <testInput >testOutput
*
* some edge cases ferreted in cooperating with Jared
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cctype>
#include <cassert>
#include <cmath>
int ASCII2Int(const char ch);
int computeSum(std::vector<int> const & digits);
int tenPow(int p);
int main() {
/* mutable state */
std::vector<int> currentDigits;
char thisChar;
/* input loop */
while(std::cin >> thisChar) {
const bool inNumber = currentDigits.size() > 0;
if(isdigit(thisChar)) {
const int thisDigit = ASCII2Int(thisChar);
if(inNumber) {
/* in number, got another digit => continuation of number */
const int currentSum = computeSum(currentDigits);
std::cerr << "\ncontinuation of number...\n"
<< "\n running total before this number: "
<< currentSum << std::endl;
/* append digit to vector */
currentDigits.push_back(thisDigit);
const int nextSum = computeSum(currentDigits);
/* check to see if the next digit causes an overflow */
if(nextSum < 0) {
currentDigits.pop_back();
std::cout << currentSum << std::endl;
std::cerr << "\noverflow! starting new number\n";
/* digit that caused overflow => the first digit in the next number */
currentDigits.clear();
currentDigits.push_back(thisDigit);
} else {
std::cerr << "\n running total after this number: "
<< nextSum << std::endl;
}
} else {
/* not in number, got a digit => start of number */
std::cerr << "\nstart of number...\n";
currentDigits.push_back(thisDigit);
}
} else {
if(inNumber) {
/* in number, got non-digit => end of number*/
const int finalSum = computeSum(currentDigits);
std::cout << finalSum << std::endl;
std::cerr << "\nend of number...\n";
currentDigits.clear();
} else {
/* not in number, got a non-digit => ignore it */
std::cerr << "\nignoring non-consecutive non-digits...\n";
}
}
}
std::cerr << "\ngot EOF, preparing to exit\n";
/* there may still be digits when the EOF is encountered, so handle these */
if(currentDigits.size() > 0) {
std::cerr << "\nprocessing remaining digits at EOF\n";
const int finalSum = computeSum(currentDigits);
std::cout << finalSum << std::endl;
}
return 0;
}
int ASCII2Int(const char ch) {
assert(isdigit(ch));
int n = ch - '0';
assert(n >= 0 && n <= 9);
return n;
}
int computeSum(std::vector<int> const & digits) {
static const int maxP = floor(log10(INT_MAX));
static const int maxTenPow = tenPow(maxP);
static const int maxLeadDigit = floor(INT_MAX / maxTenPow);
int tensPos = 0;
int sum = 0;
/* remove leading zeroes from digits vector and store the result in
* processed digits */
unsigned int digitsToIgnore = 0;
while(digitsToIgnore < digits.size() && digits[digitsToIgnore] == 0) {
++digitsToIgnore;
}
std::vector<int> processedDigits(digits.begin() + digitsToIgnore,
digits.end());
/* counting from ones place to the most significant place (right to left) */
for(std::vector<int>::const_reverse_iterator cri = processedDigits.rbegin();
cri != processedDigits.rend();
++cri) {
const int currentTenMult = tenPow(tensPos);
if(currentTenMult < 0) {
return -1;
}
/* check for edge case where multiplier can be represented but the
* product can not */
if( tensPos == maxP && (*cri) > maxLeadDigit ) {
return -1;
}
const int increment = (*cri) * currentTenMult;
/* we don't handle negative signs in this program, so this is easier;
* we can just check to see if our sum is less than 0. if it is return
* -1 to signal overflow */
if(sum + increment < 0) {
return -1;
}
sum += increment;
++tensPos;
}
return sum;
}
int tenPow(int p) {
static const int maxP = floor(log10(INT_MAX));
assert( p >= 0);
if( p > maxP) {
return -1;
}
int result = 1;
for (int j = 1; j <= p; ++j) {
result *= 10;
}
return result;
}
@maxdeliso
Copy link
Copy Markdown
Author

in>

0000000000000000000000000000000,
00000000000000000000000000010,
9999999999999999999999999999999999999999999,
123,
321,
0,
1,
0,
010,
100,
010,
001

out>

0
10
999999999
999999999
999999999
999999999
9999999
123
321
0
1
0
10
100
10
1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment