{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}

{- |
    Copyright  : Copyright (C) 2006-2018 Bjorn Buckwalter
    License    : BSD3

    Maintainer : bjorn@buckwalter.se
    Stability  : Experimental
    Portability: GHC only?

Defines types for manipulation of quantities with fixed point representations.
-}
module Numeric.Units.Dimensional.FixedPoint
(
  -- * Types
  -- $types
  Dimensional,
  Unit, Quantity, SQuantity,
  Metricality(..),
  -- * Physical Dimensions
  Dimension (Dim),
  -- ** Dimension Arithmetic
  type (*), type (/), type (^), NRoot, Recip,
  -- ** Term Level Representation of Dimensions
  Dimension' (Dim'), HasDimension(..), KnownDimension,
  -- * Dimensional Arithmetic
  (*~), (/~),
  (*), (/), (+), (-),
  negate, abs,
  -- ** Transcendental Functions
  -- *** Via 'Double'
  expD, logD, sinD, cosD, tanD, asinD, acosD, atanD, sinhD, coshD, tanhD, asinhD, acoshD, atanhD, atan2D,
  -- *** Via arbitary 'Floating' type
  expVia, logVia, sinVia, cosVia, tanVia, asinVia, acosVia, atanVia, sinhVia, coshVia, tanhVia, asinhVia, acoshVia, atanhVia, atan2Via,
  -- ** Operations on Collections
  (*~~), (/~~), sum, mean, -- dimensionlessLength, nFromTo,
  -- ** Conversion Between Representations
  rescale, rescaleFinite, rescaleD, rescaleVia, KnownVariant(dmap), changeRep, changeRepRound, changeRepApproximate,
  -- * Dimension Synonyms
  DOne, DLength, DMass, DTime, DElectricCurrent, DThermodynamicTemperature, DAmountOfSubstance, DLuminousIntensity,
  -- * Quantity Synonyms
  Dimensionless, Length, Mass, Time, ElectricCurrent, ThermodynamicTemperature, AmountOfSubstance, LuminousIntensity,
  -- * Constants
  _0, epsilon,
  -- $possibly-imprecise-constants
  _1, _2, _3, _4, _5, _6, _7, _8, _9, pi, tau,
  -- * Constructing Units
  siUnit, one, mkUnitR, mkUnitQ, mkUnitZ,
  -- * Unit Metadata
  name, exactValue, weaken, strengthen, exactify,
  -- * Commonly Used Type Synonyms
  -- $synonyms
  type Q, type QScale, type Angle8, type Angle16, type Angle32
)
where

import Data.Bits
import Data.ExactPi
import qualified Data.ExactPi.TypeLevel as E
import Data.Int
import Data.Proxy
import qualified Data.Foldable as F
import Data.Ratio
import qualified GHC.TypeLits as N
import Numeric.Units.Dimensional.Coercion
import Numeric.Units.Dimensional.Internal
import Numeric.Units.Dimensional.Prelude hiding ((*~), (/~), (+), (-), recip, negate, abs, (*~~), (/~~), sum, mean, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, pi, tau, changeRep)
import Numeric.Units.Dimensional.Variants hiding (type (*), type (/))
import qualified Numeric.Units.Dimensional.UnitNames as Name
import qualified Prelude as P

{- $types

We provide access to the same 'Dimensional', 'Unit', and 'Quantity' types as are exposed by "Numeric.Units.Dimensional", but additionally
offer the 'SQuantity' type to represent scaled quantities. Fixed-point quantities are quantities backed by integers, it is frequently
necessary to scale those integers into a range appropriate for the physical problem at hand.

-}

{-

Arithmetic Operators and Functions

We will reuse the operators and function names from the Prelude.
To prevent unpleasant surprises we give operators the same fixity
as the Prelude.

-}

--infixr 8  ^, ^/, **
infixl 6  +, -

