Closed ifesdjeen closed 10 years ago
How would you shrink a float? By continuously subtracting some epsilon? By doing a binary search on the number line?
As Zach mentions, figuring out the best way to do shrinking is non-obvious. That being said, in the meantime, this should work quite nicely, and I may just go ahead and stick it in:
(def float (gen/fmap float gen/ratio))
(gen/sample float 20)
;; => (0.0 0.0 -1.0 0.0 -1.0 0.75 0.5 0.8 -2.0 -0.5714286 2.6666667 -2.0 -0.46153846 -0.125 -12.0 -1.75 -2.4 0.41666666 0.64285713 -1.125)
And to give an example, here's the set of ways that -0.71428573
will shrink:
#{0.0 -2.0 -2.5 -3.0 -4.0 -0.25 -5.0 -0.5 -0.75 -1.0 -1.25 -1.5 -0.14285715 -0.2857143 -0.5714286 -0.16666667 -0.33333334 -0.6666667 -1.3333334 -0.2 -0.4 -0.8 -0.71428573 -0.8333333 -1.6666666 -0.42857143 -0.6}
To answer your original question, yes, I think it'd be handy.
Right, shrinking would be a bit problematic, didn't think of it...
I've changed my impl (was a bit stupid) to yours.
Thanks!
Sorry to reopen that one, just for record (not sure if closed issues generate notifications):
Haskell implementation is shrinking a fraction: http://hackage.haskell.org/package/QuickCheck-2.6/docs/src/Test-QuickCheck-Arbitrary.html#shrinkRealFrac
Please feel free to close.
Yeah let's leave it open until something is merged in. Thanks.
In Haskell, it's a bit simpler because of type matching. I'll check out codebase, maybe I manage to understand how to differentiate between types when shrinking.
Definitely +1 for having float, double, bigdec, etc. in simple-check. Basing them off ratios produces some strange shrinking paths though. Here's how I'm currently generating bigdecs, mostly hijacked from data.generators:
https://gist.github.com/cemerick/7450631
The nice thing about this is that the components being shrunk are exposed in the final value, whereas (AFAICT) the numerator and denominator shrinking can have outsized impact on the actual value produced (e.g. -0.71428573
shrinking to higher-magnitude numbers).
The above can be adapted to produce doubles and floats too, but translating it to use long and int bits would obviously be faster than fmap
ping to coerce constrained bigdecs down.
Oh, IEEE 754, we meet again. Shrinking floats/doubles bitwise is (of course) going to require someone more motivated in the clever arts than I. Nevermind that the result won't be portable to JS, short of even more cleverness using typed arrays and such…
I'll see if I can whip up something slower, but more understandable.
Yeah, that's part of the reason I've punted on this so far...
Here's a crazy hack to generate doubles portably:
https://gist.github.com/cemerick/7599452
It appears to yield sane shrinks, and surprisingly isn't absurdly slow: generating 1e6 doubles takes ~20s on the JVM (v. 1.5s for longs, but > 80s for both of the big generators I gisted earlier [essentially due to the slowness of gen/bytes
, but that's another topic]). Same thing takes 500s in JS (phantomjs there, Chrome would be snappier), but them's the breaks.
Moved to Jira.
Do you think it'd be useful to have a float generator in the lib? We have a use-case for that, and thought it may be useful for others, too...