Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a Rational into a "pretty" String?

I want to display some Rational values in their decimal expansion. That is, instead of displaying 3 % 4, I would rather display 0.75. I'd like this function to be of type Int -> Rational -> String. The first Int is to specify the maximum number of decimal places, since Rational expansions may be non-terminating.

Hoogle and the haddocks for Data.Ratio didn't help me. Where can I find this function?

like image 632
Mike Izbicki Avatar asked Jun 19 '15 06:06

Mike Izbicki


3 Answers

You can make it. Not elegant, but does the job:

import Numeric
import Data.Ratio

display :: Int -> Rational -> String
display n x = (showFFloat (Just n) $ fromRat x) ""
like image 200
Alec Avatar answered Oct 17 '22 10:10

Alec


Here is an arbitrary precision solution that doesn't use floats:

import Data.Ratio

display :: Int -> Rational -> String
display len rat = (if num < 0 then "-" else "") ++ (shows d ("." ++ take len (go next)))
    where
        (d, next) = abs num `quotRem` den
        num = numerator rat
        den = denominator rat

        go 0 = ""
        go x = let (d, next) = (10 * x) `quotRem` den
               in shows d (go next)
like image 23
xnyhps Avatar answered Oct 17 '22 10:10

xnyhps


Arbitrary precision version that re-uses library code:

import Data.Number.CReal

display :: Int -> Rational -> String
display digits num = showCReal digits (fromRational num)

I know I've seen a function before that converts rationals into digits in a way that's easier to inspect (i.e. that makes it quite clear where the digits start repeating), but I can't seem to find it now. In any case, it's not hard to write, if that turns out to be a need; you just code up the usual long-division algorithm and watch for divisions you've already done.

like image 25
Daniel Wagner Avatar answered Oct 17 '22 11:10

Daniel Wagner