是否有现有的Haskell函数提供工程符号格式(字符串)?
如果没有,我读到printf
可以通过向PrintfArg
添加一个实例来扩展。你认为这是一个好的解决方案吗?
通过工程符号,我指的是指数是3的倍数的指数符号
经过一番研究,我终于得到了我想要的东西。通过几个步骤获得工程格式的功能:
1.将指数与尾数分离
有必要把指数和尾数分开。函数decodeFloat
(由base
提供)解码浮点数,并返回尾数和指数的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对大范围和大量值进行了一些测试。尽管的值差很小,但转换似乎运行良好(由于精度的原因,在计算过程中四舍五入?)。
但是,应进行另一次验证。
如果您发现这些功能存在错误或改进,请与我们分享。
在Data.Text.Format
中,有一个expt
函数可以帮助以这种方式格式化数字,尽管它位于一个非常模糊的库中,恐怕您必须从Text
转换为String
。
这似乎是唯一可用的,但你总是可以自己做一个。
我不知道标准函数。向printf
添加一些内容是一种方法,但使用起来会有点烦人(因为您需要为工程符号格式的数字添加一个新类型,并在将数字转换为该类型后再将其传递)。简单地用这样的类型编写一个独立的函数
showEngineer :: Double -> String
从长远来看,这可能是一个更简单、更可读的解决方案。