Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arb.float() stops generating NaNs if the range is not 'full' #4014

Open
YSakhno opened this issue May 10, 2024 · 0 comments
Open

Arb.float() stops generating NaNs if the range is not 'full' #4014

YSakhno opened this issue May 10, 2024 · 0 comments

Comments

@YSakhno
Copy link

YSakhno commented May 10, 2024

When using includeNonFiniteEdgeCases = true (which is true anyway by default for the version 5.9.0 of Kotest), Float.NaN are only generated when the range is the full range (-Float.MAX_VALUE..Float.MAX_VALUE, which is also the default range). When the range is reduced ever so slightly, then Float.NaN are not generated as edge-cases anymore.

Generators for Doubles (Double.arb()) also have the same problem.

Which version of Kotest are you using - 5.9.0

Code to reproduce the issue

(The code is written in FunSpec style.)

    test("no NaNs generated for -MAX_VALUE..MAX_VALUE range") {
        forAll(Arb.float(range = -Float.MAX_VALUE..Float.MAX_VALUE, includeNonFiniteEdgeCases = true)) { f ->
            !f.isNaN() // NaNs are generated, so this test fails as it should
        }
    }
    test("no NaNs generated for -1..MAX_VALUE range") {
        forAll(Arb.float(range = -1f..Float.MAX_VALUE, includeNonFiniteEdgeCases = true)) { f ->
            !f.isNaN() // NaNs are never generated, test passes (should fail)
        }
    }
    test("no NaNs generated for -MAX_VALUE..1 range") {
        forAll(Arb.float(range = -Float.MAX_VALUE..1f, includeNonFiniteEdgeCases = true)) { f ->
            !f.isNaN() // NaNs are never generated, test passes (should fail)
        }
    }
    test("no NaNs generated for -1..1 range") {
        forAll(Arb.float(range = -1f..1f, includeNonFiniteEdgeCases = true)) { f ->
            !f.isNaN() // NaNs are never generated, test passes (should fail)
        }
    }

Note, that these are 'reverse' tests, i.e. the generators behave correctly when the test fails. Yet, here only the first test fails, the other 3 pass (while they should also fail).

Documentation (in)correctness

As a side note, the documentation which says

The non-finite edge cases are Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY and Float.NaN which are only included if they are in the provided range and includeNonFiniteEdgeCases flag is true.

is also incorrect (does not match the actual result) in that the infinities technically are not in the default range. For them to be in the range, the range has to be Float.NEGATIVE_INFINITY..Float.POSITIVE_INFINITY (yes, such range is legal in Kotlin). Yet having the range that only includes the Float.MAX_VALUE (either positive or negative) is enough to generate an infinity (also positive or negative, respectively).

Expected behavior

  1. Infinities should only be generated when the range truly includes them (for example, Float.NEGATIVE_INFINITY..Float.POSITIVE_INFINITY, 1.0..Double.POSITIVE_INFINITY, etc.).
  2. Infinities should not be generated when the range does not include them, such a -Float.MAX_VALUE..Float.MAX_VALUE and any smaller range.
  3. Generator's parameter includeNonFiniteEdgeCases should be renamed to includeNaNs (as effectively it should only control generation of NaNs; generation of infinities should be controlled by the range).
  4. Float.NaN (and Double.NaN for the respective generator) should always be generated if includeNaNs argument (see point above) is true, regardless of the range (i.e. even if the range is empty).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant