Minimal complete definition: splitFraction or floor
There are probably more laws, but some laws are
splitFraction x === (fromInteger (floor x), fraction x)
fromInteger (floor x) + fraction x === x
floor x <= x x < floor x + 1
ceiling x - 1 < x x <= ceiling x
0 <= fraction x fraction x < 1 - ceiling x === floor (-x)
truncate x === signum x * floor (abs x)
ceiling (toRational x) === ceiling x :: Integer
truncate (toRational x) === truncate x :: Integer
floor (toRational x) === floor x :: IntegerThe new function fraction doesn't return the integer part of the number. This also removes a type ambiguity if the integer part is not needed.
Many people will associate rounding with fractional numbers,
and thus they are surprised about the superclass being Ring not Field.
The reason is that all of these methods can be defined
exclusively with functions from Ord and Ring.
The implementations of genericFloor and other functions demonstrate that.
They implement power-of-two-algorithms
like the one for finding the number of digits of an Integer
in FixedPoint-fractions module.
They are even reasonably efficient.
I am still uncertain whether it was a good idea
to add instances for Integer and friends,
since calling floor or fraction on an integer may well indicate a bug.
The rounding functions are just the identity function
and fraction is constant zero.
However, I decided to associate our class with Ring rather than Field,
after I found myself using repeated subtraction and testing
rather than just calling fraction,
just in order to get the constraint (Ring a, Ord a)
that was more general than (RealField a).
For the results of the rounding functions
we have chosen the constraint Ring instead of ToInteger,
since this is more flexible to use,
but it still signals to the user that only integral numbers can be returned.
This is so, because the plain Ring class only provides
zero, one and operations that allow to reach all natural numbers but not more.
As an aside, let me note the similarities
between splitFraction x and divMod x 1 (if that were defined).
In particular, it might make sense to unify the rounding modes somehow.
The new methods fraction and splitFraction
differ from properFraction semantics.
They always round to floor.
This means that the fraction is always non-negative and
is always smaller than 1.
This is more useful in practice and
can be generalised to more than real numbers.
Since every T denominator type
supports divMod,
every T can provide fraction and splitFraction,
e.g. fractions of polynomials.
However the Ring constraint for the 'integral' part of splitFraction
is too weak in order to generate polynomials.
After all, I am uncertain whether this would be useful or not.
Can there be a separate class for fraction, splitFraction, floor and ceiling since they do not need reals and their ordering?
We might also add a round method, that rounds 0.5 always up or always down. This is much more efficient in inner loops and is acceptable or even preferable for many applications.
Methods
splitFraction :: C b => a -> (b, a)Property \x -> (x::Rational) == (uncurry (+) $ mapFst fromInteger $ splitFraction x)Property \x -> uncurry (==) $ mapFst (((x::Double)-) . fromInteger) $ splitFraction xProperty \x -> uncurry (==) $ mapFst (((x::Rational)-) . fromInteger) $ splitFraction xProperty \x -> splitFraction x == (floor (x::Double) :: Integer, fraction x)Property \x -> splitFraction x == (floor (x::Rational) :: Integer, fraction x)fraction :: a -> aProperty \x -> let y = fraction (x::Double) in 0<=y && y<1Property \x -> let y = fraction (x::Rational) in 0<=y && y<1ceiling :: C b => a -> bProperty \x -> ceiling (-x) == negate (floor (x::Double) :: Integer)Property \x -> ceiling (-x) == negate (floor (x::Rational) :: Integer)floor :: C b => a -> bProperty \x -> ceiling (-x) == negate (floor (x::Double) :: Integer)Property \x -> ceiling (-x) == negate (floor (x::Rational) :: Integer)truncate :: C b => a -> bround :: C b => a -> b
Instances18C, …
C IntegerDefined in numeric-prelude-0.4.4 · Algebra.RealRingC Int16Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Int32Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Int64Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Int8Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Word16Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Word32Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Word64Defined in numeric-prelude-0.4.4 · Algebra.RealRingC Word8Defined in numeric-prelude-0.4.4 · Algebra.RealRingC DoubleDefined in numeric-prelude-0.4.4 · Algebra.RealRingC FloatDefined in numeric-prelude-0.4.4 · Algebra.RealRingC IntDefined in numeric-prelude-0.4.4 · Algebra.RealRingC TDefined in numeric-prelude-0.4.4 · Number.FixedPoint.CheckC TDefined in numeric-prelude-0.4.4 · Number.Positional.CheckRealFrac a => C (T a)Defined in numeric-prelude-0.4.4 · MathObj.Wrapper.Haskell98C a => C (T a)Defined in numeric-prelude-0.4.4 · MathObj.Wrapper.NumericPrelude(C a, C a) => C (T a)Defined in numeric-prelude-0.4.4 · Algebra.RealRing(C a, C a) => C (T a)Defined in numeric-prelude-0.4.4 · Number.NonNegative · orphan