reiddraper / simple-check

QuickCheck for Clojure
http://reiddraper.github.io/simple-check/
286 stars 18 forks source link

Float generator? #36

Closed ifesdjeen closed 10 years ago

ifesdjeen commented 10 years ago

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...

ztellman commented 10 years ago

How would you shrink a float? By continuously subtracting some epsilon? By doing a binary search on the number line?

reiddraper commented 10 years ago

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.

ifesdjeen commented 10 years ago

Right, shrinking would be a bit problematic, didn't think of it...

I've changed my impl (was a bit stupid) to yours.

Thanks!

ifesdjeen commented 10 years ago

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.

reiddraper commented 10 years ago

Yeah let's leave it open until something is merged in. Thanks.

ifesdjeen commented 10 years ago

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.

cemerick commented 10 years ago

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 fmapping to coerce constrained bigdecs down.

cemerick commented 10 years ago

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.

reiddraper commented 10 years ago

Yeah, that's part of the reason I've punted on this so far...

cemerick commented 10 years ago

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.

reiddraper commented 10 years ago

Moved to Jira.