[Haskell] 数字类型之间的转换
受Common Lisp与Scheme影响,Haskell提供了多种类型的数字。
使用类型类(type class),数字类型上面的操作符或者函数,大多是重载的(overloaded)。
(甚至,值也是重载的,见1::Num a => a 。。
不同的数值定义在了不同的类型类中。
> :t 1
> 1 :: Num a => a
> :t 1.0
> 1.0 :: Fractional a => a
如图,类型类之间是有包含关系的。。
例如,Num类型类是Eq的子集,因为每一个数字必须首先能被判断相等性。
Num的子集Real也是Ord的子集,因为实数可以比较大小,而复数不能。
Integral类型类包含了所有限制大小和无限制大小的整数。
Fractional类型类包含所有非整数类型的数字。
Floating类型类包含了所有浮点数类型的数字,包括实数和复数。
Prelude仅包含一部分数字类型,
Int,定宽整数(fixed sized integer)
Integer,任意精度的整数
Float,单精度浮点数
Double,双精度浮点数
其他数字类型,例如Rational和Complex定义在了库(library)中。
Rational类型的值是两个Integer的比例,定义在了Ratio库中。
(1)Integral to Num
Integral包含了所有的整数,该类型类两个常用的实例是Integer类型和Int类型。
Integer,表示任意精度的整数,也成为“大整数”(bignum,big-integer)。
Int,是定宽的整数,具体存储位宽取决于特定的机器,但至少应该包括-229~229-1范围内的整数。
我们主要使用fromIntegral
对Integral进行转换。
它把一个Integral类型类实例类型的值,转换成Num类型类实例类型的值。
fromIntegral :: (Integral a, Num b) => a -> b
例如,给定一个Int类型的值n,我们不能直接使用sqrt n
求平方根,
因为sqrt
只接受Floating类型类实例类型的参数。
sqrt :: Floating a => a -> a
我们必须写成,
sqrt (fromIntegral n)
关于Integer类型还有两个更具体的函数。
fromInteger :: Num a => Integer -> a
toInteger :: Integral a => a -> Integer
(2)Real to Fractional
RealFrac包含所有的整数和分数,该类型类两个常用的实例是Rational类型和Double类型。
Rational,任意精度的分数。
Double,双精度浮点数。
Real类型类包含Integral和RealFrac。
我们主要使用realToFrac
来对Real进行转换。
realToFrac :: (Real a, Fractional b) => a -> b
关于Rational类型还有两个更具体的函数。
fromRational :: Fractional a => Rational -> a
toRational :: Real a => a -> Rational
(3)RealFrac to Integral
这种转换可能会损失精度,我们可以使用下面4个函数。
ceiling :: (RealFrac a, Integral b) => a -> b
floor :: (RealFrac a, Integral b) => a -> b
truncate :: (RealFrac a, Integral b) => a -> b
round :: (RealFrac a, Integral b) => a -> b
(4)Float to Double
我们可以使用GHC.FLoat
module来对浮点数进行转换。
float2Double :: Float -> Double
double2Float :: Double -> Float
参考:
The Haskell 98 Report: Standard Haskell Classes
Converting numbers