-- SPDX-License-Identifier: MPL-2.0

{- | Radian-based checked trigonometry. Real inverse branches: asin [-pi/2,pi/2],
acos [0,pi], atan (-pi/2,pi/2), acot (0,pi). Nonfinite inputs and undefined
real domains return errors. Poles at represented multiples of pi and pi/2 are
rejected; near poles remain finite when representable. Complex functions use
the principal branches of Data.Complex (NIST DLMF sections 4.23 and 4.37).
-}
module HMath.Trigonometry (
    sinChecked,
    cosChecked,
    tanChecked,
    asinChecked,
    acosChecked,
    atanChecked,
    atan2Checked,
    sec,
    csc,
    cot,
    asec,
    acsc,
    acot,
    sinhChecked,
    coshChecked,
    tanhChecked,
    asinhChecked,
    acoshChecked,
    atanhChecked,
    sech,
    csch,
    coth,
    asech,
    acsch,
    acoth,
    sincos,
    wrap,
    normalizeAngle,
    normalizeSignedAngle,
    angleDifference,
    versine,
    haversine,
    sinc,
    cosc,
    greatCircleAngle,
    greatCircleDistance,
    sphericalSide,
    sphericalAngles,
    sphericalExcess,
    ComplexFunction (..),
    complexFunction,
    complexSin,
    complexCos,
    complexTan,
    complexAsin,
    complexAcos,
    complexAtan,
    complexSinh,
    complexCosh,
    complexTanh,
    complexAsinh,
    complexAcosh,
    complexAtanh,
    periodicSawtooth,
    periodicTriangle,
    periodicSquare,
) where

import Data.Complex (Complex (..), imagPart, realPart)
import HMath.Error (MathError (..))

finite :: (RealFloat a) => a -> Bool
finite :: forall a. RealFloat a => a -> Bool
finite a
x = Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isNaN a
x Bool -> Bool -> Bool
|| a -> Bool
forall a. RealFloat a => a -> Bool
isInfinite a
x)
checked :: (RealFloat a) => (a -> a) -> a -> Either MathError a
checked :: forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
f a
x
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite a
x) = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"non-finite angular input")
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite a
y) = MathError -> Either MathError a
forall a b. a -> Either a b
Left MathError
NonFiniteResult
    | Bool
otherwise = a -> Either MathError a
forall a b. b -> Either a b
Right a
y
  where
    y :: a
y = a -> a
f a
x
restricted :: (RealFloat a) => (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted :: forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted a -> Bool
domain String
message a -> a
f a
x
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite a
x) Bool -> Bool -> Bool
|| Bool -> Bool
not (a -> Bool
domain a
x) = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
message)
    | Bool
otherwise = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
f a
x
sinChecked
    , cosChecked
    , tanChecked
    , asinChecked
    , acosChecked
    , atanChecked ::
        (RealFloat a) => a -> Either MathError a

{- | Sine of a radian argument. Return Right result for finite input in the stated domain;
invalid input/poles or non-finite output return Left MathError.
-}
sinChecked :: forall a. RealFloat a => a -> Either MathError a
sinChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
sin

{- | Cosine of a radian argument. Return Right result for finite input in the stated domain;
invalid input/poles or non-finite output return Left MathError.
-}
cosChecked :: forall a. RealFloat a => a -> Either MathError a
cosChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
cos

{- | Tangent of a radian argument; represented poles at odd pi/2 are rejected. Return Right
result for finite input in the stated domain; invalid input/poles or non-finite output
return Left MathError.
-}
tanChecked :: forall a. RealFloat a => a -> Either MathError a
tanChecked a
x = do
    a <- a -> Either MathError a
forall a. RealFloat a => a -> Either MathError a
normalizeSignedAngle a
x
    if abs a == pi / 2 then Left (DomainError "tangent pole") else checked tan x

{- | Principal inverse sine in [-pi/2,pi/2]; require abs(x)\<=1. Return Right result for
finite input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
asinChecked :: forall a. RealFloat a => a -> Either MathError a
asinChecked = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1) String
"asin needs abs x <= 1" a -> a
forall a. Floating a => a -> a
asin

{- | Principal inverse cosine in [0,pi]; require abs(x)\<=1. Return Right result for finite
input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
acosChecked :: forall a. RealFloat a => a -> Either MathError a
acosChecked = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1) String
"acos needs abs x <= 1" a -> a
forall a. Floating a => a -> a
acos

{- | Principal inverse tangent in (-pi/2,pi/2). Return Right result for finite input in the
stated domain; invalid input/poles or non-finite output return Left MathError.
-}
atanChecked :: forall a. RealFloat a => a -> Either MathError a
atanChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
atan

-- | Conventional atan2(y,x), range [-pi,pi]. Rejects the undefined origin.
atan2Checked :: (RealFloat a) => a -> a -> Either MathError a
atan2Checked :: forall a. RealFloat a => a -> a -> Either MathError a
atan2Checked a
y a
x
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
x, a
y]) Bool -> Bool -> Bool
|| (a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 Bool -> Bool -> Bool
&& a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0) = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"invalid atan2 point")
    | Bool
otherwise = a -> Either MathError a
forall a b. b -> Either a b
Right (a -> a -> a
forall a. RealFloat a => a -> a -> a
atan2 a
y a
x)

sec, csc, cot, asec, acsc, acot :: (RealFloat a) => a -> Either MathError a

{- | Secant 1/cos(x) in radians; represented odd-pi/2 poles fail. Return Right result for
finite input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
sec :: forall a. RealFloat a => a -> Either MathError a
sec a
x = do
    a <- a -> Either MathError a
forall a. RealFloat a => a -> Either MathError a
normalizeSignedAngle a
x
    if abs a == pi / 2 then Left (DomainError "secant pole") else checked (\a
v -> a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a -> a
forall a. Floating a => a -> a
cos a
v) x

{- | Cosecant 1/sin(x) in radians; represented multiples of pi fail. Return Right result for
finite input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
csc :: forall a. RealFloat a => a -> Either MathError a
csc a
x = do
    a <- a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 a
forall a. Floating a => a
pi a
x
    if a == 0 then Left (DomainError "cosecant pole") else checked (\a
v -> a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a -> a
forall a. Floating a => a -> a
sin a
v) x

{- | Cotangent cos(x)/sin(x) in radians; represented multiples of pi fail. Return Right
result for finite input in the stated domain; invalid input/poles or non-finite output
return Left MathError.
-}
cot :: forall a. RealFloat a => a -> Either MathError a
cot a
x = do
    a <- a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 a
forall a. Floating a => a
pi a
x
    if a == 0 then Left (DomainError "cotangent pole") else checked (\a
v -> a -> a
forall a. Floating a => a -> a
cos a
v a -> a -> a
forall a. Fractional a => a -> a -> a
/ a -> a
forall a. Floating a => a -> a
sin a
v) x

{- | Principal inverse secant acos(1/x); require abs(x)>=1. Return Right result for finite
input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
asec :: forall a. RealFloat a => a -> Either MathError a
asec = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
1) String
"asec needs abs x >= 1" (a -> a
forall a. Floating a => a -> a
acos (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. Fractional a => a -> a
recip)

{- | Principal inverse cosecant asin(1/x); require abs(x)>=1. Return Right result for finite
input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
acsc :: forall a. RealFloat a => a -> Either MathError a
acsc = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
1) String
"acsc needs abs x >= 1" (a -> a
forall a. Floating a => a -> a
asin (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. Fractional a => a -> a
recip)

{- | Inverse cotangent atan2(1,x), with range (0,pi). Return Right result for finite input
in the stated domain; invalid input/poles or non-finite output return Left MathError.
-}
acot :: forall a. RealFloat a => a -> Either MathError a
acot = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (a -> a -> a
forall a. RealFloat a => a -> a -> a
atan2 a
1)

sinhChecked
    , coshChecked
    , tanhChecked
    , asinhChecked
    , acoshChecked
    , atanhChecked ::
        (RealFloat a) => a -> Either MathError a

{- | Hyperbolic sine. Return Right result for finite input in the stated domain; invalid
input/poles or non-finite output return Left MathError.
-}
sinhChecked :: forall a. RealFloat a => a -> Either MathError a
sinhChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
sinh

{- | Hyperbolic cosine. Return Right result for finite input in the stated domain; invalid
input/poles or non-finite output return Left MathError.
-}
coshChecked :: forall a. RealFloat a => a -> Either MathError a
coshChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
cosh

{- | Hyperbolic tangent. Return Right result for finite input in the stated domain; invalid
input/poles or non-finite output return Left MathError.
-}
tanhChecked :: forall a. RealFloat a => a -> Either MathError a
tanhChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
tanh

{- | Inverse hyperbolic sine. Return Right result for finite input in the stated domain;
invalid input/poles or non-finite output return Left MathError.
-}
asinhChecked :: forall a. RealFloat a => a -> Either MathError a
asinhChecked = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked a -> a
forall a. Floating a => a -> a
asinh

{- | Principal real inverse hyperbolic cosine; require x>=1. Return Right result for finite
input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
acoshChecked :: forall a. RealFloat a => a -> Either MathError a
acoshChecked = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
1) String
"acosh needs x >= 1" a -> a
forall a. Floating a => a -> a
acosh

{- | Inverse hyperbolic tangent; require abs(x)\<1. Return Right result for finite input in
the stated domain; invalid input/poles or non-finite output return Left MathError.
-}
atanhChecked :: forall a. RealFloat a => a -> Either MathError a
atanhChecked = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1) String
"atanh needs abs x < 1" a -> a
forall a. Floating a => a -> a
atanh

sech, csch, coth, asech, acsch, acoth :: (RealFloat a) => a -> Either MathError a

-- exponential formulas avoid overflowing cosh/sinh for large finite arguments.

{- | Hyperbolic secant 1/cosh(x), using a scaled exponential formula for large arguments.
Return Right result for finite input in the stated domain; invalid input/poles or
non-finite output return Left MathError.
-}
sech :: forall a. RealFloat a => a -> Either MathError a
sech = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (\a
x -> let e :: a
e = a -> a
forall a. Floating a => a -> a
exp (-a -> a
forall a. Num a => a -> a
abs a
x) in a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
e a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
1 a -> a -> a
forall a. Num a => a -> a -> a
+ a
e a -> a -> a
forall a. Num a => a -> a -> a
* a
e))

{- | Hyperbolic cosecant 1/sinh(x); reject zero. Return Right result for finite input in the
stated domain; invalid input/poles or non-finite output return Left MathError.
-}
csch :: forall a. RealFloat a => a -> Either MathError a
csch =
    (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted
        (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0)
        String
"csch pole"
        (\a
x -> if a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1 then a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a -> a
forall a. Floating a => a -> a
sinh a
x else let e :: a
e = a -> a
forall a. Floating a => a -> a
exp (-a -> a
forall a. Num a => a -> a
abs a
x) in a -> a
forall a. Num a => a -> a
signum a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
e a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
1 a -> a -> a
forall a. Num a => a -> a -> a
- a
e a -> a -> a
forall a. Num a => a -> a -> a
* a
e))

{- | Hyperbolic cotangent 1/tanh(x); reject zero. Return Right result for finite input in
the stated domain; invalid input/poles or non-finite output return Left MathError.
-}
coth :: forall a. RealFloat a => a -> Either MathError a
coth = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0) String
"coth pole" (a -> a
forall a. Fractional a => a -> a
recip (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. Floating a => a -> a
tanh)

{- | Inverse hyperbolic secant; require 0\<x\<=1. Return Right result for finite input in the
stated domain; invalid input/poles or non-finite output return Left MathError.
-}
asech :: forall a. RealFloat a => a -> Either MathError a
asech =
    (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted
        (\a
x -> a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0 Bool -> Bool -> Bool
&& a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1)
        String
"asech needs 0 < x <= 1"
        (\a
x -> a -> a
forall a. Floating a => a -> a
log (a
1 a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a. Floating a => a -> a
sqrt (a
1 a -> a -> a
forall a. Num a => a -> a -> a
- a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
x)) a -> a -> a
forall a. Num a => a -> a -> a
- a -> a
forall a. Floating a => a -> a
log a
x)

{- | Inverse hyperbolic cosecant; reject zero and use a log formula near zero. Return Right
result for finite input in the stated domain; invalid input/poles or non-finite output
return Left MathError.
-}
acsch :: forall a. RealFloat a => a -> Either MathError a
acsch =
    (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted
        (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
0)
        String
"acsch needs x /= 0"
        (\a
x -> if a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1e-15 then a -> a
forall a. Num a => a -> a
signum a
x a -> a -> a
forall a. Num a => a -> a -> a
* (a -> a
forall a. Floating a => a -> a
log a
2 a -> a -> a
forall a. Num a => a -> a -> a
- a -> a
forall a. Floating a => a -> a
log (a -> a
forall a. Num a => a -> a
abs a
x)) else a -> a
forall a. Floating a => a -> a
asinh (a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
x))

{- | Inverse hyperbolic cotangent; require abs(x)>1. Return Right result for finite input in
the stated domain; invalid input/poles or non-finite output return Left MathError.
-}
acoth :: forall a. RealFloat a => a -> Either MathError a
acoth = (a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
forall a.
RealFloat a =>
(a -> Bool) -> String -> (a -> a) -> a -> Either MathError a
restricted (\a
x -> a -> a
forall a. Num a => a -> a
abs a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
1) String
"acoth needs abs x > 1" (a -> a
forall a. Floating a => a -> a
atanh (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. Fractional a => a -> a
recip)

{- | Given a finite radian angle, return Right (sin x,cos x), propagating checked
input/result failures. Example: sincos 0 == Right (0,1).
-}
sincos :: (RealFloat a) => a -> Either MathError (a, a)
sincos :: forall a. RealFloat a => a -> Either MathError (a, a)
sincos a
x = do s <- a -> Either MathError a
forall a. RealFloat a => a -> Either MathError a
sinChecked a
x; c <- cosChecked x; Right (s, c)

{- | Wrap to [lo,hi). Exact rational reduction avoids overflowing x-lo and
preserves the interval contract even for huge finite values. The period is
the represented endpoints' difference; no accuracy claim is made for reducing
enormous angles modulo the mathematical irrational 2*pi.
-}
wrap :: (RealFloat a) => a -> a -> a -> Either MathError a
wrap :: forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
lo a
hi a
x
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
lo, a
hi, a
x]) Bool -> Bool -> Bool
|| a
lo a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
hi = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"invalid wrapping interval")
    | Bool
otherwise =
        let a :: Rational
a = a -> Rational
forall a. Real a => a -> Rational
toRational a
lo
            b :: Rational
b = a -> Rational
forall a. Real a => a -> Rational
toRational a
hi
            period :: Rational
period = Rational
b Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Rational
a
            v :: Rational
v = a -> Rational
forall a. Real a => a -> Rational
toRational a
x Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Rational
a
            r :: a
r = Rational -> a
forall a. Fractional a => Rational -> a
fromRational (Rational
a Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
v Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Integer -> Rational
forall a. Num a => Integer -> a
fromInteger (Rational -> Integer
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Rational
v Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
period)) Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
period)
         in a -> Either MathError a
forall a b. b -> Either a b
Right (if a
r a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
hi then a
lo else a -> a -> a
forall a. Ord a => a -> a -> a
max a
lo a
r)

normalizeAngle, normalizeSignedAngle :: (RealFloat a) => a -> Either MathError a

{- | Wrap a finite radian angle into [0,2*pi). Non-finite input fails. Reduction uses the
represented period; no exact huge-angle reduction against irrational pi is promised.
-}
normalizeAngle :: forall a. RealFloat a => a -> Either MathError a
normalizeAngle = a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 (a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
forall a. Floating a => a
pi)

{- | Wrap a finite radian angle into [-pi,pi). Non-finite input fails. The positive endpoint
pi wraps to -pi.
-}
normalizeSignedAngle :: forall a. RealFloat a => a -> Either MathError a
normalizeSignedAngle = a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap (-a
forall a. Floating a => a
pi) a
forall a. Floating a => a
pi

{- | Given angles a then b, return the signed wrapped difference a-b in [-pi,pi). Reject
non-finite input. Normalize operands first to avoid avoidable subtraction overflow.
-}
angleDifference :: (RealFloat a) => a -> a -> Either MathError a
angleDifference :: forall a. RealFloat a => a -> a -> Either MathError a
angleDifference a
a a
b
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
a, a
b]) = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"non-finite angle")
    | Bool
