Re: [AD] div-by-zero... math3d.c

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


Vincent Penquerc'h wrote:
against this sort of stupidity, but users that pass  "small
vectors" to a
function should be aware of a possible crash.

They should be aware of it, even if the docs don't mention it.
Normalization of a vector does not change its orientation, and
the zero vector has no orientation. Mathematically, it is not
possible to normalize the zero vector. Unless you consider any
unit vector to be a valid normalization of the zero vector.

I think you are right about the zero vector, we may well leave the result undefined. But I also think the current implementation may give strange results for vectors close to but different from zero, because if their squares are zero then vector_length() returns zero. What about the following algorithm:


   void normalize_vector_f(float *x, float *y, float *z)
   {
      float length = vector_length_f(*x, *y, *z);
      float scale;

      if (length == 0.0f) {
         float max = MAX(ABS(*x), MAX(ABS(*y), ABS(*z)));
         float max_inv = 1/max;
         *x *= max;
         *y *= max;
         *z *= max;
         length = vector_length_f(*x, *y, *z);
      }

      scale = 1.0 / length;
      *x *= scale;
      *y *= scale;
      *z *= scale;
   }

It's untested, but I think it should work:

1.  If length == 0.0 in the if(), then one of two things has happened:

  1.1.  All arguments were 0.  Then max becomes zero, and everything
        returned is NaN.  This is ok: you're not allowed to pass all
        arguments zero.

  1.2.  At least one argument was different from zero, but all
        arguments were so small that their squares are zero.  Then we
        first scale up the arguments so that the biggest (in absolute
        value) is +-1.0, and normalize the result.

2.  If length > 0.0 in the if(), then at least one argument is so big
    that its square is nonzero.  Hence length is also so big that its
    square is nonzero.  Thus length is already moderately far away from
    zero and the rest of the code should be ok.

Also, the new test shouldn't add too much relative speed penalty, since we are already doing a square root. I don't think we need to bother about speed in the rare case that the if()'s condition evaluates to true.

Sven





Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/