-- | Adds two possibly scaled 'SQuantity's, preserving any scale factor.
--
-- Use in conjunction with 'changeRepRound' to combine quantities with differing scale factors.
(+) :: (Num a) => SQuantity s d a -> SQuantity s d a -> SQuantity s d a
+ :: SQuantity s d a -> SQuantity s d a -> SQuantity s d a
(+) = (a -> a -> a)
-> SQuantity s d a -> SQuantity s d a -> SQuantity s d a
forall a (s1 :: ExactPi') (d1 :: Dimension) (s2 :: ExactPi')
       (d2 :: Dimension) (s3 :: ExactPi') (d3 :: Dimension).
(a -> a -> a)
-> SQuantity s1 d1 a -> SQuantity s2 d2 a -> SQuantity s3 d3 a
liftQ2 a -> a -> a
forall a. Num a => a -> a -> a
(P.+)

-- | Subtracts one possibly scaled 'SQuantity' from another, preserving any scale factor.
--
-- Use in conjunction with 'changeRepRound' to combine quantities with differing scale factors.
(-) :: (Num a) => SQuantity s d a -> SQuantity s d a -> SQuantity s d a
(-) = (a -> a -> a)
-> SQuantity s d a -> SQuantity s d a -> SQuantity s d a
forall a (s1 :: ExactPi') (d1 :: Dimension) (s2 :: ExactPi')
       (d2 :: Dimension) (s3 :: ExactPi') (d3 :: Dimension).
(a -> a -> a)
-> SQuantity s1 d1 a -> SQuantity s2 d2 a -> SQuantity s3 d3 a
liftQ2 a -> a -> a
forall a. Num a => a -> a -> a
(P.-)

-- | Takes the absolute value of a possibly scaled 'SQuantity', preserving any scale factor.
abs :: (Num a) => SQuantity s d a -> SQuantity s d a
abs :: SQuantity s d a -> SQuantity s d a
abs = (a -> a) -> SQuantity s d a -> SQuantity s d a
forall a (s1 :: ExactPi') (d1 :: Dimension) (s2 :: ExactPi')
       (d2 :: Dimension).
(a -> a) -> SQuantity s1 d1 a -> SQuantity s2 d2 a
liftQ (a -> a
forall a. Num a => a -> a
P.abs)

-- | Negates the value of a possibly scaled 'SQuantity', preserving any scale factor.
negate :: (Num a) => SQuantity s d a -> SQuantity s d a
negate :: SQuantity s d a -> SQuantity s d a
negate = (a -> a) -> SQuantity s d a -> SQuantity s d a
forall a (s1 :: ExactPi') (d1 :: Dimension) (s2 :: ExactPi')
       (d2 :: Dimension).
(a -> a) -> SQuantity s1 d1 a -> SQuantity s2 d2 a
liftQ (a -> a
forall a. Num a => a -> a
P.negate)

infixl 7  *~~, /~~

-- | Applies '*~' to all values in a functor.
(*~~) :: (Functor f, RealFrac a, Integral b, E.MinCtxt s a) => f a -> Unit m d a -> f (SQuantity s d b)
f a
xs *~~ :: f a -> Unit m d a -> f (SQuantity s d b)
*~~ Unit m d a
u = (a -> SQuantity s d b) -> f a -> f (SQuantity s d b)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (a -> Unit m d a -> SQuantity s d b
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(RealFrac a, Integral b, MinCtxt s a) =>
a -> Unit m d a -> SQuantity s d b
*~ Unit m d a
u) f a
xs

-- | Applies '/~' to all values in a functor.
(/~~) :: (Functor f, Real a, Fractional b, E.MinCtxt s b) => f (SQuantity s d a) -> Unit m d b -> f b
f (SQuantity s d a)
xs /~~ :: f (SQuantity s d a) -> Unit m d b -> f b
/~~ Unit m d b
u = (SQuantity s d a -> b) -> f (SQuantity s d a) -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (SQuantity s d a -> Unit m d b -> b
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(Real a, Fractional b, MinCtxt s b) =>
SQuantity s d a -> Unit m d b -> b
/~ Unit m d b
u) f (SQuantity s d a)
xs

-- | The sum of all elements in a list.
sum :: (Num a, F.Foldable f) => f (SQuantity s d a) -> SQuantity s d a
sum :: f (SQuantity s d a) -> SQuantity s d a
sum = (SQuantity s d a -> SQuantity s d a -> SQuantity s d a)
-> SQuantity s d a -> f (SQuantity s d a) -> SQuantity s d a
forall (t :: Type -> Type) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr SQuantity s d a -> SQuantity s d a -> SQuantity s d a
forall a (s :: ExactPi') (d :: Dimension).
Num a =>
SQuantity s d a -> SQuantity s d a -> SQuantity s d a
(+) SQuantity s d a
forall a (s :: ExactPi') (d :: Dimension). Num a => SQuantity s d a
_0

-- | The arithmetic mean of all elements in a list.
mean :: (Fractional a, F.Foldable f) => f (SQuantity s d a) -> SQuantity s d a
mean :: f (SQuantity s d a) -> SQuantity s d a
mean = (SQuantity s d a, Int) -> SQuantity s d a
forall (v :: Variant) a2 a (d :: Dimension).
(KnownVariant v, Fractional a2, Integral a) =>
(Dimensional v d a2, a) -> Dimensional v d a2
reduce ((SQuantity s d a, Int) -> SQuantity s d a)
-> (f (SQuantity s d a) -> (SQuantity s d a, Int))
-> f (SQuantity s d a)
-> SQuantity s d a
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (SQuantity s d a
 -> (SQuantity s d a, Int) -> (SQuantity s d a, Int))
-> (SQuantity s d a, Int)
-> f (SQuantity s d a)
-> (SQuantity s d a, Int)
forall (t :: Type -> Type) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr SQuantity s d a -> (SQuantity s d a, Int) -> (SQuantity s d a, Int)
forall a b (s :: ExactPi') (d :: Dimension).
(Num a, Num b) =>
SQuantity s d a -> (SQuantity s d a, b) -> (SQuantity s d a, b)
accumulate (SQuantity s d a
forall a (s :: ExactPi') (d :: Dimension). Num a => SQuantity s d a
_0, Int
0 :: Int)
  where
    reduce :: (Dimensional v d a2, a) -> Dimensional v d a2
reduce (Dimensional v d a2
s, a
n) = (a2 -> a2) -> Dimensional v d a2 -> Dimensional v d a2
forall (v :: Variant) a1 a2 (d :: Dimension).
KnownVariant v =>
(a1 -> a2) -> Dimensional v d a1 -> Dimensional v d a2
dmap (a2 -> a2 -> a2
forall a. Fractional a => a -> a -> a
P./ a -> a2
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n) Dimensional v d a2
s
    accumulate :: SQuantity s d a -> (SQuantity s d a, b) -> (SQuantity s d a, b)
accumulate SQuantity s d a
val (SQuantity s d a
accum, b
count) = (SQuantity s d a
accum SQuantity s d a -> SQuantity s d a -> SQuantity s d a
forall a (s :: ExactPi') (d :: Dimension).
Num a =>
SQuantity s d a -> SQuantity s d a -> SQuantity s d a
+ SQuantity s d a
val, b
count b -> b -> b
forall a. Num a => a -> a -> a
P.+ b
1)

expD, logD, sinD, cosD, tanD, asinD, acosD, atanD, sinhD, coshD, tanhD, asinhD, acoshD, atanhD
  :: (Integral a, Integral b, E.MinCtxt s1 Double, E.MinCtxt s2 Double) => SQuantity s1 DOne a -> SQuantity s2 DOne b
expD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
expD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
expVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
logD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
logD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
logVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
sinD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
sinD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
sinVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
cosD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
cosD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
cosVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
tanD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
tanD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
tanVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
asinD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
asinD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
asinVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
acosD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
acosD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
acosVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
atanD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
atanD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
atanVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
sinhD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
sinhD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
sinhVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
coshD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
coshD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
coshVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
tanhD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
tanhD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
tanhVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
asinhD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
asinhD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
asinhVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
acoshD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
acoshD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
acoshVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)
atanhD :: SQuantity s1 DOne a -> SQuantity s2 DOne b
atanhD = Proxy Double -> SQuantity s1 DOne a -> SQuantity s2 DOne b
forall a b c (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
atanhVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)

-- | The standard two argument arctangent function.
-- Since it interprets its two arguments in comparison with one another, the input may have any dimension.
atan2D :: (Integral a, Integral b, E.MinCtxt s1 Double, E.MinCtxt s2 Double, E.MinCtxt s3 Double) => SQuantity s1 DOne a -> SQuantity s2 DOne a -> SQuantity s3 DOne b
atan2D :: SQuantity s1 DOne a -> SQuantity s2 DOne a -> SQuantity s3 DOne b
atan2D = Proxy Double
-> SQuantity s1 DOne a
-> SQuantity s2 DOne a
-> SQuantity s3 DOne b
forall (s1 :: ExactPi') (s2 :: ExactPi') (s3 :: ExactPi') a b c
       (d :: Dimension).
(Integral a, RealFloat b, Integral c, MinCtxt s1 b, MinCtxt s2 b,
 MinCtxt s3 b, KnownDimension d) =>
Proxy b
-> SQuantity s1 d a -> SQuantity s2 d a -> SQuantity s3 DOne c
atan2Via (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy P.Double)

expVia, logVia, sinVia, cosVia, tanVia, asinVia, acosVia, atanVia, sinhVia, coshVia, tanhVia, asinhVia, acoshVia, atanhVia
  :: (Integral a, RealFrac b, Floating b, Integral c, E.MinCtxt s1 b, E.MinCtxt s2 b) => Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
expVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
expVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.exp
logVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
logVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.log
sinVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
sinVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia (ExactPi
2 ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
forall a. Floating a => a
P.pi) forall a. Floating a => a -> a
P.sin
cosVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
cosVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia (ExactPi
2 ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
forall a. Floating a => a
P.pi) forall a. Floating a => a -> a
P.cos
tanVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
tanVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia ExactPi
forall a. Floating a => a
P.pi forall a. Floating a => a -> a
P.tan
asinVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
asinVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.asin
acosVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
acosVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.acos
atanVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
atanVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.atan
sinhVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
sinhVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia (ExactPi
2 ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
forall a. Floating a => a
P.pi) forall a. Floating a => a -> a
P.sinh
coshVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
coshVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia (ExactPi
2 ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
forall a. Floating a => a
P.pi) forall a. Floating a => a -> a
P.cosh
tanhVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
tanhVia = ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Integral a, RealFrac b, Floating b, Integral c, MinCtxt s1 b,
 MinCtxt s2 b) =>
ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia ExactPi
forall a. Floating a => a
P.pi forall a. Floating a => a -> a
P.tanh
asinhVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
asinhVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.asinh
acoshVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
acoshVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.acosh
atanhVia :: Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
atanhVia = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
P.atanh

-- | The standard two argument arctangent function.
-- Since it interprets its two arguments in comparison with one another, the input may have any dimension.
atan2Via :: forall s1 s2 s3 a b c d.(Integral a, RealFloat b, Integral c, E.MinCtxt s1 b, E.MinCtxt s2 b, E.MinCtxt s3 b, KnownDimension d) => Proxy b -> SQuantity s1 d a -> SQuantity s2 d a -> SQuantity s3 DOne c
atan2Via :: Proxy b
-> SQuantity s1 d a -> SQuantity s2 d a -> SQuantity s3 DOne c
atan2Via Proxy b
_ SQuantity s1 d a
y SQuantity s2 d a
x = (b -> Unit 'NonMetric DOne b -> SQuantity s3 DOne c
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(RealFrac a, Integral b, MinCtxt s a) =>
a -> Unit m d a -> SQuantity s d b
*~ Unit 'NonMetric DOne b
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
siUnit) (b -> SQuantity s3 DOne c) -> b -> SQuantity s3 DOne c
forall a b. (a -> b) -> a -> b
$ (b -> b -> b
forall a. RealFloat a => a -> a -> a
P.atan2 :: b -> b -> b) (SQuantity s1 d a
y SQuantity s1 d a -> Unit 'NonMetric d b -> b
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(Real a, Fractional b, MinCtxt s b) =>
SQuantity s d a -> Unit m d b -> b
/~ Unit 'NonMetric d b
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
siUnit) (SQuantity s2 d a
x SQuantity s2 d a -> Unit 'NonMetric d b -> b
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(Real a, Fractional b, MinCtxt s b) =>
SQuantity s d a -> Unit m d b -> b
/~ Unit 'NonMetric d b
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
siUnit)

-- | Lift a function on dimensionless values of a specified intermediate type to operate on possibly scaled dimensionless values.
liftDimensionlessVia :: forall s1 s2 a b c.(Real a, RealFrac b, Integral c, E.MinCtxt s1 b, E.MinCtxt s2 b) => (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia :: (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
f Proxy b
_ = (b -> Unit 'NonMetric DOne b -> SQuantity s2 DOne c
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(RealFrac a, Integral b, MinCtxt s a) =>
a -> Unit m d a -> SQuantity s d b
*~ Unit 'NonMetric DOne b
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
siUnit) (b -> SQuantity s2 DOne c)
-> (SQuantity s1 DOne a -> b)
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (b -> b
f :: b -> b) (b -> b) -> (SQuantity s1 DOne a -> b) -> SQuantity s1 DOne a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (SQuantity s1 DOne a -> Unit 'NonMetric DOne b -> b
forall (s :: ExactPi') (m :: Metricality) (d :: Dimension) a b.
(Real a, Fractional b, MinCtxt s b) =>
SQuantity s d a -> Unit m d b -> b
/~ Unit 'NonMetric DOne b
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
siUnit)

-- | Lift a periodic function on dimensionless values of a specified intermediate type to operate on possibly scaled dimensionless values.
--
-- If the scale factor of the input type is an exact integer divisor of the function's period, the argument
-- will be clamped via an integer `mod` operation prior to applying the function to avoid errors introduced by a floating point modulus.
liftDimensionlessPeriodicVia :: forall s1 s2 a b c.(Integral a, RealFrac b, Floating b, Integral c, E.MinCtxt s1 b, E.MinCtxt s2 b) => ExactPi -> (forall d.Floating d => d -> d) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessPeriodicVia :: ExactPi
-> (forall a. Floating a => a -> a)
-> Proxy b
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
liftDimensionlessPeriodicVia ExactPi
p forall a. Floating a => a -> a
f Proxy b
proxy | Just a
p'' <- Maybe a
p', a
p'' a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0 = ((b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
f Proxy b
proxy) (SQuantity s1 DOne a -> SQuantity s2 DOne c)
-> (SQuantity s1 DOne a -> SQuantity s1 DOne a)
-> SQuantity s1 DOne a
-> SQuantity s2 DOne c
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (a -> a) -> SQuantity s1 DOne a -> SQuantity s1 DOne a
forall (v :: Variant) a1 a2 (d :: Dimension).
KnownVariant v =>
(a1 -> a2) -> Dimensional v d a1 -> Dimensional v d a2
dmap (a -> a -> a
forall a. Integral a => a -> a -> a
`mod` a
p'')
                                       | Bool
otherwise = (b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
forall (s1 :: ExactPi') (s2 :: ExactPi') a b c.
(Real a, RealFrac b, Integral c, MinCtxt s1 b, MinCtxt s2 b) =>
(b -> b) -> Proxy b -> SQuantity s1 DOne a -> SQuantity s2 DOne c
liftDimensionlessVia b -> b
forall a. Floating a => a -> a
f Proxy b
proxy
  where
    p' :: Maybe a
    p' :: Maybe a
p' = (Integer -> a) -> Maybe Integer -> Maybe a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Integer -> a
forall a. Num a => Integer -> a
fromInteger (Maybe Integer -> Maybe a)
-> (Proxy s1 -> Maybe Integer) -> Proxy s1 -> Maybe a
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ExactPi -> Maybe Integer
toExactInteger (ExactPi -> Maybe Integer)
-> (Proxy s1 -> ExactPi) -> Proxy s1 -> Maybe Integer
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ExactPi -> ExactPi
forall a. Fractional a => a -> a
P.recip (ExactPi -> ExactPi)
-> (Proxy s1 -> ExactPi) -> Proxy s1 -> ExactPi
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (ExactPi -> ExactPi -> ExactPi
forall a. Fractional a => a -> a -> a
P./ ExactPi
p) (ExactPi -> ExactPi)
-> (Proxy s1 -> ExactPi) -> Proxy s1 -> ExactPi
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Proxy s1 -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal (Proxy s1 -> Maybe a) -> Proxy s1 -> Maybe a
forall a b. (a -> b) -> a -> b
$ (Proxy s1
forall k (t :: k). Proxy t
Proxy :: Proxy s1)

{-
We give '*~' and '/~' the same fixity as '*' and '/' defined below.
Note that this necessitates the use of parenthesis when composing
units using '*' and '/', e.g. "1 *~ (meter / second)".
-}

infixl 7  *~, /~

-- | Forms a possibly scaled 'SQuantity' by multipliying a number and a unit.
(*~) :: forall s m d a b.(RealFrac a, Integral b, E.MinCtxt s a) => a -> Unit m d a -> SQuantity s d b
a
x *~ :: a -> Unit m d a -> SQuantity s d b
*~ (Unit _ _ y) = b -> SQuantity s d b
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity (b -> SQuantity s d b) -> (a -> b) -> a -> SQuantity s d b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (a -> SQuantity s d b) -> a -> SQuantity s d b
forall a b. (a -> b) -> a -> b
$ (a
x a -> a -> a
forall a. Num a => a -> a -> a
P.* a
y a -> a -> a
forall a. Fractional a => a -> a -> a
P./ a
s)
  where
    s :: a
s = Proxy s -> a
forall (v :: ExactPi') a. MinCtxt v a => Proxy v -> a
E.injMin (Proxy s
forall k (t :: k). Proxy t
Proxy :: Proxy s)

-- | Divides a possibly scaled 'SQuantity' by a 'Unit' of the same physical dimension, obtaining the
-- numerical value of the quantity expressed in that unit.
(/~) :: forall s m d a b.(Real a, Fractional b,  E.MinCtxt s b) => SQuantity s d a -> Unit m d b -> b
(Quantity x) /~ :: SQuantity s d a -> Unit m d b -> b
/~ (Unit _ _ y) = ((a -> b
forall a b. (Real a, Fractional b) => a -> b
realToFrac a
x) b -> b -> b
forall a. Num a => a -> a -> a
P.* b
s b -> b -> b
forall a. Fractional a => a -> a -> a
P./ b
y)
  where
    s :: b
s = Proxy s -> b
forall (v :: ExactPi') a. MinCtxt v a => Proxy v -> a
E.injMin (Proxy s
forall k (t :: k). Proxy t
Proxy :: Proxy s)

{-

Rescaling Operations

-}

-- | Rescales a fixed point quantity, accomodating changes both in its scale factor and its representation type.
--
-- Note that this uses an arbitrary precision representation of 'pi', which may be quite slow.
rescale :: forall a b d s1 s2.(Integral a, Integral b, E.KnownExactPi s1, E.KnownExactPi s2) => SQuantity s1 d a -> SQuantity s2 d b
rescale :: SQuantity s1 d a -> SQuantity s2 d b
rescale | Just Integer
s' <- ExactPi -> Maybe Integer
toExactInteger ExactPi
s           = (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b (s1 :: ExactPi') (d :: Dimension) (s2 :: ExactPi').
(Integral a, Integral b) =>
(Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
P.* Integer
s')
        | Just Integer
s' <- ExactPi -> Maybe Integer
toExactInteger (ExactPi -> ExactPi
forall a. Fractional a => a -> a
P.recip ExactPi
s) = (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b (s1 :: ExactPi') (d :: Dimension) (s2 :: ExactPi').
(Integral a, Integral b) =>
(Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger (Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`P.quot` Integer
s')
        | Just Rational
q  <- ExactPi -> Maybe Rational
toExactRational ExactPi
s          = (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b (s1 :: ExactPi') (d :: Dimension) (s2 :: ExactPi').
(Integral a, Integral b) =>
(Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger ((Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b)
-> (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b. (a -> b) -> a -> b
$ Rational -> Integer -> Integer
timesRational Rational
q
        | Bool
otherwise                             = (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b (s1 :: ExactPi') (d :: Dimension) (s2 :: ExactPi').
(Integral a, Integral b) =>
(Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger ((Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b)
-> (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
forall a b. (a -> b) -> a -> b
$ \Integer
x -> [Integer] -> Integer
forall a. Eq a => [a] -> a
fixedPoint ((Rational -> Integer) -> [Rational] -> [Integer]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (((Integer -> Integer) -> Integer -> Integer
forall a b. (a -> b) -> a -> b
$ Integer
x) ((Integer -> Integer) -> Integer)
-> (Rational -> Integer -> Integer) -> Rational -> Integer
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Rational -> Integer -> Integer
timesRational) (ExactPi -> [Rational]
rationalApproximations ExactPi
s))
  where
    s :: ExactPi
s = (ExactPi
s1' ExactPi -> ExactPi -> ExactPi
forall a. Fractional a => a -> a -> a
P./ ExactPi
s2')
    s1' :: ExactPi
s1' = Proxy s1 -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal (Proxy s1
forall k (t :: k). Proxy t
Proxy :: Proxy s1)
    s2' :: ExactPi
s2' = Proxy s2 -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal (Proxy s2
forall k (t :: k). Proxy t
Proxy :: Proxy s2)
    timesRational :: Rational -> Integer -> Integer
    timesRational :: Rational -> Integer -> Integer
timesRational Rational
q = (Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`P.quot` Rational -> Integer
forall a. Ratio a -> a
denominator Rational
q) (Integer -> Integer) -> (Integer -> Integer) -> Integer -> Integer
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
P.* Rational -> Integer
forall a. Ratio a -> a
numerator Rational
q)

-- | Rescales a fixed point quantity, accomodating changes both in its scale factor and its representation type.
--
-- Expected to outperform `rescale` when a `FiniteBits` context is available for the source and destination representation types.
rescaleFinite :: (Integral a, FiniteBits a, Integral b, FiniteBits b, E.KnownExactPi s1, E.KnownExactPi s2) => SQuantity s1 d a -> SQuantity s2 d b
rescaleFinite :: SQuantity s1 d a -> SQuantity s2 d b
rescaleFinite = SQuantity s1 d a -> SQuantity s2 d b
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale -- It should be possible to do this more quickly, since we have a priori knowledge of how well we need to approximate the result

-- | Approximately rescales a fixed point quantity, accomodating changes both in its scale factor and its representation type.
--
-- Uses approximate arithmetic by way of an intermediate `Floating` type, to which a proxy must be supplied.
rescaleVia :: forall a b c d s1 s2.(Integral a, RealFrac b, Floating b, Integral c, E.KnownExactPi s1, E.KnownExactPi s2) => Proxy b -> SQuantity s1 d a -> SQuantity s2 d c
rescaleVia :: Proxy b -> SQuantity s1 d a -> SQuantity s2 d c
rescaleVia Proxy b
_ = (b -> b) -> SQuantity s1 d a -> SQuantity s2 d c
forall a b c (s1 :: ExactPi') (d :: Dimension) (s2 :: ExactPi').
(Integral a, RealFrac b, Integral c) =>
(b -> b) -> SQuantity s1 d a -> SQuantity s2 d c
viaIntermediate (b -> b -> b
forall a. Num a => a -> a -> a
P.* b
s)
  where
    s :: b
s = ExactPi -> b
forall a. Floating a => ExactPi -> a
approximateValue (ExactPi
s1' ExactPi -> ExactPi -> ExactPi
forall a. Fractional a => a -> a -> a
P./ ExactPi
s2') :: b
    s1' :: ExactPi
s1' = Proxy s1 -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal (Proxy s1 -> ExactPi) -> Proxy s1 -> ExactPi
forall a b. (a -> b) -> a -> b
$ (Proxy s1
forall k (t :: k). Proxy t
Proxy :: Proxy s1)
    s2' :: ExactPi
s2' = Proxy s2 -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal (Proxy s2 -> ExactPi) -> Proxy s2 -> ExactPi
forall a b. (a -> b) -> a -> b
$ (Proxy s2
forall k (t :: k). Proxy t
Proxy :: Proxy s2)

-- | Approximately rescales a fixed point quantity, accomodating changes both in its scale factor and its representation type.
--
-- Uses approximate arithmetic by way of an intermediate `Double` representation.
rescaleD :: (Integral a, Integral b, E.KnownExactPi s1, E.KnownExactPi s2) => SQuantity s1 d a -> SQuantity s2 d b
rescaleD :: SQuantity s1 d a -> SQuantity s2 d b
rescaleD = Proxy Double -> SQuantity s1 d a -> SQuantity s2 d b
forall a b c (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, RealFrac b, Floating b, Integral c, KnownExactPi s1,
 KnownExactPi s2) =>
Proxy b -> SQuantity s1 d a -> SQuantity s2 d c
rescaleVia (Proxy Double
forall k (t :: k). Proxy t
Proxy :: Proxy Double)

-- Note that this does not respect scaling factors at all.
viaInteger :: (Integral a, Integral b) => (P.Integer -> P.Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger :: (Integer -> Integer) -> SQuantity s1 d a -> SQuantity s2 d b
viaInteger Integer -> Integer
f = b -> SQuantity s2 d b
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity (b -> SQuantity s2 d b)
-> (SQuantity s1 d a -> b) -> SQuantity s1 d a -> SQuantity s2 d b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Integer -> b
forall a. Num a => Integer -> a
fromInteger (Integer -> b)
-> (SQuantity s1 d a -> Integer) -> SQuantity s1 d a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Integer -> Integer
f (Integer -> Integer)
-> (SQuantity s1 d a -> Integer) -> SQuantity s1 d a -> Integer
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Integer)
-> (SQuantity s1 d a -> a) -> SQuantity s1 d a -> Integer
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SQuantity s1 d a -> a
forall (s :: ExactPi') (d :: Dimension) a. SQuantity s d a -> a
unQuantity

-- Note that this does not respect scaling factors at all.
viaIntermediate :: (Integral a, RealFrac b, Integral c) => (b -> b) -> SQuantity s1 d a -> SQuantity s2 d c
viaIntermediate :: (b -> b) -> SQuantity s1 d a -> SQuantity s2 d c
viaIntermediate b -> b
f = c -> SQuantity s2 d c
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity (c -> SQuantity s2 d c)
-> (SQuantity s1 d a -> c) -> SQuantity s1 d a -> SQuantity s2 d c
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. b -> c
forall a b. (RealFrac a, Integral b) => a -> b
round (b -> c) -> (SQuantity s1 d a -> b) -> SQuantity s1 d a -> c
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. b -> b
f (b -> b) -> (SQuantity s1 d a -> b) -> SQuantity s1 d a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> b) -> (SQuantity s1 d a -> a) -> SQuantity s1 d a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SQuantity s1 d a -> a
forall (s :: ExactPi') (d :: Dimension) a. SQuantity s d a -> a
unQuantity

fixedPoint :: (Eq a) => [a] -> a
fixedPoint :: [a] -> a
fixedPoint []                     = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"Fixed point of empty list."
fixedPoint [a
x]                    = a
x
fixedPoint (a
x1:a
x2:[a]
xs) | a
x1 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x2  = a
x1
                      | Bool
otherwise = [a] -> a
forall a. Eq a => [a] -> a
fixedPoint (a
x2a -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs)

{-

Changes of Representation

-}

-- | Convenient conversion between numerical types while retaining dimensional information.
changeRep :: forall v1 v2 d a b.
            (KnownVariant v1, KnownVariant v2,
             CompatibleVariants v1 v2,
             E.MinCtxt (ScaleFactor v1 E./ ScaleFactor v2) b,
             Real a, Fractional b)
          => Dimensional v1 d a -> Dimensional v2 d b
changeRep :: Dimensional v1 d a -> Dimensional v2 d b
changeRep = (ExactPi -> ExactPi)
-> (a -> b)
-> UnitNameTransformer
-> Dimensional v1 d a
-> Dimensional v2 d b
forall (v1 :: Variant) (v2 :: Variant) a b (d1 :: Dimension)
       (d2 :: Dimension).
(KnownVariant v1, KnownVariant v2) =>
(ExactPi -> ExactPi)
-> (a -> b)
-> UnitNameTransformer
-> Dimensional v1 d1 a
-> Dimensional v2 d2 b
liftD (ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
s) ((b -> b -> b
forall a. Num a => a -> a -> a
P.* b
s') (b -> b) -> (a -> b) -> a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> b
forall a b. (Real a, Fractional b) => a -> b
realToFrac) UnitNameTransformer
Name.weaken
  where
    p :: Proxy (ScaleFactor v1 E./ ScaleFactor v2)
    p :: Proxy (ScaleFactor v1 / ScaleFactor v2)
p = Proxy (ScaleFactor v1 / ScaleFactor v2)
forall k (t :: k). Proxy t
Proxy
    s :: ExactPi
s = Proxy (ScaleFactor v1 / ScaleFactor v2) -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal Proxy (ScaleFactor v1 / ScaleFactor v2)
p
    s' :: b
s' = Proxy (ScaleFactor v1 / ScaleFactor v2) -> b
forall (v :: ExactPi') a. MinCtxt v a => Proxy v -> a
E.injMin Proxy (ScaleFactor v1 / ScaleFactor v2)
p

-- | Convenient conversion to types with `Integral` representations using `round`.
changeRepRound :: forall v1 v2 d a b.
                 (KnownVariant v1, KnownVariant v2,
                  CompatibleVariants v1 v2,
                  E.MinCtxt (ScaleFactor v1 E./ ScaleFactor v2) a,
                  RealFrac a, Integral b)
               => Dimensional v1 d a -> Dimensional v2 d b
changeRepRound :: Dimensional v1 d a -> Dimensional v2 d b
changeRepRound = (ExactPi -> ExactPi)
-> (a -> b)
-> UnitNameTransformer
-> Dimensional v1 d a
-> Dimensional v2 d b
forall (v1 :: Variant) (v2 :: Variant) a b (d1 :: Dimension)
       (d2 :: Dimension).
(KnownVariant v1, KnownVariant v2) =>
(ExactPi -> ExactPi)
-> (a -> b)
-> UnitNameTransformer
-> Dimensional v1 d1 a
-> Dimensional v2 d2 b
liftD (ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
s) (a -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (a -> b) -> (a -> a) -> a -> b
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (a -> a -> a
forall a. Num a => a -> a -> a
P.* a
s')) UnitNameTransformer
Name.weaken
  where
    p :: Proxy (ScaleFactor v1 E./ ScaleFactor v2)
    p :: Proxy (ScaleFactor v1 / ScaleFactor v2)
p = Proxy (ScaleFactor v1 / ScaleFactor v2)
forall k (t :: k). Proxy t
Proxy
    s :: ExactPi
s = Proxy (ScaleFactor v1 / ScaleFactor v2) -> ExactPi
forall (v :: ExactPi'). KnownExactPi v => Proxy v -> ExactPi
E.exactPiVal Proxy (ScaleFactor v1 / ScaleFactor v2)
p
    s' :: a
s' = Proxy (ScaleFactor v1 / ScaleFactor v2) -> a
forall (v :: ExactPi') a. MinCtxt v a => Proxy v -> a
E.injMin Proxy (ScaleFactor v1 / ScaleFactor v2)
p

{-

Useful Constant Values

-}

{- $possibly-imprecise-constants

Note that, other than '_0' and 'epsilon', these constants may not be exactly representable with certain scale factors.

-}

-- | The constant for zero is polymorphic, allowing
-- it to express zero 'Length' or 'Capacitance' or 'Velocity' etc, in addition
-- to the 'Dimensionless' value zero.
_0 :: Num a => SQuantity s d a
_0 :: SQuantity s d a
_0 = a -> SQuantity s d a
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity a
0

_1, _2, _3, _4, _5, _6, _7, _8, _9 :: (Integral a, E.KnownExactPi s) => SQuantity s DOne a
_1 :: SQuantity s DOne a
_1 = SQuantity One DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity One DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity E.One DOne Integer)
_2 :: SQuantity s DOne a
_2 = SQuantity (ExactNatural 2) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 2) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 2) DOne Integer)
_3 :: SQuantity s DOne a
_3 = SQuantity (ExactNatural 3) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 3) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 3) DOne Integer)
_4 :: SQuantity s DOne a
_4 = SQuantity (ExactNatural 4) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 4) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 4) DOne Integer)
_5 :: SQuantity s DOne a
_5 = SQuantity (ExactNatural 5) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 5) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 5) DOne Integer)
_6 :: SQuantity s DOne a
_6 = SQuantity (ExactNatural 6) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 6) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 6) DOne Integer)
_7 :: SQuantity s DOne a
_7 = SQuantity (ExactNatural 7) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 7) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 7) DOne Integer)
_8 :: SQuantity s DOne a
_8 = SQuantity (ExactNatural 8) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 8) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 8) DOne Integer)
_9 :: SQuantity s DOne a
_9 = SQuantity (ExactNatural 9) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity (ExactNatural 9) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 9) DOne Integer)

pi :: (Integral a, E.KnownExactPi s) => SQuantity s DOne a
pi :: SQuantity s DOne a
pi = SQuantity Pi DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (SQuantity Pi DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity E.Pi DOne Integer)

-- | Twice 'pi'.
--
-- For background on 'tau' see https://tauday.com/tau-manifesto (but also
-- feel free to review https://web.archive.org/web/20200926221249/http://www.thepimanifesto.com/).
tau :: (Integral a, E.KnownExactPi s) => SQuantity s DOne a
tau :: SQuantity s DOne a
tau = SQuantity ('ExactPi' 'Pos1 2 1) DOne Integer -> SQuantity s DOne a
forall a b (d :: Dimension) (s1 :: ExactPi') (s2 :: ExactPi').
(Integral a, Integral b, KnownExactPi s1, KnownExactPi s2) =>
SQuantity s1 d a -> SQuantity s2 d b
rescale (Dimensional ('DQuantity (ExactNatural 2 * Pi)) DOne Integer
forall a (s :: ExactPi') (d :: Dimension).
Integral a =>
SQuantity s d a
epsilon :: SQuantity (E.ExactNatural 2 E.* E.Pi) DOne Integer)

-- | The smallest positive representable value in a given fixed-point scaled quantity type.
epsilon :: (Integral a) => SQuantity s d a
epsilon :: SQuantity s d a
epsilon = a -> SQuantity s d a
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity a
1

{- $synonyms

These type synonyms for commonly used fixed-point types are provided for convenience.

-}

-- | A binary scale factor.
type QScale n = (E.One E./ (E.ExactNatural (2 N.^ n)))

-- | A dimensionless number with `n` fractional bits, using a representation of type `a`.
type Q n a = SQuantity (QScale n) DOne a

-- | A single-turn angle represented as a signed 8-bit integer.
type Angle8  = SQuantity (E.Pi E.* (QScale 7))  DPlaneAngle Int8

-- | A single-turn angle represented as a signed 16-bit integer.
type Angle16 = SQuantity (E.Pi E.* (QScale 15)) DPlaneAngle Int16

-- | A single-turn angle represented as a signed 32-bit integer.
type Angle32 = SQuantity (E.Pi E.* (QScale 31)) DPlaneAngle Int32