工程符号 Haskell

Engineering notation with Haskell

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

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


通过工程符号,我指的是指数符号,其指数是 3 的倍数。

Data.Text.Format 中有一个 expt 函数可以帮助以这种方式格式化数字,但恐怕它在一个非常模糊的库中,你必须从 TextString.

似乎只有这一个可用,但您总是可以自己制作一个。

我不知道标准函数。添加一些东西到 printf 是一种可行的方法,但使用起来会有点烦人(因为你需要为工程符号格式的数字添加一个新类型,并在处理之前将数字转换为这种类型他们关闭)。只需编写一个类型为

的独立函数
showEngineer :: Double -> String

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

经过一番研究,我设法得到了我想要的东西。 只需几步即可获得工程格式的功能:

1.将指数与尾数分离

有必要将指数与尾数分开。 函数 decodeFloat(由 base 提供)解码浮点数和 return 尾数和指数 的 2 次幂(mant2 * 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做了一些大范围、大数值的测试。转换 似乎 尽管存在 非常小的 值差异(由于精度而在计算期间四舍五入?)。

但是,还需要再验证一下。

如果您在这些功能中发现错误或改进,请分享。