Haskell 如何将有理数转换为;“漂亮”;一串

Haskell 如何将有理数转换为;“漂亮”;一串,haskell,formatting,rational-number,Haskell,Formatting,Rational Number,我想在十进制扩展中显示一些Rational值。也就是说,我宁愿显示0.75,而不是显示3%4。我希望这个函数的类型是Int->Rational->String。第一个Int是指定最大小数位数,因为Rational扩展可能是非终止的 而这对我没有帮助。在哪里可以找到此功能?您可以创建它。虽然不优雅,但能做到: import Numeric import Data.Ratio display :: Int -> Rational -> String display n x = (sho

我想在十进制扩展中显示一些
Rational
值。也就是说,我宁愿显示
0.75,而不是显示
3%4
。我希望这个函数的类型是
Int->Rational->String
。第一个
Int
是指定最大小数位数,因为
Rational
扩展可能是非终止的


而这对我没有帮助。在哪里可以找到此功能?

您可以创建它。虽然不优雅,但能做到:

import Numeric
import Data.Ratio

display :: Int -> Rational -> String
display n x = (showFFloat (Just n) $ fromRat x) ""

以下是不使用浮动的任意精度解决方案:

导入数据。比率
显示::Int->Rational->String
显示len rat=(如果num<0,则为“-”else”“)+(显示d(“.“++获取len(下一步)))
哪里
(d,next)=abs num`quotRem`den
num=分子鼠
den=分母鼠
go 0=“”
走x=让(d,next)=(10*x)`quotRem`den
在节目d中(下一步)

可重复使用的任意精度版本:


我知道我以前见过一个函数,它以一种更容易检查的方式将有理数转换为数字(也就是说,这使得数字开始重复的位置非常清楚),但我现在似乎找不到它。在任何情况下,这并不难写,如果这被证明是一种需要;您只需编写通常的长除法算法,并查看您已经完成的除法。

这是我几周前编写的一个除法。您可以指定所需的小数位数(正确舍入),或者只传递
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
模块ShowRational在哪里
导入数据列表(findIndex,splitAt)
--|使用给定的小数位数将“有理数”转换为“字符串”。
--如果未给出小数位数,则使用(DDD)表示重复数字的完整精度。
--例如,13.7/3显示为“4.5(6)”。
showRational::可能是Int->Rational->String
showRational(Just n)r=
设d=圆形(abs r*10^n)
s=显示(d::整数)
s'=复制(n-长度s+1)'0'+s
(h,f)=在(长度s'-n)s'处拆分
在(如果r<0,则“-”else“)++h++++”中
--重复数字的长度与分母的toticent函数有关。
--这意味着计算它们的复杂性至少和因子分解一样糟糕,也就是说,它很快变得不可行。
showr=
设(i,f)=性质分数(absr)::(整数,有理数)
si=如果r<0,则“-”++显示i,否则显示i
小数点f=循环f[]”
循环x fs ds=
如果x==0,则
ds
其他的
案例findIndex(x==)fs的
Just i->let(l,r)=在l++“(“++r++”)中拆分i ds
Nothing->let(c,f)=properFraction(10*x)::(整数,有理数)在循环f(fs++[x])(ds++show c)
如果f==0,则si else si++“+++小数点f
导入数据。列表为L
导入数据。比率
显示::(积分i,显示i)=>Int->Ratio i->String
显示len rat=(如果num<0,则“-”else“)++显示ip+++”++L.取len(go(abs num-ip*den))
哪里
num=分子鼠
den=分母鼠
ip=abs编号'quot'den
go 0=“”
go x=显示d(下一步)
哪里
(d,next)=(10*x)`quotRem`den

使用
Numeric.fromRat
转换为
realfoat
,然后使用
Numeric.show*float
函数显示浮点值,这不是一个选项吗?当您最后只需要十进制近似值时,您确定需要
Rational
?十进制近似值只是为了使调试更容易。我想要高达数千位的准确度。如果没有人提供标准的库解决方案,我会接受这一点。
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
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