# Int does not wrap around and returns 0?

I noticed that int does not wrap around when I run my exponential functions. E.g., if you run 4^31 with my program:

you will get int of -4611686018427387904. But 4^32 returns 0. I also got the following in an interactive prompt of OCaml:

• : int = 0

# max_int * -max_int ;;

• : int = -1

I’m confused as to the actual specification of int. It seems it wraps around in certain cases but returns 0 in certain cases?

OCaml ints use two’s complement. I find it useful to use a function to print an int in base 2, like this crude one for example:

``````let rec bits x =
if x = 0 then ""
else bits (x lsr 1) ^ (if x mod 2 = 0 then "0" else "1")
``````
1 Like

Thank you. That helped me head to the right direction.

I realized that int in OCaml has the range of 63-bit signed int on 64-bit processors. That is, 2^63 returns 0. Any multiple of that also returns 0. Therefore, 4^32 = 2^64 = 2^63*2 returns 0. 8^21 = 2^63 also returns 0 while 8^20 returns 1152921504606846976. Base with non-multiple of 2 does not return zero. These are all expected behaviour!

All this brings a question to my mind: if I want a type that exceptions if there’s an overflow, because I never meant for the int type to overflow, is there a solution for me?

1 Like

Good point! I’d like to know how to catch when an int wraps around too! Thanks!

A while ago, Xavier Leroy posted some code that checks for int overflows. This may be worth studying (I haven’t).

However I don’t see int overflows as a common problem in practice for general-purpose programming because everyday integers just don’t get that big and we don’t square them.

If you were doing math with integers, you’d quickly become aware that ints are not integers and you’d use a specialized arithmetic library like Zarith.

Floating-point computation has no overflow problem in practice either but they have a bunch of other issues, including but not limited to: rounding, architecture-dependent rounding, NaNs, infinities, negative zero.

2 Likes

You are, sadly, incorrect. I used to think the way you do, but the literature and bitter experience has convinced me otherwise. Numerous security problems in the literature have been caused by integer overflows, and it turns out programmers are very terrible at reasoning about circumstances in which integers do overflow. I direct you to John Regehr’s work on the topic, he’s published a bunch of paper on it, almost exclusively in the realm of C and C++, but some of the content (not the stuff associated with C undefined signed integer overflow behavior) remains relevant in other contexts.

I would prefer if, in a safe language, integer overflow were always caught unless I explicitly intended to be working in a mod 2^32 or 2^64 context.

1 Like

I said “in practice”. ymmv.

In practice, people do things like attacking systems by getting people to wrap integers, causing the systems to then behave in ways unexpected by the authors.

Or, people write softwares which run for a long time and forget about the few int32 counters hidden somewhere in their code.

2 Likes

Either way, it’s a problem when things programmers are reasoning about as though they were integers unexpectedly behave quite differently some of the time. It’s fine if they’re explicitly asking for this behavior and want it, but that’s not the norm.

some time ago I wrote the library usane with that behaviour – well, instead of raising exceptions, the operations return the carry bit explicitly. This library is not (yet) released, and since newer OCaml runtimes come with `add_with_overflow` (see this OCaml PR), there’s no need for external C depedencies anymore.

For some purposes, like implementing multiple word arithmetic, explicit carries are great. For some purposes, like doing every-day math where you don’t think you will ever overflow, exceptions seem like the right thing.

I think it depends, as is often the case, on whether the condition being caught is ordinary or something so odd you want to end execution.