
Bodigrim pushed to branch wip/fix-toRational at Glasgow Haskell Compiler / GHC Commits: 8aa42af4 by Andrew Lelechenko at 2025-06-15T17:25:10+01:00 Fix issues with toRational for types capable to represent infinite and not-a-number values This commit fixes all of the following pitfalls:
toRational (read "Infinity" :: Double) 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216 % 1 toRational (read "NaN" :: Double) 269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824 % 1
realToFrac (read "NaN" :: Double) -- With -O0 Infinity realToFrac (read "NaN" :: Double) -- With -O1 NaN
realToFrac (read "NaN" :: Double) :: CDouble Infinity realToFrac (read "NaN" :: CDouble) :: Double Infinity
Implements https://github.com/haskell/core-libraries-committee/issues/338 - - - - - 4 changed files: - libraries/base/changelog.md - libraries/ghc-internal/src/GHC/Internal/Float.hs - libraries/ghc-internal/src/GHC/Internal/Real.hs - testsuite/tests/numeric/should_run/T9810.stdout Changes: ===================================== libraries/base/changelog.md ===================================== @@ -11,6 +11,7 @@ * `instance Functor NonEmpty` is now specified using `map` (rather than duplicating code). ([CLC proposal #300](https://github.com/haskell/core-libraries-committee/issues/300)) * `fail` from `MonadFail` now carries `HasCallStack` constraint. ([CLC proposal #327](https://github.com/haskell/core-libraries-committee/issues/327)) * The `Data.Enum.enumerate` function was introduced ([CLC #306](https://github.com/haskell/core-libraries-committee/issues/306)) + * Fix issues with toRational for types capable to represent infinite and not-a-number values ([CLC proposal #338](https://github.com/haskell/core-libraries-committee/issues/338) * Worker threads used by various `base` facilities are now labelled with descriptive thread labels ([CLC proposal #305](https://github.com/haskell/core-libraries-committee/issues/305), [GHC #25452](https://gitlab.haskell.org/ghc/ghc/-/issues/25452)). Specifically, these include: * `Control.Concurrent.threadWaitRead` * `Control.Concurrent.threadWaitWrite` ===================================== libraries/ghc-internal/src/GHC/Internal/Float.hs ===================================== @@ -430,14 +430,10 @@ naturalToFloat# (NB b) = case integerToBinaryFloat' (IP b) of -- | @since base-2.01 -- --- Beware that 'toRational' generates garbage for non-finite arguments: --- --- >>> toRational (1/0 :: Float) --- 340282366920938463463374607431768211456 % 1 --- >>> toRational (0/0 :: Float) --- 510423550381407695195061911147652317184 % 1 --- instance Real Float where + toRational x + | isInfinite x = if x > 0 then infinity else -infinity + | isNaN x = notANumber toRational (F# x#) = case decodeFloat_Int# x# of (# m#, e# #) @@ -686,14 +682,10 @@ naturalToDouble# (NB b) = case integerToBinaryFloat' (IP b) of -- | @since base-2.01 -- --- Beware that 'toRational' generates garbage for non-finite arguments: --- --- >>> toRational (1/0) --- 179769313 (and 300 more digits...) % 1 --- >>> toRational (0/0) --- 269653970 (and 300 more digits...) % 1 --- instance Real Double where + toRational x + | isInfinite x = if x > 0 then infinity else -infinity + | isNaN x = notANumber toRational (D# x#) = case integerDecodeDouble# x# of (# m, e# #) ===================================== libraries/ghc-internal/src/GHC/Internal/Real.hs ===================================== @@ -703,15 +703,6 @@ fromIntegral = fromInteger . toInteger -- | General coercion to 'Fractional' types. -- --- WARNING: This function goes through the 'Rational' type, which does not have values for 'NaN' for example. --- This means it does not round-trip. --- --- For 'Double' it also behaves differently with or without -O0: --- --- > Prelude> realToFrac nan -- With -O0 --- > -Infinity --- > Prelude> realToFrac nan --- > NaN realToFrac :: (Real a, Fractional b) => a -> b {-# NOINLINE [1] realToFrac #-} -- See Note [Allow time for type-specialisation rules to fire] ===================================== testsuite/tests/numeric/should_run/T9810.stdout ===================================== @@ -1,14 +1,14 @@ ## Double ## Infinity -Infinity -Infinity +NaN Infinity -Infinity Infinity ## Float ## Infinity -Infinity -Infinity +NaN Infinity -Infinity Infinity View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8aa42af4edde8c6614abd618237bde7c... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8aa42af4edde8c6614abd618237bde7c... You're receiving this email because of your account on gitlab.haskell.org.