Computing the Ackermann Function The Next CEO of Stack OverflowComputing the distribution of a Jonckheere-Terpstra statisticGeneric absolute value functionHaskell Ackermann functionComputing the n-th primeComputing the de Bruijn sequenceIterative implementation of the Ackermann functionComputing the Mean Average PrecisionComputing the improper integral of several functionsComputing the gradient of a functionComputing function time in C++

Math-accent symbol over parentheses enclosing accented symbol (amsmath)

Why do airplanes bank sharply to the right after air-to-air refueling?

Why don't programming languages automatically manage the synchronous/asynchronous problem?

How to avoid supervisors with prejudiced views?

Is it possible to replace duplicates of a character with one character using tr

Prepend last line of stdin to entire stdin

Is it okay to majorly distort historical facts while writing a fiction story?

Why is the US ranked as #45 in Press Freedom ratings, despite its extremely permissive free speech laws?

Recycling old answers

If Nick Fury and Coulson already knew about aliens (Kree and Skrull) why did they wait until Thor's appearance to start making weapons?

RigExpert AA-35 - Interpreting The Information

Domestic-to-international connection at Orlando (MCO)

Newlines in BSD sed vs gsed

Is it professional to write unrelated content in an almost-empty email?

WOW air has ceased operation, can I get my tickets refunded?

How to sed chunks text from a stream of files from find

Why doesn't UK go for the same deal Japan has with EU to resolve Brexit?

Is there a way to save my career from absolute disaster?

Why, when going from special to general relativity, do we just replace partial derivatives with covariant derivatives?

Need help understanding a power circuit (caps and diodes)

Rotate a column

Writing differences on a blackboard

How to get from Geneva Airport to Metabief?

The exact meaning of 'Mom made me a sandwich'



Computing the Ackermann Function



The Next CEO of Stack OverflowComputing the distribution of a Jonckheere-Terpstra statisticGeneric absolute value functionHaskell Ackermann functionComputing the n-th primeComputing the de Bruijn sequenceIterative implementation of the Ackermann functionComputing the Mean Average PrecisionComputing the improper integral of several functionsComputing the gradient of a functionComputing function time in C++










3












$begingroup$


How can I improve this code? It computes the Ackermann function as long as m<4 and n<13.



#include <iostream>
#include <limits>

// 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)

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
<< "nnCALCULATING..." << std::endl;

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

return 0;



A majority of the code is for detecting errors (such as invalid or negative input) and for preventing overflow errors (such as Ackermann(4,2)). A minority of the code actually calculates the Ackermann function.










share|improve this question









