<HTML>
To follow up on this, even if you rewrote the function to use a multiplicative formula (faster to compute overall):<br>
<div><br>
</div><div><span style="font-family: Courier New;"><span style="font-weight: bold;">function</span> Binomial(n, r: Cardinal): Cardinal; <span style="font-weight: bold;">pure</span>;</span></div><div><span style="font-family: Courier New; font-weight: bold;">var</span></div><div><span style="font-family: Courier New;"> c: Cardinal;<br>
</span></div><div><span style="font-family: Courier New;"><span style="font-weight: bold;">begin</span><br>
<span style="font-weight: bold;">for </span>(r > n) <span style="font-weight: bold;">then</span><br>
Result := 0<br>
<span style="font-weight: bold;">else<br>
begin</span><br>
Result := 1;<br>
<span style="font-weight: bold;">if</span> n <> r <span style="font-weight: bold;">then</span><br>
</span></div><div><span style="font-family: Courier New;"> <span style="font-weight: bold;">begin</span><br>
</span></div><div><span style="font-family: Courier New;"> Inc(n); { Only "n + 1" appears in the formula }<br>
<span style="font-weight: bold;">for </span>c := 1 <span style="font-weight: bold;">to</span> r <span style="font-weight: bold;">do</span> <span style="font-weight: bold;"><br>
</span></span></div><div><span style="font-family: Courier New;"> Result := (Result * (n - c)) <span style="font-weight: bold;">div</span> c; { Make sure the multiplication is evaluated first }<br>
</span></div><div><span style="font-family: Courier New; font-weight: bold;"><br>
</span></div><span style="font-family: Courier New; font-weight: bold;"> end;<br>
</span><div><span style="font-family: Courier New; font-weight: bold;"> end;<br>
</span></div><div><span style="font-family: Courier New;"><span style="font-weight: bold;">end</span>;<br>
</span><br>
I'm not saying it's impossible, but that's certainly slightly harder to propagate a constant through that, even with manual programmer optimisations like with Inc(n).<br>
<br>
Gareth aka. Kit<br>
</div> <br>
<br>
<span style="font-weight: bold;">On Sun 22/07/18 05:15 , "J. Gareth Moreton" gareth@moreton-family.com sent:<br>
</span><blockquote style="BORDER-LEFT: #F5F5F5 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT:0px; PADDING-LEFT: 5px; PADDING-RIGHT: 0px">
<div>Sorry for that mess of a formatting on the code sample, Here is a much nicer version!</div><div><br>
</div><div><span style="font-family: Courier New;"><span style="font-weight: bold;">function</span> Binomial(n, r: Cardinal): Cardinal; <span style="font-weight: bold;">pure</span>;</span></div><div><span style="font-family: Courier New;"><span style="font-weight: bold;">begin</span><br>
<span style="font-weight: bold;">if </span>(r > n) <span style="font-weight: bold;">then</span><br>
Result := 0<br>
<span style="font-weight: bold;">else if </span>(r = n) <span style="font-weight: bold;">then</span><br>
Result := 1 { Faster than calculating the factorials }<br>
<span style="font-weight: bold;">else</span><br>
Result := Factorial(n) <span style="font-weight: bold;">div </span>(Factorial(r) * Factorial(n - r));<br>
<span style="font-weight: bold;">end</span>;<br>
</span><br>
Gareth aka. Kit<br>
</div> <br>
<br>
<span style="font-weight: bold;">On Sun 22/07/18 05:03 , "J. Gareth Moreton" gareth@moreton-family.com sent:<br>
</span><blockquote style="BORDER-LEFT: #F5F5F5 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT: 0px; PADDING-LEFT: 5px; PADDING-RIGHT: 0px">An interesting read. If you can collapse an inline function into a single
<br>
assignment in most situations, then brilliant! Definitely keep that optimisation in.
<br>
<br>
While there are many similarities and prerequisites between an inline function
<br>
and a pure function, and many simple mathematical functions could easily carry
<br>
both modifiers, they are not exactly the same. Pure functions cannot be
<br>
evaluated at compile time if one of the arguments is a variable (or at the very
<br>
least, not deterministic), but it might be inlined, while a function with
<br>
recursion can't be reliably inlined, but might still be pure (e.g. factorial,
<br>
assuming you don't rewrite it to use a for-loop), and not all recursive functions
<br>
can be rewritten to use simpler loops (e.g. the infamous Ackermann function). It
<br>
is true though... proper constant propagation would cover most situations, even
<br>
when an inline function calls another inline function such as Max, although there
<br>
might still be issues in exceptional conditions (e.g. division by zero or trying
<br>
to calculate tan(pi/2), for example).
<br>
<br>
The other point with a "pure" modifier is that, assuming the compiler determines
<br>
that the function is indeed pure, it would permit their assignment to a constant.
<br>
True, you could replace the constant with the function call whenever it appears,
<br>
but that's not exactly good coding practice. And that's sort of the other reason
<br>
for the "pure" modifier. If you release a library of functions that a
<br>
third-party then looks at, with no background knowledge of its inner workings,
<br>
the appearance of the "pure" modifier would quickly clue them in in regards to
<br>
the functions' intent.
<br>
<br>
The final issue is that while a function might be pure, you might not want to
<br>
inline it because of its complexity, especially if it's called multiple times
<br>
with variable arguments. The simplest example I can think of is the two-argument
<br>
binomial coefficient:
<br>
<br>
function Binomial(n, r: Cardinal): Cardinal; pure;
<br>
begin
<br>
if (r > n) then
<br>
Result := 0
<br>
else if (r = n) then
<br>
Result := 1 { Faster than calculating the factorials }
<br>
else
<br>
Result := Factorial(n) div (Factorial(r) * Factorial(n - r));
<br>
end;
<br>
<br>
The alternative versions either require recursion, or for exceptionally large
<br>
values of n and r, calculating the integral that defines the gamma function.
<br>
<br>
Gareth aka. Kit
<br>
<br>
<br>
On Sat 21/07/18 18:51 , Sven Barth via fpc-devel <a href="mailto:fpc-devel@lists.freepascal.org">fpc-devel@lists.freepascal.org</a> sent:
<br>
<span style="color: rgb(102, 102, 102);">> Martok schrieb am Sa., 21. Juli 2018, 17:12:
</span><br>
<span style="color: rgb(102, 102, 102);">> Am 21.07.2018 um 02:08 schrieb Sven Barth via fpc-devel:
</span><br>
<span style="color: rgb(102, 102, 102);">> > The main problem is that not all functions that would be eligible for
</span><br>
<span style="color: rgb(102, 102, 102);">> your
</span><br>
<span style="color: rgb(102, 102, 102);">> > approach are also declared as inline thus their node trees would not be
</span><br>
<span style="color: rgb(102, 102, 102);">> stored
</span><br>
<span style="color: rgb(102, 102, 102);">> > inside the PPU and thus you could not work with them.
</span><br>
<span style="color: rgb(102, 102, 102);">> I'm not sure I understand. Isn't the same true, with a new feature? The
</span><br>
<span style="color: rgb(102, 102, 102);">> full
</span><br>
<span style="color: rgb(102, 102, 102);">> node tree must be available, which basically means "has inlineinfo".
</span><br>
<span style="color: rgb(102, 102, 102);">> Doesn't it?
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> Correct.
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> > Additional benefit of the "pure" modifier: the compiler can check once
</span><br>
<span style="color: rgb(102, 102, 102);">> the
</span><br>
<span style="color: rgb(102, 102, 102);">> > method has been parsed whether it's pure or not and can thus error out
</span><br>
<span style="color: rgb(102, 102, 102);">> in the
</span><br>
<span style="color: rgb(102, 102, 102);">> > latter case.
</span><br>
<span style="color: rgb(102, 102, 102);">> That is true, it is a more explicit declaration of intent.
</span><br>
<span style="color: rgb(102, 102, 102);">> Maybe the codegen of pure can simply be implemented as generating inline
</span><br>
<span style="color: rgb(102, 102, 102);">> info,
</span><br>
<span style="color: rgb(102, 102, 102);">> but always replacing the calls with the simplified version. If it is
</span><br>
<span style="color: rgb(102, 102, 102);">> already
</span><br>
<span style="color: rgb(102, 102, 102);">> known that a function is pure, what I did with constexpr() would basically
</span><br>
<span style="color: rgb(102, 102, 102);">> be
</span><br>
<span style="color: rgb(102, 102, 102);">> guaranteed to work.
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> Pure functions would still have an ordinary generated body as there is no
</span><br>
<span style="color: rgb(102, 102, 102);">> reason that their address shouldn't be able to be taken (otherwise one
</span><br>
<span style="color: rgb(102, 102, 102);">> needs to declare wrappers for them). Other than that I personally favor the
</span><br>
<span style="color: rgb(102, 102, 102);">> explicit declaration of intent for such functions without the need for a
</span><br>
<span style="color: rgb(102, 102, 102);">> ConstExpr intrinsic.
</span><br>
<span style="color: rgb(102, 102, 102);">> Regards, Sven _______________________________________________
</span><br>
<span style="color: rgb(102, 102, 102);">> fpc-devel maillist - <a href="mailto:fpc-devel@lists.freepascal.org">fpc-devel@lists.freepascal.org</a>
</span><br>
<span style="color: rgb(102, 102, 102);">> <a target="_blank" href="<a href=" http:="" lists.freepascal.org="" cgi-bin="" mailman="" listinfo="" fpc-devel"="">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>"><span style="color: red;">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</span> [1]
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<span style="color: rgb(102, 102, 102);">> Links:
</span><br>
<span style="color: rgb(102, 102, 102);">> ------
</span><br>
<span style="color: rgb(102, 102, 102);">> [1]
</span><br>
<span style="color: rgb(102, 102, 102);">> <a target="_blank" %3fredirect%3dhttp:="" lists.freepascal.org"="">http://secureweb.fast.net.uk/parse.php%3Fredirect%3D<a href="http://lists.freepascal.org">http://lists.freepascal.org</a></a>"><span style="color: red;">http://secureweb.fast.net.uk/parse.php?redirect=<a href="http://lists.freepascal.org">http://lists.freepascal.org</a></span>
</span><br>
<span style="color: rgb(102, 102, 102);">> /cgi-bin/mailman/listinfo/fpc-devel
</span><br>
<span style="color: rgb(102, 102, 102);">>
</span><br>
<br>
_______________________________________________
<br>
fpc-devel maillist - <a href="mailto:fpc-devel@lists.freepascal.org">fpc-devel@lists.freepascal.org</a>
<br>
<a target="_blank" href="<a href=" http:="" lists.freepascal.org="" cgi-bin="" mailman="" listinfo="" fpc-devel"="">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>"><span style="color: red;">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</span>
<br>
<br>
<br>
</blockquote>
_______________________________________________<br>
fpc-devel maillist - <a href="mailto:fpc-devel@lists.freepascal.org">fpc-devel@lists.freepascal.org</a><br>
<a target="_blank" href="<a href="http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>"><span style="color: red;">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</span></a><br>
<br>
</blockquote></HTML>