{-# 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 ()
nextUp :: RealFloat a => a -> a
nextUp :: a -> a
nextUp x :: a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error "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
> 0) = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x
| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= 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 #-}
nextDown :: RealFloat a => a -> a
nextDown :: a -> a
nextDown x :: a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error "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
< 0) = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x
| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= 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 #-}
nextTowardZero :: RealFloat a => a -> a
nextTowardZero :: a -> a
nextTowardZero x :: a
x | Bool -> Bool
not (a -> Bool
forall a. RealFloat a => a -> Bool
isIEEE a
x) = [Char] -> a
forall a. HasCallStack => [Char] -> a
error "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
== 0 = a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
x
| a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= 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 x :: 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
< 0 = [Char] -> a
forall a. HasCallStack => [Char] -> a
error "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
== 0 = Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat 1 (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d)
| Bool
otherwise = let m :: Integer
e :: Int
(m :: Integer
m,e :: Int
e) = a -> (Integer, Int)
forall a. RealFloat a => a -> (Integer, Int)
decodeFloat a
x
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
if Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 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
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ 0
else
Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 1) Int
e
else
let m' :: Integer
m' = if Integer
base Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 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
+ 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
(expMin :: Int
expMin,expMax :: Int
expMax) = a -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange a
x
{-# INLINE nextUp_positive #-}
nextDown_positive :: RealFloat a => a -> a
nextDown_positive :: a -> a
nextDown_positive x :: 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
< 0 = [Char] -> a
forall a. HasCallStack => [Char] -> a
error "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
== 0 = Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat (-1) (Int
expMin Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
d)
| Bool
otherwise = let m :: Integer
e :: Int
(m :: Integer
m,e :: Int
e) = a -> (Integer, Int)
forall a. RealFloat a => a -> (Integer, Int)
decodeFloat a
x
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
let m1 :: Integer
m1 = Integer
m Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 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
- 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
- 1) (Int
e Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1)
else
Integer -> Int -> a
forall a. RealFloat a => Integer -> Int -> a
encodeFloat Integer
m1 Int
e
else
let m' :: Integer
m' = if Integer
base Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 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
- 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
(expMin :: Int
expMin,_expMax :: Int
_expMax) = a -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange a
x
{-# 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
#-}
nextUpFloat :: Float -> Float
nextUpFloat :: Float -> Float
nextUpFloat x :: Float
x =
case Float -> Word32
castFloatToWord32 Float
x of
w :: Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. 0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7f80_0000
, Word32
w Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0xff80_0000 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x
0x8000_0000 -> Float
forall a. RealFloat a => a
minPositive
w :: Word32
w | Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
w 31 -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- 1)
| Bool
otherwise -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ 1)
where
!Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Float is IEEE binary32"
nextUpDouble :: Double -> Double
nextUpDouble :: Double -> Double
nextUpDouble x :: Double
x =
case Double -> Word64
castDoubleToWord64 Double
x of
w :: Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. 0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7ff0_0000_0000_0000
, Word64
w Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0xfff0_0000_0000_0000 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x
0x8000_0000_0000_0000 -> Double
forall a. RealFloat a => a
minPositive
w :: Word64
w | Word64 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word64
w 63 -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- 1)
| Bool
otherwise -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ 1)
where
!Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Double is IEEE binary64"
nextDownFloat :: Float -> Float
nextDownFloat :: Float -> Float
nextDownFloat x :: Float
x =
case Float -> Word32
castFloatToWord32 Float
x of
w :: Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. 0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7f80_0000
, Word32
w Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0x7f80_0000 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x
0x0000_0000 -> - Float
forall a. RealFloat a => a
minPositive
w :: Word32
w | Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word32
w 31 -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ 1)
| Bool
otherwise -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- 1)
where
!Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Float is IEEE binary32"
nextDownDouble :: Double -> Double
nextDownDouble :: Double -> Double
nextDownDouble x :: Double
x =
case Double -> Word64
castDoubleToWord64 Double
x of
w :: Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. 0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7ff0_0000_0000_0000
, Word64
w Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0x7ff0_0000_0000_0000 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x
0x0000_0000_0000_0000 -> - Double
forall a. RealFloat a => a
minPositive
w :: Word64
w | Word64 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Word64
w 63 -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ 1)
| Bool
otherwise -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- 1)
where
!Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Double is IEEE binary64"
nextTowardZeroFloat :: Float -> Float
nextTowardZeroFloat :: Float -> Float
nextTowardZeroFloat x :: Float
x =
case Float -> Word32
castFloatToWord32 Float
x of
w :: Word32
w | Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. 0x7f80_0000 Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7f80_0000
, Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. 0x007f_ffff Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0 -> Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
x
0x8000_0000 -> Float
x
0x0000_0000 -> Float
x
w :: Word32
w -> Word32 -> Float
castWord32ToFloat (Word32
w Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- 1)
where
!Bool
True = Bool
isFloatBinary32 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Float is IEEE binary32"
nextTowardZeroDouble :: Double -> Double
nextTowardZeroDouble :: Double -> Double
nextTowardZeroDouble x :: Double
x =
case Double -> Word64
castDoubleToWord64 Double
x of
w :: Word64
w | Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. 0x7ff0_0000_0000_0000 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x7ff0_0000_0000_0000
, Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. 0x000f_ffff_ffff_ffff Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0 -> Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x
0x8000_0000_0000_0000 -> Double
x
0x0000_0000_0000_0000 -> Double
x
w :: Word64
w -> Word64 -> Double
castWord64ToDouble (Word64
w Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- 1)
where
!Bool
True = Bool
isDoubleBinary64 Bool -> Bool -> Bool
|| [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error "Numeric.Floating.Extra assumes Double is IEEE binary64"