summaryrefslogtreecommitdiff
path: root/ext/rational/rational.c
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-02-05 14:11:08 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-02-05 14:11:08 +0000
commitd2e30d50cf20a87f6d2e8a2cfd2b559af6da28bf (patch)
tree02c2fc5104feac11b2723360d56aa22a544d3a57 /ext/rational/rational.c
parent4abbe7814af053438de0c863b0e0803dae79804a (diff)
* ext/rational/rational.c: Added to provide a fast implementation
of Fixnum#gcd (and maybe some others in the future) in C. The base code was submitted by Kurt Stephens. [Feature #2561] * ext/rational/lib/rational.rb: Moved from lib/rational.rb. Make overall code optimization; submitted by Kurt Stephens. [Feature #2561] * test/rational/test_rational.rb, test/rational/test_rational2.rb: Add tests for Rational, ported from trunk. * test/rational/test_fixnum_gcd.rb: Add a test for Integer#gcd. Case values are only provided for i386 and amd64 at the moment; submitted by Kurt Stephens. [Feature #2561] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@26581 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/rational/rational.c')
-rw-r--r--ext/rational/rational.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/ext/rational/rational.c b/ext/rational/rational.c
new file mode 100644
index 0000000000..18024e9497
--- /dev/null
+++ b/ext/rational/rational.c
@@ -0,0 +1,42 @@
+#include "ruby.h"
+
+/*
+ * call-seq:
+ * fixnum.gcd(fixnum) -> fixnum
+ *
+ * Fixnum-specific optimized version of Integer#gcd. Delegates to
+ * Integer#gcd as necessary.
+ */
+static VALUE
+fix_gcd(self, other)
+ VALUE self, other;
+{
+ long a, b, min, max;
+
+ /*
+ * Note: Cannot handle values <= FIXNUM_MIN here due to overflow during negation.
+ */
+ if (!FIXNUM_P(other) ||
+ (a = FIX2LONG(self)) <= FIXNUM_MIN ||
+ (b = FIX2LONG(other)) <= FIXNUM_MIN ) {
+ /* Delegate to Integer#gcd */
+ return rb_call_super(1, &other);
+ }
+
+ min = a < 0 ? -a : a;
+ max = b < 0 ? -b : b;
+
+ while (min > 0) {
+ long tmp = min;
+ min = max % min;
+ max = tmp;
+ }
+
+ return LONG2FIX(max);
+}
+
+void
+Init_rational()
+{
+ rb_define_method(rb_cFixnum, "gcd", fix_gcd, 1);
+}