Menu

linspace: numerical errors in last value

2010-10-11
2012-09-15
  • Bogdan Cristea

    Bogdan Cristea - 2010-10-11

    There is currently a bug report related to this issue:

    The syntax of the linspace function

    vec linspace(double from, double to, int length = 100);

    indicates that the first value is exactly equal to "from" and the last value
    is exactly equal to "to". With the current implementation the last value of
    the vector will however be slightly offset from "to", due to numerical errors.

    There are two proposed solutions:

    1. change linspace() function so that the last generated value will be exactly to. With this approach the generated vector does not have a constant step, but the implementation complies with MATLAB
    2. add a second function linspaces(double from, double to, int step = 1) which is the equivalent of "from:step:to" in MATLAB so that the generated vector has a constant step and the last value is less or equal than to.

    Could you please comment on these two solutions and vote for the best one ?

     
  • David Hammarwall

    Hi all,

    Regarding the bug report ID:3010881, I would like to share my views.

    In short, the interface of the current linspace function is as follows:

    vec linspace(double from, double to, int length = 100)

    The problem is that the current implementation can produce an output where the
    last element is larger or smaller (depending on the system and architecture it
    is run on) than the specified to value.

    This is because the function computes a step_size as step_size = (to-
    from)/(length-1), and next applies this fix step_size between each neighboring
    vector element. The problem arises when the correct step_size cannot be
    represented exactly in double precision, and is thus rounded to the closes
    double precision point. In this case the last element will, due to numerical
    errors (that grow with increasing length of the vector), be slightly larger or
    smaller than the specified to value.

    Hence we have a problem where the interface is difficult to fulfill. On one
    hand, the naming of the function indicates that there should be a “linear”
    spacing between the elements, but on the other hand the input parameters let
    you specify the last element to, (this contract is currently not fulfilled).
    When the step_size cannot be expressed in exact binary precision, both of
    these contracts cannot be fulfilled at the same time.

    In my view, the interface contract of the input parameters is more explicit
    than the naming of the function and should therefore supersede, and we should
    therefore alter the implementation as, suggested in the above bug-report, so
    that the last element is always equal to the specified to value, at the cost
    of having a jittering in the step_size (note that the step_size is not part of
    the interface) when it cannot be represented in binary precision. This is also
    the behavior adopted in the corresponding function in Matlab. My basic
    question is, why is it more correct to repeatedly apply a static but
    numerically incorrect step_size than to jitter about the correct step_size to
    fulfill the contract of the specified to value.

    Regarding the solution in 2) above, I presume that the intended interface is
    really:

    vec linspaces(double from, double to, double step = 1.0);

    where the step is given as a double (not an int). Personally I think that this
    formulation is inconvenient since the user would have to compute both the step
    size and the to value (which as discussed above can be conflicting).
    Typically the user is interested in either the step size or the to value.
    Moreover, there will still not be a way for the user to create a vector with a
    specific from and to value, where the samples are as uniform as
    numerically possible.

    My proposal to fulfill both needs is as follows:

    We change the behavior of the linspace function such that the first and last
    elements of the vector corresponds to the given from and to values, and
    the sample spacing is as uniform as numerically possible.

    We also introduce a new function with the syntax

    vec linspace_fix_step(double from, double step_size, int length = 100)

    which can be used to enforce a specific given step_size. Here we will not have
    a problem with numeric precision since the step_size is explicitly given (and
    thus exactly represented by double precision), and moreover there is no to
    value in the interface that can be violated.

    Any thoughts on this issue?

     
  • li li

    li li - 2010-12-03

    To employ two linspace functions is a good idea, which could be effectively
    solve the bug above. But If we have to choose one of solutions, I personally
    prefer the first one.

     
  • Bogdan Cristea

    Bogdan Cristea - 2010-12-03

    linspace() has been changed so that the last element is always "to". A new
    function has been added linspace_fix_step(double from, double step_size,
    double length = 1.0) in order to have from:step:to from MATLAB.

    Changes have been committed to trunk and tests have been made on openSUSE
    11.3. Please test on other distros and report any problems.

     
  • Bogdan Cristea

    Bogdan Cristea - 2010-12-03

    sorry, the new function signature is

    linspace_fix_step(double from, double to, double step = 1.0)

     

Log in to post a comment.