3 ms·
If a function calls itself exactly once, it’s a trivial recursion. Same is true if it calls itself exactly four times. If the entire problem can be reasonably i
by dahart 2y ago
If a function calls itself exactly once, it’s a trivial recursion. Same is true if it calls itself exactly four times. If the entire problem can be reasonably inlined or “unrolled”, it’s trivial. Having to use fixed bounds and a small amount of memory might mean that all recursion is trivial. Reversing a list is a perfect example of something that is best solved without recursion. Do you really want to use as many stack frames as you have list entries? No, not really. Can you tell me off the top of your head what the limit on max list size is without looking it up for a list-reversing recursive algorithm?
Yes NASA’s rule is intended to prevent loops with only boolean conditions. Everyone (i.e. people who did not write the code) should be able to know for certain by glancing at a loop whether it will finish, and fixed bounds gets you most of the way there. It is fine if you put a fixed call count on the recursion, assuming that recursion is actually the best choice. It’s just that actual recursion is almost never the actual best choice. Having a fixed call count and a fixed recursion depth nearly always suggest that the problem can be easily translated to iteration, and iteration is cheaper. Even something as simple as using a simulated stack structure to replace function calls is usually preferable to burning memory with stack frames and wasting registers and cycles passing parameters around. People who do high performance work or just care about efficiency don’t question these things.
NASA’s rules aren’t weird when it comes to other organizations that do safety-critical code. Even video games, like I mentioned used to do nearly everything on NASA’s list. Embedded code on small devices still does all of this; car manufacturers follow the same rules. When memory is very small or limited, and when crashes have high consequence and are unrecoverable, the situation is completely different than a grad student sitting at a terminal.
Their rules aren’t very onerous either, most of the time, they just require changing habits and thinking differently. Once you get used to them, just like with any coding practices, there are simple patterns you can follow to implement just about anything.
One exercise that might(?) be fun for you is take some of your research code and port it to the smallest Arduino you can buy, and get it to run. Even if Prolog is an option on that platform, you might find that standard recursion is not.
“Production code” is a fairly common/standard term (Google it and browse multiple answers) that does mean in part who it’s for. The term is meant for situations where code is usually written by teams, most often large teams, and where the code is written in service of a product, and will be run by people other than the authors of the code. Production code is not a comment on the quality of the code nor of the choice of language, but it does mean the code will be tested by a QA department and that it will be run under uncontrollable conditions by people who are not experts or coders.
If you write code for your PhD and you run it yourself, it’s not production code, period, no matter how stable or high quality you believe it to be. For sure there are cases where research code and production code overlap. They are relatively rare, but you might be in that part of the Venn diagram.
- YeGoblynQueenne 2y agoI think your analysis about efficiency is specific to one kind of implementation of recursion that is not the only possible one and certainly not the most efficient one, or how it's done in Prolog. But talk is cheap so I offer the following as a proof of concept. This is my factorial predicate in Prolog, tail-recursive style: %! factorial(+N,-Factorial) is det. % % Calculate the Factorial of N % factorial(0,1):- !. factorial(N, F):- factorial(N, 1, F). %! factorial(+N,+F,-G) is det. % % Business end of factorial/2. % factorial(1,F,F):- !. factorial(N,F,G):- F_ is N * F ,N_ is N - 1 ,factorial(N_,F_,G). And this is its output running on SWI-Prolog and printing out statistics about its execution: ?- time( factorial(100_000, _N) ), format('~e~n',[_N]). % 199,999 inferences, 0.672 CPU in 1.184 seconds (57% CPU, 297673 Lips) 2.824229e+456573 true. ?- statistics. % Started at Sun Jan 05 16:47:25 2025 % 0.672 seconds cpu time for 546,365 inferences % 6,574 atoms, 4,766 functors, 3,441 predicates, 51 modules, 134,446 VM-codes % % Limit Allocated In use % Local stack: - 20 Kb 2,432 b % Global stack: - 508 Kb 380 Kb % Trail stack: - 30 Kb 384 b % Total: 1,024 Mb 558 Kb 383 Kb % % 22,105 garbage collections gained 9,936,079,752 bytes in 0.063 seconds. % 4 atom garbage collections gained 1,573 atoms in 0.000 seconds. % 7 clause garbage collections gained 156 clauses in 0.000 seconds. % Stack shifts: 2 local, 7 global, 7 trail in 0.000 seconds % 2 threads, 0 finished threads used 0.000 seconds true. That will run on the smallest Arduino you can find, or at least the smallest embedded system you'll likely find that runs an OS. Note that the above is measuring all utilisation since I started up SWI-Prolog, not just to run my code (e.g. 3,441 predicates is all the SWI-Prolog libraries). If I try to do the same calculation on the Windows 11 Calculator (switch to "Scientific" version), I get the following output: Overflow That's on my 64 GB RAM laptop. I'm saying this to show that 100k! is not a small calculation, but it can be done efficiently with tail-call optimisation. >> People who do high performance work or just care about efficiency don’t question these things. I'll try not to be hurt by your words :P
- dahart 2y agoI think you’re misunderstanding my points. I already said (more than once) tail recursion doesn’t count - it is implemented as iteration, and factorial is trivial to do without recursion, it just doesn’t help you make a good case. The 10GB of garbage collection doesn’t help either, and implies more time spent in memory allocation and cache churn than it’s reporting. BTW, I am including (and NASA is talking about) embedded systems without an OS. Most of my game programming career involved platforms with no OS.