otherwise = do x <- a -> Either MathError a
forall a. RealFloat a => a -> Either MathError a
normalizeSignedAngle a
a; y <- normalizeSignedAngle b; normalizeSignedAngle (x - y)

versine, haversine, sinc, cosc :: (RealFloat a) => a -> Either MathError a

{- | Versine 1-cos(x), evaluated as 2*sin(x/2)^2 for a radian input. Return Right result for
finite input in the stated domain; invalid input/poles or non-finite output return Left
MathError.
-}
versine :: forall a. RealFloat a => a -> Either MathError a
versine = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (\a
x -> a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int))

{- | Haversine sin(x/2)^2 for a radian input. Return Right result for finite input in the
stated domain; invalid input/poles or non-finite output return Left MathError.
-}
haversine :: forall a. RealFloat a => a -> Either MathError a
haversine = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (\a
x -> a -> a
forall a. Floating a => a -> a
sin (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int))

{- | Unnormalized sinc sin(x)/x for radians, with continuous value 1 at zero. Return Right
result for finite input in the stated domain; invalid input/poles or non-finite output
return Left MathError.
-}
sinc :: forall a. RealFloat a => a -> Either MathError a
sinc a
x
    | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = a -> Either MathError a
forall a b. b -> Either a b
Right a
1
    | Bool
