Help to create a macro do avoid integer overflow


#1

Hi guys!

I need help to create a macro to do the following:

  • On every integer operation, check if overflow will happen.
  • If it does, then promote the arguments to integer representations with higher number of bits.

I do not know how the compiler will work, but I am wondering if this can be done without much performance decrease if the operands do not lead to an integer overflow.

My usage is because I have in my code things like:

f100 = C1*Δt^2 + C2*Δt^3

where Δt is selected by the user and can be a very big number. Hence, if the user input a big integer, the ^ will overflow.

Of course I can always promote the Δt to Float64, but I want to try this to see how it works.


#2

Macros don’t know about types, so macros can’t do this. If you want different integer semantics, you generally need to define a different integer type. (See e.g. https://github.com/JeffreySarnoff/SaferIntegers.jl)

If you only want to look at operations on integer literals, that could be done with a macro, but I’m not sure how useful it would be.

If it does, then promote the arguments to integer representations with higher number of bits. I do not know how the compiler will work, but I am wondering if this can be done without much performance decrease if the operands do not lead to an integer overflow.

I doubt that this can be done at runtime without a substantial performance hit, but you are welcome to try to define a type that behaves in this way.


#3

Hi @stevengj,

Thanks for the answer, but by macro, I mean something like @inbounds that I can add to certain operations so that they can behave like I described.


#4

A macro is just a rewrite of an expression into another. What expression do you want to apply the macro to and what expression do you want to come out in the end?


#5

I understood. But, I really do not know :smiley: I want something that, at every integer operation (+, * and ^) it checks the operands and, if overflow will happen, then change the type to a representation with higher bit. I have no idea how to code this in Julia.


#6

Why don’t you use https://github.com/JeffreySarnoff/SaferIntegers.jl ?


#7

There is no way to know that at compile time, so macros will not help you. You should use try blocks with the saferintegers.


#8

For three reasons:

  1. It does not support (at least it is not documented) the function ^.
  2. I want to learn new things :smiley:
  3. I want to see the performance hit when doing such things like check the type and promoting if necessary.

Actually, I am thinking of a macro that overload / change (do not know the correct name) the operations. Something like, change + to another function that performs the verification as I described. This macro will be used just trigger such behavior like:

@check_overflow f100 = C1*Δt^2 + C2*Δt^3

However, if I give up and use SafeIntegers, I would do something like:

try
    f100 = C1*Δt^2 + C2*Δt^3
catch
    f100 = C1*BigInt(Δt)^ + C2*BigInt(Δt)^3
end

Correct?


#9

I think this is exactly what SaferIntegers does. It creates primitives that work the same way as integers but checks for overflow by defining their own methods for common functions.


#10

Nice! I will see :slight_smile: The macro I mentioned is because I just want to do this in some parts of the code, because there are other in which I know it is not necessary. Hence, I think if I can trigger this behavior only when necessary, the performance hit will not be big (at least I hope).

Anyway, in some tests here with SafeIntegers and such things, I am starting to see that my best approach in terms of performance is to convert everything to Float64 just as MATLAB does :smiley:


#11

You could a macro that does something where @check_overflow f100 = C1*Δt^2 + C2*Δt^3 lowers to

try
    f100 = C1*SafeInt(Δt)^2 + C2*SafeInt(Δt)^3
catch
    f100 = C1*BigInt(Δt)^ + C2*BigInt(Δt)^3
end

#12

Presumably there was a reason you used Integers in the first place?


#13

Actually I am using Numbers. The user decide. The input variable is the number of seconds from a specific epoch. Hence, many users will like to write something like:

propagate!(orbs, 1000)

Instead of

propagate!(orbs, 100.0)

I would not like to force them to use Float literals because this is targeted to MATLAB users.


#14

In this case you could do something along

function propagate!(a,s::Float64)
#define function here
...
end

propagate!(a,s::Number) = propagate!(a,float(s))

#15

Yeah, that is what I mentioned before. I am starting to think this is the best approach, which is basically what MATLAB does, convert everything to Double.