unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* number-sequence
@ 2003-11-20  3:39 Luc Teirlinck
  2003-11-20 10:39 ` number-sequence Kim F. Storm
  2003-11-20 13:27 ` number-sequence Juri Linkov
  0 siblings, 2 replies; 7+ messages in thread
From: Luc Teirlinck @ 2003-11-20  3:39 UTC (permalink / raw)


The function number-sequence in its present form is dangerous.  If the
increment accidentally winds up being 0 or negative and FROM is less
than TO, Emacs will start to construct an infinite list and keep
chewing up CPU and worse, memory.  Just try:

(number-sequence 1 3 -1) or (number-sequence 1 3 0)

If nothing else, if number-sequence can not handle negative increments
correctly, it should signal an error instead of trying to construct
the infinite sequence.  However, I believe there is better.  A zero
increment definitely should throw an error, except in some harmless
cases.  If TO is less than FROM however, negative increments do make
perfect sense and they are trivial to handle.  Hence, it seems stupid
to throw an error instead of doing the logical and expected thing.
The included version of number-sequence does that:

===File ~/number-sequence.el================================
(defun number-sequence (from &optional to inc)
  "Return a sequence of numbers from FROM to TO (both inclusive) as a list.
INC is the increment used between numbers in the sequence.
So, the Nth element of the list is (+ FROM (* N INC)) where N counts from
zero.
If INC is nil, it defaults to 1 (one).
If TO is nil or numerically equal to FROM, return (FROM).
If INC is positive and TO is less than FROM, or INC is negative
and TO is larger than FROM, return nil.
If INC is zero and TO is neither nil nor numerically equal to
FROM, signal an error.
Note that FROM, TO and INC can be integer or float."
  (if (or (not to) (= from to))
      (list from)
    (or inc (setq inc 1))
    (when (zerop inc) (error "The increment can not be zero"))
    (let (seq)
      (if (> inc 0)
	  (while (<= from to)
	    (setq seq (cons from seq)
		  from (+ from inc)))
	(while (>= from to)
	  (setq seq (cons from seq)
		from (+ from inc))))
      (nreverse seq))))
============================================================

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-20  3:39 number-sequence Luc Teirlinck
@ 2003-11-20 10:39 ` Kim F. Storm
  2003-11-20 13:27 ` number-sequence Juri Linkov
  1 sibling, 0 replies; 7+ messages in thread
From: Kim F. Storm @ 2003-11-20 10:39 UTC (permalink / raw)
  Cc: emacs-devel

Luc Teirlinck <teirllm@dms.auburn.edu> writes:

