2 /**********************************************
3 * This module implements integral arithmetic primitives that check
4 * for out-of-range results.
6 * Integral arithmetic operators operate on fixed width types.
7 * Results that are not representable in those fixed widths are silently
9 * This module offers integral arithmetic primitives that produce the
10 * same results, but set an 'overflow' flag when such truncation occurs.
11 * The setting is sticky, meaning that numerous operations can be cascaded
12 * and then the flag need only be checked at the end.
13 * Whether the operation is signed or unsigned is indicated by an 's' or 'u'
14 * suffix, respectively. While this could be achieved without such suffixes by
15 * using overloading on the signedness of the types, the suffix makes it clear
16 * which is happening without needing to examine the types.
18 * While the generic versions of these functions are computationally expensive
19 * relative to the cost of the operation itself, compiler implementations are free
20 * to recognize them and generate equivalent and faster code.
22 * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
23 * Copyright: Copyright (c) Walter Bright 2014.
24 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
25 * Authors: Walter Bright
26 * Source: $(DRUNTIMESRC core/_checkedint.d)
29 module core
.checkedint
;
36 /*******************************
37 * Add two signed integers, checking for overflow.
39 * The overflow is sticky, meaning a sequence of operations can
40 * be done and overflow need only be checked at the end.
44 * overflow = set if an overflow occurs, is not affected otherwise
50 int adds(int x
, int y
, ref bool overflow
)
52 long r
= cast(long)x
+ cast(long)y
;
53 if (r
< int.min || r
> int.max
)
61 assert(adds(2, 3, overflow
) == 5);
63 assert(adds(1, int.max
- 1, overflow
) == int.max
);
65 assert(adds(int.min
+ 1, -1, overflow
) == int.min
);
67 assert(adds(int.max
, 1, overflow
) == int.min
);
70 assert(adds(int.min
, -1, overflow
) == int.max
);
72 assert(adds(0, 0, overflow
) == 0);
73 assert(overflow
); // sticky
78 long adds(long x
, long y
, ref bool overflow
)
80 long r
= cast(ulong)x
+ cast(ulong)y
;
81 if (x
< 0 && y
< 0 && r
>= 0 ||
82 x
>= 0 && y
>= 0 && r
< 0)
90 assert(adds(2L, 3L, overflow
) == 5);
92 assert(adds(1L, long.max
- 1, overflow
) == long.max
);
94 assert(adds(long.min
+ 1, -1, overflow
) == long.min
);
96 assert(adds(long.max
, 1, overflow
) == long.min
);
99 assert(adds(long.min
, -1, overflow
) == long.max
);
101 assert(adds(0L, 0L, overflow
) == 0);
102 assert(overflow
); // sticky
109 cent adds(cent x
, cent y
, ref bool overflow
)
111 cent r
= cast(ucent)x
+ cast(ucent)y
;
112 if (x
< 0 && y
< 0 && r
>= 0 ||
113 x
>= 0 && y
>= 0 && r
< 0)
121 assert(adds(cast(cent)2L, 3L, overflow
) == 5);
123 assert(adds(1L, cent.max
- 1, overflow
) == cent.max
);
125 assert(adds(cent.min
+ 1, -1, overflow
) == cent.min
);
127 assert(adds(cent.max
, 1, overflow
) == cent.min
);
130 assert(adds(cent.min
, -1, overflow
) == cent.max
);
132 assert(adds(cast(cent)0L, 0L, overflow
) == 0);
133 assert(overflow
); // sticky
138 /*******************************
139 * Add two unsigned integers, checking for overflow (aka carry).
141 * The overflow is sticky, meaning a sequence of operations can
142 * be done and overflow need only be checked at the end.
146 * overflow = set if an overflow occurs, is not affected otherwise
152 uint addu(uint x
, uint y
, ref bool overflow
)
154 immutable uint r
= x
+ y
;
163 assert(addu(2, 3, overflow
) == 5);
165 assert(addu(1, uint.max
- 1, overflow
) == uint.max
);
167 assert(addu(uint.min
, -1, overflow
) == uint.max
);
169 assert(addu(uint.max
, 1, overflow
) == uint.min
);
172 assert(addu(uint.min
+ 1, -1, overflow
) == uint.min
);
174 assert(addu(0, 0, overflow
) == 0);
175 assert(overflow
); // sticky
180 ulong addu(ulong x
, ulong y
, ref bool overflow
)
182 immutable ulong r
= x
+ y
;
191 assert(addu(2L, 3L, overflow
) == 5);
193 assert(addu(1, ulong.max
- 1, overflow
) == ulong.max
);
195 assert(addu(ulong.min
, -1L, overflow
) == ulong.max
);
197 assert(addu(ulong.max
, 1, overflow
) == ulong.min
);
200 assert(addu(ulong.min
+ 1, -1L, overflow
) == ulong.min
);
202 assert(addu(0L, 0L, overflow
) == 0);
203 assert(overflow
); // sticky
206 static if (is(ucent))
210 ucent addu(ucent x
, ucent y
, ref bool overflow
)
212 immutable ucent r
= x
+ y
;
221 assert(addu(cast(ucent)2L, 3L, overflow
) == 5);
223 assert(addu(1, ucent.max
- 1, overflow
) == ucent.max
);
225 assert(addu(ucent.min
, -1L, overflow
) == ucent.max
);
227 assert(addu(ucent.max
, 1, overflow
) == ucent.min
);
230 assert(addu(ucent.min
+ 1, -1L, overflow
) == ucent.min
);
232 assert(addu(cast(ucent)0L, 0L, overflow
) == 0);
233 assert(overflow
); // sticky
238 /*******************************
239 * Subtract two signed integers, checking for overflow.
241 * The overflow is sticky, meaning a sequence of operations can
242 * be done and overflow need only be checked at the end.
246 * overflow = set if an overflow occurs, is not affected otherwise
252 int subs(int x
, int y
, ref bool overflow
)
254 immutable long r
= cast(long)x
- cast(long)y
;
255 if (r
< int.min || r
> int.max
)
263 assert(subs(2, -3, overflow
) == 5);
265 assert(subs(1, -int.max
+ 1, overflow
) == int.max
);
267 assert(subs(int.min
+ 1, 1, overflow
) == int.min
);
269 assert(subs(int.max
, -1, overflow
) == int.min
);
272 assert(subs(int.min
, 1, overflow
) == int.max
);
274 assert(subs(0, 0, overflow
) == 0);
275 assert(overflow
); // sticky
280 long subs(long x
, long y
, ref bool overflow
)
282 immutable long r
= cast(ulong)x
- cast(ulong)y
;
283 if (x
< 0 && y
>= 0 && r
>= 0 ||
284 x
>= 0 && y
< 0 && (r
< 0 || y
== long.min
))
292 assert(subs(2L, -3L, overflow
) == 5);
294 assert(subs(1L, -long.max
+ 1, overflow
) == long.max
);
296 assert(subs(long.min
+ 1, 1, overflow
) == long.min
);
298 assert(subs(-1L, long.min
, overflow
) == long.max
);
300 assert(subs(long.max
, -1, overflow
) == long.min
);
303 assert(subs(long.min
, 1, overflow
) == long.max
);
305 assert(subs(0L, 0L, overflow
) == 0);
306 assert(overflow
); // sticky
313 cent subs(cent x
, cent y
, ref bool overflow
)
315 immutable cent r
= cast(ucent)x
- cast(ucent)y
;
316 if (x
< 0 && y
>= 0 && r
>= 0 ||
317 x
>= 0 && y
< 0 && (r
< 0 || y
== long.min
))
325 assert(subs(cast(cent)2L, -3L, overflow
) == 5);
327 assert(subs(1L, -cent.max
+ 1, overflow
) == cent.max
);
329 assert(subs(cent.min
+ 1, 1, overflow
) == cent.min
);
331 assert(subs(-1L, cent.min
, overflow
) == cent.max
);
333 assert(subs(cent.max
, -1, overflow
) == cent.min
);
336 assert(subs(cent.min
, 1, overflow
) == cent.max
);
338 assert(subs(cast(cent)0L, 0L, overflow
) == 0);
339 assert(overflow
); // sticky
344 /*******************************
345 * Subtract two unsigned integers, checking for overflow (aka borrow).
347 * The overflow is sticky, meaning a sequence of operations can
348 * be done and overflow need only be checked at the end.
352 * overflow = set if an overflow occurs, is not affected otherwise
358 uint subu(uint x
, uint y
, ref bool overflow
)
368 assert(subu(3, 2, overflow
) == 1);
370 assert(subu(uint.max
, 1, overflow
) == uint.max
- 1);
372 assert(subu(1, 1, overflow
) == uint.min
);
374 assert(subu(0, 1, overflow
) == uint.max
);
377 assert(subu(uint.max
- 1, uint.max
, overflow
) == uint.max
);
379 assert(subu(0, 0, overflow
) == 0);
380 assert(overflow
); // sticky
386 ulong subu(ulong x
, ulong y
, ref bool overflow
)
396 assert(subu(3UL, 2UL, overflow
) == 1);
398 assert(subu(ulong.max
, 1, overflow
) == ulong.max
- 1);
400 assert(subu(1UL, 1UL, overflow
) == ulong.min
);
402 assert(subu(0UL, 1UL, overflow
) == ulong.max
);
405 assert(subu(ulong.max
- 1, ulong.max
, overflow
) == ulong.max
);
407 assert(subu(0UL, 0UL, overflow
) == 0);
408 assert(overflow
); // sticky
411 static if (is(ucent))
415 ucent subu(ucent x
, ucent y
, ref bool overflow
)
425 assert(subu(cast(ucent)3UL, 2UL, overflow
) == 1);
427 assert(subu(ucent.max
, 1, overflow
) == ucent.max
- 1);
429 assert(subu(1UL, 1UL, overflow
) == ucent.min
);
431 assert(subu(cast(ucent)0UL, 1UL, overflow
) == ucent.max
);
434 assert(subu(ucent.max
- 1, ucent.max
, overflow
) == ucent.max
);
436 assert(subu(cast(ucent)0UL, 0UL, overflow
) == 0);
437 assert(overflow
); // sticky
442 /***********************************************
447 * overflow = set if x cannot be negated, is not affected otherwise
453 int negs(int x
, ref bool overflow
)
463 assert(negs(0, overflow
) == -0);
465 assert(negs(1234, overflow
) == -1234);
467 assert(negs(-5678, overflow
) == 5678);
469 assert(negs(int.min
, overflow
) == -int.min
);
471 assert(negs(0, overflow
) == -0);
472 assert(overflow
); // sticky
477 long negs(long x
, ref bool overflow
)
487 assert(negs(0L, overflow
) == -0);
489 assert(negs(1234L, overflow
) == -1234);
491 assert(negs(-5678L, overflow
) == 5678);
493 assert(negs(long.min
, overflow
) == -long.min
);
495 assert(negs(0L, overflow
) == -0);
496 assert(overflow
); // sticky
503 cent negs(cent x
, ref bool overflow
)
513 assert(negs(cast(cent)0L, overflow
) == -0);
515 assert(negs(cast(cent)1234L, overflow
) == -1234);
517 assert(negs(cast(cent)-5678L, overflow
) == 5678);
519 assert(negs(cent.min
, overflow
) == -cent.min
);
521 assert(negs(cast(cent)0L, overflow
) == -0);
522 assert(overflow
); // sticky
527 /*******************************
528 * Multiply two signed integers, checking for overflow.
530 * The overflow is sticky, meaning a sequence of operations can
531 * be done and overflow need only be checked at the end.
535 * overflow = set if an overflow occurs, is not affected otherwise
541 int muls(int x
, int y
, ref bool overflow
)
543 long r
= cast(long)x
* cast(long)y
;
544 if (r
< int.min || r
> int.max
)
552 assert(muls(2, 3, overflow
) == 6);
554 assert(muls(-200, 300, overflow
) == -60_000);
556 assert(muls(1, int.max
, overflow
) == int.max
);
558 assert(muls(int.min
, 1, overflow
) == int.min
);
560 assert(muls(int.max
, 2, overflow
) == (int.max
* 2));
563 assert(muls(int.min
, -1, overflow
) == int.min
);
565 assert(muls(0, 0, overflow
) == 0);
566 assert(overflow
); // sticky
571 long muls(long x
, long y
, ref bool overflow
)
573 immutable long r
= cast(ulong)x
* cast(ulong)y
;
575 if ((x
& not0or1
) && ((r
== y
)? r
: (r
/ x
) != y
))
583 assert(muls(2L, 3L, overflow
) == 6);
585 assert(muls(-200L, 300L, overflow
) == -60_000);
587 assert(muls(1, long.max
, overflow
) == long.max
);
589 assert(muls(long.min
, 1L, overflow
) == long.min
);
591 assert(muls(long.max
, 2L, overflow
) == (long.max
* 2));
594 assert(muls(-1L, long.min
, overflow
) == long.min
);
597 assert(muls(long.min
, -1L, overflow
) == long.min
);
599 assert(muls(0L, 0L, overflow
) == 0);
600 assert(overflow
); // sticky
607 cent muls(cent x
, cent y
, ref bool overflow
)
609 immutable cent r
= cast(ucent)x
* cast(ucent)y
;
611 if ((x
& not0or1
) && ((r
== y
)? r
: (r
/ x
) != y
))
619 assert(muls(cast(cent)2L, 3L, overflow
) == 6);
621 assert(muls(cast(cent)-200L, 300L, overflow
) == -60_000);
623 assert(muls(1, cent.max
, overflow
) == cent.max
);
625 assert(muls(cent.min
, 1L, overflow
) == cent.min
);
627 assert(muls(cent.max
, 2L, overflow
) == (cent.max
* 2));
630 assert(muls(-1L, cent.min
, overflow
) == cent.min
);
633 assert(muls(cent.min
, -1L, overflow
) == cent.min
);
635 assert(muls(cast(cent)0L, 0L, overflow
) == 0);
636 assert(overflow
); // sticky
641 /*******************************
642 * Multiply two unsigned integers, checking for overflow (aka carry).
644 * The overflow is sticky, meaning a sequence of operations can
645 * be done and overflow need only be checked at the end.
649 * overflow = set if an overflow occurs, is not affected otherwise
655 uint mulu(uint x
, uint y
, ref bool overflow
)
657 immutable ulong r
= ulong(x
) * ulong(y
);
665 void test(uint x
, uint y
, uint r
, bool overflow
) @nogc nothrow
668 assert(mulu(x
, y
, o
) == r
);
669 assert(o
== overflow
);
671 test(2, 3, 6, false);
672 test(1, uint.max
, uint.max
, false);
673 test(0, 1, 0, false);
674 test(0, uint.max
, 0, false);
675 test(uint.max
, 2, 2 * uint.max
, true);
676 test(1 << 16, 1U << 16, 0, true);
678 bool overflow
= true;
679 assert(mulu(0, 0, overflow
) == 0);
680 assert(overflow
); // sticky
685 ulong mulu(ulong x
, uint y
, ref bool overflow
)
696 ulong mulu(ulong x
, ulong y
, ref bool overflow
)
698 immutable ulong r
= x
* y
;
708 void test(T
, U
)(T x
, U y
, ulong r
, bool overflow
) @nogc nothrow
711 assert(mulu(x
, y
, o
) == r
);
712 assert(o
== overflow
);
714 // One operand is zero
715 test(0, 3, 0, false);
716 test(0UL, 3, 0, false);
717 test(0UL, 3UL, 0, false);
718 test(3, 0, 0, false);
719 test(3UL, 0, 0, false);
720 test(3UL, 0UL, 0, false);
722 test(2, 3, 6, false);
723 test(2UL, 3, 6, false);
724 test(2UL, 3UL, 6, false);
725 // At the 32/64 border
726 test(1, ulong(uint.max
), uint.max
, false);
727 test(1UL, ulong(uint.max
), uint.max
, false);
728 test(ulong(uint.max
), 1, uint.max
, false);
729 test(ulong(uint.max
), 1UL, uint.max
, false);
730 test(1, 1 + ulong(uint.max
), 1 + ulong(uint.max
), false);
731 test(1UL, 1 + ulong(uint.max
), 1 + ulong(uint.max
), false);
732 test(1 + ulong(uint.max
), 1, 1 + ulong(uint.max
), false);
733 test(1 + ulong(uint.max
), 1UL, 1 + ulong(uint.max
), false);
735 test(1, ulong.max
, ulong.max
, false);
736 test(1UL, ulong.max
, ulong.max
, false);
737 test(ulong.max
, 1, ulong.max
, false);
738 test(ulong.max
, 1UL, ulong.max
, false);
740 test(0, 1, 0, false);
741 test(0, ulong.max
, 0, false);
742 test(ulong.max
, 2, 2 * ulong.max
, true);
743 test(1UL << 32, 1UL << 32, 0, true);
745 bool overflow
= true;
746 assert(mulu(0UL, 0UL, overflow
) == 0);
747 assert(overflow
); // sticky
750 static if (is(ucent))
754 ucent mulu(ucent x
, ucent y
, ref bool overflow
)
756 immutable ucent r
= x
* y
;
757 if (x
&& (r
/ x
) != y
)
764 void test(ucent x
, ucent y
, ucent r
, bool overflow
) @nogc nothrow
767 assert(mulu(x
, y
, o
) == r
);
768 assert(o
== overflow
);
770 test(2, 3, 6, false);
771 test(1, ucent.max
, ucent.max
, false);
772 test(0, 1, 0, false);
773 test(0, ucent.max
, 0, false);
774 test(ucent.max
, 2, 2 * ucent.max
, true);
775 test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true);
777 bool overflow
= true;
778 assert(mulu(0UL, 0UL, overflow
) == 0);
779 assert(overflow
); // sticky