otherwise = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (\a
v -> a -> a
forall a. Floating a => a -> a
sin a
v a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
v) a
x

-- | (1-cos x)/x with its continuous value 0 at x=0.
cosc :: forall a. RealFloat a => a -> Either MathError a
cosc a
x
    | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = a -> Either MathError a
forall a b. b -> Either a b
Right a
x
    | Bool
otherwise = (a -> a) -> a -> Either MathError a
forall a. RealFloat a => (a -> a) -> a -> Either MathError a
checked (\a
v -> (a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin (a
v a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
v) a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin (a
v a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2)) a
x

-- | Latitudes in [-pi/2,pi/2], longitudes any finite radians. Central angle [0,pi].
greatCircleAngle :: (RealFloat a) => (a, a) -> (a, a) -> Either MathError a
greatCircleAngle :: forall a. RealFloat a => (a, a) -> (a, a) -> Either MathError a
greatCircleAngle (a
lat1, a
lon1) (a
lat2, a
lon2)
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
lat1, a
lon1, a
lat2, a
lon2]) Bool -> Bool -> Bool
|| a -> a
forall a. Num a => a -> a
abs a
lat1 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
forall a. Floating a => a
pi a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2 Bool -> Bool -> Bool
|| a -> a
forall a. Num a => a -> a
abs a
lat2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
forall a. Floating a => a
pi a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2 =
        MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"invalid spherical coordinates")
    | Bool