> ===File ~/number-sequence.el================================
> (defun number-sequence (from &optional to inc)
>   "Return a sequence of numbers from FROM to TO (both inclusive) as a list.

TO is only inclusive if there is an N for which TO = FROM + N * INC.

> INC is the increment used between numbers in the sequence.
> So, the Nth element of the list is (+ FROM (* N INC)) where N counts from
> zero.
> If INC is nil, it defaults to 1 (one).
> If TO is nil or numerically equal to FROM, return (FROM).
> If INC is positive and TO is less than FROM, or INC is negative
> and TO is larger than FROM, return nil.
> If INC is zero and TO is neither nil nor numerically equal to
> FROM, signal an error.
> Note that FROM, TO and INC can be integer or float."
>   (if (or (not to) (= from to))
>       (list from)
>     (or inc (setq inc 1))
>     (when (zerop inc) (error "The increment can not be zero"))
>     (let (seq)
>       (if (> inc 0)
> 	  (while (<= from to)
> 	    (setq seq (cons from seq)
> 		  from (+ from inc)))
> 	(while (>= from to)
> 	  (setq seq (cons from seq)
> 		from (+ from inc))))

When we are using floats here, there is a risk of accumulating errors,
and thus not getting the exact TO value into the list.  

This could be better (but marginally slower):

    (let (seq (n 0) (next from))
      (if (> inc 0)
	  (while (<= next to)
	    (setq seq (cons next seq)
                  n (1+ n)
                  next (+ from (* inc n))))
	(while (>= next to)
	  (setq seq (cons next seq)
                n (1+ n)
                next (+ from (* inc n))))



-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-20  3:39 number-sequence Luc Teirlinck
  2003-11-20 10:39 ` number-sequence Kim F. Storm
@ 2003-11-20 13:27 ` Juri Linkov
  2003-11-21  4:37   ` number-sequence Luc Teirlinck
  2003-11-23 16:09   ` number-sequence Luc Teirlinck
  1 sibling, 2 replies; 7+ messages in thread
From: Juri Linkov @ 2003-11-20 13:27 UTC (permalink / raw)
  Cc: emacs-devel

Luc Teirlinck <teirllm@dms.auburn.edu> writes:
> (number-sequence 1 3 -1) or (number-sequence 1 3 0)

There is another case that makes sense: if INC is nil and TO is less
than FROM, then INC could default to -1, i.e.

    (number-sequence 3 1) => (3 2 1)

To do this you could replace in your version:

- If INC is nil, it defaults to 1 (one).
+ If INC is nil, it defaults to 1 (one) if TO is larger than FROM,
+ or to -1 if TO is less than FROM.

-     (or inc (setq inc 1))
+     (or inc (setq inc (if (< from to) 1 -1)))

BTW, it couldn't hurt to add examples to the docstring:

Examples:
    (number-sequence 1) => (1)
    (number-sequence 1 1) => (1)
    (number-sequence 1 3) => (1 2 3)
    (number-sequence 1 3 2) => (1 3)
    (number-sequence 3 1) => (3 2 1)
    (number-sequence 3 1 -2) => (3 1)

-- 
http://www.jurta.org/emacs/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-20 13:27 ` number-sequence Juri Linkov
@ 2003-11-21  4:37   ` Luc Teirlinck
  2003-11-21 12:06     ` number-sequence Kim F. Storm
  2003-11-23 16:09   ` number-sequence Luc Teirlinck
  1 sibling, 1 reply; 7+ messages in thread
From: Luc Teirlinck @ 2003-11-21  4:37 UTC (permalink / raw)
  Cc: emacs-devel

Below is the latest revised version of number-sequence, taking the
suggestions of Kim and Juri into account.  Even though Kim's changes
improved number-sequence's handling of floating point arguments, the
function does not handle floats ideally, but I do not believe that
anything can be done about that.  The function was mainly designed
for, and, I believe, is mainly useful, for integer arguments.  I
pointed this out in the doc string (this is an additional change from
the previous version).

Juri Linkov wrote:

   BTW, it couldn't hurt to add examples to the docstring:

The doc string is already getting long and there already are examples
in the Elisp manual which I will update.  After updating, depending on
the actual examples in the updated version, I might add a sentence:

For examples, see Info node `(elisp)Building Lists'.

to the very end of the doc string, if this would appear to be useful.

I will wait a while (at least till Sunday) to see whether there are
any objections or further suggestions, after which I will commit,
update the Elisp manual and the NEWS.

===File ~/new-number-sequence.el============================
(defun number-sequence (from &optional to inc)
  "Return a sequence of numbers from FROM to TO (both inclusive) as a list.
INC is the increment used between numbers in the sequence.
So, the Nth element of the list is (+ FROM (* N INC)) where N counts from
zero.
TO is only included if there is an N for which TO = FROM + N * INC.  
If INC is nil, it defaults to 1 (one) if TO is larger than FROM,
or to -1 if TO is less than FROM.
If TO is nil or numerically equal to FROM, return (FROM).
If INC is positive and TO is less than FROM, or INC is negative
and TO is larger than FROM, return nil.
If INC is zero and TO is neither nil nor numerically equal to
FROM, signal an error.

This function was primarily designed for integer arguments.
Nevertheless, FROM, TO and INC can be integer or float.  However,
floating point arithmetic is inexact.  For instance, depending on
the machine, it may quite well happen that
\(number-sequence 0.4 0.6 0.2) returns the one element list (0.4),
whereas \(number-sequence 0.4 0.8 0.2) returns a list with three
elements.  Thus, if some of the arguments are floats and one
wants to make sure that TO is included, one may have to
explicitly write TO as \(+ FROM \(* N INC)) or use a variable
whose value was computed with this exact expression."
  (if (or (not to) (= from to))
      (list from)
    (or inc (setq inc (if (< from to) 1 -1)))    
    (when (zerop inc) (error "The increment can not be zero"))
    (let (seq (n 0) (next from))
      (if (> inc 0)
          (while (<= next to)
            (setq seq (cons next seq)
                  n (1+ n)
                  next (+ from (* n inc))))
        (while (>= next to)
          (setq seq (cons next seq)
                n (1+ n)
                next (+ from (* n inc)))))
      (nreverse seq))))
============================================================

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-21  4:37   ` number-sequence Luc Teirlinck
@ 2003-11-21 12:06     ` Kim F. Storm
  2003-11-21 14:43       ` number-sequence Luc Teirlinck
  0 siblings, 1 reply; 7+ messages in thread
From: Kim F. Storm @ 2003-11-21 12:06 UTC (permalink / raw)
  Cc: juri, emacs-devel

Luc Teirlinck <teirllm@dms.auburn.edu> writes:

> TO is only included if there is an N for which TO = FROM + N * INC.  
> If INC is nil, it defaults to 1 (one) if TO is larger than FROM,
> or to -1 if TO is less than FROM.
> If TO is nil or numerically equal to FROM, return (FROM).
> If INC is positive and TO is less than FROM, or INC is negative
> and TO is larger than FROM, return nil.
> If INC is zero and TO is neither nil nor numerically equal to
> FROM, signal an error.

Is it really necessary to document all those cases ??

I think they are all obvious behaviours of number-sequence...

> 
> This function was primarily designed for integer arguments.
> Nevertheless, FROM, TO and INC can be integer or float.  However,
> floating point arithmetic is inexact.  For instance, depending on
> the machine, it may quite well happen that
> \(number-sequence 0.4 0.6 0.2) returns the one element list (0.4),
> whereas \(number-sequence 0.4 0.8 0.2) returns a list with three
> elements.  Thus, if some of the arguments are floats and one
> wants to make sure that TO is included, one may have to
> explicitly write TO as \(+ FROM \(* N INC)) or use a variable
> whose value was computed with this exact expression."

You could also suggest to use something like

        (number-sequence 0.4 0.61 0.2)


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-21 12:06     ` number-sequence Kim F. Storm
@ 2003-11-21 14:43       ` Luc Teirlinck
  0 siblings, 0 replies; 7+ messages in thread
From: Luc Teirlinck @ 2003-11-21 14:43 UTC (permalink / raw)
  Cc: juri, emacs-devel

Kim Storm wrote:

   > TO is only included if there is an N for which TO = FROM + N * INC.  
   > If INC is nil, it defaults to 1 (one) if TO is larger than FROM,
   > or to -1 if TO is less than FROM.
   > If TO is nil or numerically equal to FROM, return (FROM).
   > If INC is positive and TO is less than FROM, or INC is negative
   > and TO is larger than FROM, return nil.
   > If INC is zero and TO is neither nil nor numerically equal to
   > FROM, signal an error.

   Is it really necessary to document all those cases ??

All but the first and the last two sentences specify defaults, and
hence are, I believe necessary.  I believe you suggested the first.
In case of the second to last, there might be some possibility of
expecting (FROM).  Certainly, if you are going to mention that TO is
not necessarily inclusive, it makes sense to point out the one case
where FROM is not inclusive.  The last line tells exactly when an
error is going to occur, which is not obvious in all cases, like
(number-sequence 5 nil 0) or (number-sequence 5 5 0).  They do return
(5), but could equally well have thrown an error.

   You could also suggest to use something like

	   (number-sequence 0.4 0.61 0.2)

I believe that, in real programs, the arguments might not be constant
integers.  I will add:

"Alternatively, you can, of course, also replace TO by a slightly
larger value."

to the end of the doc string.

Sincerely,

Luc.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: number-sequence
  2003-11-20 13:27 ` number-sequence Juri Linkov
  2003-11-21  4:37   ` number-sequence Luc Teirlinck
@ 2003-11-23 16:09   ` Luc Teirlinck
  1 sibling, 0 replies; 7+ messages in thread
From: Luc Teirlinck @ 2003-11-23 16:09 UTC (permalink / raw)
  Cc: emacs-devel

Juri Linkov wrote:

   There is another case that makes sense: if INC is nil and TO is less
   than FROM, then INC could default to -1, i.e.

       (number-sequence 3 1) => (3 2 1)

I originally agreed with this, but I changed my mind.  Indeed, the
function's main motivation was the INC equal 1 case and there is no
sense in making the main case tricky to make a much less used case
slightly more convenient.  My original change only made the function
do something sensible in cases where it used to do something
disastrous by senselessly chewing up CPU and memory.  Changing the
default would change the behavior in the by far most often used case
and could break existing code.  I will wait till Monday evening before
committing, and, of course, changes can still be made after I commit.
Latest version:

===File ~/latest-number-sequence.el=========================
(defun number-sequence (from &optional to inc)
  "Return a sequence of numbers from FROM to TO (both inclusive) as a list.
INC is the increment used between numbers in the sequence and defaults to 1.
So, the Nth element of the list is \(+ FROM \(* N INC)) where N counts from
zero.  TO is only included if there is an N for which TO = FROM + N * INC.
If TO is nil or numerically equal to FROM, return \(FROM).
If INC is positive and TO is less than FROM, or INC is negative
and TO is larger than FROM, return nil.
If INC is zero and TO is neither nil nor numerically equal to
FROM, signal an error.

This function is primarily designed for integer arguments.
Nevertheless, FROM, TO and INC can be integer or float.  However,
floating point arithmetic is inexact.  For instance, depending on
the machine, it may quite well happen that
\(number-sequence 0.4 0.6 0.2) returns the one element list \(0.4),
whereas \(number-sequence 0.4 0.8 0.2) returns a list with three
elements.  Thus, if some of the arguments are floats and one wants
to make sure that TO is included, one may have to explicitly write
TO as \(+ FROM \(* N INC)) or use a variable whose value was
computed with this exact expression. Alternatively, you can,
of course, also replace TO with a slightly larger value
\(or a slightly more negative value if INC is negative)."
  (if (or (not to) (= from to))
      (list from)
    (or inc (setq inc 1))    
    (when (zerop inc) (error "The increment can not be zero"))
    (let (seq (n 0) (next from))
      (if (> inc 0)
          (while (<= next to)
            (setq seq (cons next seq)
                  n (1+ n)
                  next (+ from (* n inc))))
        (while (>= next to)
          (setq seq (cons next seq)
                n (1+ n)
                next (+ from (* n inc)))))
      (nreverse seq))))
============================================================

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2003-11-23 16:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-20  3:39 number-sequence Luc Teirlinck
2003-11-20 10:39 ` number-sequence Kim F. Storm
2003-11-20 13:27 ` number-sequence Juri Linkov
2003-11-21  4:37   ` number-sequence Luc Teirlinck
2003-11-21 12:06     ` number-sequence Kim F. Storm
2003-11-21 14:43       ` number-sequence Luc Teirlinck
2003-11-23 16:09   ` number-sequence Luc Teirlinck

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).