在Haskell中打印浮点数

6
我有一个在Haskell中的函数,看起来像这样:

type Price    = Int

formatPence :: Price -> String
formatPence a = show (a `div` 100) ++ "." ++ show(a `mod` 100)

比如,如果我输入 formatPence 1023,输出应该是 "10.23"。但是如果我输入 1202,输出结果将会是 "12.2"。我需要添加什么?谢谢:)

3个回答

12

也许您想要的是 Numeric 中的各种 show*Float 函数之一?

> :m Numeric
> showFFloat (Just 2) 123.456 ""
123.45

这并没有回答问题,他想要一个类型为“Float -> String”的函数。 这样可以避免那一步,使得这个解决方案变得无用...如果他想要打印到文件怎么办。 - Famous Jameis
对于这样的函数,只需将浮点数抽象出来:(\f -> showFFloat (Just 2) f "") :: Float -> String - jlwoodwa

10

这是自计算机问世以来人们一直存在的标准问题,因此它可以通过古老的printf(Haskell基本上是从C中复制过来的)完美解决。

import Text.Printf

formatPence = printf "%.2f" . (/100) . fromIntegral

哦,需要注意的是...对于非常大的数值,这个方法存在精度问题,因为该方法中隐式使用了Double来进行除法运算,而Double的分辨率没有Int高。

Prelude Text.Printf> formatPence 10000000000000013
"100000000000000.13"
Prelude Text.Printf> formatPence 100000000000000013
"1000000000000000.10"
Prelude Text.Printf> formatPence 1000000000000000013
"10000000000000000.00"

所以如果你处理的金额达到数万亿美元,最好不要使用这个方法。

(我猜如果你正在处理这么多的金额,你可能不会在这里询问这个问题...而且你也不会使用Int。)

要解决这个问题,你可以使用原始方法,但仍然使用printf来格式化多余的零:

type Price' = Integer

formatPence' :: Price' -> String
formatPence' a = show (a `div` 100) ++ "." ++ printf "%02u" (a `mod` 100) 

这将能够处理任意荒谬的数量:

> formatPence' 1000000000000000103
"10000000000000001.03"
> formatPence' 6529857623987620347562395876204395876395762398417639852764958726398527634972365928376529384
"65298576239876203475623958762043958763957623984176398527649587263985276349723659283765293.84"

请注意,手动计算除余数(div/mod)在处理负数情况下会出现问题,但这很容易解决。


2
@SitiAisyah,把printf称为解决任何问题的完美方案是过于夸张了。我认为formatting提供了一个更好的替代方案来取代C语言中的printf。它避免了printf运行时格式字符串处理的错误风险,采用了强类型方法;缺点是当你犯错时,编译器可能会给出难以理解的错误信息。我个人希望有一个非常惯用、命名良好的blah -> String函数的大型集合,但我不确定是否有人有这样的集合。 - dfeuer
1
同意。我并不是printf的狂热支持者,因为它具有奇怪的可变参数签名,基本上只在运行时进行类型检查;但对于单个数字的简单格式化,它已经足够了,并且它在base中,所以对于这个特定的任务,我建议使用它。 - leftaroundabout

0

你需要在小数点后面补零。

twoDP :: Int -> String
twoDP v = if length str == 1 then '0':str else str
   where str = show v

你可以编写一个更通用的填充函数:
leadingZeros :: Int -> Int -> String
leadingZeros n v = replicate (n - length str) '0' ++ str
   where str = show v

在这种情况下,不要使用"show"或"printf"的浮点类型版本:那是一条通往疯狂之路。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接