From 15af272eb3d859b993a0287919f33cb1317d4e52 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Thu, 19 Dec 2019 09:08:20 -0500 Subject: [PATCH 1/3] Fix abs in the Num instance of Frac `abs x * signum x` is supposed to be the same as `x`. Make this the case, as well as making `abs` work as you'd expect for fractions in math. --- posts/2019-12-14-stern-brocot.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2019-12-14-stern-brocot.markdown b/posts/2019-12-14-stern-brocot.markdown index b4375b60..1f7508a5 100644 --- a/posts/2019-12-14-stern-brocot.markdown +++ b/posts/2019-12-14-stern-brocot.markdown @@ -112,7 +112,7 @@ instance Num Frac where (x :/ xd) * (y :/ yd) = (x * y) :/ (xd * yd) (x :/ xd) + (y :/ yd) = (x * yd + y * xd) :/ (xd * yd) signum = (:/ 1) . signum . numerator - abs = id + abs (x :/ xd) = abs x :/ xd (x :/ xd) - (y :/ yd) = (x * yd - y * xd) :/ (xd * yd) ``` From 7e4b8a85a9df210ed55779ca0aaaeccff903c911 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Thu, 19 Dec 2019 09:20:38 -0500 Subject: [PATCH 2/3] Make the Num instance compile Turn `Natural`s into `Integer`s before trying to multiply them by other `Integer`s, and don't call a non-existent `numerator` function. --- posts/2019-12-14-stern-brocot.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/posts/2019-12-14-stern-brocot.markdown b/posts/2019-12-14-stern-brocot.markdown index 1f7508a5..d3e20ad1 100644 --- a/posts/2019-12-14-stern-brocot.markdown +++ b/posts/2019-12-14-stern-brocot.markdown @@ -110,10 +110,10 @@ Th `Num` instance is pretty much just a restating of the axioms for fractions. instance Num Frac where fromInteger n = fromInteger n :/ 1 (x :/ xd) * (y :/ yd) = (x * y) :/ (xd * yd) - (x :/ xd) + (y :/ yd) = (x * yd + y * xd) :/ (xd * yd) - signum = (:/ 1) . signum . numerator + (x :/ xd) + (y :/ yd) = (x * toInteger yd + y * toInteger xd) :/ (xd * yd) + signum (x :/ _) = signum x :/ 1 abs (x :/ xd) = abs x :/ xd - (x :/ xd) - (y :/ yd) = (x * yd - y * xd) :/ (xd * yd) + (x :/ xd) - (y :/ yd) = (x * toInteger yd - y * toInteger xd) :/ (xd * yd) ``` From bf2ccfeda2926d5e4335652b0587ee6d42d1252b Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Thu, 19 Dec 2019 09:37:39 -0500 Subject: [PATCH 3/3] Convert between `Natural` and `Integer` properly everywhere else --- posts/2019-12-14-stern-brocot.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/posts/2019-12-14-stern-brocot.markdown b/posts/2019-12-14-stern-brocot.markdown index d3e20ad1..87bd09ff 100644 --- a/posts/2019-12-14-stern-brocot.markdown +++ b/posts/2019-12-14-stern-brocot.markdown @@ -88,10 +88,10 @@ In Haskell, that kind of means doing the following: ```haskell instance Eq Frac where - (x :/ xd) == (y :/ yd) = (x * yd) == (y * xd) + (x :/ xd) == (y :/ yd) = (x * toInteger yd) == (y * toInteger xd) instance Ord Frac where - compare (x :/ xd) (y :/ yd) = compare (x * yd) (y * xd) + compare (x :/ xd) (y :/ yd) = compare (x * toInteger yd) (y * toInteger xd) ``` We don't have real quotient types in Haskell, but this gets the idea across: we @@ -184,10 +184,10 @@ type Rational = [Bit] abs :: Frac -> Rational abs = unfoldr f where - f (n :/ d) = case compare n d of + f (n :/ d) = case compare n (toInteger d) of EQ -> Nothing - LT -> Just (O, n :/ (d - n)) - GT -> Just (I, (n - d) :/ d) + LT -> Just (O, n :/ (d - fromInteger n)) + GT -> Just (I, (n - toInteger d) :/ d) ``` And since we used `unfoldr`, it's easy to reverse the algorithm to convert from @@ -197,8 +197,8 @@ the representation to a pair of numbers. rep :: Rational -> Frac rep = foldr f (1 :/ 1) where - f I (n :/ d) = (n + d) :/ d - f O (n :/ d) = n :/ (n + d) + f I (n :/ d) = (n + toInteger d) :/ d + f O (n :/ d) = n :/ (fromInteger n + d) ``` Now `abs . rep` is the identity function, and `rep . abs` reduces a fraction!