Skip to content

randomR could produce NaNs when the upper bound is infinity #54

Description

@shaobo-he

When the upper bound is infinity, NaNs could be produced. For example,

filter (\x-> x/= (1/0)) $ randomRs ((0::Float), 1/0) $ mkStdGen 0
[NaN,NaN,NaN

Although it's unclear what should be produced when the upper bound is infinity, I don't think NaNs should be there anyways.

Activity

  1. cartazio commented on Apr 3, 2019

    @cartazio
    Contributor
  2. added a commit that references this issue on May 5, 2020
  3. added a commit that references this issue on May 19, 2020
  4. Bodigrim commented on Jun 24, 2020

    @Bodigrim
    Contributor

    NaN is caused by 0 * ±Infinity, happening in uniformRM when uniformFloat01M returns exactly 0 or 1.

    We can probably guard this case explicitly:

    instance UniformRange Float where
      uniformRM (l, h) g
        | isNaN l = l 
        | isNaN h = h 
        | l == h = return l
        | isInfinite l, isInfinite h = 0/0
        | isInfinite l = l 
        | isInfinite h = h 
        | otherwise = do
          x <- uniformFloat01M g
          return $ x * l + (1 - x) * h

    @curiousleo what do you think about it?

  5. lehins commented on Jun 24, 2020

    @lehins
    Contributor

    @Bodigrim you might be interested to look at discussion in this PR: idontgetoutmuch#138

  6. curiousleo commented on Jun 25, 2020

    @curiousleo
    Contributor

    Or directly here: https://hackage.haskell.org/package/random-1.2.0/docs/System-Random-Stateful.html#g:14

    @Bodigrim great minds think alike :) Here's what I cooked up for my "truly random floats" experiment.

        | isNaN l = l 
        | isNaN h = h 

    The isNaN guards unnecessary; if one of l or h is NaN, the result will be NaN.

        | l == h = return l

    (This guard already exists, added here: idontgetoutmuch#169)

        | isInfinite l, isInfinite h = 0/0

    This is the current behaviour: you get NaN. One alternative would be to generate Inf or -Inf each with p=0.5.

        | isInfinite l = l 
        | isInfinite h = h 

    This is already the current behaviour for x \in (0,1). If x == 0 or x == 1, you can currently get NaN instead, as you pointed out. This case is currently not documented.

    I see two alternatives:

    • We document that when l or h is infinite, you can get a NaN back (if x == 1 or x == 0)
    • We add guards for infinities

    @Bodigrim, would you mind clarifying whether the intent of the code you proposed was to change behaviour, or primarily to "document" current behaviour?

    (Edited heavily, sorry - I misunderstood part of the proposed code.)

  7. idontgetoutmuch commented on Jun 25, 2020

    @idontgetoutmuch
    Member

    In the email notification I just received, I see

        | isInfinite l && isInfinite h = bool negate id <$> uniformM
    

    I think asking to sample a range with infinties is indication that the user has made a mistake. If they really wanted +Inf / -Inf with equal probability then it would be much better for them to be explicit about it. I'd much prefer a NaN here.

  8. idontgetoutmuch commented on Jun 25, 2020

    @idontgetoutmuch
    Member

    | isInfinite l, isInfinite h = 0/0

    I think this is right thing to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions