Difference between revisions of "Converting numbers"
m (added FAQ and Idioms categories) 
(don't use realToFrac for fractional types) 

(5 intermediate revisions by 4 users not shown)  
Line 1:  Line 1:  
−  +  Conversion between numerical types in Haskell must be done explicitly. This is unlike many traditional languages (such as C or Java) that automatically coerce between numerical types. 

−  == Converting from 
+  == Converting from and between integral types (integerlike types) == 
−  Integral types are ones which may only contain whole numbers and not fractions. <hask>Int</hask> (fixedsize machine integers) and <hask>Integer</hask> (arbitrary precision integers) are the two Integral types in the standard Haskell libraries. 

+  <hask>Integral</hask> types contain only whole numbers and not fractions. The most commonly used integral types are: 

−  The workhorse for converting Integral types is <hask>fromIntegral</hask>, which will convert any integral type into any numeric type (e.g. <hask>Rational</hask>, <hask>Double</hask>...): 

+  * <hask>Integer</hask>, which are arbitraryprecision integers, often called "bignum" or "bigintegers" in other languages, and 

−  <haskell> 

+  * <hask>Int</hask>, which fixedwidth machinespecific integers with a minimum guaranteed range of <code>−2<sup>29</sup></code> to <code>2<sup>29</sup> − 1</code>. In practice, its range can be much larger: on the x8664 version of Glasgow Haskell Compiler, it can store any signed 64bit integer. 

+  
+  The workhorse for converting from integral types is <hask>fromIntegral</hask>, which will convert from any <hask>Integral</hask> type into any <hask>Num</hask>eric type (which includes <hask>Int</hask>, <hask>Integer</hask>, <hask>Rational</hask>, and <hask>Double</hask>): 

+  
+  : <haskell> 

fromIntegral :: (Num b, Integral a) => a > b 
fromIntegral :: (Num b, Integral a) => a > b 

</haskell> 
</haskell> 

−  For example, 
+  For example, given an <hask>Int</hask> value <hask>n</hask>, one does not simply take its square root by typing <hask>sqrt n</hask>, since <hask>sqrt</hask> can only be applied to <hask>Floating</hask>point numbers. Instead, one must write <hask>sqrt (fromIntegral n)</hask> to explicitly convert <hask>n</hask> to a floatingpoint number. 
−  == Converting to Rational == 

+  There are special cases for converting from <hask>Integer</hask>s: 

+  
+  : <haskell> 

+  fromInteger :: Num a => Integer > a 

+  </haskell> 

+  
+  as well as for converting to <hask>Integer</hask>s: 

+  
+  : <haskell> 

+  toInteger:: Integral a => a > Integer 

+  </haskell> 

+  
+  == Converting from real and between realfractional types (rationallike types) == 

+  
+  <hask>RealFrac</hask>tional types can contain either whole numbers or fractions. The most commonly used realfractional types are: 

+  
+  * <hask>Rational</hask>, which are [[Rationalarbitraryprecision fractions]], and 

+  * <hask>Double</hask>, which are doubleprecision floatingpoint numbers. 

+  
+  <hask>Real</hask> types include both <hask>Integral</hask> and <hask>RealFrac</hask>tional types. The name "real" indicates that it excludes <hask>Complex</hask> numbers. 

+  
+  The workhorse for converting from real types is <hask>realToFrac</hask>, which will convert from any <hask>Real</hask> type into any <hask>Fractional</hask> type (which includes <hask>Rational</hask> and <hask>Double</hask>): 

+  
+  : <haskell> 

+  realToFrac:: (Real a, Fractional b) => a > b 

+  </haskell> 

+  
+  It can also be used to convert between realfractional types. (Warning: Avoid using <hask>realToFrac</hask> to convert between floatingpoint types; see [[#Converting between different floatingpoint precisionsbelow]].) 

+  
+  There are special cases for converting from <hask>Rational</hask>s: 

+  
+  : <haskell> 

+  fromRational :: Fractional a => Rational > a 

+  </haskell> 

+  
+  as well as for converting to <hask>Rational</hask>s: 

+  
+  : <haskell> 

+  toRational :: Real a => a > Rational 

+  </haskell> 

+  
+  == Converting from realfractional numbers to integral numbers == 

+  
+  This is an inherently lossy transformation since integral types cannot express nonwhole numbers. Depending on how you wish to convert, you may choose any of the following: 

−  To convert something to a <hask>Rational</hask> type, you can use the function <hask>toRational</hask>: 

<haskell> 
<haskell> 

−  +  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 

</haskell> 
</haskell> 

−  Values of type <hask>Rational</hask> represent rational numbers exactly as the ratio of two <hask>Integer</hask>s. Applying <hask>toRational</hask> to an <hask>Integral</hask> value <hask>n</hask> will produce the rational number <hask>n % 1</hask>; applying <hask>toRational</hask> to a decimal (i.e. <hask>Fractional</hask> or <hask>Floating</hask>) value will produce a rational approximation. 

−  You can also construct <hask>Rational</hask> values explicitly using the <hask>%</hask> operator. 

+  == Converting between different floatingpoint precisions == 

−  == Converting to Integral == 

+  Conversion between <hask>Float</hask> and <hask>Double</hask> can be done using the GHCspecific functions in the [https://hackage.haskell.org/package/base/docs/src/GHCFloat.html GHC.Float module]: 

−  This is an inherently lossy transformation since integral types cannot express nonwhole numbers. Depending on how you wish to convert, you might choose one of several methods. 

+  <haskell> 

+  float2Double :: Float > Double 

+  double2Float :: Double > Float 

+  </haskell> 

−  * <hask>ceiling</hask> 

+  Avoid using <hask>realToFrac</hask> to convert between floatingpoint types as the intermediate type <hask>Rational</hask> is unable to represent exceptional values like infinity or NaN. See [https://ghc.haskell.org/trac/ghc/ticket/3676 GHC ticket #3676]. 

−  * <hask>floor</hask> 

−  * <hask>truncate</hask> 

−  * <hask>round</hask> 

== Automatic conversion == 
== Automatic conversion == 

Line 35:  Line 80:  
Repeatedly people ask for automatic conversion between numbers. This is usually not a good idea; for more information, refer to the thoughts about a [[Generic number type]]. 
Repeatedly people ask for automatic conversion between numbers. This is usually not a good idea; for more information, refer to the thoughts about a [[Generic number type]]. 

−  == 
+  == Example == 
−  Hi, I am trying to write some 
+  Hi, I am trying to write some functions that convert between two coordinate systems. The first coordinate system, which ill call coord1, starts in the upper left at (0, 0) and ends in the lower right at (500, 500). Coordinates in coord1 have type (Int, Int). The second coord system, which I'll call coord2, starts in the lower left at (0.0, 0.0) and ends in the upper right at (1.0, 1.0). Coords in coord2 have type (Float, Float). I was hoping someone could help me figure out how I can rewrite the two functions below so that the type checker will accept them. 
<haskell> 
<haskell> 

coord1ToCoord2 :: (Int, Int) > (Float, Float) 
coord1ToCoord2 :: (Int, Int) > (Float, Float) 

Line 57:  Line 102:  
coord2ToCoord1 (1.0, 1.0) > (500, 0) 
coord2ToCoord1 (1.0, 1.0) > (500, 0) 

</haskell> 
</haskell> 

−  Ah. I realize what is messing me up. 

+  One of the thing that confused me was that I expected 500 to be an Int, but in fact the literals are automatically converted to a correct Num instance. 

−  When i saw an expression like 

+  The solution here was to use fromIntegral and round : 

<haskell> 
<haskell> 

−  500 * 0.2 

+  coord1ToCoord2 :: (Int, Int) > (Float, Float) 

−  </haskell> 

+  coord1ToCoord2 (x, y) = (fromIntegral x/500, (500  fromIntegral y)/500) 

−  i had assumed that 500 :: Integer because it didnt end in a .0. but it actually has type Double. so my problem was i would do something like this 

+  
−  <haskell> 

+  coord2ToCoord1 :: (Float, Float) > (Int, Int) 

−  (toInteger (500 :: Int)) * 0.2 

+  coord2ToCoord1 (x, y) = (round (500 * x), round (500  500 * y)) 

−  </haskell> 

−  which of course the typechecker wouldnt accept. now that i have rid myself of my incorrect assumptions i see that i should be writing 

−  <haskell> 

−  (fromRational (toRational (500 :: Int)) * 0.2) :: Float 

</haskell> 
</haskell> 

−  now that i have a better understanding i am able to write my funs. thank you for your help :) 

[[Category:Mathematics]] 
[[Category:Mathematics]] 
Latest revision as of 01:28, 14 April 2016
Conversion between numerical types in Haskell must be done explicitly. This is unlike many traditional languages (such as C or Java) that automatically coerce between numerical types.
Contents
Converting from and between integral types (integerlike types)
Integral
types contain only whole numbers and not fractions. The most commonly used integral types are:

Integer
, which are arbitraryprecision integers, often called "bignum" or "bigintegers" in other languages, and 
Int
, which fixedwidth machinespecific integers with a minimum guaranteed range of−2^{29}
to2^{29} − 1
. In practice, its range can be much larger: on the x8664 version of Glasgow Haskell Compiler, it can store any signed 64bit integer.
The workhorse for converting from integral types is fromIntegral
, which will convert from any Integral
type into any Num
eric type (which includes Int
, Integer
, Rational
, and Double
):

fromIntegral :: (Num b, Integral a) => a > b
For example, given an Int
value n
, one does not simply take its square root by typing sqrt n
, since sqrt
can only be applied to Floating
point numbers. Instead, one must write sqrt (fromIntegral n)
to explicitly convert n
to a floatingpoint number.
There are special cases for converting from Integer
s:

fromInteger :: Num a => Integer > a
as well as for converting to Integer
s:

toInteger:: Integral a => a > Integer
Converting from real and between realfractional types (rationallike types)
RealFrac
tional types can contain either whole numbers or fractions. The most commonly used realfractional types are:

Rational
, which are arbitraryprecision fractions, and 
Double
, which are doubleprecision floatingpoint numbers.
Real
types include both Integral
and RealFrac
tional types. The name "real" indicates that it excludes Complex
numbers.
The workhorse for converting from real types is realToFrac
, which will convert from any Real
type into any Fractional
type (which includes Rational
and Double
):

realToFrac:: (Real a, Fractional b) => a > b
It can also be used to convert between realfractional types. (Warning: Avoid using realToFrac
to convert between floatingpoint types; see below.)
There are special cases for converting from Rational
s:

fromRational :: Fractional a => Rational > a
as well as for converting to Rational
s:

toRational :: Real a => a > Rational
Converting from realfractional numbers to integral numbers
This is an inherently lossy transformation since integral types cannot express nonwhole numbers. Depending on how you wish to convert, you may choose any of the following:
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
Converting between different floatingpoint precisions
Conversion between Float
and Double
can be done using the GHCspecific functions in the GHC.Float module:
float2Double :: Float > Double
double2Float :: Double > Float
Avoid using realToFrac
to convert between floatingpoint types as the intermediate type Rational
is unable to represent exceptional values like infinity or NaN. See GHC ticket #3676.
Automatic conversion
Repeatedly people ask for automatic conversion between numbers. This is usually not a good idea; for more information, refer to the thoughts about a Generic number type.
Example
Hi, I am trying to write some functions that convert between two coordinate systems. The first coordinate system, which ill call coord1, starts in the upper left at (0, 0) and ends in the lower right at (500, 500). Coordinates in coord1 have type (Int, Int). The second coord system, which I'll call coord2, starts in the lower left at (0.0, 0.0) and ends in the upper right at (1.0, 1.0). Coords in coord2 have type (Float, Float). I was hoping someone could help me figure out how I can rewrite the two functions below so that the type checker will accept them.
coord1ToCoord2 :: (Int, Int) > (Float, Float)
coord1ToCoord2 (x, y) = (x/500, (500y)/500)
coord2ToCoord1 :: (Float, Float) > (Int, Int)
coord2ToCoord1 (x, y) = (500/(1/x), 500  500/(1/y))
examples of what i want. i think i have the logic right :)
coord1ToCoord2 (0, 0) > (0.0, 1.0)
coord1ToCoord2 (250, 250) > (0.5, 0.5)
coord1ToCoord2 (350, 350) > (0.7, 0.3)
coord1ToCoord2 (500, 500) > (1.0, 0.0)
coord2ToCoord1 (0.0, 0.0) > (0, 500)
coord2ToCoord1 (0.5, 0.5) > (250, 250)
coord2ToCoord1 (0.7, 0.7) > (350, 150)
coord2ToCoord1 (1.0, 1.0) > (500, 0)
One of the thing that confused me was that I expected 500 to be an Int, but in fact the literals are automatically converted to a correct Num instance.
The solution here was to use fromIntegral and round :
coord1ToCoord2 :: (Int, Int) > (Float, Float)
coord1ToCoord2 (x, y) = (fromIntegral x/500, (500  fromIntegral y)/500)
coord2ToCoord1 :: (Float, Float) > (Int, Int)
coord2ToCoord1 (x, y) = (round (500 * x), round (500  500 * y))