Haskell工程符号

Haskell工程符号,haskell,floating-point,formatting,floating-point-precision,scientific-notation,Haskell,Floating Point,Formatting,Floating Point Precision,Scientific Notation,是否有现有的Haskell函数提供工程符号格式(作为字符串) 如果没有,我读到printf可以通过向PrintfArg添加实例来扩展。你认为这是一个好的解决方案吗 所谓工程符号,我指的是一种指数符号,它的指数是3的倍数,在这里有一个expt函数,它将以这种方式帮助格式化数字,尽管它在一个非常混乱的库中,我担心,你必须从文本转换为字符串 这似乎是唯一可用的功能,但您可以自己制作。我不知道标准功能。向printf添加一些东西是一种方法,但使用起来会有点烦人(因为您需要为工程符号格式的数字添加一种新

是否有现有的Haskell函数提供工程符号格式(作为字符串)

如果没有,我读到
printf
可以通过向
PrintfArg
添加实例来扩展。你认为这是一个好的解决方案吗


所谓工程符号,我指的是一种指数符号,它的指数是3的倍数,在这里有一个
expt
函数,它将以这种方式帮助格式化数字,尽管它在一个非常混乱的库中,我担心,你必须从
文本
转换为
字符串


这似乎是唯一可用的功能,但您可以自己制作。

我不知道标准功能。向printf添加一些东西是一种方法,但使用起来会有点烦人(因为您需要为工程符号格式的数字添加一种新类型,并将数字转换为这种类型,然后再进行传递)。简单地编写一个独立函数,类型如下

showEngineer :: Double -> String

从长远来看,这可能是一个更简单、更具可读性的解决方案。

经过一些研究,我设法得到了我想要的。 通过以下几个步骤实现工程格式工作的功能:

1。将指数与尾数分离

有必要把尾数的指数分开。 函数
decodeFloat
(由
base
提供)对浮点数进行解码,并返回尾数和指数,其幂为2(尾数2*2^ex2)

2。获取以正确基数表示的尾数和指数

需要10次幂的转换。这就是该功能的作用

decompose :: Double -> (Double,Int)
decompose val = if mant2 > 0 
                     then (mant10,ex10)
                     else (-mant10,ex10)
  where
        (mant2,ex2) = decodeFloat val
        res = logBase 10 (fromIntegral (abs mant2)::Double) + logBase 10 (2 ** (fromIntegral ex2::Double)) 
        ex10 = floor res
        mant10 = 10**(res - (fromIntegral ex10::Double))
3。将指数设置为3的倍数

函数
ingen
测试指数整数除法的结果,并对尾数和指数进行调整

ingen :: Double -> (Double,Int)
ingen val 
  | mod ex 3 == 0 = (mant,ex)
  | mod ex 3 == 1 = (mant*10,ex-1)
  | mod ex 3 == 2 = (mant*100,ex-2)
  where
        (mant,ex) = decompose val
以下是一些转换:

Prelude> ingen 10e7
(99.99999999999979,6)
Prelude> ingen 10e-41
(100.0,-42)
Prelude> ingen (-72364e81)
(-72.36399999999853,84)

我使用quickCheck在大范围和大量值上执行了一些测试。尽管值差很小(由于精度的原因,在计算过程中四舍五入),但转换似乎运行良好

但是,应进行另一次核查


如果您在这些函数中发现错误或改进,请与他人分享。

这似乎不符合规范“其指数为3的倍数”。具体地说,
expt10
给出了
“1e2”
,2不是3的倍数。@DanielWagner这很奇怪;在图书馆里,它说它是用工程符号表示的。那可能是个错误。