-
Notifications
You must be signed in to change notification settings - Fork 30
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
Proposed fix for issue #185 #186
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for looking at this ❤️ I think what's happening here is that we're hitting some off-by-one error. Here's the result of your test, without applying any other code change:
Starting test execution, please wait...
[xUnit.net 00:00:07.0504320] Hedgehog.Tests.GenTests.can create exponentially bounded uint64 [FAIL]
X Hedgehog.Tests.GenTests.can create exponentially bounded uint64 [1s 970ms]
Error Message:
System.OverflowException : Value was either too large or too small for a UInt64.
Stack Trace:
at System.Numerics.BigInteger.op_Explicit(BigInteger value)
at <StartupCode$Hedgehog>[email protected](BigInteger x) in ..\fsharp-hedgehog\src\Hedgehog\Numeric.fs:line 205
at Hedgehog.Tests.GenTests.can create exponentially bounded [email protected](Int32 sz) in ..\fsharp-hedgehog\tests\Hedgehog.Tests\GenTests.fs:line 90
at Hedgehog.Range.Bounds[a](Int32 sz, Range`1 _arg1) in ..\fsharp-hedgehog\src\Hedgehog\Range.fs:line 42
at [email protected](Seed seed, Int32 size) in ..\fsharp-hedgehog\src\Hedgehog\Gen.fs:line 473
at Hedgehog.Random.unsafeRun[a](Seed seed, Int32 size, Random`1 _arg1) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 11
at [email protected](Seed seed, Int32 size) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 40
at Hedgehog.Random.unsafeRun[a](Seed seed, Int32 size, Random`1 _arg1) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 11
at Hedgehog.Random.run[a](Seed seed, Int32 size, Random`1 r) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 14
at [email protected](Seed seed, Random`1 random) in ..\fsharp-hedgehog\src\Hedgehog\Gen.fs:line 45
at [email protected](Seed seed0, Int32 size) in ..\fsharp-hedgehog\src\Hedgehog\Gen.fs:line 47
at Hedgehog.Random.unsafeRun[a](Seed seed, Int32 size, Random`1 _arg1) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 11
at [email protected](Seed seed, Int32 size) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 18
at Hedgehog.Random.unsafeRun[a](Seed seed, Int32 size, Random`1 _arg1) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 11
at Hedgehog.Random.run[a](Seed seed, Int32 size, Random`1 r) in ..\fsharp-hedgehog\src\Hedgehog\Random.fs:line 14
at [email protected](Seed seed, Int32 size, Int32 tests, Int32 discards) in ..\fsharp-hedgehog\src\Hedgehog\Property.fs:line 343
at Hedgehog.Property.Report(Int32 n, Property`1 p) in ..\fsharp-hedgehog\src\Hedgehog\Property.fs:line 356
at Hedgehog.Property.Report(Property`1 p) in ..\fsharp-hedgehog\src\Hedgehog\Property.fs:line 360
at Hedgehog.Property.Check(Property`1 p) in ..\fsharp-hedgehog\src\Hedgehog\Property.fs:line 369
at Hedgehog.Tests.GenTests.can create exponentially bounded uint64() in ..\fsharp-hedgehog\tests\Hedgehog.Tests\GenTests.fs:line 89
[xUnit.net 00:00:07.6352928] Hedgehog.Tests.GenTests.can create exponentially bounded int64 [FAIL]
Notice this:
at <StartupCode$Hedgehog>[email protected](BigInteger x) in ..\fsharp-hedgehog\src\Hedgehog\Numeric.fs:line 205
When the test fails, the input to that function is 18446744073709551616 which is exactly off-by-one the largest possible value of UInt64:
18446744073709551616 // Off-by-one
18446744073709551615 // UInt64.MaxValue
If that's the case (I'm 88% sure at this point), we shouldn't then need to re-arrange clamp
and scale
.
This reverts commit 9a95b50.
@@ -122,7 +122,7 @@ module Range = | |||
fromBigInt (z + diff) | |||
|
|||
/// Scale an integral exponentially with the size parameter. | |||
let inline scaleExponential (sz0 : Size) (z0 : 'a) (n0 : 'a) : 'a = | |||
let inline scaleExponential (lo : 'a) (hi : 'a) (sz0 : Size) (z0 : 'a) (n0 : 'a) : 'a = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jacobstanley, I don't like this change, but other alternatives I've tried make the F# compiler infer 'a
as bigint
and breaks everything. Since scaleExponential
is internal
I'll go ahead and merge this.
Right now exponential 64-bit un/signed integers can cause arithmetic overflows, and break upstream packages, so I'll go ahead and proceed with this fix.
@marklam, do you have a Twitter account? Usually, when doing a new release, we announce it on Twitter and give credit to all contributors that helped get the release out. |
Thanks @moodmosaic, I'm |
#185
The problem looks to be that the clamp on exponential ranges is performed after the conversion to the target type, so if the value falls just outside the range then an exception is thrown before the clamp occurs.
This moves the clamp to before the conversion, but maybe a better fix would be to sort out the calculation that's going out of bounds in the first place.