list-of-numbers influenced by tolerances
Created by: reiniervandijk
The current implementation of list-of-numbers is naive and leads to several complications. Consider:
(setq u1 8.875776655249117e-4)
(setq u2 3.7043572627844927)
(setq lst (list-of-numbers u1 u2 (/ (- u2 u1) (1- 100))))
Now you would assume the list-of-numbers to have a length of 100, since I defined the step size like that. However:
> (length lst)
99
This is due to tolerances, I understand. However, now consider the function equi-spaced-points in the curve object. You provide a number of points, say 100. Since the internal code uses the aforementioned method to calculate all (assumingly) 100 parametric values in the range of u1 - u2, it actually returns 99 points. This gave me errors, because I anticipated the same number of points that I've asked for.
Looking at body of list-of-numbers, erroneous line is:
(dotimes (i (1+ (floor (/ (- num2 num1) increment))) ...
Because this gives:
> (/ (- u2 u1) (/ (- u2 u1) (1- 100)))
98.99999999999999
Documentation of list-of-numbers says: "Returns a list of incrementing numbers starting from num1 and ending with num2, inclusive." That's actually not true, as shown.
Imported comments:
By reiniervandijk on 2013-03-11 12:35:55 UTC
Proposed fix:
(defun list-of-numbers (num1 num2 &optional (increment 1) (tolerance (/ increment 10)))
"List of Numbers. Returns a list of incrementing numbers starting from
<b>num1</b> and ending with <b>num2</b>, inclusive.
:arguments (num1 \"Number\"
num2 \"Number\")
:&optional ((increment 1) \"Number. The distance between the returned listed numbers.\")"
(cond ((= increment 0.0) (error "increment of zero is not allowed"))
((and (< increment 0.0) (> num2 num1)) (error "increment is negative, while difference between num2 and num1 is positive."))
((and (> increment 0.0) (< num2 num1)) (error "increment is positive, while difference between num2 and num1 is negative."))
(t (let ((predicate (if (> increment 0.0) #'>= #'<=))
(result-list nil))
(do ((num num1 (+ num increment)))
((or (funcall predicate num num2) (< (abs (- num2 num)) tolerance)) (nreverse (cons num2 result-list)))
(push num result-list))))))
By reiniervandijk on 2015-02-18 17:16:11 UTC
This fix is now pending for almost two years and has manifested itself again in student code while working with the MMG. Is this issue representative indicative for the speed with which user-contributions are merged into the language? If so, we, TUD, will manage our own set of fixes to the language that we will circulate among students.
By reiniervandijk on 2015-02-18 17:17:02 UTC
Another contribution to the language (name of the function can be subject to change):
(defun list-of-n-numbers (num1 num2 n)
"returns a list of n numbers between bounds num1 and num2. Bounds are inclusive"
(let ((increment (/ (- num2 num1) (- n 1)))
(result-list nil))
(dotimes (i (- n 1) (nreverse (cons num2 result-list)))
(push (+ num1 (* i increment)) result-list))))
By genworks on 2015-02-20 03:32:26 UTC
The fixes will be rolled into next major release, slated for January 2016, including clear release notes. This will not be included in an interim patch, due to risk of breaking existing code (even though the current function indeed can produce incorrect results, some production applications may be depending on these results).
Indeed, applications which require the fixed behavior can and should carry the code for the fix locally, which code can be retired when it moves to the next major release which includes the fix.
By genworks on 2015-02-20 03:33:35 UTC
The issue will be closed when it is committed into current development work-in-progress. Work-in-progress builds are also expected to be made available between now and January 2016.
By genworks on 2015-03-18 20:09:07 UTC
updated list-of-numbers and list-of-n-numbers have been rolled into current "devo" branch.