$endgroup$
















    3












    $begingroup$


    How can I improve this code? It computes the Ackermann function as long as m<4 and n<13.



    #include <iostream>
    #include <limits>

    // 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)

    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
    << "nnCALCULATING..." << std::endl;

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

    return 0;



    A majority of the code is for detecting errors (such as invalid or negative input) and for preventing overflow errors (such as Ackermann(4,2)). A minority of the code actually calculates the Ackermann function.










    share|improve this question









    $endgroup$














      3












      3








      3


      1



      $begingroup$


      How can I improve this code? It computes the Ackermann function as long as m<4 and n<13.



      #include <iostream>
      #include <limits>

      // 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)

      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
      << "nnCALCULATING..." << std::endl;

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

      return 0;



      A majority of the code is for detecting errors (such as invalid or negative input) and for preventing overflow errors (such as Ackermann(4,2)). A minority of the code actually calculates the Ackermann function.










      share|improve this question









      $endgroup$




      How can I improve this code? It computes the Ackermann function as long as m<4 and n<13.



      #include <iostream>
      #include <limits>

      // 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)

      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
      << "nnCALCULATING..." << std::endl;

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

      return 0;



      A majority of the code is for detecting errors (such as invalid or negative input) and for preventing overflow errors (such as Ackermann(4,2)). A minority of the code actually calculates the Ackermann function.







      c++ performance c++14






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Sep 24 '16 at 3:26









      esoteesote

      2,89611038




      2,89611038




















          2 Answers
          2






          active

          oldest

          votes


















          2












          $begingroup$

          bool inputCheck()
          if(!std::cin.fail())
          return false;

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



          Carefully name your functions with a meaningful name. inputCheck doesn't really tell anyone what to expect as a result.



          Prefer to distinguish language constructs with spaces.



          You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().



          Prefer to avoid std::endl. Be aware of what the manipulator std::endl actually does. Stream 'n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.



          bool isInvalidInput() 
          if (std::cin)
          return false;

          std::cout << "Invalid input!n";
          return true;




          bool numCheck(int i, char name)
          if(i < 0) /* ... */
          if(name == 'm' && i > 3) /* ... */
          if(name == 'n' && i > 12) /* ... */
          return false;



          Specify const for immutable variables. const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.



          Prefer enumerations to represent sets of related named constants.



          Avoid magic constants as they are difficult to understand and may be overlooked. Prefer symbolic constants to give values contextual meaning.




          bool check(int x, char y) numCheck(x, y);
          std::cin.clear();
          std::cin.ignore();
          return result;



          Do you really want to ignore the remaining buffer on success?




          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));



          The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach. If you really care for performance, calculate Ackerman values in constant time using the formula's for $A(m,n)$.



          $$
          A(0,n) = n + 1\
          A(1,n) = n + 2\
          A(2,n) = 2n + 3\
          A(3,n) = 2^(n+3) - 3\
          A(4,0) = 13\
          A(4,1) = A(5,0) = 65533
          $$




          Contractually enforce your preconditions by testing them in the function that requires them.



          namespace impl 
          unsigned Ackermann(unsigned m, unsigned n)
          // calculate A(m,n)

          void check_overflow_bounds(unsigned m, unsigned n)
          if (m > 3

          unsigned Ackermann(unsigned m, unsigned n)
          impl::check_overflow_bounds(m, n);
          return impl::Ackermann(m, n);



          If your return type is an unsigned int, will Ackermann values overflow if $m < 4$ and $n = 13$? Are there Ackermann values that don't overflow when $m = 4$ or $m = 5$? Consider what actually is computable and throw an overflow exception for values that are not computable.






          share|improve this answer











          $endgroup$












          • $begingroup$
            I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
            $endgroup$
            – esote
            Sep 24 '16 at 15:21










          • $begingroup$
            Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
            $endgroup$
            – user1118321
            Sep 24 '16 at 17:33











          • $begingroup$
            Expanded on both your concerns in the edit.
            $endgroup$
            – Snowhawk
            Sep 24 '16 at 18:11


















          0












          $begingroup$

          One way to improve is to use a database of lookup values to avoid repeated function calls. For example if your function calls ackermann(1,1) many times, retrieving from a database will prevent your program from naïvely opening unnecessary stack frames.



          (Note: I don’t know C++ so my answer is in JavaScript.)



          /** Database: a two-dimensional array of numbers */
          const db = []

          /** Set a value to an entry in the database. */
          db.set = function (m, n, value)

          /** Retrieve a value from the database. */
          db.get = function (m, n)
          // if row is an array and cell is a number, return that; else throw error
          if (this[m] instanceof Array && typeof this[m][n] === 'number')
          return this[m][n]

          throw new ReferenceError('No entry found.')


          /** The Ackermann Function */
          function ack(m, n) !Number.isFinite(m + n))
          throw new RangeError('Only natural numbers allowed.')

          /** The returned result (the answer) */
          let returned;
          try
          // try to get a database entry, if it exists
          returned = db.get(m, n)
          catch (err)
          // else, do Ackermann’s algorithm
          if (m === 0)
          returned = n + 1
          else if (n === 0)
          returned = ack(m - 1, 1)
          else
          returned = ack(m - 1, ack(m, n - 1))

          // make a new database entry for the result
          db.set(m, n, returned)

          return returned






          share|improve this answer









          $endgroup$













            Your Answer





            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f142304%2fcomputing-the-ackermann-function%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2












            $begingroup$

            bool inputCheck()
            if(!std::cin.fail())
            return false;

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



            Carefully name your functions with a meaningful name. inputCheck doesn't really tell anyone what to expect as a result.



            Prefer to distinguish language constructs with spaces.



            You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().



            Prefer to avoid std::endl. Be aware of what the manipulator std::endl actually does. Stream 'n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.



            bool isInvalidInput() 
            if (std::cin)
            return false;

            std::cout << "Invalid input!n";
            return true;




            bool numCheck(int i, char name)
            if(i < 0) /* ... */
            if(name == 'm' && i > 3) /* ... */
            if(name == 'n' && i > 12) /* ... */
            return false;



            Specify const for immutable variables. const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.



            Prefer enumerations to represent sets of related named constants.



            Avoid magic constants as they are difficult to understand and may be overlooked. Prefer symbolic constants to give values contextual meaning.




            bool check(int x, char y) numCheck(x, y);
            std::cin.clear();
            std::cin.ignore();
            return result;



            Do you really want to ignore the remaining buffer on success?




            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));



            The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach. If you really care for performance, calculate Ackerman values in constant time using the formula's for $A(m,n)$.



            $$
            A(0,n) = n + 1\
            A(1,n) = n + 2\
            A(2,n) = 2n + 3\
            A(3,n) = 2^(n+3) - 3\
            A(4,0) = 13\
            A(4,1) = A(5,0) = 65533
            $$




            Contractually enforce your preconditions by testing them in the function that requires them.



            namespace impl 
            unsigned Ackermann(unsigned m, unsigned n)
            // calculate A(m,n)

            void check_overflow_bounds(unsigned m, unsigned n)
            if (m > 3

            unsigned Ackermann(unsigned m, unsigned n)
            impl::check_overflow_bounds(m, n);
            return impl::Ackermann(m, n);



            If your return type is an unsigned int, will Ackermann values overflow if $m < 4$ and $n = 13$? Are there Ackermann values that don't overflow when $m = 4$ or $m = 5$? Consider what actually is computable and throw an overflow exception for values that are not computable.






            share|improve this answer











            $endgroup$












            • $begingroup$
              I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
              $endgroup$
              – esote
              Sep 24 '16 at 15:21










            • $begingroup$
              Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
              $endgroup$
              – user1118321
              Sep 24 '16 at 17:33











            • $begingroup$
              Expanded on both your concerns in the edit.
              $endgroup$
              – Snowhawk
              Sep 24 '16 at 18:11















            2












            $begingroup$

            bool inputCheck()
            if(!std::cin.fail())
            return false;

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



            Carefully name your functions with a meaningful name. inputCheck doesn't really tell anyone what to expect as a result.



            Prefer to distinguish language constructs with spaces.



            You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().



            Prefer to avoid std::endl. Be aware of what the manipulator std::endl actually does. Stream 'n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.



            bool isInvalidInput() 
            if (std::cin)
            return false;

            std::cout << "Invalid input!n";
            return true;




            bool numCheck(int i, char name)
            if(i < 0) /* ... */
            if(name == 'm' && i > 3) /* ... */
            if(name == 'n' && i > 12) /* ... */
            return false;



            Specify const for immutable variables. const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.



            Prefer enumerations to represent sets of related named constants.



            Avoid magic constants as they are difficult to understand and may be overlooked. Prefer symbolic constants to give values contextual meaning.




            bool check(int x, char y) numCheck(x, y);
            std::cin.clear();
            std::cin.ignore();
            return result;



            Do you really want to ignore the remaining buffer on success?




            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));



            The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach. If you really care for performance, calculate Ackerman values in constant time using the formula's for $A(m,n)$.



            $$
            A(0,n) = n + 1\
            A(1,n) = n + 2\
            A(2,n) = 2n + 3\
            A(3,n) = 2^(n+3) - 3\
            A(4,0) = 13\
            A(4,1) = A(5,0) = 65533
            $$




            Contractually enforce your preconditions by testing them in the function that requires them.



            namespace impl 
            unsigned Ackermann(unsigned m, unsigned n)
            // calculate A(m,n)

            void check_overflow_bounds(unsigned m, unsigned n)
            if (m > 3

            unsigned Ackermann(unsigned m, unsigned n)
            impl::check_overflow_bounds(m, n);
            return impl::Ackermann(m, n);



            If your return type is an unsigned int, will Ackermann values overflow if $m < 4$ and $n = 13$? Are there Ackermann values that don't overflow when $m = 4$ or $m = 5$? Consider what actually is computable and throw an overflow exception for values that are not computable.






            share|improve this answer











            $endgroup$












            • $begingroup$
              I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
              $endgroup$
              – esote
              Sep 24 '16 at 15:21










            • $begingroup$
              Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
              $endgroup$
              – user1118321
              Sep 24 '16 at 17:33











            • $begingroup$
              Expanded on both your concerns in the edit.
              $endgroup$
              – Snowhawk
              Sep 24 '16 at 18:11













            2












            2








            2





            $begingroup$

            bool inputCheck()
            if(!std::cin.fail())
            return false;

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



            Carefully name your functions with a meaningful name. inputCheck doesn't really tell anyone what to expect as a result.



            Prefer to distinguish language constructs with spaces.



            You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().



            Prefer to avoid std::endl. Be aware of what the manipulator std::endl actually does. Stream 'n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.



            bool isInvalidInput() 
            if (std::cin)
            return false;

            std::cout << "Invalid input!n";
            return true;




            bool numCheck(int i, char name)
            if(i < 0) /* ... */
            if(name == 'm' && i > 3) /* ... */
            if(name == 'n' && i > 12) /* ... */
            return false;



            Specify const for immutable variables. const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.



            Prefer enumerations to represent sets of related named constants.



            Avoid magic constants as they are difficult to understand and may be overlooked. Prefer symbolic constants to give values contextual meaning.




            bool check(int x, char y) numCheck(x, y);
            std::cin.clear();
            std::cin.ignore();
            return result;



            Do you really want to ignore the remaining buffer on success?




            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));



            The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach. If you really care for performance, calculate Ackerman values in constant time using the formula's for $A(m,n)$.



            $$
            A(0,n) = n + 1\
            A(1,n) = n + 2\
            A(2,n) = 2n + 3\
            A(3,n) = 2^(n+3) - 3\
            A(4,0) = 13\
            A(4,1) = A(5,0) = 65533
            $$




            Contractually enforce your preconditions by testing them in the function that requires them.



            namespace impl 
            unsigned Ackermann(unsigned m, unsigned n)
            // calculate A(m,n)

            void check_overflow_bounds(unsigned m, unsigned n)
            if (m > 3

            unsigned Ackermann(unsigned m, unsigned n)
            impl::check_overflow_bounds(m, n);
            return impl::Ackermann(m, n);



            If your return type is an unsigned int, will Ackermann values overflow if $m < 4$ and $n = 13$? Are there Ackermann values that don't overflow when $m = 4$ or $m = 5$? Consider what actually is computable and throw an overflow exception for values that are not computable.






            share|improve this answer











            $endgroup$



            bool inputCheck()
            if(!std::cin.fail())
            return false;

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



            Carefully name your functions with a meaningful name. inputCheck doesn't really tell anyone what to expect as a result.



            Prefer to distinguish language constructs with spaces.



            You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().



            Prefer to avoid std::endl. Be aware of what the manipulator std::endl actually does. Stream 'n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.



            bool isInvalidInput() 
            if (std::cin)
            return false;

            std::cout << "Invalid input!n";
            return true;




            bool numCheck(int i, char name)
            if(i < 0) /* ... */
            if(name == 'm' && i > 3) /* ... */
            if(name == 'n' && i > 12) /* ... */
            return false;



            Specify const for immutable variables. const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.



            Prefer enumerations to represent sets of related named constants.



            Avoid magic constants as they are difficult to understand and may be overlooked. Prefer symbolic constants to give values contextual meaning.




            bool check(int x, char y) numCheck(x, y);
            std::cin.clear();
            std::cin.ignore();
            return result;



            Do you really want to ignore the remaining buffer on success?




            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));



            The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach. If you really care for performance, calculate Ackerman values in constant time using the formula's for $A(m,n)$.



            $$
            A(0,n) = n + 1\
            A(1,n) = n + 2\
            A(2,n) = 2n + 3\
            A(3,n) = 2^(n+3) - 3\
            A(4,0) = 13\
            A(4,1) = A(5,0) = 65533
            $$




            Contractually enforce your preconditions by testing them in the function that requires them.



            namespace impl 
            unsigned Ackermann(unsigned m, unsigned n)
            // calculate A(m,n)

            void check_overflow_bounds(unsigned m, unsigned n)
            if (m > 3

            unsigned Ackermann(unsigned m, unsigned n)
            impl::check_overflow_bounds(m, n);
            return impl::Ackermann(m, n);



            If your return type is an unsigned int, will Ackermann values overflow if $m < 4$ and $n = 13$? Are there Ackermann values that don't overflow when $m = 4$ or $m = 5$? Consider what actually is computable and throw an overflow exception for values that are not computable.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Sep 24 '16 at 18:10

























            answered Sep 24 '16 at 6:55









            SnowhawkSnowhawk

            5,55611229




            5,55611229











            • $begingroup$
              I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
              $endgroup$
              – esote
              Sep 24 '16 at 15:21










            • $begingroup$
              Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
              $endgroup$
              – user1118321
              Sep 24 '16 at 17:33











            • $begingroup$
              Expanded on both your concerns in the edit.
              $endgroup$
              – Snowhawk
              Sep 24 '16 at 18:11
















            • $begingroup$
              I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
              $endgroup$
              – esote
              Sep 24 '16 at 15:21










            • $begingroup$
              Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
              $endgroup$
              – user1118321
              Sep 24 '16 at 17:33











            • $begingroup$
              Expanded on both your concerns in the edit.
              $endgroup$
              – Snowhawk
              Sep 24 '16 at 18:11















            $begingroup$
            I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
            $endgroup$
            – esote
            Sep 24 '16 at 15:21




            $begingroup$
            I have made most of the changes you recommended, and the code looks much nicer now. What do you mean by calculating the Ackermann values in constant time and validating preconditions?
            $endgroup$
            – esote
            Sep 24 '16 at 15:21












            $begingroup$
            Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
            $endgroup$
            – user1118321
            Sep 24 '16 at 17:33





            $begingroup$
            Since you only have (3*12)=36 possible input values, you can simply pre-calculate all the results and put them into a table. It can be a 3x12 table and you can simply look up the answer by indexing into it with m and n. Validating preconditions means ensuring that the inputs to your functions are in a valid range.
            $endgroup$
            – user1118321
            Sep 24 '16 at 17:33













            $begingroup$
            Expanded on both your concerns in the edit.
            $endgroup$
            – Snowhawk
            Sep 24 '16 at 18:11




            $begingroup$
            Expanded on both your concerns in the edit.
            $endgroup$
            – Snowhawk
            Sep 24 '16 at 18:11













            0












            $begingroup$

            One way to improve is to use a database of lookup values to avoid repeated function calls. For example if your function calls ackermann(1,1) many times, retrieving from a database will prevent your program from naïvely opening unnecessary stack frames.



            (Note: I don’t know C++ so my answer is in JavaScript.)



            /** Database: a two-dimensional array of numbers */
            const db = []

            /** Set a value to an entry in the database. */
            db.set = function (m, n, value)

            /** Retrieve a value from the database. */
            db.get = function (m, n)
            // if row is an array and cell is a number, return that; else throw error
            if (this[m] instanceof Array && typeof this[m][n] === 'number')
            return this[m][n]

            throw new ReferenceError('No entry found.')


            /** The Ackermann Function */
            function ack(m, n) !Number.isFinite(m + n))
            throw new RangeError('Only natural numbers allowed.')

            /** The returned result (the answer) */
            let returned;
            try
            // try to get a database entry, if it exists
            returned = db.get(m, n)
            catch (err)
            // else, do Ackermann’s algorithm
            if (m === 0)
            returned = n + 1
            else if (n === 0)
            returned = ack(m - 1, 1)
            else
            returned = ack(m - 1, ack(m, n - 1))

            // make a new database entry for the result
            db.set(m, n, returned)

            return returned






            share|improve this answer









            $endgroup$

















              0












              $begingroup$

              One way to improve is to use a database of lookup values to avoid repeated function calls. For example if your function calls ackermann(1,1) many times, retrieving from a database will prevent your program from naïvely opening unnecessary stack frames.



              (Note: I don’t know C++ so my answer is in JavaScript.)



              /** Database: a two-dimensional array of numbers */
              const db = []

              /** Set a value to an entry in the database. */
              db.set = function (m, n, value)

              /** Retrieve a value from the database. */
              db.get = function (m, n)
              // if row is an array and cell is a number, return that; else throw error
              if (this[m] instanceof Array && typeof this[m][n] === 'number')
              return this[m][n]

              throw new ReferenceError('No entry found.')


              /** The Ackermann Function */
              function ack(m, n) !Number.isFinite(m + n))
              throw new RangeError('Only natural numbers allowed.')

              /** The returned result (the answer) */
              let returned;
              try
              // try to get a database entry, if it exists
              returned = db.get(m, n)
              catch (err)
              // else, do Ackermann’s algorithm
              if (m === 0)
              returned = n + 1
              else if (n === 0)
              returned = ack(m - 1, 1)
              else
              returned = ack(m - 1, ack(m, n - 1))

              // make a new database entry for the result
              db.set(m, n, returned)

              return returned






              share|improve this answer









              $endgroup$















                0












                0








                0





                $begingroup$

                One way to improve is to use a database of lookup values to avoid repeated function calls. For example if your function calls ackermann(1,1) many times, retrieving from a database will prevent your program from naïvely opening unnecessary stack frames.



                (Note: I don’t know C++ so my answer is in JavaScript.)



                /** Database: a two-dimensional array of numbers */
                const db = []

                /** Set a value to an entry in the database. */
                db.set = function (m, n, value)

                /** Retrieve a value from the database. */
                db.get = function (m, n)
                // if row is an array and cell is a number, return that; else throw error
                if (this[m] instanceof Array && typeof this[m][n] === 'number')
                return this[m][n]

                throw new ReferenceError('No entry found.')


                /** The Ackermann Function */
                function ack(m, n) !Number.isFinite(m + n))
                throw new RangeError('Only natural numbers allowed.')

                /** The returned result (the answer) */
                let returned;
                try
                // try to get a database entry, if it exists
                returned = db.get(m, n)
                catch (err)
                // else, do Ackermann’s algorithm
                if (m === 0)
                returned = n + 1
                else if (n === 0)
                returned = ack(m - 1, 1)
                else
                returned = ack(m - 1, ack(m, n - 1))

                // make a new database entry for the result
                db.set(m, n, returned)

                return returned






                share|improve this answer









                $endgroup$



                One way to improve is to use a database of lookup values to avoid repeated function calls. For example if your function calls ackermann(1,1) many times, retrieving from a database will prevent your program from naïvely opening unnecessary stack frames.



                (Note: I don’t know C++ so my answer is in JavaScript.)



                /** Database: a two-dimensional array of numbers */
                const db = []

                /** Set a value to an entry in the database. */
                db.set = function (m, n, value)

                /** Retrieve a value from the database. */
                db.get = function (m, n)
                // if row is an array and cell is a number, return that; else throw error
                if (this[m] instanceof Array && typeof this[m][n] === 'number')
                return this[m][n]

                throw new ReferenceError('No entry found.')


                /** The Ackermann Function */
                function ack(m, n) !Number.isFinite(m + n))
                throw new RangeError('Only natural numbers allowed.')

                /** The returned result (the answer) */
                let returned;
                try
                // try to get a database entry, if it exists
                returned = db.get(m, n)
                catch (err)
                // else, do Ackermann’s algorithm
                if (m === 0)
                returned = n + 1
                else if (n === 0)
                returned = ack(m - 1, 1)
                else
                returned = ack(m - 1, ack(m, n - 1))

                // make a new database entry for the result
                db.set(m, n, returned)

                return returned







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 14 mins ago









                chharveychharvey

                1015




                1015



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f142304%2fcomputing-the-ackermann-function%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

                    Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

                    Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar