is_nan()

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

is_nan()

RevarBat
I'm sure this has come up before, but in a cursory check I didn't see anyone else post an actual solution.

The FP value `nan` is handled in OpenSCAD in a very awkward manner. First-off, there's no constants for nan or inf, so lets work around that:

        NAN = acos(2);
        INF = 1/0;

Secondly, the comparators for nan, while arguably true from an academic point of view, are almost completely useless from a programming perspective:

- `is_num(NAN)` returns false. (Even though nan is of the same type as inf and 0.)
- `NAN == NAN` returns false.
- `NAN != NAN` returns true.

Combined, these really make it very ugly to tell if a value is nan.  The obvious tests are all useless:

        x = foo();
        if (x==NAN) echo("This branch is NEVER executed for any value or type of x.");
        if (x!=NAN) echo("This branch is executed for ALL values of x, no matter the type.");

As far as I can tell, the only way to detect NaN correctly is a complex construct like this:

        function is_nan(x) =
                !is_num(x) && !is_undef(x) && !is_string(x) &&
                !is_list(x) && !(x<=INF) && is_undef(x[0]);

The !(x<=INF) test disallows INF, -INF, and booleans. The is_undef(x[0]) shows that x is not a range like [0:10].

- Revar


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

Whosawhatsis
function is_nan(x) = (x != x) ? true : false;

On February 7, 2020 at 00:25:59, Revar Desmera ([hidden email]) wrote:

I'm sure this has come up before, but in a cursory check I didn't see anyone else post an actual solution.

The FP value `nan` is handled in OpenSCAD in a very awkward manner. First-off, there's no constants for nan or inf, so lets work around that:

NAN = acos(2);
INF = 1/0;

Secondly, the comparators for nan, while arguably true from an academic point of view, are almost completely useless from a programming perspective:

- `is_num(NAN)` returns false. (Even though nan is of the same type as inf and 0.)
- `NAN == NAN` returns false.
- `NAN != NAN` returns true.

Combined, these really make it very ugly to tell if a value is nan. The obvious tests are all useless:

x = foo();
if (x==NAN) echo("This branch is NEVER executed for any value or type of x.");
if (x!=NAN) echo("This branch is executed for ALL values of x, no matter the type.");

As far as I can tell, the only way to detect NaN correctly is a complex construct like this:

function is_nan(x) =
!is_num(x) && !is_undef(x) && !is_string(x) &&
!is_list(x) && !(x<=INF) && is_undef(x[0]);

The !(x<=INF) test disallows INF, -INF, and booleans. The is_undef(x[0]) shows that x is not a range like [0:10].

- Revar


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

RevarBat
Huh.  Even shorter:

function is_nan(x) = x!=x;

That is somehow both elegant in its simplicity and horribly twisted in its logic.

- Revar


On Feb 7, 2020, at 12:31 AM, Whosawhatsis <[hidden email]> wrote:

function is_nan(x) = (x != x) ? true : false;

On February 7, 2020 at 00:25:59, Revar Desmera ([hidden email]) wrote:

I'm sure this has come up before, but in a cursory check I didn't see anyone else post an actual solution. 

The FP value `nan` is handled in OpenSCAD in a very awkward manner. First-off, there's no constants for nan or inf, so lets work around that: 

NAN = acos(2); 
INF = 1/0; 

Secondly, the comparators for nan, while arguably true from an academic point of view, are almost completely useless from a programming perspective: 

- `is_num(NAN)` returns false. (Even though nan is of the same type as inf and 0.) 
- `NAN == NAN` returns false. 
- `NAN != NAN` returns true. 

Combined, these really make it very ugly to tell if a value is nan. The obvious tests are all useless:

x = foo(); 
if (x==NAN) echo("This branch is NEVER executed for any value or type of x."); 
if (x!=NAN) echo("This branch is executed for ALL values of x, no matter the type."); 

As far as I can tell, the only way to detect NaN correctly is a complex construct like this: 

function is_nan(x) = 
!is_num(x) && !is_undef(x) && !is_string(x) && 
!is_list(x) && !(x<=INF) && is_undef(x[0]); 

The !(x<=INF) test disallows INF, -INF, and booleans. The is_undef(x[0]) shows that x is not a range like [0:10]. 

- Revar 


_______________________________________________ 
OpenSCAD mailing list 
[hidden email] 
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
tp3
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

tp3
On 07.02.20 11:02, Revar Desmera wrote:
> function is_nan(x) = x!=x;
> That is somehow both elegant in its simplicity and horribly
> twisted in its logic.

Also nobody will claim any responsibility if it breaks at
some point.

If it makes sense to have that check, it would probably be
better to actually implemented it in the core like the other
test functions.

The missing tokens are indeed a problem as that is one case
where we can export files as CSG that can't be imported back.

   nan = 0/0;
   inf = 1/0;
   ninf = -1/0;
   echo(inf, ninf, nan);

Just to highlight the point it's not an OpenSCAD invention:

$ python3
Python 3.7.6 (default, Jan 19 2020, 22:34:52)
[GCC 9.2.1 20200117] on linux
Type "help", "copyright", "credits" or "license" for more information.
 >>> import math
 >>> nan = math.nan
 >>> nan == nan
False
 >>> nan != nan
True
 >>>

ciao,
   Torsten.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
-- Torsten
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

acwest
Nan is pretty much defined to not be equal to itself, part of the floating point spec

On Fri, 7 Feb 2020, 15:01 Torsten Paul, <[hidden email]> wrote:
On 07.02.20 11:02, Revar Desmera wrote:
> function is_nan(x) = x!=x;
> That is somehow both elegant in its simplicity and horribly
> twisted in its logic.

Also nobody will claim any responsibility if it breaks at
some point.

If it makes sense to have that check, it would probably be
better to actually implemented it in the core like the other
test functions.

The missing tokens are indeed a problem as that is one case
where we can export files as CSG that can't be imported back.

   nan = 0/0;
   inf = 1/0;
   ninf = -1/0;
   echo(inf, ninf, nan);

Just to highlight the point it's not an OpenSCAD invention:

$ python3
Python 3.7.6 (default, Jan 19 2020, 22:34:52)
[GCC 9.2.1 20200117] on linux
Type "help", "copyright", "credits" or "license" for more information.
 >>> import math
 >>> nan = math.nan
 >>> nan == nan
False
 >>> nan != nan
True
 >>>

ciao,
   Torsten.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

doug.moen
In reply to this post by tp3
The IEEE floating point standard provides programming languages with two different options
when evaluating 0/0: either it raises an exception, or it returns the NaN value.

Once you have a NaN value x, then x!=x must return true, according to IEEE.

In Python, 0.0/0.0 raises an exception, it doesn't return NaN.
In OpenSCAD, 0/0 returns NaN instead of raising an exception.
Both languages are compatible with the IEEE standard in this circumstance.

If you prefer your programming language to report an error when you have performed
an illegal operation, rather than silently returning Nan or undef, then you probably
want the Python semantics of 0/0 raising an exception.

In my own 3D modelling language (Curv), arithmetic operations always report an error
rather than return NaN. Since there's no way to generate a NaN, I don't need an is_nan()
function, and it is guaranteed that x==x is always true and x!=x is always false.
The only time I've actually seen this error reported was due to a bug in my program, that
would otherwise have resulted in exporting an invalid STL file if the bug hadn't been fixed.

My opinion is that disabling floating point exceptions and returning NaN for invalid arithmetic
operations is something that should only be attempted by numerical analysts who know what
they are doing. The semantics of NaN are too confusing, and propagating NaN values through
an OpenSCAD program will probably result in bad geometry. I don't think that 0/0 should
return NaN by default in a programming language that isn't targeted at high performance
numerical analysis. Python gets this right.

Doug Moen.

On Fri, Feb 7, 2020, at 8:00 PM, Torsten Paul wrote:

> On 07.02.20 11:02, Revar Desmera wrote:
> > function is_nan(x) = x!=x;
> > That is somehow both elegant in its simplicity and horribly
> > twisted in its logic.
>
> Also nobody will claim any responsibility if it breaks at
> some point.
>
> If it makes sense to have that check, it would probably be
> better to actually implemented it in the core like the other
> test functions.
>
> The missing tokens are indeed a problem as that is one case
> where we can export files as CSG that can't be imported back.
>
>    nan = 0/0;
>    inf = 1/0;
>    ninf = -1/0;
>    echo(inf, ninf, nan);
>
> Just to highlight the point it's not an OpenSCAD invention:
>
> $ python3
> Python 3.7.6 (default, Jan 19 2020, 22:34:52)
> [GCC 9.2.1 20200117] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> import math
>  >>> nan = math.nan
>  >>> nan == nan
> False
>  >>> nan != nan
> True
>  >>>
>
> ciao,
>    Torsten.
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

RevarBat
In reply to this post by tp3
Yeah, I'd like to see a proper is_nan(x) builtin.  And an is_range(x) as well.

IEEE754 is correct to specify that nan!=nan, as that is what you want when comparing results from two calculations.
Most languages, however, also provide ways to test for nan.

$ python3
>>> import math
>>> nan = math.nan
>>> nan is math.nan
True
>>> math.isnan(nan)
True

Even C/C++ has isnan(x).

I'm fine with nan!=nan, so long as there exists a clean way to test for it.  We need is_nan().

- Revar


> On Feb 7, 2020, at 12:00 PM, Torsten Paul <[hidden email]> wrote:
>
> On 07.02.20 11:02, Revar Desmera wrote:
>> function is_nan(x) = x!=x;
>> That is somehow both elegant in its simplicity and horribly
>> twisted in its logic.
>
> Also nobody will claim any responsibility if it breaks at
> some point.
>
> If it makes sense to have that check, it would probably be
> better to actually implemented it in the core like the other
> test functions.
>
> The missing tokens are indeed a problem as that is one case
> where we can export files as CSG that can't be imported back.
>
>  nan = 0/0;
>  inf = 1/0;
>  ninf = -1/0;
>  echo(inf, ninf, nan);
>
> Just to highlight the point it's not an OpenSCAD invention:
>
> $ python3
> Python 3.7.6 (default, Jan 19 2020, 22:34:52)
> [GCC 9.2.1 20200117] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import math
> >>> nan = math.nan
> >>> nan == nan
> False
> >>> nan != nan
> True
> >>>
>
> ciao,
>  Torsten.
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: is_nan()

thehans
Here's an is_range function I came up with a while ago:
is_range = function (x) !is_list(x) && !is_string(x) && !is_undef(x[0]);

It works because you can access start,step,end as the first 3 "elements", but its not a list.

On Fri, Feb 7, 2020 at 6:55 PM Revar Desmera <[hidden email]> wrote:
Yeah, I'd like to see a proper is_nan(x) builtin.  And an is_range(x) as well.

IEEE754 is correct to specify that nan!=nan, as that is what you want when comparing results from two calculations.
Most languages, however, also provide ways to test for nan.

$ python3
>>> import math
>>> nan = math.nan
>>> nan is math.nan
True
>>> math.isnan(nan)
True

Even C/C++ has isnan(x).

I'm fine with nan!=nan, so long as there exists a clean way to test for it.  We need is_nan().

- Revar


> On Feb 7, 2020, at 12:00 PM, Torsten Paul <[hidden email]> wrote:
>
> On 07.02.20 11:02, Revar Desmera wrote:
>> function is_nan(x) = x!=x;
>> That is somehow both elegant in its simplicity and horribly
>> twisted in its logic.
>
> Also nobody will claim any responsibility if it breaks at
> some point.
>
> If it makes sense to have that check, it would probably be
> better to actually implemented it in the core like the other
> test functions.
>
> The missing tokens are indeed a problem as that is one case
> where we can export files as CSG that can't be imported back.
>
>  nan = 0/0;
>  inf = 1/0;
>  ninf = -1/0;
>  echo(inf, ninf, nan);
>
> Just to highlight the point it's not an OpenSCAD invention:
>
> $ python3
> Python 3.7.6 (default, Jan 19 2020, 22:34:52)
> [GCC 9.2.1 20200117] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import math
> >>> nan = math.nan
> >>> nan == nan
> False
> >>> nan != nan
> True
> >>>
>
> ciao,
>  Torsten.
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org