otherwise = do
        dl <- a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> Either MathError a
angleDifference a
lon2 a
lon1
        let a = a -> a
forall a. Floating a => a -> a
sin ((a
lat2 a -> a -> a
forall a. Num a => a -> a -> a
- a
lat1) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int) a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a. Floating a => a -> a
cos a
lat1 a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
cos a
lat2 a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin (a
dl a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2) a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)
            h = a -> a -> a
forall a. Ord a => a -> a -> a
max a
0 (a -> a -> a
forall a. Ord a => a -> a -> a
min a
1 a
a)
        Right (2 * atan2 (sqrt h) (sqrt (1 - h)))

{- | Given finite nonnegative sphere radius and two (latitude,longitude) radian pairs,
return radius times the central angle. Reject invalid latitude, non-finite input, or
result overflow. Distance uses the radius units.
-}
greatCircleDistance :: (RealFloat a) => a -> (a, a) -> (a, a) -> Either MathError a
greatCircleDistance :: forall a.
RealFloat a =>
a -> (a, a) -> (a, a) -> Either MathError a
greatCircleDistance a
radius (a, a)
a (a, a)
b
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite a
radius) Bool -> Bool -> Bool
|| a
radius a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"invalid sphere radius")
    | Bool
otherwise =
        (a, a) -> (a, a) -> Either MathError a
forall a. RealFloat a => (a, a) -> (a, a) -> Either MathError a
greatCircleAngle (a, a)
a (a, a)
b Either MathError a
-> (a -> Either MathError a) -> Either MathError a
forall a b.
Either MathError a
-> (a -> Either MathError b) -> Either MathError b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \a
v -> if a -> Bool
forall a. RealFloat a => a -> Bool
finite (a
radius a -> a -> a
forall a. Num a => a -> a -> a
* a
v) then a -> Either MathError a
forall a b. b -> Either a b
Right (a
radius a -> a -> a
forall a. Num a => a -> a -> a
* a
v) else MathError -> Either MathError a
forall a b. a -> Either a b
Left MathError
NonFiniteResult

