[CLJ-1166] Range function accumulates minor errors when called on floating-point numbers Created: 19/Feb/13 Updated: 29/Mar/13 Resolved: 01/Mar/13 |
|
| Status: | Closed |
| Project: | Clojure |
| Component/s: | None |
| Affects Version/s: | Release 1.5 |
| Fix Version/s: | None |
| Type: | Defect | Priority: | Trivial |
| Reporter: | Stephen Nelson | Assignee: | Unassigned |
| Resolution: | Declined | Votes: | 0 |
| Labels: | None | ||
| Description |
|
Due to range's incremental computation minor errors introduced by floating point arithmetic accumulate, becoming more noticeable in long ranges and causing unexpected behaviour. Compare the output of the following: => (range 0.0 10.0 0.1) => (defn range' [start end step] (map #(+ start (* % step)) (range 0 (/ (- end start) step) 1))) |
| Comments |
| Comment by Stephen Nelson [ 19/Feb/13 3:06 PM ] |
|
=> (last (range 0.0 10000000.0 0.1)) |
| Comment by Stuart Halloway [ 01/Mar/13 10:08 AM ] |
|
Range is incremental by design, and that is how floats work. Something with the desired behavior would need to be a different fn with a different name. |
| Comment by Stephen Nelson [ 03/Mar/13 2:38 PM ] |
|
"Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step" What specifically about that wording specifically suggests that the implementation will use naive increment-and-recurse behaviour? My reading is that the function will return a lazy sequence of numbers from start to end separated by step, not separated by 'almost step'. This implementation leads to unexpected behaviour with bounds: => (count (range 0 100 1)) |
| Comment by Timothy Pratley [ 29/Mar/13 5:09 PM ] |
|
range could avoid this issue cleanly by converting floats to bigdecimals (let me know if you think this is a good idea?) I ran into this problem recently, and have to say it was pretty ugly. This is how I avoided the issue: (defn rangef Hope that helps any disillusioned float users out there, or just pass in BigDecimals to range instead of floats... I would go so far as to say using floats with range as it stands is almost always going to end in tears (or worse as Stephen describes |
| Comment by Timothy Pratley [ 29/Mar/13 5:10 PM ] |
|
[and just to be clear if it is considered an error, it would be nice if range explicitly forbade it] |