Numeric Overflows
Most numeric types like i64
have a limited range of possible
values they can hold. Some numeric operations such as addition or multiplication
can lead to an overflow. Fuzion's basic types provide a choice of means to deal
with overflows. These will be presented here.
Runtime Checks via Preconditions
The standard operations perform runtime checks to detect overflows at runtime:
If runtime checks are enabled, an error is produced and the application is stopped.
Alternatively, runtime checks can be disabled:
This results in wrap-around numeric behaviour, which in most cases leads to wrong results.
Explicit handling of Overflows
Alternatively, a set of operations +?
, -?
and *?
produce an optional result in case of an overflow:
A match
-statement can be used to distinguish the successful case
from the overflow.
A disadvantage of this approach is that one needs to check for an overflow after every operation that might overflow, otherwise we might see overflows in intermediate values:
The postfix ?
operator provides syntactic sugar that simplifies
these tests: When applied to a choice type like num_option
,
postfix ?
returns immediately from the current feature in case the
value does not match the first type in the choice. In this case, the value is
returned as the feature's result.
Saturating Semantics
In some cases, it might be sufficient to record a large (or small) number in
case of a numeric overflow (or underflow). An example is counting some entity
while it does not matter to distinguish very large amounts. A set of saturating
operations +^
, -^
and *^
does this: After
an overflow (or underflow), the largest (or smallest) representable value is
produced:
Note that, unlike the operations +?
, -?
and *?
that return an option, the saturating operations return a
normal numeric value that can be used in further arithmetic:
The fact that an intermediate operation resulted in an overflow may no longer be obvious after additional operations.
Wrap-Around Semantics
In some applications, it might be desirable to have wrap-around semantics,
i.e., the value represented is always the lowest bits that fit in the respective
type. This is possible using a new set of operations +°
, -°
and *°
: