{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE BangPatterns #-}
module Numeric.Floating.IEEE.Internal.NextFloat where
import           Data.Bits
import           GHC.Float.Compat (castDoubleToWord64, castFloatToWord32,
                                   castWord32ToFloat, castWord64ToDouble)
import           MyPrelude
import           Numeric.Floating.IEEE.Internal.Base

default ()

-- $setup
-- >>> :set -XHexFloatLiterals -XNumericUnderscores

-- |
-- Returns the smallest value that is larger than the argument.
--
-- IEEE 754 @nextUp@ operation.
--
-- >>> nextUp 1 == (0x1.000002p0 :: Float)
-- True
-- >>> nextUp 1 == (0x1.0000_0000_0000_1p0 :: Double)
-- True
-- >>> nextUp (1/0) == (1/0 :: Double)
-- True
-- >>> nextUp (-1/0) == (- maxFinite :: Double)
-- True
-- >>> nextUp 0 == (0x1p-1074 :: Double)
-- True
-- >>> nextUp (-0) == (0x1p-1074 :: Double)
-- True
-- >>> nextUp (-0x1p-1074) :: Double -- returns negative zero
-- -0.0
nextUp :: RealFloat a => a -> a
nextUp :: a -> a
nextUp a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"non-IEEE numbers are not supported"
         | 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 Bool -> Bool -> Bool
&& a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0) = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x -- NaN or positive infinity
         | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 = a -> a
forall a. RealFloat a => a -> a
nextUp_positive a
x
         | Bool
otherwise = - a -> a
forall a. RealFloat a => a -> a
nextDown_positive (- a
x)
{-# INLINE [1] nextUp #-}

-- |
-- Returns the largest value that is smaller than the argument.
--
-- IEEE 754 @nextDown@ operation.
--
-- >>> nextDown 1 == (0x1.ffff_ffff_ffff_fp-1 :: Double)
-- True
-- >>> nextDown 1 == (0x1.fffffep-1 :: Float)
-- True
-- >>> nextDown (1/0) == (maxFinite :: Double)
-- True
-- >>> nextDown (-1/0) == (-1/0 :: Double)
-- True
-- >>> nextDown 0 == (-0x1p-1074 :: Double)
-- True
-- >>> nextDown (-0) == (-0x1p-1074 :: Double)
-- True
-- >>> nextDown 0x1p-1074 -- returns positive zero
-- 0.0
-- >>> nextDown 0x1p-1022 == (0x0.ffff_ffff_ffff_fp-1022 :: Double)
-- True
nextDown :: RealFloat a => a -> a
nextDown :: a -> a
nextDown a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"non-IEEE numbers are not supported"
           | 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 Bool -> Bool -> Bool
&& a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0) = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x -- NaN or negative infinity
           | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 = a -> a
forall a. RealFloat a => a -> a
nextDown_positive a
x
           | Bool
otherwise = - a -> a
forall a. RealFloat a => a -> a
nextUp_positive (- a
x)
{-# INLINE [1] nextDown #-}

-- |
-- Returns the value whose magnitude is smaller than that of the argument, and is closest to the argument.
--
-- This operation is not in IEEE, but may be useful to some.
--
-- >>> nextTowardZero 1 == (0x1.ffff_ffff_ffff_fp-1 :: Double)
-- True
-- >>> nextTowardZero 1 == (0x1.fffffep-1 :: Float)
-- True
-- >>> nextTowardZero (1/0) == (maxFinite :: Double)
-- True
-- >>> nextTowardZero (-1/0) == (-maxFinite :: Double)
-- True
-- >>> nextTowardZero 0 :: Double -- returns positive zero
-- 0.0
-- >>> nextTowardZero (-0 :: Double) -- returns negative zero
-- -0.0
-- >>> nextTowardZero 0x1p-1074 :: Double
-- 0.0
nextTowardZero :: RealFloat a => a -> a
nextTowardZero :: a -> a
nextTowardZero a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"non-IEEE numbers are not supported"
                 | a -> Bool
forall a. RealFloat a => a -> Bool
isNaN a
x Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x -- NaN or zero
                 | a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 = a -> a
forall a. RealFloat a => a -> a
nextDown_positive a
x
                 | Bool
otherwise = - a -> a
forall a. RealFloat a => a -> a
nextDown_positive (- a
x)
{-# INLINE [1] nextTowardZero #-}

nextUp_positive :: RealFloat a => a -> a
nextUp_positive :: a -> a
nextUp_positive a
x
  | a -> Bool
forall a. RealFloat a => a -> Bool
isNaN a
x Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"nextUp_positive"
  | a -> Bool
forall a. RealFloat a => a -> Bool
isInfinite a
x = a
x
  | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat Integer
1 (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d) -- min positive
  | Bool
otherwise = let m :: Integer
                    e :: Int
                    (Integer
m,Int
e) = a -> (Integer, Int)
forall a. RealFloat a => a -> (Integer, Int)
decodeFloat a
x
                    -- x = m * 2^e, 2^(d-1) <= m < 2^d
                    -- 2^expMin < x < 2^expMax
                    -- 2^(expMin-d): min positive
                    -- 2^(expMin - 1): min normal 0x1p-1022
                    -- expMin - d <= e <= expMax - d (-1074 .. 971)
                in if Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
e then
                     -- normal
                     if Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
base Integer -> Int -> Integer
^! Int
d Bool -> Bool -> Bool
&& Int
e Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
expMax Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d then
                       a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
0 -- max finite -> infinity
                     else
                       Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1) Int
e
                   else
                     -- subnormal
                     let m' :: Integer
m' = if Integer
base Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
2 then
                                Integer
m Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
`unsafeShiftR` (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
e)
                              else
                                Integer
m Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` (Integer
base Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
e))
                     in Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (Integer
m' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1) (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d)
  where
    d, expMin :: Int
    base :: Integer
base = a -> Integer
forall a. RealFloat a => a -> Integer
floatRadix a
x
    d :: Int
d = a -> Int
forall a. RealFloat a => a -> Int
floatDigits a
x -- 53 for Double
    (Int
expMin,Int
expMax) = a -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange a
x -- (-1021,1024) for Double
{-# INLINE nextUp_positive #-}

nextDown_positive :: RealFloat a => a -> a
nextDown_positive :: a -> a
nextDown_positive a
x
  | a -> Bool
forall a. RealFloat a => a -> Bool
isNaN a
x Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"nextDown_positive"
  | a -> Bool
forall a. RealFloat a => a -> Bool
isInfinite a
x = a
forall a. RealFloat a => a
maxFinite
  | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (-Integer
1) (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d) -- max negative
  | Bool
otherwise = let m :: Integer
                    e :: Int
                    (Integer
m,Int
e) = a -> (Integer, Int)
forall a. RealFloat a => a -> (Integer, Int)
decodeFloat a
x
                    -- x = m * 2^e, 2^(d-1) <= m < 2^d
                    -- 2^expMin < x < 2^expMax
                    -- 2^(expMin-d): min positive
                    -- 2^(expMin - 1): min normal 0x1p-1022
                    -- expMin - d <= e <= expMax - d (-1074 .. 971)
                in if Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
e then
                     -- normal
                     let m1 :: Integer
m1 = Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1
                     in if Integer
m Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
base Integer -> Int -> Integer
^! (Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Bool -> Bool -> Bool
&& Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
e then
                          Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (Integer
base Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1) (Int
e Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
                        else
                          Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat Integer
m1 Int
e
                   else
                     -- subnormal
                     let m' :: Integer
m' = if Integer
base Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
2 then
                                Integer
m Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
`unsafeShiftR` (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
e)
                              else
                                Integer
m Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` (Integer
base Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
e))
                     in Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (Integer
m' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1) (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d)
  where
    d, expMin :: Int
    base :: Integer
base = a -> Integer
forall a. RealFloat a => a -> Integer
floatRadix a
x
    d :: Int
d = a -> Int
forall a. RealFloat a => a -> Int
floatDigits a
x -- 53 for Double
    (Int
expMin,Int
_expMax) = a -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange a
x -- (-1021,1024) for Double
{-# INLINE nextDown_positive #-}

{-# RULES
"nextUp/Float" nextUp = nextUpFloat
"nextUp/Double" nextUp = nextUpDouble
"nextDown/Float" nextDown = nextDownFloat
"nextDown/Double" nextDown = nextDownDouble
"nextTowardZero/Float" nextTowardZero = nextTowardZeroFloat
"nextTowardZero/Double" nextTowardZero = nextTowardZeroDouble
  #-}

-- |
-- prop> nextUpFloat 1 == 0x1.000002p0
-- prop> nextUpFloat (1/0) == 1/0
-- prop> nextUpFloat (-1/0) == - maxFinite
-- prop> nextUpFloat 0 == 0x1p-149
-- prop> nextUpFloat (-0) == 0x1p-149
-- prop> isNegativeZero (nextUpFloat (-0x1p-149))
nextUpFloat :: Float -> Float
nextUpFloat :: Float -> Float
nextUpFloat Float
x =
  case Float -> Word32
castFloatToWord32 Float
x of
    Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
0x7f80_0000
      , Word32
w Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word32
0xff80_0000 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x -- NaN or positive infinity -> itself
    Word32
0x8000_0000 -> Float
forall a. RealFloat a => a
minPositive -- -0 -> min positive
    Word32
w | Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
w Int
31 -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
1) -- negative
      | Bool
otherwise -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1) -- positive
  where
    !Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Float is IEEE binary32"

-- |
-- prop> nextUpDouble 1 == 0x1.0000_0000_0000_1p0
-- prop> nextUpDouble (1/0) == 1/0
-- prop> nextUpDouble (-1/0) == - maxFinite
-- prop> nextUpDouble 0 == 0x1p-1074
-- prop> nextUpDouble (-0) == 0x1p-1074
-- prop> isNegativeZero (nextUpDouble (-0x1p-1074))
nextUpDouble :: Double -> Double
nextUpDouble :: Double -> Double
nextUpDouble Double
x =
  case Double -> Word64
castDoubleToWord64 Double
x of
    Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0x7ff0_0000_0000_0000
      , Word64
w Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word64
0xfff0_0000_0000_0000 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x -- NaN or positive infinity -> itself
    Word64
0x8000_0000_0000_0000 -> Double
forall a. RealFloat a => a
minPositive -- -0 -> min positive
    Word64
w | Word64 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word64
w Int
63 -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1) -- negative
      | Bool
otherwise -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1) -- positive
  where
     !Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Double is IEEE binary64"

-- |
-- prop> nextDownFloat 1 == 0x1.fffffep-1
-- prop> nextDownFloat (1/0) == maxFinite
-- prop> nextDownFloat (-1/0) == -1/0
-- prop> nextDownFloat 0 == -0x1p-149
-- prop> nextDownFloat (-0) == -0x1p-149
-- prop> nextDownFloat 0x1p-149 == 0
nextDownFloat :: Float -> Float
nextDownFloat :: Float -> Float
nextDownFloat Float
x =
  case Float -> Word32
castFloatToWord32 Float
x of
    Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
0x7f80_0000
      , Word32
w Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word32
0x7f80_0000 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x -- NaN or negative infinity -> itself
    Word32
0x0000_0000 -> - Float
forall a. RealFloat a => a
minPositive -- +0 -> max negative
    Word32
w | Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
w Int
31 -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1) -- negative
      | Bool
otherwise -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
1) -- positive
  where
    !Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Float is IEEE binary32"

-- |
-- prop> nextDownDouble 1 == 0x1.ffff_ffff_ffff_fp-1
-- prop> nextDownDouble (1/0) == maxFinite
-- prop> nextDownDouble (-1/0) == -1/0
-- prop> nextDownDouble 0 == -0x1p-1074
-- prop> nextDownDouble (-0) == -0x1p-1074
-- prop> nextDownDouble 0x1p-1074 == 0
nextDownDouble :: Double -> Double
nextDownDouble :: Double -> Double
nextDownDouble Double
x =
  case Double -> Word64
castDoubleToWord64 Double
x of
    Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0x7ff0_0000_0000_0000
      , Word64
w Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word64
0x7ff0_0000_0000_0000 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x -- NaN or negative infinity -> itself
    Word64
0x0000_0000_0000_0000 -> - Double
forall a. RealFloat a => a
minPositive -- +0 -> max negative
    Word64
w | Word64 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word64
w Int
63 -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1) -- negative
      | Bool
otherwise -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1) -- positive
  where
     !Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Double is IEEE binary64"

-- |
-- prop> nextTowardZeroFloat 1 == 0x1.fffffep-1
-- prop> nextTowardZeroFloat (-1) == -0x1.fffffep-1
-- prop> nextTowardZeroFloat (1/0) == maxFinite
-- prop> nextTowardZeroFloat (-1/0) == -maxFinite
-- prop> nextTowardZeroFloat 0 == 0
-- prop> isNegativeZero (nextTowardZeroFloat (-0))
-- prop> nextTowardZeroFloat 0x1p-149 == 0
nextTowardZeroFloat :: Float -> Float
nextTowardZeroFloat :: Float -> Float
nextTowardZeroFloat Float
x =
  case Float -> Word32
castFloatToWord32 Float
x of
    Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
0x7f80_0000
      , Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0x007f_ffff Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word32
0 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x -- NaN -> itself
    Word32
0x8000_0000 -> Float
x -- -0 -> itself
    Word32
0x0000_0000 -> Float
x -- +0 -> itself
    Word32
w -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
1) -- positive / negative
  where
    !Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Float is IEEE binary32"

-- |
-- prop> nextTowardZeroDouble 1 == 0x1.ffff_ffff_ffff_fp-1
-- prop> nextTowardZeroDouble (-1) == -0x1.ffff_ffff_ffff_fp-1
-- prop> nextTowardZeroDouble (1/0) == maxFinite
-- prop> nextTowardZeroDouble (-1/0) == -maxFinite
-- prop> nextTowardZeroDouble 0 == 0
-- prop> isNegativeZero (nextTowardZeroDouble (-0))
-- prop> nextTowardZeroDouble 0x1p-1074 == 0
nextTowardZeroDouble :: Double -> Double
nextTowardZeroDouble :: Double -> Double
nextTowardZeroDouble Double
x =
  case Double -> Word64
castDoubleToWord64 Double
x of
    Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0x7ff0_0000_0000_0000
      , Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x000f_ffff_ffff_ffff Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word64
0 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x -- NaN -> itself
    Word64
0x8000_0000_0000_0000 -> Double
x -- -0 -> itself
    Word64
0x0000_0000_0000_0000 -> Double
x -- +0 -> itself
    Word64
w -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1) -- positive / negative
  where
    !Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"Numeric.Floating.Extra assumes Double is IEEE binary64"