-- | Two spherical sides and their included angle, all in [0,pi].
sphericalSide :: (RealFloat a) => a -> a -> a -> Either MathError a
sphericalSide :: forall a. RealFloat a => a -> a -> a -> Either MathError a
sphericalSide a
a a
b a
included
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
a, a
b, a
included]) Bool -> Bool -> Bool
|| (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\a
x -> a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
forall a. Floating a => a
pi) [a
a, a
b, a
included] =
        MathError -> Either MathError a
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"invalid spherical sides/angle")
    | Bool
otherwise = a -> Either MathError a
forall a b. b -> Either a b
Right (a -> a
forall a. Floating a => a -> a
acos (a -> a -> a
forall a. Ord a => a -> a -> a
max (-a
1) (a -> a -> a
forall a. Ord a => a -> a -> a
min a
1 (a -> a
forall a. Floating a => a -> a
cos a
a a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
cos a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a. Floating a => a -> a
sin a
a a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin a
b a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
cos a
included))))

-- | Interior angles for a nondegenerate minor spherical triangle, sides (0,pi).
sphericalAngles :: (RealFloat a) => a -> a -> a -> Either MathError (a, a, a)
sphericalAngles :: forall a. RealFloat a => a -> a -> a -> Either MathError (a, a, a)
sphericalAngles a
a a
b a
c
    | Bool -> Bool
not ((a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all a -> Bool
forall a. RealFloat a => a -> Bool
finite [a
a, a
b, a
c])
        Bool -> Bool -> Bool
|| (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\a
x -> a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0 Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
forall a. Floating a => a
pi) [a
a, a
b, a
c]
        Bool -> Bool -> Bool
|| a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
b a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
c
        Bool -> Bool -> Bool
|| a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
b
        Bool -> Bool -> Bool
|| a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
a
        Bool -> Bool -> Bool
|| a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
b a -> a -> a
forall a. Num a => a -> a -> a
+ a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
2 a -> a -> a
forall a. Num a => a -> a -> a
* a
forall a. Floating a => a
pi =
        MathError -> Either MathError (a, a, a)
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"degenerate spherical triangle")
    | Bool
otherwise = (a, a, a) -> Either MathError (a, a, a)
forall a b. b -> Either a b
Right (a -> a -> a -> a
forall {a}. (Floating a, Ord a) => a -> a -> a -> a
angle a
a a
b a
c, a -> a -> a -> a
forall {a}. (Floating a, Ord a) => a -> a -> a -> a
angle a
b a
a a
c, a -> a -> a -> a
forall {a}. (Floating a, Ord a) => a -> a -> a -> a
angle a
c a
a a
b)
  where
    angle :: a -> a -> a -> a
angle a
x a
y a
z = a -> a
forall a. Floating a => a -> a
acos (a -> a -> a
forall a. Ord a => a -> a -> a
max (-a
1) (a -> a -> a
forall a. Ord a => a -> a -> a
min a
1 ((a -> a
forall a. Floating a => a -> a
cos a
x a -> a -> a
forall a. Num a => a -> a -> a
- a -> a
forall a. Floating a => a -> a
cos a
y a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
cos a
z) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a -> a
forall a. Floating a => a -> a
sin a
y a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Floating a => a -> a
sin a
z))))

{- | Given three side angles of a nondegenerate minor spherical triangle, compute
interior-angle sum minus pi. Side/domain errors propagate from sphericalAngles.
Multiply by radius squared for area.
-}
sphericalExcess :: (RealFloat a) => a -> a -> a -> Either MathError a
sphericalExcess :: forall a. RealFloat a => a -> a -> a -> Either MathError a
sphericalExcess a
a a
b a
c = do (x, y, z) <- a -> a -> a -> Either MathError (a, a, a)
forall a. RealFloat a => a -> a -> a -> Either MathError (a, a, a)
sphericalAngles a
a a
b a
c; Right (x + y + z - pi)

