What is the difference is between the Floating
and Fractional
classes in Haskell?
Fractional is the class of types that can represent (exactly or at least in a decent approximation) any rational number. It may ad lib also be able to represent other numbers, but that's not important.
Introduction. Haskell has two types for floating-point numbers, namely Float (single-precisionsingle-precisionSingle-precision floating-point format (sometimes called FP32 or float32) is a computer number format, usually occupying 32 bits in computer memory; it represents a wide dynamic range of numeric values by using a floating radix point.https://en.wikipedia.org › wiki › Single-precision_floating-poi...Single-precision floating-point format - Wikipedia) and Double (double-precision). Floating-point numbers can be represented in two ways. First, using a decimal point: 2.0 33.873 -8.3377. Second, by means of the so-called scientific notation: 33.61e6 3.7e-2 -3.7e2.
A float is a rational number expressed in floating-point format, usually to base 10 or decimal. What does that mean? Consider the number 110. We can write it as 1.1 x 102, where the decimal point one digit before the end indicates that that first number is really the fraction 11 / 10.
Floating-point numbers do not store fractions generally. Typically, a single-precision floating-pointsingle-precision floating-pointSingle-precision floating-point format (sometimes called FP32 or float32) is a computer number format, usually occupying 32 bits in computer memory; it represents a wide dynamic range of numeric values by using a floating radix point.https://en.wikipedia.org › wiki › Single-precision_floating-poi...Single-precision floating-point format - Wikipedia number, a "float", stores a sign, a 24-bit binary numeral (the "significand"), and an eight-bit exponent by which to scale the numeral.
Very roughly:
Fractional
is the class of types that can represent (exactly or at least in a decent approximation) any rational number. It may ad lib also be able to represent other numbers, but that's not important.
In other terms, it's just the class of number types that have a division operation; since it's a subclass of Num
it follows from this that the types must contain the rational numbers.
Floating
is the class of number types that are closed under limits in the Cauchy sense, i.e. complete spaces. This is necessary to do any sort of calculus. The methods of the Floating
class are functions that are mathematically defined as limits, namely infinite sums (which are the limits of the sequence of partial sums of taylor series).
Since you can define the real numbers as limits of sequences of rational numbers and because again Floating
is a subclass of Fractional
, any Floating
type is able to represent (again, at least to a decent approximation) any real number.
A good way to visualise the difference is through topology: Floating
types are connected spaces, i.e. they form a continuum. What this means for floating point numbers is: every value is understood as a whole interval of real numbers (because floating-point always has some uncertainty). When you lay these intervals side by side, you tile the entire real numbers (at least to ±10300) without gaps.
By contrast, some Fractional
types are not connected. In particular, Rational
can exactly represent all its (rational-number) values, so each value is just an “infinitely small point”. You can never cover the entire real line with such points, and you can not compute functions like sin
or log
since the result of these functions is usually a non-rational real number.
It's worth pondering a bit what this “decent approximation” means. The Haskell standard doesn't define this. This story about every floating point number representing a whole interval of real numbers captures it quite well IMO. More generally, we might say: Num
/Fractional
/Floating
are the classes of types that represent equivalance classes of integer/rational/real numbers. In fact, these classes need not even be “small” intervals: in particular the finite types like Word32
or the standard Int
can be understood in a modular arithmetic sense, manifesting in results like (2^70 :: Int) == 0
, i.e. the equivalence classes are then numbers spaces by a multiple of 264.
In cases like Integer
or Rational
, the equivalence classes actually contain only a single element, i.e. the numbers are represented exactly. For real numbers, this is actually also possible, but much more tricky, it's called exact real arithmetic. There are libraries such as aern that do this.
The definitions of Fractional
and Floating
can be found in the documentation of the Prelude:
class Num a => Fractional a where (/) :: a -> a -> a recip :: a -> a fromRational :: Rational -> a
Fractional numbers, supporting real division.
[...]
class Fractional a => Floating a where pi :: a exp :: a -> a log :: a -> a sqrt :: a -> a (**) :: a -> a -> a logBase :: a -> a -> a sin :: a -> a cos :: a -> a tan :: a -> a asin :: a -> a acos :: a -> a atan :: a -> a sinh :: a -> a cosh :: a -> a tanh :: a -> a asinh :: a -> a acosh :: a -> a atanh :: a -> a
Trigonometric and hyperbolic functions and related functions.
[...]
So to translate that into English: A Fractional
is any kind of number for which I can define a division:
(/) :: Fractional a => a -> a -> a
That can for instance be the case for floating point numbers, but also for fractions (where a fraction has a numerator and denominator). This is not the case for Int
because if dividing an Int
by an Int
does not always produce an Int
(well technically floating point division on a computer is not exact, but that is another story).
A subset of Fractional
numbers are Floating
numbers where trigonometric are defined. It is for instance impossible that the sin
of a fraction always produces a fraction: a sin
is defined as an sum over an infinite sequence. Only for a very limited number of cases (like sin 0
) it holds. Basically the only numbers on a computer for which trigonometric are defined (approximatively) are floating point numbers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With