haskell 使用printf的条件宽度和精度

pftdvrlh  于 2022-11-14  发布在  其他
关注(0)|答案(4)|浏览(99)

我正想打印如下:

1.0 -> 1
18.0 -> 18
370.0 -> 370
1.2 -> 1.2
3.4 -> 3.4

换句话说,当尾数为0.0时,打印为整数,否则打印为精度为1的浮点数。我可以检查浮点数是否实际上是整数,并相应地打印,但有没有办法让printf做这件事?我检查了printf "%2f" 10.0打印10.0,所以,这并不明显。

5fjcxozz

5fjcxozz1#

根据Hackage文档,您可能无法直接使用printf来实现这一点。
Haskell printf将尽可能在小数点后放置零。
如果你一定要去掉尾随的.0,你可能需要寻找一种替代的方法来格式化你的数据。作为一个快速而肮脏的黑客,你可以从Numeric中使用floatToDigits

import Numeric (floatToDigits)
showFloat :: RealFloat a => a -> String
showFloat n = (concat $ map show prefix) <>
              separator                  <>
              (concat $ map show suffix)
  where
    (digits, precision) = floatToDigits 10 n
    (prefix, suffix)    = splitAt precision digits
    separator           = if null suffix then "" else "."

main = do
  putStrLn $ showFloat (0.123 :: Float) -- 0.123
  putStrLn $ showFloat (1.230 :: Float) -- 1.23
  putStrLn $ showFloat (12.30 :: Float) -- 12.3
  putStrLn $ showFloat (123.0 :: Float) -- 123
c3frrgcw

c3frrgcw2#

我的pragmatic-show包有一个替代的Show类(和相应的print),它的浮点示例给予了您所要求的所有示例作为默认行为。

$ cabal new-repl --build-depends 'pragmatic-show'
...
> import qualified Text.Show.Pragmatic as SP
> SP.print 1.0
1
> SP.print 18.0
18
> SP.print 370.0
370
> SP.print 1.2
1.2
> SP.print 3.4
3.4

请注意,与您的临时解决方案不同,它 * 不会 * 压制小而重要的小数部分:

> SP.print 5.0000245
5.0000245

然而,它确实抑制了微小的浮点偏差,这种偏差几乎不可避免地出现在任何应该解析地给予整数的计算中:

> SP.print $ 1 + sin pi
1
> Prelude.print $ 1 + sin pi
1.0000000000000002
jhkqcmku

jhkqcmku3#

我最后得到了这个:

fmt :: Float -> String
fmt x = if int then show y else printf "%.1f" x
  where
    y = round x :: Int
    int = abs (x - fromIntegral y) < 0.1
5vf7fwbs

5vf7fwbs4#

%g使用最短的表示法。
浮点数通常不是以10为基数存储的,而是以2为基数存储的(性能、大小、实用性等原因)。然而,无论你的表示是以什么为基数,总会有一些有理数在存储它们的变量的任意大小限制下是不可表达的。
如果最短的表示有超过16位数,printf将通过剪切最后的2位数来缩短数字串,留下3122.550000000000,它实际上是最短形式的3122.55,解释您获得的结果。
一般来说,%g总是会给予尽可能短的结果,这意味着如果表示数字的数字序列可以被缩短而不损失任何精度,那么它就会被缩短。

#include <stdio.h>

int main(void) {
    double x = 123.0;
    printf("%e\n", x);
    printf("%f\n", x);
    printf("%g\n", x);

    double y = 123.10;
    printf("%e\n", y);
    printf("%f\n", y);
    printf("%g\n", y);
}

输出量:

1.230000e+02
123.000000
123

1.231000e+02
123.100000
123.1

相关问题