我想Rational
在它们的十进制扩展中显示一些值。也就是说3 % 4
,我宁愿显示,而不是显示0.75
。我希望这个函数是 type Int -> Rational -> String
。第一个Int
是指定最大小数位数,因为Rational
扩展可能是非终止的。
问问题
1982 次
5 回答
9
你可以做到。不优雅,但可以完成工作:
import Numeric
import Data.Ratio
display :: Int -> Rational -> String
display n x = (showFFloat (Just n) $ fromRat x) ""
于 2015-06-19T07:01:00.540 回答
8
这是一个不使用浮点数的任意精度解决方案:
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)
于 2015-06-19T12:36:48.137 回答
7
重用库代码的任意精度版本:
import Data.Number.CReal
display :: Int -> Rational -> String
display digits num = showCReal digits (fromRational num)
我知道我之前看过一个函数,它以一种更容易检查的方式将有理数转换为数字(即,这使得数字开始重复的位置非常清楚),但我现在似乎找不到它。无论如何,如果需要的话,写起来并不难;您只需编写通常的长除法算法并注意您已经完成的除法。
于 2015-06-19T17:18:51.403 回答
2
这是我几周前写的。您可以指定您想要的小数位数(正确四舍五入),或者只是传递Nothing
,在这种情况下它将打印完整的精度,包括标记重复的小数。
module ShowRational where
import Data.List(findIndex, splitAt)
-- | Convert a 'Rational' to a 'String' using the given number of decimals.
-- If the number of decimals is not given the full precision is showed using (DDD) for repeating digits.
-- E.g., 13.7/3 is shown as \"4.5(6)\".
showRational :: Maybe Int -> Rational -> String
showRational (Just n) r =
let d = round (abs r * 10^n)
s = show (d :: Integer)
s' = replicate (n - length s + 1) '0' ++ s
(h, f) = splitAt (length s' - n) s'
in (if r < 0 then "-" else "") ++ h ++ "." ++ f
-- The length of the repeating digits is related to the totient function of the denominator.
-- This means that the complexity of computing them is at least as bad as factoring, i.e., it quickly becomes infeasible.
showRational Nothing r =
let (i, f) = properFraction (abs r) :: (Integer, Rational)
si = if r < 0 then "-" ++ show i else show i
decimals f = loop f [] ""
loop x fs ds =
if x == 0 then
ds
else
case findIndex (x ==) fs of
Just i -> let (l, r) = splitAt i ds in l ++ "(" ++ r ++ ")"
Nothing -> let (c, f) = properFraction (10 * x) :: (Integer, Rational) in loop f (fs ++ [x]) (ds ++ show c)
in if f == 0 then si else si ++ "." ++ decimals f
于 2015-06-22T12:12:22.217 回答
2
import Data.List as L
import Data.Ratio
display :: (Integral i, Show i) => Int -> Ratio i -> String
display len rat = (if num < 0 then "-" else "") ++ show ip ++ "." ++ L.take len (go (abs num - ip * den))
where
num = numerator rat
den = denominator rat
ip = abs num `quot` den
go 0 = ""
go x = shows d (go next)
where
(d, next) = (10 * x) `quotRem` den
于 2016-11-19T15:35:04.110 回答