12
$\begingroup$

It seems that Log2 in Compile gives numerical errors (CompiledFunction::cfn) if the input is not a power of 2.

For instance:

test1 = Compile[{{in, _Integer}}, Log2[in]];
test1[3]

gives an error and proceeds with an uncompiled evaluation.

However:

test2 = Compile[{{in, _Integer}}, Log[2, in]];
test2[3]

works correctly.

Is this intentional or a bug?

$\endgroup$
6
  • 1
    $\begingroup$ Log10[] is also affected. $\endgroup$ Jul 23, 2016 at 21:05
  • 1
    $\begingroup$ Just for noting it: Log2[N[in]] works. $\endgroup$ Jul 23, 2016 at 21:07
  • $\begingroup$ Log2[N[in]] adds a integer to real conversion. $\endgroup$
    – Karsten7
    Jul 23, 2016 at 21:28
  • 3
    $\begingroup$ Compile[{{in, _Real}}, Log2[in]] works. $\endgroup$
    – Karsten7
    Jul 23, 2016 at 21:30
  • 5
    $\begingroup$ If you look at CompilePrint@test1 and CompilePrint@test2, I think one can infer that Log2[integer] is intentionally a special-case integer function. (Apparently undocumented?) $\endgroup$
    – Michael E2
    Jul 23, 2016 at 22:45

1 Answer 1

9
$\begingroup$

Looking at the internal structure of the compiled functions, we can see a distinct call to an integer-valued function Log2 of an integer argument. There is also one for a real-valued function Log2 of a real argument. The first example I think shows that the integer Log2 is intentional. There are similar special integer functions for Log10, Power, Gamma and perhaps others. It is easy to imagine reasons why one would want to do integer calculations with such functions. As far as I know, these special cases are not documented.

Needs["CompiledFunctionTools`"];

test1 = Compile[{{in, _Integer}}, Log2[in]];
CompilePrint@test1

(*
        1 argument
        2 Integer registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        I0 = A1
        Result = I1

1   I1 = Log2[ I0]
2   Return
*)

test3 = Compile[{{re, _Real}}, Log2[re]];
CompilePrint@test3

(*
        1 argument
        2 Real registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        R0 = A1
        Result = R1

1   R1 = Log2[ R0]
2   Return
*)

The byte codes (from List @@ test1, List @@ test3) for the Log2 instructions are respectively

{40, 36, 2, 0, 0, 2, 0, 1}    (* I1 = Log2[ I0] *)
{40, 36, 3, 0, 0, 3, 0, 1}    (* R1 = Log2[ R0] *)

The 40, 36 identifies Log2; the 2, 0, x and 3, 0, x specify the register types of the input and output, _Integer (2) and _Real (3), of rank 0 (scalar), and of register numbers 0, 1 resp.

I tried constructing a CompiledFunction with the "instruction"

{40, 36, 2, 0, 0, 3, 0, 0}    (* R0 = Log2[ I0] *)

but it crashed the kernel. (I tried doing it by hand imitating the output of List @@ test1 and other compiled functions.) I concluded that such a function is not implemented.

$\endgroup$
2
  • $\begingroup$ Nice analysis, very insightful! $\endgroup$
    – sebhofer
    Jul 26, 2016 at 7:42
  • 1
    $\begingroup$ @sebhofer Thanks! -- Side note: "Type conversion" can be accomplished with Compile[{{in, _Integer}}, Log2[N[in]]]. (There is no call to N per se; it just converts to Real via R0 = I0 and then calls Log2[ R0]. If in is type _Real to begin with, then N is ignored.) $\endgroup$
    – Michael E2
    Jul 26, 2016 at 12:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.