Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ vNext
unknown dimension, suitable for performing arithmetic with such quantities.
* Added `nroot` function for term-level dimensions.
* Added the Numeric.Units.Dimensional.Float module with convenient wrappers around functions
from RealFloat for inspecting floating point quantities.
from RealFloat and IEEE for inspecting floating point quantities.
* Added an `AEq` instance for `Quantity`.
* Added the `btu`, a unit of energy.
* Relocated git repository to https://github.com/bjornbm/dimensional

Expand Down
1 change: 1 addition & 0 deletions dimensional.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ library
build-depends: base >= 4.7 && < 5,
deepseq >= 1.3,
exact-pi >= 0.2.1.1 && < 0.5,
ieee754 >= 0.7.6,
numtype-dk >= 0.5 && < 1.1,
vector >= 0.10
hs-source-dirs: src
Expand Down
87 changes: 87 additions & 0 deletions src/Numeric/Units/Dimensional/Float.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

Defines convenience functions for inspecting and manipulating quantities with 'RealFloat'
floating-point representations.

The dimensionally-typed versions of functions from Patrick Perry's @ieee754@ package
copy that package's API as closely as possible, by permission. In turn they are based on
the @tango@ math library for the D language.

-}

{-# LANGUAGE ScopedTypeVariables #-}
Expand All @@ -17,12 +22,25 @@ module Numeric.Units.Dimensional.Float
isDenormalized, isInfinite, isNaN, isNegativeZero
-- * Convenience Functions
, isFiniteNumber, scaleFloat
-- * Lifted Functions from "Numeric.IEEE"
-- ** Values
, infinity, minNormal, maxFinite, epsilon, nan
-- ** Arithmetic
, predIEEE, succIEEE, bisectIEEE, copySign
-- ** NaN with Payload
, nanWithPayload, nanPayload, F.maxNaNPayload
-- ** Comparisons
, identicalIEEE, minNum, maxNum, minNaN, maxNaN
)
where

import Control.Applicative
import Data.Word (Word64)
import Prelude (RealFloat)
import qualified Prelude as P
import Numeric.IEEE (IEEE)
import qualified Numeric.IEEE as F
import Numeric.Units.Dimensional.Internal (liftQ, liftQ2)
import Numeric.Units.Dimensional.Prelude hiding (RealFloat(..))
import Numeric.Units.Dimensional.Coercion

Expand Down Expand Up @@ -64,3 +82,72 @@ isNegativeZero = P.isNegativeZero . unQuantity
-- True
scaleFloat :: RealFloat a => Int -> Quantity d a -> Quantity d a
scaleFloat x = Quantity . P.scaleFloat x . unQuantity

-- | An infinite floating-point quantity.
infinity :: IEEE a => Quantity d a
infinity = Quantity $ F.infinity

-- | The smallest representable positive quantity whose representation is normalized.
minNormal :: IEEE a => Quantity d a
minNormal = Quantity $ F.minNormal

-- | The largest representable finite floating-point quantity.
maxFinite :: IEEE a => Quantity d a
maxFinite = Quantity $ F.maxFinite

-- | The smallest positive value @x@ such that @1 + x@ is representable.
epsilon :: IEEE a => Dimensionless a
epsilon = Quantity $ F.epsilon

-- | @copySign x y@ returns the quantity @x@ with its sign changed to match that of @y@.
copySign :: IEEE a => Quantity d a -> Quantity d a -> Quantity d a
copySign = liftQ2 F.copySign

-- | Return 'True' if two floating-point quantities are /exactly/ (bitwise) equal.
identicalIEEE :: IEEE a => Quantity d a -> Quantity d a -> Bool
identicalIEEE (Quantity x) (Quantity y) = F.identicalIEEE x y

-- | Return the next largest representable floating-point quantity (@Infinity@ and @NaN@ are unchanged).
succIEEE :: IEEE a => Quantity d a -> Quantity d a
succIEEE = liftQ F.succIEEE

-- | Return the next smallest representable floating-point quantity (@Infinity@ and @NaN@ are unchanged).
predIEEE :: IEEE a => Quantity d a -> Quantity d a
predIEEE = liftQ F.predIEEE

-- | Given two floating-point quantities with the same sign, return the quantity whose representation is halfway
-- between their representations on the IEEE number line. If the signs of the values differ or either is @NaN@,
-- the value is undefined.
bisectIEEE :: IEEE a => Quantity d a -> Quantity d a -> Quantity d a
bisectIEEE (Quantity x) (Quantity y) = Quantity $ F.bisectIEEE x y

-- | Default @NaN@ quantity.
nan :: IEEE a => Quantity d a
nan = Quantity $ F.nan

-- | Quiet @NaN@ quantity with a positive integer payload.
-- Payload must be less than 'maxNaNPayload' of the representation type.
--
-- Beware that while some platforms allow using 0 as a payload, this behavior is not portable.
nanWithPayload :: IEEE a => Word64 -> Quantity d a
nanWithPayload = Quantity . F.nanWithPayload

-- | The payload stored in a @NaN@ quantity. Undefined if the argument is not @NaN@.
nanPayload :: IEEE a => Quantity d a -> Word64
nanPayload = F.nanPayload . unQuantity

-- | Return the minimum of two quantities; if one value is @NaN@, return the other. Prefer the first if both values are @NaN@.
minNum :: RealFloat a => Quantity d a -> Quantity d a -> Quantity d a
minNum = liftQ2 F.minNum

-- | Return the maximum of two quantities; if one value is @NaN@, return the other. Prefer the first if both values are @NaN@.
maxNum :: RealFloat a => Quantity d a -> Quantity d a -> Quantity d a
maxNum = liftQ2 F.maxNum

-- | Return the minimum of two quantities; if one value is @NaN@, return it. Prefer the first if both values are @NaN@.
minNaN :: RealFloat a => Quantity d a -> Quantity d a -> Quantity d a
minNaN = liftQ2 F.minNaN

-- | Return the maximum of two quantities; if one value is @NaN@, return it. Prefer the first if both values are @NaN@.
maxNaN :: RealFloat a => Quantity d a -> Quantity d a -> Quantity d a
maxNaN = liftQ2 F.maxNaN
4 changes: 3 additions & 1 deletion src/Numeric/Units/Dimensional/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-} -- for Vector instances only
{-# LANGUAGE RankNTypes #-}
Expand All @@ -27,6 +28,7 @@ where
import Control.Applicative
import Control.DeepSeq
import Control.Monad (liftM)
import Data.AEq (AEq)
import Data.Coerce (coerce)
import Data.Data
import Data.ExactPi
Expand Down Expand Up @@ -75,7 +77,7 @@ deriving instance Typeable Dimensional

instance KnownVariant 'DQuantity where
newtype Dimensional 'DQuantity d a = Quantity a
deriving (Eq, Ord, Data, Generic, Generic1
deriving (Eq, Ord, AEq, Data, Generic, Generic1
#if MIN_VERSION_base(4,8,0)
, Typeable -- GHC 7.8 doesn't support deriving this instance
#endif
Expand Down