In Mathematica, numbers have certain types and switching between them happens without that you have to care about this. As example take your two expressions:
x = 1;
2^-x
1/2^x
(* 1/2 *)
(* 1/2 *)
The transition from integers to rational numbers just happens during the evaluation. Within compile, everything is different because there, types are associated with each expression and operations on them need to be consistent. In addition, the type Rational
does not exist.
In your first example inside compile, the expression 2^-x
denotes the integer power of 2 and -x. You can see this pretty clearly when using CompilePrint
of the CompiledFunctionTools`
package:

All the Ix
are integer registers and there is no way that I3
allows anything else than an integer in the assignment. When you violate this, then Mathematica catches this error and gives you the result that is computed with the Kernel. In your error message, you additionally see that the error happened at instruction 2 which is exactly the line I3 = Power[ I1, I2]
.
Looking at your second example g
shows why this works:

The 2^x
part is still an integer register but for x=1
everything is good because it will result in an integer. Then, a cast from Integer to Real is done with R0=I2
which is fine too. After that, the reciprocal is calculated which is a perfectly valid operation for real numbers.
This is why your second example works for x=1
. However, if you read carefully, you see how we can break g
. The first instruction relies on the fact that the Power
gives an integer which is not true for e.g. x=-1
. This is why g[-1]
fails

Finally, the way to ensure that the Power
is always correctly calculated is to enforce its calculation on real numbers. This can simply be done by using
h = Compile[{{x, _Integer}}, 2.0^-x];
CompilePrint[h]
because then, the compiled code looks like this

The second instruction is now the power of real numbers and not integers.
{h[-1], h[1], h[0]}
(* {2., 0.5, 1.} *)
2.
instead of an integer2
:f = Compile[{{x, _Integer}}, 2.^-x];
$\endgroup$ – Henrik Schumacher Feb 21 '18 at 22:15Compile
can work with integers, reals (i.e., _Real) and complexes. It will not work with rationals (i.e. _Rational). In the first case, the Compiler thinks the result might be an integer, while in the second case it thinks the result is a real. Since a rational can be coerced into a real, the second example works and the first doesn't. $\endgroup$ – Carl Woll Feb 21 '18 at 22:31Compile
the type of result expected $\endgroup$ – LLlAMnYP Feb 22 '18 at 13:20Module
and predefining the variables. For instance, this enforces a complex result, although all computations are perfectly valid with integers:Compile[{{x, _Integer}}, Module[{result = 0. I}, result = 1 + x]];
$\endgroup$ – halirutan♦ Feb 25 '18 at 5:34result = Most[{0.}]
to tellCompile
that I'm dealing with a rank 1 real tensor, just didn't realize how to apply it for a lone real. $\endgroup$ – LLlAMnYP Feb 25 '18 at 11:45