{- | Checked complex trigonometric/hyperbolic principal-branch function selector,including
reciprocal secant/cosecant/cotangent variants.
-}
data ComplexFunction
    = CSin
    | CCos
    | CTan
    | CAsin
    | CAcos
    | CAtan
    | CSinh
    | CCosh
    | CTanh
    | CAsinh
    | CAcosh
    | CAtanh
    | CSec
    | CCsc
    | CCot
    | CSech
    | CCsch
    | CCoth
    deriving (ComplexFunction -> ComplexFunction -> Bool
(ComplexFunction -> ComplexFunction -> Bool)
-> (ComplexFunction -> ComplexFunction -> Bool)
-> Eq ComplexFunction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ComplexFunction -> ComplexFunction -> Bool
== :: ComplexFunction -> ComplexFunction -> Bool
$c/= :: ComplexFunction -> ComplexFunction -> Bool
/= :: ComplexFunction -> ComplexFunction -> Bool
Eq, Int -> ComplexFunction -> ShowS
[ComplexFunction] -> ShowS
ComplexFunction -> String
(Int -> ComplexFunction -> ShowS)
-> (ComplexFunction -> String)
-> ([ComplexFunction] -> ShowS)
-> Show ComplexFunction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ComplexFunction -> ShowS
showsPrec :: Int -> ComplexFunction -> ShowS
$cshow :: ComplexFunction -> String
show :: ComplexFunction -> String
$cshowList :: [ComplexFunction] -> ShowS
showList :: [ComplexFunction] -> ShowS
Show)

{- | Given a ComplexFunction selector then complex input, compute the selected
principal-branch Data.Complex function or reciprocal. Reject non-finite components and
non-finite results/poles with Left DomainError.
-}
complexFunction :: (RealFloat a) => ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction :: forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
name Complex a
z
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite (Complex a -> a
forall a. Complex a -> a
realPart Complex a
z) Bool -> Bool -> Bool
&& a -> Bool
forall a. RealFloat a => a -> Bool
finite (Complex a -> a
forall a. Complex a -> a
imagPart Complex a
z)) =
        MathError -> Either MathError (Complex a)
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"non-finite complex argument")
    | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
finite (Complex a -> a
forall a. Complex a -> a
realPart Complex a
value) Bool -> Bool -> Bool
&& a -> Bool
forall a. RealFloat a => a -> Bool
finite (Complex a -> a
forall a. Complex a -> a
imagPart Complex a
value)) =
        MathError -> Either MathError (Complex a)
forall a b. a -> Either a b
Left (String -> MathError
DomainError String
"complex pole or overflow")
    | Bool
otherwise = Complex a -> Either MathError (Complex a)
forall a b. b -> Either a b
Right Complex a
value
  where
    value :: Complex a
value = case ComplexFunction
name of
        ComplexFunction
CSin -> Complex a -> Complex a
forall a. Floating a => a -> a
sin Complex a
z
        ComplexFunction
CCos -> Complex a -> Complex a
forall a. Floating a => a -> a
cos Complex a
z
        ComplexFunction
CTan -> Complex a -> Complex a
forall a. Floating a => a -> a
tan Complex a
z
        ComplexFunction
CAsin -> Complex a -> Complex a
forall a. Floating a => a -> a
asin Complex a
z
        ComplexFunction
CAcos -> Complex a -> Complex a
forall a. Floating a => a -> a
acos Complex a
z
        ComplexFunction
CAtan -> Complex a -> Complex a
forall a. Floating a => a -> a
atan Complex a
z
        ComplexFunction
CSinh -> Complex a -> Complex a
forall a. Floating a => a -> a
sinh Complex a
z
        ComplexFunction
CCosh -> Complex a -> Complex a
forall a. Floating a => a -> a
cosh Complex a
z
        ComplexFunction
CTanh -> Complex a -> Complex a
forall a. Floating a => a -> a
tanh Complex a
z
        ComplexFunction
CAsinh -> Complex a -> Complex a
forall a. Floating a => a -> a
asinh Complex a
z
        ComplexFunction
CAcosh -> Complex a -> Complex a
forall a. Floating a => a -> a
acosh Complex a
z
        ComplexFunction
CAtanh -> Complex a -> Complex a
forall a. Floating a => a -> a
atanh Complex a
z
        ComplexFunction
CSec -> Complex a
1 Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
cos Complex a
z
        ComplexFunction
CCsc -> Complex a
1 Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
sin Complex a
z
        ComplexFunction
CCot -> Complex a -> Complex a
forall a. Floating a => a -> a
cos Complex a
z Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
sin Complex a
z
        ComplexFunction
CSech -> Complex a
1 Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
cosh Complex a
z
        ComplexFunction
CCsch -> Complex a
1 Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
sinh Complex a
z
        ComplexFunction
CCoth -> Complex a -> Complex a
forall a. Floating a => a -> a
cosh Complex a
z Complex a -> Complex a -> Complex a
forall a. Fractional a => a -> a -> a
/ Complex a -> Complex a
forall a. Floating a => a -> a
sinh Complex a
z

complexSin
    , complexCos
    , complexTan
    , complexAsin
    , complexAcos
    , complexAtan
    , complexSinh
    , complexCosh
    , complexTanh
    , complexAsinh
    , complexAcosh
    , complexAtanh ::
        (RealFloat a) => Complex a -> Either MathError (Complex a)

{- | Principal complex sine, dispatched through complexFunction. Return Right complex
result; non-finite input components or a pole/overflow producing non-finite components
return Left DomainError. Angles use radians.
-}
complexSin :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexSin = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CSin

{- | Principal complex cosine, dispatched through complexFunction. Return Right complex
result; non-finite input components or a pole/overflow producing non-finite components
return Left DomainError. Angles use radians.
-}
complexCos :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexCos = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CCos

{- | Principal complex tangent, dispatched through complexFunction. Return Right complex
result; non-finite input components or a pole/overflow producing non-finite components
return Left DomainError. Angles use radians.
-}
complexTan :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexTan = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CTan

{- | Principal complex inverse sine, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexAsin :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAsin = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAsin

{- | Principal complex inverse cosine, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexAcos :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAcos = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAcos

{- | Principal complex inverse tangent, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexAtan :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAtan = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAtan

{- | Principal complex hyperbolic sine, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexSinh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexSinh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CSinh

{- | Principal complex hyperbolic cosine, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexCosh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexCosh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CCosh

{- | Principal complex hyperbolic tangent, dispatched through complexFunction. Return Right
complex result; non-finite input components or a pole/overflow producing non-finite
components return Left DomainError. Angles use radians.
-}
complexTanh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexTanh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CTanh

{- | Principal complex inverse hyperbolic sine, dispatched through complexFunction. Return
Right complex result; non-finite input components or a pole/overflow producing
non-finite components return Left DomainError. Angles use radians.
-}
complexAsinh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAsinh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAsinh

{- | Principal complex inverse hyperbolic cosine, dispatched through complexFunction. Return
Right complex result; non-finite input components or a pole/overflow producing
non-finite components return Left DomainError. Angles use radians.
-}
complexAcosh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAcosh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAcosh

{- | Principal complex inverse hyperbolic tangent, dispatched through complexFunction.
Return Right complex result; non-finite input components or a pole/overflow producing
non-finite components return Left DomainError. Angles use radians.
-}
complexAtanh :: forall a. RealFloat a => Complex a -> Either MathError (Complex a)
complexAtanh = ComplexFunction -> Complex a -> Either MathError (Complex a)
forall a.
RealFloat a =>
ComplexFunction -> Complex a -> Either MathError (Complex a)
complexFunction ComplexFunction
CAtanh

{- | Unit-amplitude periodic waves. Period must be positive and finite. Square
wave is +1 on the first half-cycle, -1 on the second, including midpoint.
-}
periodicSawtooth, periodicTriangle, periodicSquare :: (RealFloat a) => a -> a -> Either MathError a
periodicSawtooth :: forall a. RealFloat a => a -> a -> Either MathError a
periodicSawtooth a
period a
x = do t <- a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 a
period a
x; Right (2 * (t / period) - 1)
periodicTriangle :: forall a. RealFloat a => a -> a -> Either MathError a
periodicTriangle a
period a
x = do t <- a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 a
period a
x; Right (1 - 4 * abs (t / period - 0.5))
periodicSquare :: forall a. RealFloat a => a -> a -> Either MathError a
periodicSquare a
period a
x = do t <- a -> a -> a -> Either MathError a
forall a. RealFloat a => a -> a -> a -> Either MathError a
wrap a
0 a
period a
x; Right (if t / period < 0.5 then 1 else -1)