# Bounds for LibraryFunction arguments of integer type

I am trying to load a function written in C++ using LibaryFunctionLoad. Doing so, I have encountered an issue I believe to be a bug (I wanted to ask here first in case I'm missing something obvious):

Take e.g. the following C/C++ function:

EXTERN_C DLLEXPORT int inc(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res)
{
MArgument_setInteger(Res, MArgument_getInteger(Args[0]) + 1);

return LIBRARY_NO_ERROR;
}


inc = LibraryFunctionLoad[NotebookDirectory[] <> "inc.dll", "inc", {_Integer}, _Integer];


This works mostly as expected:

inc[5]
(* 6 *)

inc[2^63]
(* Error, should be machine-sized integer *)

inc[2^63-1]
(* -9223372036854775808 *)

% == -2^63
(* True *)

inc[-2^63+1]
(* -9223372036854775806 *)


However:

inc[-2^63]
(* Error, should be machine-sized integer *)


As you can see, it seems as if the bound check for machine-sized integers is off by one on the negative end. Is my observation correct or am I missing something? What speaks for this interpretation is the fact that inc[2^63-1] correctly returns -2^63 but this returned value can not be passed back to the function.

## Update

Yes, this is a slightly unfortunate consequence of the discrepancy between the machine integer range in C and in WL. Specifically, -2^63 is a machine integer in C, but is not DeveloperMachineIntegerQ.

The reasons for this design decision go far back.

The actual machine integer -2^63 is excluded from the definition of "machine integer in WL" even though it is one, because that allows an optimization -- don't need to check for packing/unpacking when negating a machine integer matrix.

I will try to find the easiest workaround for this issue and will update the post once I found one.

• Probably this Developer$MaxMachineInteger – halirutan Dec 17 '17 at 17:08 • @halirutan what do you want to say with that? Normally, integer bounds for signed integers are$-2^{n-1},...,2^{n-1}-1\$. – Lukas Lang Dec 17 '17 at 17:19
• This does work: RawArray["Integer64", {-2^63}] (for raw arrays it would seem to be more important to accurately represent the full range). – Szabolcs Dec 17 '17 at 18:03
• Interestingly, it is still possible to return a packed array containing -2^63 from LibraryLink. Negating this packed array will trigger unpacking. I guess not all packed arrays are the same. – Szabolcs Dec 25 '17 at 14:21

My comment was only a pointer to the bound in Mathematica. I too believe that the bound check is weird. Let me give a simple example that probably makes it a bit clearer than the ones from Mathe172

dec = Compile[{{i, _Integer, 0}},
i - 1,
CompilationTarget -> "C"
];


When we decrement the smallest possible integer, the sign should flip and we should end with the largest possible integer. This gives us a warning and falls back to Kernel evaluation:

Therefore, the smallest possible machine integer must be larger:

dec[-2^63 + 1]
(* -9223372036854775808 *)


However, note that we end up with the negative number -2^63 which was claimed before to not be a machine integer. Therefore, I believe the bound-check is off as well.

One possible explanation is that not all integer representations are asymmetric like the twos-complement. In fact, all other ones I know are symmetric (ones-complement, sign-representation). Probably the bound-check is a compromise to work on all machines.

• This is a bit similar to how it is possible to return Infinity from a LibraryFunction, but not pass it to it. If the Infinity is in a packed array, it will cause weird behaviour unless the array is unpacked first. – Szabolcs Dec 17 '17 at 17:54
• Thanks a lot for your answer! I have updated the main question with a reply from Wolfram support - apparently, the reason for the decision was really the symmetry of the integer representation – Lukas Lang Dec 24 '17 at 10:09

This is a long comment.

It could be a bug, but it could also be some weirdness in the handling of machine integers. I think the only thing you can do is contact Wolfram Support, and let us know what they said.

Mathematica's behaviour seems much too consistent for this to be a "bug" (i.e. something they overlooked).

DeveloperMachineIntegerQ[-2^63]
(* False *)

DeveloperPackedArrayQ[
DeveloperToPackedArray[{-2^63 + 1}]
]
(* True *)

DeveloperPackedArrayQ[
DeveloperToPackedArray[{-2^63 + 1}] - 1
]
(* False *)


If I try to return this value from a LibraryLink library, the result also isn't a machine integer according to these functions.

However, if I try to return a single-element Integer array containing a value, then it is still treated as a packed array.

This very last finding is inconsistent with the rest and suggests a possible bug to me.

The LTemplate code I used for testing (for reference):

<< LTemplate

SetDirectory@CreateDirectory[];

tem = LClass["Bounds", {
LFun["lowest", {}, Integer],
LFun["lowestArr", {}, {Integer, 1}]
}];

code = "
struct Bounds {

mint lowest() { return (1L << 63); }

mma::IntTensorRef lowestArr() {
auto arr = mma::makeVector<mint>(1);
arr[0] = (1L << 63);
return arr;
}
};";
Export["Bounds.h", code, "String"];

CompileTemplate[tem]

DeveloperPackedArrayQ[obj@"lowestArr"[]]
`