{-#
    LANGUAGE
      BangPatterns,
      MagicHash,
      UnboxedTuples,
      UnliftedNewtypes
  #-}

-- | Real numbers in [0,1), represented as fixed-point reals stored in
-- a machine word.
--
-- `Fractional` would arguably be a better name, but is of course
-- already in use.
module Numeric.Mantissa.Unboxed (
  Mantissa#(..),
  eqMantissa#,
  neMantissa#,
  gtMantissa#,
  ltMantissa#,
  geMantissa#,
  leMantissa#,
  plusMod1Mantissa#,
  minusMod1Mantissa#,
  plusWithOverflowMantissa#,
  minusWithOverflowMantissa#,
  timesMantissa#,
  quotMantissa#,
  ) where

import GHC.Exts


-- | A real number in [0,1), represented as an unboxed word
newtype Mantissa# = Mantissa# Word#

eqMantissa# :: Mantissa# -> Mantissa# -> Int#
eqMantissa# :: Mantissa# -> Mantissa# -> Int#
eqMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
eqWord# Word#
a Word#
b

neMantissa# :: Mantissa# -> Mantissa# -> Int#
neMantissa# :: Mantissa# -> Mantissa# -> Int#
neMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
neWord# Word#
a Word#
b

ltMantissa# :: Mantissa# -> Mantissa# -> Int#
ltMantissa# :: Mantissa# -> Mantissa# -> Int#
ltMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
ltWord# Word#
a Word#
b

gtMantissa# :: Mantissa# -> Mantissa# -> Int#
gtMantissa# :: Mantissa# -> Mantissa# -> Int#
gtMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
gtWord# Word#
a Word#
b

leMantissa# :: Mantissa# -> Mantissa# -> Int#
leMantissa# :: Mantissa# -> Mantissa# -> Int#
leMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
leWord# Word#
a Word#
b

geMantissa# :: Mantissa# -> Mantissa# -> Int#
geMantissa# :: Mantissa# -> Mantissa# -> Int#
geMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Word# -> Int#
geWord# Word#
a Word#
b

-- | Addition modulo 1
plusMod1Mantissa# :: Mantissa# -> Mantissa# -> Mantissa#
plusMod1Mantissa# :: Mantissa# -> Mantissa# -> Mantissa#
plusMod1Mantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Mantissa#
Mantissa# (Word# -> Word# -> Word#
plusWord# Word#
a Word#
b)

-- | Subtraction modulo 1
minusMod1Mantissa# :: Mantissa# -> Mantissa# -> Mantissa#
minusMod1Mantissa# :: Mantissa# -> Mantissa# -> Mantissa#
minusMod1Mantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = Word# -> Mantissa#
Mantissa# (Word# -> Word# -> Word#
minusWord# Word#
a Word#
b)

-- | The second Int# component is nonzero on overflow
plusWithOverflowMantissa# :: Mantissa# -> Mantissa# -> (# Mantissa#, Int# #)
plusWithOverflowMantissa# :: Mantissa# -> Mantissa# -> (# Mantissa#, Int# #)
plusWithOverflowMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = let
  !(# Word#
c, Int#
i #) = Word# -> Word# -> (# Word#, Int# #)
addWordC# Word#
a Word#
b
  in (# Word# -> Mantissa#
Mantissa# Word#
c, Int#
i #)

-- | The second Int# component is nonzero on overflow
minusWithOverflowMantissa# :: Mantissa# -> Mantissa# -> (# Mantissa#, Int# #)
minusWithOverflowMantissa# :: Mantissa# -> Mantissa# -> (# Mantissa#, Int# #)
minusWithOverflowMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = let
  !(# Word#
c, Int#
i #) = Word# -> Word# -> (# Word#, Int# #)
subWordC# Word#
a Word#
b
  in (# Word# -> Mantissa#
Mantissa# Word#
c, Int#
i #)

timesMantissa# :: Mantissa# -> Mantissa# -> Mantissa#
timesMantissa# :: Mantissa# -> Mantissa# -> Mantissa#
timesMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = let
  !(# Word#
c, Word#
_ #) = Word# -> Word# -> (# Word#, Word# #)
timesWord2# Word#
a Word#
b
  in Word# -> Mantissa#
Mantissa# Word#
c

-- | The user is responsible for ensuring that, when they take
-- dividend/divisor, then the dividend is less than the divisor.
quotMantissa# :: Mantissa# -> Mantissa# -> Mantissa#
quotMantissa# :: Mantissa# -> Mantissa# -> Mantissa#
quotMantissa# (Mantissa# Word#
a) (Mantissa# Word#
b) = let
  !(# Word#
c, Word#
_ #) = Word# -> Word# -> Word# -> (# Word#, Word# #)
quotRemWord2# Word#
a Word#
0## Word#
b
  in Word# -> Mantissa#
Mantissa# Word#
c