summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorcremno <[email protected]>2016-05-10 19:07:57 +0200
committercremno <[email protected]>2016-05-10 19:10:49 +0200
commit6369374f79e01e099439c961fb22a05080f39d3d (patch)
tree87d1bd9b86ce2e4649afba78a4efe32fbb40953a /include
parent0be4b8960e1a04ff0681847811bee4398b5664a5 (diff)
downloadmruby-6369374f79e01e099439c961fb22a05080f39d3d.tar.gz
mruby-6369374f79e01e099439c961fb22a05080f39d3d.zip
add mrb_int_mul_overflow(); close #3149
- call __builtin_mul_overflow() if it's available - perform a 64-bit multiplication for 32-bit mrb_int (default) - otherwise a much slower method is used
Diffstat (limited to 'include')
-rw-r--r--include/mruby/numeric.h35
1 files changed, 35 insertions, 0 deletions
diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h
index b16c299a4..e4086487e 100644
--- a/include/mruby/numeric.h
+++ b/include/mruby/numeric.h
@@ -62,6 +62,12 @@ mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
return __builtin_sub_overflow(minuend, subtrahend, difference) || WBCHK(*difference);
}
+static inline mrb_bool
+mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product)
+{
+ return __builtin_mul_overflow(multiplier, multiplicand, product) || WBCHK(*product);
+}
+
#undef WBCHK
#else
@@ -92,6 +98,35 @@ mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK);
}
+static inline mrb_bool
+mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product)
+{
+#if MRB_INT_BIT == 32
+ int64_t n = (int64_t)multiplier * multiplicand;
+ *product = (mrb_int)n;
+ return !FIXABLE(n);
+#else
+ if (multiplier > 0) {
+ if (multiplicand > 0) {
+ if (multiplier > MRB_INT_MAX / multiplicand) return TRUE;
+ }
+ else {
+ if (multiplicand < MRB_INT_MAX / multiplier) return TRUE;
+ }
+ }
+ else {
+ if (multiplicand > 0) {
+ if (multiplier < MRB_INT_MAX / multiplicand) return TRUE;
+ }
+ else {
+ if (multiplier != 0 && multiplicand < MRB_INT_MAX / multiplier) return TRUE;
+ }
+ }
+ *product = multiplier * multiplicand;
+ return FALSE;
+#endif
+}
+
#undef MRB_INT_OVERFLOW_MASK
#undef mrb_uint
#undef MRB_UINT_MAKE