# New Ticket Created by  Lanny Ripple 
# Please include the string:  [perl #69550]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=69550 >


>From 8a240dd7b58e36d2b563a87c63eb89336662ddb9 Mon Sep 17 00:00:00 2001
From: Lanny Ripple <[email protected]>
Date: Fri, 2 Oct 2009 15:00:18 -0500
Subject: [PATCH] add a cast for Num to Rat with optional error

---
 src/setting/Num.pm |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/src/setting/Num.pm b/src/setting/Num.pm
index 27fa8e6..9f69133 100644
--- a/src/setting/Num.pm
+++ b/src/setting/Num.pm
@@ -250,6 +250,34 @@ class Num is also {
         ~self
     }
 
+    sub _modf($num) { my $q = $num.Int; $num - $q, $q; }
+
+    multi method Rat($epsilon = 1.0e-6) {
+        my $num = +self;
+        my $signum = $num < 0 ?? -1 !! 1;
+        $num = -$num if $signum == -1;
+
+        # Find convergents of the continued fraction.
+
+        my ($r, $q) = _modf($num);
+        my ($a, $b) = 1, $q;
+        my ($c, $d) = 0, 1;
+
+        while $r != 0 && abs($num - ($b/$d)) > $epsilon {
+            ($r, $q) = _modf(1/$r);
+
+            ($a, $b) = ($b, $q*$b + $a);
+            ($c, $d) = ($d, $q*$d + $c);
+        }
+
+        # Note that this result has less error than any Rational with a
+        # smaller denominator but it is not (necessarily) the Rational
+        # with the smallest denominator that has less than $epsilon error.
+        # However, to find that Rational would take more processing.
+
+        Rat.new($signum * $b, $d);
+    }
+
     our Num multi method sec($base = 'radians') {
         my $x = self!to-radians($base);
         Q:PIR {
-- 
1.6.0.4



Reply via email to