summaryrefslogtreecommitdiff
path: root/internal.h
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-02-04 18:14:42 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-02-04 18:14:42 +0000
commit68e10755d469dfe26e3cf34439bae046dff06c1c (patch)
tree1a142600a9e59c0b0fbf4fc9d092228a804ff170 /internal.h
parentb163b3ff64638a012998078e7af78b5da69c2ab8 (diff)
fix description for current implementation
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57534 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'internal.h')
-rw-r--r--internal.h22
1 files changed, 17 insertions, 5 deletions
diff --git a/internal.h b/internal.h
index 7d9250c886..5baac16957 100644
--- a/internal.h
+++ b/internal.h
@@ -360,12 +360,24 @@ rb_fix_plus_fix(VALUE x, VALUE y)
#ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
long lz;
/* NOTE
- * (1) Fixnum's LSB is always 1.
+ * (1) `LONG2FIX(FIX2LONG(x)+FIX2LONG(y))`
+ + = `((lx*2+1)/2 + (ly*2+1)/2)*2+1`
+ + = `lx*2 + ly*2 + 1`
+ + = `(lx*2+1) + (ly*2+1) - 1`
+ + = `x + y - 1`
+ * (2) Fixnum's LSB is always 1.
* It means you can always run `x - 1` without overflow.
- * (2) Of course `z = x + (y-1)` may overflow.
- * Now z's LSB is always 1, and the MSB of true result is also 1.
- * You can get true result in long as `(1<<63)|(z>>1)`,
- * and it equals to `(z<<63)|(z>>1)` == `ror(z)`.
+ * (3) Of course `z = x + (y-1)` may overflow.
+ * At that time true value is
+ * * positive: 0b0 1xxx...1, and z = 0b1xxx...1
+ * * nevative: 0b1 0xxx...1, and z = 0b0xxx...1
+ * To convert this true value to long,
+ * (a) Use arithmetic shift
+ * * positive: 0b11xxx...
+ * * negative: 0b00xxx...
+ * (b) invert MSB
+ * * positive: 0b01xxx...
+ * * negative: 0b10xxx...
*/
if (__builtin_add_overflow((long)x, (long)y-1, &lz)) {
return rb_int2big(rb_overflowed_fix_to_int(lz));