lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Sun, Mar 06, 2005 at 09:01:42PM -0500, Rici Lake wrote:
> 
> On 6-Mar-05, at 6:36 PM, Shannon Stewman wrote:
> 
> >Your first suggestion would make it hard to track down dumb bugs in
> >numerical code.
> 
> That depends on how the arithmetic operations responded to receiving
> a nil / NaN. Indeed, both of them could throw an error. Or both of
> them could do pass through. 

Sure, but nil isn't a number type, and is rather overloaded as is.  I
can see the advantage of having NaN test to false, but where is the
advantage of letting nil and NaN be equivalent?

In any calculation I've ever written in Lua, there's a chance you've
mistyped something obvious and a chance your algorithm is off or your
data isn't clean.  I'd rather pick up on the obvious (non-numerical)
errors first.  There are lots of ways to change behavior; command-line
flags and what-not.  But there is some merit to keeping clean
boundaries between different types, like numbers and nil, even in a
value-typed language.  I'm pretty sure the ick factor of automatically
coercing something like

  "this is a string" .. {}

to nil would be high.  It's a programmatic error, currently the same as
saying '1+nil'.

Incidentally, when I say dumb errors, I mean something like the
following:

  local function bindata( data, minval, maxval, nbins )
    local bins = {}
    local binwidth = (maxval - minval) / (nbins-1)
  
    for _,datum in ipairs(data) do
      local bidx = 1 + floor( (datum-minval)/binwidth )
  
      --
      -- ERROR: forgot to initialize bins to zero
      --
      bins[bidx] = bins[bidx] + 1
    end
  
    return bins
  end

It's much easier to see the problem under the current behavior.  The
table 'bins' returns nil on unset values, and the VM throws an error
when (nil + 1) is encountered.  Looking at a bunch of NaNs or nils in
the result won't help much.

It's true that I can surround all my computations with 'assert(...)'
statements, but this becomes pretty onerous when the bulk of your code
has some numerical aspect to it.  It also clouds the code, and can slow
things down.

> In fact, making NaN test false makes it easier to test for dumb bugs:
> you just throw an assert around your arithmetic computations.

I'm not sure why 

  assert( result_of_computation ) 

would be any more or less desirable than

  function is_valid_compuation( x )
    if math.isnan(x) then
      return false 
    else 
      return x 
    end
  end

  assert( is_valid_computation( result_of_computation ) )

> The whole point of NaNs was to avoid having to do a whole bunch of
> tests on a complicated arithmetic expression; the intention was never
> that the result would not be tested. 

The results of any computation have to be tested.  NaNs are just a
strong cue that something's seriously amiss.  The way I've seen most
NaN-related problems diagnosed is post mortem in the output, and then
the debugging begins.

> There was also the desire to avoid having to serialise computations
> which could be done in parallel.

I'm not sure I following how NaNs help this.

> It's not actually clear to me that a scripting language should
> even preserve NaN behaviour rather than simply returning an immediate
> error, but if a programmer were conscientious about checking, that
> might get in the way.

There's some value in preserving IEEE754 semantics, especially if the
code interfaces with C/Fortran/C++/OCaml routines that follow these
semantics.  It would be nice to have a flag for this, though.  I
currently rely on non-portable SIGFPE-enabling code.

> So I'd be ok with NaN's being checked for by Lua, but the alternative
> of letting me use assert rather than some mysterious and possibly
> non-functional self-inequality check seems more pleasant.

I'm definitely not advocating that, but the C99 standard has a set of
isnan, isinf, isfinite, etc. functions that would do the job quite well
without further overloading the nil type.

> >1. I divided by zero somewhere
> 
> That will give you +/- infinity unless you divided 0 by 0

You're right.  Usually when my code starts dividing by zero, it's often
0/0, hence the confusion.

Best,

-- 
Shannon Stewman         | Let us walk through the waning night,
Caught in a whirlpool,  | As dawn-rays tickle our toes, the dew soothes
A quartering act:       | Our blistered soles, and damp bones stir
Solitude or society?    | As crimson cracks under the blue-grey sky.