c++ recursion with big numbers to find mod

0

Hi while practicing recursion I found an exercise to find modulos without using the % operator. So I wrote my function and everything works fine. Except when I hit numbers with 5 digits or more this function fails. And I'm not sure whether I'm doing something wrong or it fails because there are too many calls. If there are too many calls, is it normal? Can there really be too many function calls? How can I prevent it from ever happening if in the future I have a recursion function that is actually useful? Because it doesn't make sense to me really. I did the tower of Hanoi recursion and it never has this problem, no matter how many disks I want to move.

Here's my function and the premise also that both numbers are always positive:

#include <iostream>

using namespace std;
int modulo(int n, int m) {
    if (n < m) return n;
    else return modulo(n - m, m);
}

int main()
{
    int n{ 0 }, m{ 0 };
    char check{ 'a' };
    do {
        cout << "Enter 2 positive integers to calculate their modulo: ";
        cin >> n >> m;
        if (cin.fail()) {
            cerr << "Numbers must be a positive integers. Please try again.\n";
            cin.clear(); //clear input stream
            cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard any unprocessed characters
        }
        else if (n < 0 || m <= 0) {
            cerr << "Numbers must be positive and second number cannot be zero.\nPlease try again.\n";
        }
        else {
            cout << "n%m = " << n << "%" << m << " = " << modulo(n, m) << endl;
            cout << " Try again? (enter 'n' to quit): ";
            cin >> check;
        }
    } while (check != 'n');
}

The error is:

Unhandled exception at 0x00007FF77D5C2793 in GuessNumber.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000006F322F3F30).

for the numbers i tried 40001 % 10, it works but 44001 % 10 fails and everything past 44001 fails for me also. i haven't tried any other number

c++
recursion
modulo
asked on Stack Overflow Mar 10, 2019 by Artem Khizhnyak • edited Mar 10, 2019 by Artem Khizhnyak

2 Answers

1

If the recursion is too deep, then the program runs out of stack memory. It is called Stack Overflow.

int modulo(int n, int m) 
{ 
    if (n < m) return n; 
    else return modulo(n - m, m); 
}

For example, modulo(1000000, 2) calls modulo(999998, 2), which calls modulo(999996, 2), and so on until modulo(0, 2) at the end there are 500001 active modulo functions on the stack. Two integers, return address, and a frame pointer, should take at least 16 bytes per function call on any reasonable system. In total 8 megabytes of stack space, which is usually above the maximum stack size.

Each function call has to wait for the results of the next function, until it can complete its calculation and return. Until it returns the stack had to hold all variables, parameters, and the return address. The return address is the location in the program of where the program should resume after a return statement.

These calls fill up the stack, until its maximum limit is reached and the program crashes.

In some cases, the compiler can convert recursion into a loop. In this case, since the recursion is at the return statement, it can simply goto to the beginning of the function, without performing a call at all. This is called tail call optimization:

int modulo(int n, int m) 
{ 
    start:
    if (n < m) return n; 
    else {
       n -= m;
       goto start;
    }
}

Had you enabled optimization (-O2 in clang or G++, or release mode on Visual C++) there would have been no crash since the compiler would have created a loop instead of recursion. To avoid the crash, simply enable optimizations.

Note that the compiler is not required to optimize this, nor it always can. That's why it is not advisable to have such a deep recursion.

answered on Stack Overflow Mar 10, 2019 by Michael Veksler • edited Mar 10, 2019 by Michael Veksler
0

You are recursing to a depth of 4400, which is asking for trouble. Also it's unnecessary here, because you can implement the same algorithm with a loop:

while (n >= m) n -= m ;
return n ;
answered on Stack Overflow Mar 10, 2019 by TonyK

User contributions licensed under CC BY-SA 3.0