0

I have a program that simply calculates the Ackermann function:

#include <iostream>

// Ackermann function calculations
unsigned int ackermann(unsigned int m, unsigned int n){
    if(m == 0)
        return n+1;
    if(n == 0)
        return ackermann(m-1,1);
    return ackermann(m-1,ackermann(m,n-1));
}

// Check for non-integer input
bool inputCheck(){
    if(!std::cin.fail())
        return false;

    std::cout << "Invalid input!" << std::endl;
    return true;
}

// Check for negative or overflow errors
bool numCheck(int i, char name){
    if(i < 0){
        std::cout << "Negative error!" << std::endl;
        return true;
    }

    if(name == 'm' && i > 3){
        std::cout << "Overflow error (m > 3)!" << std::endl;
        return true;
    }

    if(name == 'n' && i > 12){
        std::cout << "Overflow error (n > 12)!" << std::endl;
        return true;
    }

    return false;
}

// Run input and num checks
bool check(int x, char y){
    bool result = inputCheck() || numCheck(x, y);

    std::cin.clear();
    std::cin.ignore();

    return result;
}

int main(){

    int m, n;
    bool valM, valN;

    do{
        std::cout << "m = ";
        std::cin >> m;
        valM = check(m, 'm');
    } while(valM);

    do{
        std::cout << "n = ";
        std::cin >> n;
        valN = check(n, 'n');
    } while(valN);

    std::cout << "\nM = " << m << "\nN = " << n
            << "\n\nCALCULATING..." << std::endl;

    std::cout << "A(" << m << ',' << n << ") = " << ackermann(m,n) << std::endl;

    return 0;
}

A majority of the code is checking for invalid input. For computational reasons, m cannot be larger than 3, and n cannot be larger than 12. It also checks if the input is negative.

Known problems:

  • If the user inputs something like 3z. cin just takes the 3 and ignores the z. Obviously, 3z is different than 3, and I would like to detect such an invalid input.

  • If the user inputs something like 1.2. cin takes 1 for m and then 2 for n. The program is ignoring the period and taking it as two inputs, and I would like to detect such an invalid input.

How can I modify or fix my code so it only takes correct input?

esote
  • 831
  • 12
  • 25
  • Can you explain what you should be happening for ``3z``? What does the ``z`` represent? – nathanesau Sep 22 '16 at 22:56
  • @nathanesau The program should only accept integer inputs. When `3z` (or similar) is entered, it ignores the `z` and takes the `3` like the z doesn't exist. In some sense, I want it to detect such an invalid input (like `3z`). – esote Sep 22 '16 at 22:59

3 Answers3

0

This post may be relevant to what you're asking:

Checking input value is an integer

It shows how to check if a freshly read value from cin into an int was a valid int.

Community
  • 1
  • 1
Ian H
  • 105
  • 1
  • 9
0

I'd recommend reading in a string and converting the string to an int. Something like this would work.

#include <iostream>
#include <cctype>
#include <string>

// true is s is an int, false otherwise

bool is_number(const std::string& s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

// Ackermann function calculations
unsigned int ackermann(unsigned int m, unsigned int n) {
    if (m == 0)
        return n + 1;
    if (n == 0)
        return ackermann(m - 1, 1);
    return ackermann(m - 1, ackermann(m, n - 1));
}

// Check for non-integer input
bool inputCheck() {
    if (!std::cin.fail())
        return false;

    std::cout << "Invalid input!" << std::endl;
    return true;
}

// Check for negative or overflow errors
bool numCheck(int i, char name) {
    if (i < 0) {
        std::cout << "Negative error!" << std::endl;
        return true;
    }

    if (name == 'm' && i > 3) {
        std::cout << "Overflow error (m > 3)!" << std::endl;
        return true;
    }

    if (name == 'n' && i > 12) {
        std::cout << "Overflow error (n > 12)!" << std::endl;
        return true;
    }

    return false;
}

// Run input and num checks
bool check(int x, char y) {
    bool result = inputCheck() || numCheck(x, y);

    std::cin.clear();
    std::cin.ignore();

    return result;
}

int main() {

    std::string mstr, nstr; // parse int from string
    int m, n;
    bool valM, valN;

    std::cout << "m = ";
    std::getline(std::cin, mstr);

    if (is_number(mstr))
    {
        m = atoi(mstr.c_str()); // now we have m as an int
    }

    valM = check(m, 'm');

    std::cout << "n = ";
    std::getline(std::cin, nstr);

    if (is_number(nstr))
    {
        n = atoi(nstr.c_str()); // now we have n as an int
    }

    valN = check(n, 'n');

    std::cout << "\nM = " << m << "\nN = " << n
        << "\n\nCALCULATING..." << std::endl;

    std::cout << "A(" << m << ',' << n << ") = " << ackermann(m, n) << std::endl;

    return 0;
}
nathanesau
  • 1,681
  • 16
  • 27
0

I figured out a way to check if the input is something like 1.2.

Instead of initializing m and n as integers, I can initialize them as doubles. Then I can check if the rounded double is the same as the initial double:

double x;

if(floor(x) != x){
    // not an integer
}

Using this I can check if something like 1.2 is an integer or not. Then I can convert the double to an integer and continue on in the program.

However, I am still unable to check for invalid inputs like 3z.

esote
  • 831
  • 12
  • 25