Twig icon indicating copy to clipboard operation
Twig copied to clipboard

Power function not working as expected

Open sm8ps opened this issue 3 years ago • 1 comments

I tried to define random values with arbitrary sign and have come to the conclusion that the power function seems to be implemented in a non-standard fashion. Twig version is 3.4.6 and it is used within the Coderunner extension of Moodle. For testing purposes, I define Twig powers which should be positive or negative, respectively, if the exponent is even or odd.

(-1)^0 = 1: {{ (-1)**0 }}, (-1)^1 = -1: {{(-1)**1}}, (-1)^2 = 1: {{(-1)**2}}
(-2)^0 = 1: {{(-2)**0}} , (-2)^1 = -2: {{(-2)**1}} , (-2)^2 = 4: {{(-2)**2}}
(-1.5)^0 = 1: {{ (-1.5)**0 }} , (-1.5)^1 = -1.5: {{ (-1.5)**1 }} , (-1.5)^2 = 2.25: {{ (-1.5)**2 }}

This does not yield the expected result when interpreting powers with natural exponent as successive multiplication with the zeroth power being the "empty" multiplication which yields the neutral element 1.

(-1)^0 = 1: -1, (-1)^1 = -1: -1, (-1)^2 = 1: -1
(-2)^0 = 1: -1 , (-2)^1 = -2: -2 , (-2)^2 = 4: -4
(-1.5)^0 = 1: -1 , (-1.5)^1 = -1.5: -1.5 , (-1.5)^2 = 2.25: -2.25

The power function seems to set aside any negative sign and put it to the respective power of the absolute value of the base. In a way, this is fine because powers with non-integer exponent are in principle not defined for negative bases because of the definition of general powers as b**c := exp(c*ln(b)) via the exponential function and the natural logarithm where the latter is only defined for positive values. Twig seems to use the following definition instead which yields a value for any power of any base. It has the advantage that any power is defined.

b**c := sign(b)*abs(b)**c = sign(b)*exp(c*ln(abs(b)))

This leads, however, to contradictory results when applying it to base zero.

0^0 = ?: {{ 0**0 }}, 0^1 = 0: {{ 0**0 }}, 0^2 = 0: {{ 0**0 }}
(-0)^0 = ?: {{ (-0)**0 }}, 0^1 = 0: {{ (-0)**0 }}, 0^2 = 0: {{ (-0)**0 }}

Setting aside the fact that 0^0 is mathematically undefined, the results are all wrong and -0 even behaves differently from 0.

0^0 = ?: 1, 0^1 = 0: 1, 0^2 = 0: 1
(-0)^0 = ?: -1, (-0)^1 = 0: -1, (-0)^2 = 0: -1

So on top of the above, Twig seems to define ln(0) := 0 which is simply false. This all is quite unexpected and even confusing. I do see good reasons for having a universally defined function even if non-standard. However, it should be clearly pointed out in the documentation. This may sound pedantic but I had to spend quite some time analysing the problem in depth before discovering the source of the error in my application.

sm8ps avatar May 17 '22 07:05 sm8ps

Looking at the compiled template in twigfiddle, the parenthesis are missing when the expression is compiled. ** takes precedence over -.

echo "(-1)^0 = 1: ";
echo twig_escape_filter($this->env, ( -1 ** 0), "html", null, true);

GromNaN avatar May 17 '22 13:05 GromNaN