Looking through the minutes of interviews on the developer’s position, I discovered the following task: “Offer a code that prints numbers in descending order from n to 0, without using (hidden or explicitly) comparison operators (implementation of the print function does not count).” Despite the fact that this task had nothing to do with me, it took me up and I decided to think about ways to solve it (although to whom and in solving which task such a code optimization method might be needed, I was left unknown, but nonetheless).
The first thing that came to mind was to try to use patterns. Like so
template<int n> void print() { printf("%d\n", n); print<n - 1>(); } template<> void print<0>() { printf("0\n"); } int main(int argc, char* argv[]) { print<N>(); return 0; }
The problem is that programming is an engineering discipline, not an occult one, and if “something” should occur in the system, then “it” should be described and resources should be allocated to it, and in this case, since the development of templates at the compilation stage, there are restrictions on the nesting of this kind of constructions (and this is good and right, and thank God that it is), and the compiler rightly issued "fatal error C1202: recursive type or function dependency context too complex" with size N more 2000
The next thing that came to mind is to use the classic method with function pointers.
typedef void(*PrintFunc)(int); void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); } void printNumber(int n) { printf("%d\n", n--); g_functors[!!n](n); } int main(int argc, char* argv[]) { printNumber(N); return 0; }
But even here the restrictions imposed on us by the law of nature made themselves felt, and since the nesting of function calls is limited by the size of the stack, then at a value of N> 4630 a legitimate “Stack overflow” was obtained.
At this place, frustration and anger completely took possession of me, and I realized that in order to complete this task, you should not disdain anything, including the dirtiest stunts. The problem is that for certain values of N we need to transfer control to the necessary parts of the code. And there are no problems in this when we have conditional operators at our disposal, but when they are not there, we have to resort to witchcraft. In ancient times, this could be solved using the goto method, but since then witch hunters and other dragon slayers have severely limited its functionality (and this is also good and proper) and we would like to write something like this
g_functors[0] = [](int){print("0\n"); goto end; } g_functors[1] = [](int n){print("%d\n", n); goto begin; } begin: g_functors[!!n](n--); end:
but we can't.
Therefore, although I was forbidden to engage in black magic, in this case I decided to make an exception, adding a bit of magic to the previous example.
void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); throw 0; } void printNumber(int n) { printf("%d\n", n); } int main(int argc, char* argv[]) { int n = N; try{ begin: g_functors[!!n](n--); goto begin; } catch (...){} return 0; }
And this completely solved the problem (with any N).
PS: I will be glad to hear about other methods for solving this problem.
Source: https://habr.com/ru/post/428343/
All Articles