Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to check a Float for NaN

1,574 views
Skip to first unread message

Jerry

unread,
Apr 30, 2008, 6:27:51 AM4/30/08
to
How would one check a Float or Long_Float if it has value NaN? The
only ways that I can come up with are to import a C function (isnan, I
think) or to write Long_Float'image(Some_Float) to a string and
examine the first three characters to see if they are "NaN" (and that
seems to be a GNAT implementation choice so might not be portable,
which is OK for my use).

Jerry

christo...@eurocopter.com

unread,
Apr 30, 2008, 6:47:54 AM4/30/08
to
Try Float'Valid (X), see RM 13.9.2

christo...@eurocopter.com

unread,
Apr 30, 2008, 6:50:15 AM4/30/08
to
On 30 Apr., 12:47, christoph.gr...@eurocopter.com wrote:
> Try Float'Valid (X), see RM 13.9.2

Ahem, I meant X'Valid for X of type Float

Adam Beneschan

unread,
Apr 30, 2008, 11:02:05 AM4/30/08
to

I'm not sure if this will produce the desired results, since it should
return False for +/- infinity also. That may be OK with the original
poster, or not.

The problem here is that if you're dealing with NaN's on purpose,
you're not really dealing with Ada, as far as I can tell, unless your
purpose is to test for an uninitialized variable (in which case
X'Valid makes sense). Otherwise, though, NaN's and infinities are not
possible values of floating-point types, and therefore they can't be
returned by operations that return floating-point values, even if
Float'Machine_Overflows is False. (There are certain passages in the
RM that say a result is implementation-defined if the
Machine_Overflows attribute is False; however, I do not think
assigning a variable to an invalid value, as a NaN would be, is an
allowed "implementation-defined" result. 13.9.2(4-11) lists the ways
that invalid data could be created, and the "result of a floating-
point operation that cannot return a valid result" is not one of those
listed. Yes, I know that this is a NOTE and is not normative.)

Of course, if you compile with checking turned off or your code does
something to turn off the floating-point overflow-checking bit in the
processor (if there is one), you're outside the bounds of Ada, so you
can't really come up with an Ada solution to the question, and
whatever you do won't be portable. In that case, "whatever works" is
fine. If I had to do this, I'd just do an Unchecked_Conversion to
some data structure with a rep clause that represents an IEEE-754
float, or to a modular integer type or array of modular integer types,
and then just test the bits myself. Testing the 'Image for "NaN" will
probably work, but if efficiency is a concern I wouldn't do this
because if the float is a valid one, it's a *lot* of work to convert
the float to a decimal representation, and that's especially painful
here because you're just going to throw all that work out.

P.S. Has the ARG or anyone discussed the possibility of building
support for infinities and/or NaN's into the language---i.e. defining
a floating-point type that includes those "values"? G.1.1(56) makes
me think that maybe there were some thoughts that this might be done
sometime in the future, if there's a demand for it, but I could be
reading something into this paragraph that isn't there.

-- Adam

Jerry

unread,
Apr 30, 2008, 4:33:17 PM4/30/08
to

Thanks for the insight. From my point of view, not having access to
the all the IEEE-754 features is a nuisance. I'm not sure what I'm
going to do--probably try in import the C function isnan. My need
isn't terribly important--just converting an example for PLplot that
is written in C. Frankly, I'm a little surprised that this isn't
handled by Ada--but I'm sure there's an excellent reason ;).

FWIW, I just now found this passage from the Annotated ARM at
http://www.adaic.org/standards/05aarm/html/AA-A-5-1.html, in A.5.1,
34.b (IEC 559 = IEEE 754):

"Discussion: It is anticipated that an Ada binding to IEC 559:1989
will be developed in the future. As part of such a binding, the
Machine_Overflows attribute of a conformant floating point type will
be specified to yield False, which will permit both the predefined
arithmetic operations and implementations of the elementary functions
to deliver signed infinities (and set the overflow flag defined by the
binding) instead of raising Constraint_Error in overflow situations,
when traps are disabled. Similarly, it is appropriate for the
elementary functions to deliver signed infinities (and set the zero-
divide flag defined by the binding) instead of raising
Constraint_Error at poles, when traps are disabled. Finally, such a
binding should also specify the behavior of the elementary functions,
when sensible, given parameters with infinite values."

Jerry


Jerry

unread,
Apr 30, 2008, 4:36:21 PM4/30/08
to

Check this out:

function Is_NaN(x : Long_Float) return Boolean is
begin
return x /= x;
end Is_NaN;

A couple of minutes on Wikipedia saves the day. From
http://en.wikipedia.org/wiki/NaN#NaN_encodings:

"A NaN does not compare equal to any floating-point number or NaN,
even if the latter has an identical representation. One can therefore
test whether a variable has a NaN value by comparing it to itself."

Jerry

Adam Beneschan

unread,
Apr 30, 2008, 5:53:54 PM4/30/08
to
On Apr 30, 1:36 pm, Jerry <lancebo...@qwest.net> wrote:

> Check this out:
>
> function Is_NaN(x : Long_Float) return Boolean is
> begin
> return x /= x;
> end Is_NaN;

Maybe that will work, but I wouldn't count on it. First of all, you
don't know that the compiler will actually do anything. It may get
clever and decide that this is trivially False, and thus generate code
that doesn't even look at x. Second, if it generates a "floating-
point comparison" instruction, you may not get the behavior you think
you're getting. My Pentium manual, for instance, says of the FCOM*
(Compare Real) instructions: "If either operand is a NaN or is in an
undefined format, ... the invalid-operation exception is raised, and
the condition bits are set to 'unordered'". Which means that (on that
processor) the comparison attempt will probably fault, and if it
doesn't because the fault is masked, the condition-code bits will be
set to an "unordered" relation that your compiler may not be
expecting, which means that it may not be translated to "inequality"
the way you think it will.


> A couple of minutes on Wikipedia saves the day. Fromhttp://en.wikipedia.org/wiki/NaN#NaN_encodings:


>
> "A NaN does not compare equal to any floating-point number or NaN,
> even if the latter has an identical representation. One can therefore
> test whether a variable has a NaN value by comparing it to itself."

But if you read further, you'll find that signaling NaNs "should raise
an invalid exception". (Why the Pentium FCOM instructions appear to
raise exceptions for quiet NaN's as well as signed NaN's, I don't
know.)

Anyway, Wikipedia describes the IEC 559/IEEE 754 standard, but as
we've already discussed, (1) Ada doesn't fully support this standard
and (2) NaN's aren't valid values in Ada, so you can't reliably use
the IEC/IEEE standard to predict what will happen if you do this in
Ada. You're welcome to try it, of course, but don't be surprised or
disappointed if it doesn't work.

-- Adam

Adam Beneschan

unread,
Apr 30, 2008, 7:23:13 PM4/30/08
to
On Apr 30, 1:33 pm, Jerry <lancebo...@qwest.net> wrote:

> Thanks for the insight. From my point of view, not having access to
> the all the IEEE-754 features is a nuisance. I'm not sure what I'm
> going to do--probably try in import the C function isnan.

Be careful with that, too. On my (Pentium Linux) system, the man page
for "isnan" says it takes a "double", which I think means a 64-bit
float. You'll probably be OK if you use a 64-bit float type (probably
Long_Float). But if you want to test a 32-bit float type, I don't see
a C function that works on 32-bit floats, and doing an Ada type
conversion is very likely to fail---probably cause a processor fault
when the compiler generates a floating-point conversion instruction
and the processor then faults because you gave it a NaN as an
instruction operand.

-- Adam

Randy Brukardt

unread,
Apr 30, 2008, 7:29:14 PM4/30/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:93b0d930-102a-4ac4...@j33g2000pri.googlegroups.com...
...

> P.S. Has the ARG or anyone discussed the possibility of building
> support for infinities and/or NaN's into the language---i.e. defining
> a floating-point type that includes those "values"? G.1.1(56) makes
> me think that maybe there were some thoughts that this might be done
> sometime in the future, if there's a demand for it, but I could be
> reading something into this paragraph that isn't there.

The "Rationale for Ada 2005" notes that AI95-00315 proposed such support:
see http://www.adaic.com/standards/05rat/html/Rat-9-3-3.html.

To expand a bit on the reasons for not including this: The proposal would
have required vastly different (and much worse in general) code generation
and optimization: much of what you can prove about values and expressions
goes out the window when you include NaNs and infinitities in the equation.
The proposal suggested a different mode for this, but some implementers did
not want to have to really support separate modes (they treat the "relaxed"
and "strict" modes the same). Moreover, the ARG didn't have any experts that
could really tell us if the proposal was useful or overkill, and vendors
didn't seem to have paying customers with specific concerns. As such, there
was no consensus on how to proceed, and it was tabled to put our energies
toward areas that we understood and had consensus for.

I believe the ARG will revisit this area if we get the right expertise (and
vendors have paying customers who care: I know RR does not have such
customers today).

Randy.


Adam Beneschan

unread,
Apr 30, 2008, 9:00:21 PM4/30/08
to
On Apr 30, 4:23 pm, I wrote:
> On Apr 30, 1:33 pm, Jerry <lancebo...@qwest.net> wrote:
>
> > Thanks for the insight. From my point of view, not having access to
> > the all the IEEE-754 features is a nuisance. I'm not sure what I'm
> > going to do--probably try in import the C function isnan.
>
> Be careful with that, too. On my (Pentium Linux) system, the man page
> for "isnan" says it takes a "double", which I think means a 64-bit
> float.

Ha, ha, ha, the man page lied. Apparently (on my system) isnan is a C
macro (in <math.h>), which will call one of three routines depending
on the size of the float. But since isnan is a macro, doing an Import
pragma on it is likely going to fail since "isnan" is not the name of
an actual routine in the library. That's on my OS, though; who knows
how it works on yours.

Anyway, good luck and have fun getting this to work.

-- Adam

Jerry

unread,
Apr 30, 2008, 9:05:41 PM4/30/08
to

Adam,
Your points are well made. For "normal" use my little hack should be
considered suspect. For my trivial use of getting this pesky binding
example code out of my hair, I think it should be OK.

Just for completeness, I suppose, I'll add (as I alluded to in my
original post), that this:

dum1 := 0.0;
dum2 := 0.0;
Put_Line(Long_Float'image(dum1 / dum2));

outputs this:

NaN*****************

Certainly not 754 compliance, but perhaps a bit of "awareness."
Jerry

Stuart

unread,
May 1, 2008, 4:04:11 AM5/1/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:93b0d930-102a-4ac4...@j33g2000pri.googlegroups.com...
> On Apr 30, 3:50 am, christoph.gr...@eurocopter.com wrote:
>> On 30 Apr., 12:47, christoph.gr...@eurocopter.com wrote:
>>
>> > Try Float'Valid (X), see RM 13.9.2
>>
>> Ahem, I meant X'Valid for X of type Float
<snip>

> The problem here is that if you're dealing with NaN's on purpose,
> you're not really dealing with Ada, as far as I can tell, unless your
> purpose is to test for an uninitialized variable (in which case
> X'Valid makes sense). Otherwise, though, NaN's and infinities are not
> possible values of floating-point types, and therefore they can't be
> returned by operations that return floating-point values, even if
> Float'Machine_Overflows is False. (There are certain passages in the
> RM that say a result is implementation-defined if the
> Machine_Overflows attribute is False; however, I do not think
> assigning a variable to an invalid value, as a NaN would be, is an
> allowed "implementation-defined" result. 13.9.2(4-11) lists the ways
> that invalid data could be created, and the "result of a floating-
> point operation that cannot return a valid result" is not one of those
> listed. Yes, I know that this is a NOTE and is not normative.)

Would not 13.9.2(10) cover this:
"disrupting an assignment due to the failure of a language-defined check
(see 11.6)"

Thus if a floating point operation creates a NaN, which would indicate an
ill-conditioned computation that should violate some language-defined check,
the object (X) that was to receive the result would be considered invalid.

As noted elsewhere, 'valid encompasses more than NaNs - which may or may not
suit the OPs purpose.

Regards
--
Stuart


Adam Beneschan

unread,
May 1, 2008, 10:38:40 AM5/1/08
to
On May 1, 1:04 am, "Stuart" <stu...@0.0> wrote:
> "Adam Beneschan" <a...@irvine.com> wrote in message

> > 13.9.2(4-11) lists the ways
> > that invalid data could be created, and the "result of a floating-
> > point operation that cannot return a valid result" is not one of those
> > listed. Yes, I know that this is a NOTE and is not normative.)
>
> Would not 13.9.2(10) cover this:
> "disrupting an assignment due to the failure of a language-defined check
> (see 11.6)"

Did you read 11.6?

I think all this says is that if an assignment statement raises an
exception (due to a language-defined check), then in the exception
handler and further on in the code, you can't count on the value of
the target object being normal. You can't count on it being abnormal,
either. But if no exception is raised, then this doesn't apply.

-- Adam

Stuart

unread,
May 1, 2008, 1:14:09 PM5/1/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:fe6a8cc1-eac7-4b25...@k1g2000prb.googlegroups.com...

> On May 1, 1:04 am, "Stuart" <stu...@0.0> wrote:
>> "Adam Beneschan" <a...@irvine.com> wrote in message
>
>> > 13.9.2(4-11) lists the ways
>> > that invalid data could be created, and the "result of a floating-
>> > point operation that cannot return a valid result" is not one of those
>> > listed. Yes, I know that this is a NOTE and is not normative.)
>>
>> Would not 13.9.2(10) cover this:
>> "disrupting an assignment due to the failure of a language-defined
>> check
>> (see 11.6)"
>
> Did you read 11.6?

I tried, but legalese is not my first language and I find some of the
'language lawyerly' stuff rather impenetrable at times. ;-)

> I think all this says is that if an assignment statement raises an
> exception (due to a language-defined check), then in the exception
> handler and further on in the code, you can't count on the value of
> the target object being normal. You can't count on it being abnormal,
> either. But if no exception is raised, then this doesn't apply.

I agree with what you are saying here; which I read as 'you can't count on
the target object being obviously invalid (e.g. a NaN), but it _could_ be'.
As such 13.9.2(10) appears to support a case by which a NaN value could
arise in an object during computation.

In a nominal Ada program it would be sensible to deal with the situation in
the exception handler, rather than let it slide and try and resolve it later
using 'valid. But then, I think, we are picking-over the innards of some
murky corner case of the language - so good-sense need not apply ;-)

I would hazard a guess that we have strayed well away from the OP's original
area of interest (he was probably validating inputs), and as you noted
earlier.

Regards
--
Stuart


Randy Brukardt

unread,
May 1, 2008, 3:22:35 PM5/1/08
to
"Stuart" <stuart@0.0> wrote in message
news:4819f65b$1...@glkas0286.greenlnk.net...

> "Adam Beneschan" <ad...@irvine.com> wrote in message
> news:fe6a8cc1-eac7-4b25...@k1g2000prb.googlegroups.com...
...

> >> Would not 13.9.2(10) cover this:
> >> "disrupting an assignment due to the failure of a language-defined
> >> check
> >> (see 11.6)"
> >
> > Did you read 11.6?
>
> I tried, but legalese is not my first language and I find some of the
> 'language lawyerly' stuff rather impenetrable at times. ;-)

If either of you can clearly understand and explain 11.6, then you need to
join the ARG immediately and explain it to us. ;-)

Seriously, 11.6 is a very murky part of the Standard, while everyone
understands what is generally intended, its not clear that the wording
actually has the right effect in many detailed cases. Nor is it clear
exactly what boundaries are correct. It was the best that the Ada 95 team
could do, and no one much wants to open the can of worms that it represents.

We had a series of lengthy and rather heated discussions about the data
validity model in Ada during the Amendment process. We were trying to fix
the Ada 95 problem that if an Unchecked_Conversion produces an invalid
result, using 'Valid to check that result made your program erroneous (thus,
'Valid could always return True in that case, and in fact at least one
compiler did that). We hacked around with the rules to eliminate that
particular problem (at the cost of making them much more complex).

But we weren't able to completely eliminate the problem (exceptions still
can be raised in this case): the problem being one camp that thinks that
there should be no checks on Unchecked_Conversion ever and the other camp
that will not allow valid objects to become invalid in any circumstances
(the alternative being erroneous execution, which is uncalled for for
something whose primary purpose is to eliminate checks). We ended up
compromising in the middle (I would have preferred to get rid of the
erroneousness completely, but at least the current rules don't require an
implementer to generate erroneous programs - you can make extra checks to
prevent it).

Randy.


Keith Thompson

unread,
May 1, 2008, 3:52:16 PM5/1/08
to

The C99 C standard (which is not widely implemented, at least not
completely) specifies that isnan() is a macro that can take an
argument of any floating-point type (float, double, long double). It
might typically be implemented by invoking one of three functions
depending on the size of the argument, but the standard doesn't
specify any particular method; it could be pure magic. The earlier
C90 standard doesn't provide any such floating-point classification
macros or functions. Some C90 implementations might provide a
function, rather than macro, called "isnan"; perhaps that's what your
system documents.

You can't interface to a C macro from Ada (as far as I know), but you
can easily write a wrapper function. Assuming your C implementation
provides the isnan() macro as specified by C99, you can do this:

#include <math.h>

int float_isnan (float x) { return isnan(x); }
int double_isnan (double x) { return isnan(x); }
int long_double_isnan (long double x) { return isnan(x); }

and then provide Ada interfaces to those C functions.

It's a bit of a roundabout way to do it (providing three distinct
function wrappers for a single macro that's probably a wrapper for
three distinct underlying functions), but it should work.

--
Keith Thompson (The_Other_Keith) <ks...@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Jerry

unread,
May 1, 2008, 7:57:26 PM5/1/08
to
On May 1, 12:52 pm, Keith Thompson <ks...@mib.org> wrote:

That looks doable.

As an aside, I remember the early Pascal compilers on Macintosh
(Apple's own and the much-missed THINK Pascal nee MacPascal) dealt
with all of the 754 spec (as far as I know, which isn't very far) and
was very well documented in a book called Apple Numerics Manual with
unspecified authorship but with a forward by Prof. Kahan of UC
Berkeley. MacPascal did 96-bit floating point when it ran without
hardware acceleration and fell back to 80 bits with a FPU.

Jerry

Jerry

unread,
May 1, 2008, 8:04:53 PM5/1/08
to
On May 1, 1:04 am, "Stuart" <stu...@0.0> wrote:
> "Adam Beneschan" <a...@irvine.com> wrote in message

Not sure. Apparently, the plotting example I'm translating from C
needs to check for NaN when the underlying surface plot machinery is
working. It seems odd that this heavy a responsibility should appear
to the user in an example, but that's out of my control. I suppose
'valid would work since I doubt that other pathologies would arise.

Jerry
>
> Regards
> --
> Stuart

Martin Krischik

unread,
May 5, 2008, 2:23:02 PM5/5/08
to
Jerry wrote:

How about an Unchecked Conversion to an Unsigned_64 and comparing
>2#0111_1111_1111_0000_0000_0000_0000_0000#

Note that it's '>' as 2#0111_1111_1111_0000_0000_0000_0000_0000# is positive
infinity.

Martin
--
mailto://kris...@users.sourceforge.net
Ada programming at: http://ada.krischik.com

Adam Beneschan

unread,
May 5, 2008, 4:49:25 PM5/5/08
to
On May 5, 11:23 am, Martin Krischik <krisc...@users.sourceforge.net>
wrote:

> Jerry wrote:
> > How would one check a Float or Long_Float if it has value NaN? The
> > only ways that I can come up with are to import a C function (isnan, I
> > think) or to write Long_Float'image(Some_Float) to a string and
> > examine the first three characters to see if they are "NaN" (and that
> > seems to be a GNAT implementation choice so might not be portable,
> > which is OK for my use).
>
> How about an Unchecked Conversion to an Unsigned_64 and comparing
>
> >2#0111_1111_1111_0000_0000_0000_0000_0000#
>
> Note that it's '>' as 2#0111_1111_1111_0000_0000_0000_0000_0000# is positive
> infinity.

Any negative float (including negative infinity) would be > than the
binary number you give, since the leftmost bit (sign bit) would be 1.
I think you need to clear the sign bit first, then your comparison
will work:

Is_NaN := (To_Unsigned_64(X) and not
2#1000_0000_0000_0000_0000_0000_0000_0000#)
> 2#0111_1111_1111_0000_0000_0000_0000_0000#;

But I haven't tried it.

-- Adam


Jerry

unread,
May 6, 2008, 2:09:56 PM5/6/08
to

I thought about doing something like this once I saw the bit patterns
on the Wikipedia page. However, I would guess that the bit pattern for
quiet and signaling NaNs is different, so the test would be somewhat
more complicated if one wanted to detect both types.

Jerry

Wiljan Derks

unread,
May 6, 2008, 2:45:47 PM5/6/08
to
The following code works fine for us:

type Ieee_Short_Real is
record
Mantisse_Sign : Integer range 0 .. 1;
Exponent : Integer range 0 .. 2 ** 8 - 1;
Mantisse : Integer range 0 .. 2 ** 23 - 1;
end record;

for Ieee_Short_Real use
record
Mantisse_Sign at 0 range 31 .. 31;
Exponent at 0 range 23 .. 30;
Mantisse at 0 range 0 .. 22;
end record;

function Valid_Real (Number : Float) return Boolean is
function To_Ieee_Short_Real is
new Ada.Unchecked_Conversion (Float, Ieee_Short_Real);
begin
return To_Ieee_Short_Real (Number).Exponent /= 255;
end Valid_Real;

Wiljan


Adam Beneschan

unread,
May 6, 2008, 6:18:39 PM5/6/08
to

It might make sense to use modular types instead of signed integer
types for Mantisse_Sign, Exponent, and Mantisse (or Mantissa, if you
want to use English); then you can use "and", "or", and "not"
operations to test bits. Actually, I'd probably define a couple
constants here:

Exponent_Size : constant := 8;
Mantissa_Size : constant := 23;

type Exponent_Type is mod 2 ** Exponent_Size;
type Mantissa_Type is mod 2 ** Mantissa_Size;
type Mantissa_Sign_Type is mod 2;

Using constants makes it easy to re-implement this for 64- and 80-bit
floats.

type Ieee_Short_Real is
record
Mantissa_Sign : Mantissa_Sign_Type;
Exponent : Exponent_Type;
Mantissa : Mantissa_Type;
end record;

(I've omitted the rep clause because I think the one above might work
only for big-endian and not little-endian machines or vice versa, and
I don't feel like figuring it out because I have a cold and my head
hurts enough already.)

Then, if X is the result of the Unchecked_Conversion:

Number is a valid float if X.Exponent /= Exponent_Type'Last

Number is an infinity if X.Exponent = Exponent_Type'Last and
X.Mantissa = 0

Number is a qNaN if X.Exponent = Exponent_Type'Last and
(X.Mantissa and 2**(Mantissa_Size-1) /= 0)

Number is a sNaN if X.Exponent = Exponent_Type'Last and X.Mantissa /=
0 and
(X.Mantissa and 2**(Mantissa_Size-1) = 0)

On the Pentium, Number is a "real indefinite" if
X.Exponent = Exponent_Type'Last and
X.Mantissa = 2**(Mantissa_Size-1)

Number is a denormal if X.Exponent = 0 and X.Mantissa /= 0

Hope this helps someone (and I hope I didn't screw up and get
something wrong),

-- Adam


Randy Brukardt

unread,
May 7, 2008, 6:56:57 PM5/7/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:95c1de75-7aa0-4f00...@b9g2000prh.googlegroups.com...
...

> type Ieee_Short_Real is
> record
> Mantissa_Sign : Mantissa_Sign_Type;
> Exponent : Exponent_Type;
> Mantissa : Mantissa_Type;
> end record;
>
> (I've omitted the rep clause because I think the one above might work
> only for big-endian and not little-endian machines or vice versa, and
> I don't feel like figuring it out because I have a cold and my head
> hurts enough already.)

Sorry about the cold, but if you omit the rep. clause, all of these
components are likely to take full bytes and that won't work at all.

IF you had given size clauses on all of the modular types AND a pragma Pack
on the record, it MIGHT have worked. But given that you need a particular
representation, omitting the rep. clause is irrational. (That said, getting
it right on both big-endian and little-endian machines is enough to make my
head explode. But it's rarely necessary, and certainly isn't in the OP's
case.)

Randy.


Randy Brukardt

unread,
May 7, 2008, 6:56:57 PM5/7/08
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:95c1de75-7aa0-4f00...@b9g2000prh.googlegroups.com...
...
> type Ieee_Short_Real is
> record
> Mantissa_Sign : Mantissa_Sign_Type;
> Exponent : Exponent_Type;
> Mantissa : Mantissa_Type;
> end record;
>
> (I've omitted the rep clause because I think the one above might work
> only for big-endian and not little-endian machines or vice versa, and
> I don't feel like figuring it out because I have a cold and my head
> hurts enough already.)

Sorry about the cold, but if you omit the rep. clause, all of these

Adam Beneschan

unread,
May 7, 2008, 7:20:55 PM5/7/08
to
On May 7, 3:56 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> "Adam Beneschan" <a...@irvine.com> wrote in message

>
> news:95c1de75-7aa0-4f00...@b9g2000prh.googlegroups.com...
> ...
>
> > type Ieee_Short_Real is
> > record
> > Mantissa_Sign : Mantissa_Sign_Type;
> > Exponent : Exponent_Type;
> > Mantissa : Mantissa_Type;
> > end record;
>
> > (I've omitted the rep clause because I think the one above might work
> > only for big-endian and not little-endian machines or vice versa, and
> > I don't feel like figuring it out because I have a cold and my head
> > hurts enough already.)
>
> Sorry about the cold, but if you omit the rep. clause, all of these
> components are likely to take full bytes and that won't work at all.

I didn't mean that this would work without a rep clause. I only meant
that I didn't feel like figuring it out (especially given that I
wanted to use the constants I defined instead of hard-coded integer
literals). Yes, it does need one. How about if I say, "Left as an
exercise for the reader"??

-- Adam

Stephen Leake

unread,
May 9, 2008, 3:24:21 AM5/9/08
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

Ada 2005 supports endian-independent rep clauses; LRM 13.5.3 9/2.

However, GNAT doesn't support them for anything bigger than 1 byte.

I don't know about other compilers.

--
-- Stephe

anon

unread,
May 9, 2008, 3:49:50 PM5/9/08
to
--
-- Nan is define to be greater than value of hex 16#FF000000#
--

function isNan ( N : Float ) return Boolean is

T : Long_Long_Integer := Long_Long_Integer ( N ) ;

begin
if T > 16#FF000000# then
return True ;
else
return False ;
end if ;
end ;


In <3132e38d-18bb-4890...@x19g2000prg.googlegroups.com>, Jerry <lance...@qwest.net> writes:
>How would one check a Float or Long_Float if it has value NaN? The
>only ways that I can come up with are to import a C function (isnan, I
>think) or to write Long_Float'image(Some_Float) to a string and
>examine the first three characters to see if they are "NaN" (and that
>seems to be a GNAT implementation choice so might not be portable,
>which is OK for my use).
>

>Jerry
>

Jerry

unread,
May 9, 2008, 10:36:58 PM5/9/08
to
On May 9, 12:49 pm, a...@anon.org (anon) wrote:
>   --
>   -- Nan is define to be greater than value of hex 16#FF000000#
>   --
>
>   function isNan ( N : Float ) return Boolean is
>
>      T : Long_Long_Integer := Long_Long_Integer ( N ) ;
>
>     begin
>       if T > 16#FF000000# then
>         return True ;
>       else
>         return False ;
>       end if ;
>     end ;
>
> In <3132e38d-18bb-4890-9cec-31056ac6e...@x19g2000prg.googlegroups.com>, Jerry <lancebo...@qwest.net> writes:
>
> >How would one check a Float or Long_Float if it has value NaN? The
> >only ways that I can come up with are to import a C function (isnan, I
> >think) or to write Long_Float'image(Some_Float) to a string and
> >examine the first three characters to see if they are "NaN" (and that
> >seems to be a GNAT implementation choice so might not be portable,
> >which is OK for my use).
>
> >Jerry

No offense to anon, but does this work? Does anyone know of a
reference for this definition of a NaN?

Also, wondering how one might detect an Inf.

It seems that there is enough information in this thread to begin
writing a little package to deal with some of these things.

Thanks for all the great tips, BTW.

Jerry

anon

unread,
May 9, 2008, 11:53:54 PM5/9/08
to
Reference Microsoft and

"isnan.asm" from

http://www.visionlab.uncc.edu/websvn/filedetails.php?repname=toolchain&path=%2Fvendor%2Fvdsplibs%2Fcurrent%2Flibdsp%2Fisnan.asm&rev=1693&sc=1

The only mistake is that T > 16#7F000000# because I forgot to adjust
for the the sign bit because NaN can have a valid sign set.

This work because in Intel the NaN is set by forcing bits 30-24 to 1 aka
16#7F000000#

The

T : Long_Long_Integer := Long_Long_Integer ( N ) ;

moves the bit-value of N a 48-bit float to a Long_Long_Integer (T)
without conversion.

In <b42cb056-f923-45d9...@t12g2000prg.googlegroups.com>, Jerry <lance...@qwest.net> writes:
>On May 9, 12:49=A0pm, a...@anon.org (anon) wrote:
>> =A0 --
>> =A0 -- Nan is define to be greater than value of hex 16#FF000000#
>> =A0 --
>>
>> =A0 function isNan ( N : Float ) return Boolean is
>>
>> =A0 =A0 =A0T : Long_Long_Integer :=3D Long_Long_Integer ( N ) ;
>>
>> =A0 =A0 begin
>> =A0 =A0 =A0 if T > 16#FF000000# then
>> =A0 =A0 =A0 =A0 return True ;
>> =A0 =A0 =A0 else
>> =A0 =A0 =A0 =A0 return False ;
>> =A0 =A0 =A0 end if ;
>> =A0 =A0 end ;
>>
>> In <3132e38d-18bb-4890-9cec-31056ac6e...@x19g2000prg.googlegroups.com>, Je=

christo...@eurocopter.com

unread,
May 10, 2008, 2:24:48 AM5/10/08
to
> T : Long_Long_Integer := Long_Long_Integer ( N ) ;

Anon, this is nonsense. What you present is a type conversion Float to
Long_Long_Integer, which will not work (it will round to the next
nearest integer value or raise Constraint_Error if the float value is
out of range). What is really needed and will work is an unchecked
conversion (this will leave all bits unchanged).

Georg Bauhaus

unread,
May 10, 2008, 4:05:33 AM5/10/08
to
Jerry wrote:
> On May 9, 12:49 pm, a...@anon.org (anon) wrote:
>> --
>> -- Nan is define to be greater than value of hex 16#FF000000#
>> --
>>
>> function isNan ( N : Float ) return Boolean is
>>
>> T : Long_Long_Integer := Long_Long_Integer ( N ) ;
>>
>> begin
>> if T > 16#FF000000# then
>> return True ;
>> else
>> return False ;
>> end if ;
>> end ;
>>

> No offense to anon, but does this work? Does anyone know of a


> reference for this definition of a NaN?
>
> Also, wondering how one might detect an Inf.
>
> It seems that there is enough information in this thread to begin
> writing a little package to deal with some of these things.

I think you will need IEEE floats, not just Ada Floats.
(Some compilers have corresponding types, or implement their
Floats accordingly.) Consulting a text book again, I find that
IEEE defines representations for NaN (both quiet and signalling NaN),
Inf, ...

IIUC, for testing for NaN, basically

- ignore the sign bit
- expect all exponent bits set to 1
- expect the fraction part to be /= 0

This would explain why there are cases when an unchecked_conversion
of an IEEE FPT word to some "scalar word" will allow you to look
at the bits and decide whether it can represents a NaN.

Showing my ignorance I wonder, though, what happens when a fpt register
is effectively unchecked_converted into a CPU register suitable
for a long...

anon

unread,
May 10, 2008, 1:00:51 PM5/10/08
to
If you look at my first post on this topic and change the 16#FF000000#
to 16#7F000000# (typo, forgot to adjust for the sign-bit) its basically
what I have done except that I use a 64-bit sign integer instead of the
Unsigned_64. In order to save coding time, did not want to add the
extra statements. Plus, if it for a final (it that time of the year) they
should be able add those lines.

And because float is normally defined by the IEEE-754 as a 32-bit
number it will fix into a 64-bit integer without raising a
Constraint_Error. The size of Long_Long_Integer is at least 64-bit
signed integer on a 32/64 bit machines.

NaN := range 2#0111_1111_1111_0000_0000_0000_0000_0000#
..
2#1111_1111_1111_1111_1111_1111_1111_1111# ;

Keith Thompson

unread,
May 11, 2008, 6:00:55 PM5/11/08
to
an...@anon.org (anon) writes:
> If you look at my first post on this topic and change the 16#FF000000#
> to 16#7F000000# (typo, forgot to adjust for the sign-bit) its basically
> what I have done except that I use a 64-bit sign integer instead of the
> Unsigned_64. In order to save coding time, did not want to add the
> extra statements. Plus, if it for a final (it that time of the year) they
> should be able add those lines.
[...]

You're using a value conversion. This converts, for example, the
Float value 3.0 to the Long_Long_Integer value 3. In your code, with
16#FF000000# changed to 16#7F000000#, this:

T : Long_Long_Integer := Long_Long_Integer ( N ) ;

...
if T > 16#7F000000# then
...

is essentially equivalent to this:

if T > 2130706432.0 then

Try isNan(2.0E9) and isNan(3.0E9).

You need an Unchecked_Conversion. You also need to make sure you
choose a floating-point and integer type of the same size, and to
allow for things like byte ordering (even if you're limiting the test
to systems that support IEEE floating-point, which is probably a
reasonable restriction since other floating-point formats may not
support NaNs at all).

anon

unread,
May 11, 2008, 10:01:18 PM5/11/08
to
If you read I answered that!

>> In order to save coding time, did not want to add the
>> extra statements. Plus, if it for a final (it that time of the year) they
>> should be able add those lines.

Last week was FINALS WEEK for most colleges. If you answer a question
durring this time you NEVER give the complete answer only a partial one.
And it does not matter if the answer is in code or a couple of paragraphs.

My answer was just that, correct in the outline but not is uncomplete. And
any Ada programmer should be able to take my program and make it work
within a minute or two. But a college student at finals would never spend
the time, they want the complete and only complete answer, so they can
study for other classes or party.

jan.de...@gmail.com

unread,
May 22, 2014, 3:27:02 AM5/22/14
to
On Wednesday, April 30, 2008 10:36:21 PM UTC+2, Jerry wrote:

>
> Check this out:
>
> function Is_NaN(x : Long_Float) return Boolean is
> begin
> return x /= x;
> end Is_NaN;
>
> A couple of minutes on Wikipedia saves the day. From
> http://en.wikipedia.org/wiki/NaN#NaN_encodings:
>
> "A NaN does not compare equal to any floating-point number or NaN,
> even if the latter has an identical representation. One can therefore
> test whether a variable has a NaN value by comparing it to itself."
>
> Jerry

This worked on the Gnat compiler, this code

if Cos_Theta /= Cos_Theta then
Gct.Trace (Debug_Str, "cos_theta is NaN******");
else
Gct.Trace (Debug_Str, "cos_theta : " & Long_Float'Image (Cos_Theta));
end if;

gives this in the log:

[MATH3D.DEBUG] 1/372 cos_theta is NaN****** (2014-05-22 09:23:24.155)(loc: math3d.adb:129)

Hope it helps someone;

Cheers,

j.


Dmitry A. Kazakov

unread,
May 22, 2014, 4:09:02 AM5/22/14
to
You could simply use range check:

X in Long_Float'Range

NaN is not a number and thus outside the range.

However, for technical computations, it is advisory to turn IEEE semantics
off. Fortunately there is a very simple way to do so in Ada:

subtype Real_Long_Float is Long_Float range Long_Float'Range;

Use this instead of Long_Float and you will never have NaN, +/-Inf again.
Constraint_Error will propagate instead.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Simon Wright

unread,
May 22, 2014, 5:24:35 AM5/22/14
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> On Thu, 22 May 2014 00:27:02 -0700 (PDT), jan.de...@gmail.com wrote:

>> if Cos_Theta /= Cos_Theta then
>> Gct.Trace (Debug_Str, "cos_theta is NaN******");
>> else
>> Gct.Trace (Debug_Str, "cos_theta : " & Long_Float'Image (Cos_Theta));
>> end if;
>>
>> gives this in the log:
>>
>> [MATH3D.DEBUG] 1/372 cos_theta is NaN****** (2014-05-22 09:23:24.155)(loc: math3d.adb:129)
>>
>> Hope it helps someone;
>
> You could simply use range check:
>
> X in Long_Float'Range
>
> NaN is not a number and thus outside the range.

This would also return False for +/-Inf, so if the OP wants specifically
to check for NaN it wouldn't do. Can't think why they would, though.

GNAT says about "X in Long_Float'Range"
inf.adb:10:60: warning: explicit membership test may be optimized away
inf.adb:10:60: warning: use 'Valid attribute instead

Dmitry A. Kazakov

unread,
May 22, 2014, 5:48:47 AM5/22/14
to
Looks like a bug, it may not be optimized away if Long_Float is IEEE 754.

> inf.adb:10:60: warning: use 'Valid attribute instead

Hmm, reading RM 13.9.2 makes me believe that NaN's 'Valid should yield
True.

Adam Beneschan

unread,
May 22, 2014, 11:28:33 AM5/22/14
to
On Thursday, May 22, 2014 2:48:47 AM UTC-7, Dmitry A. Kazakov wrote:
> On Thu, 22 May 2014 10:24:35 +0100, Simon Wright wrote:
>
> > "Dmitry A. Kazakov" writes:
>
> >> On Thu, 22 May 2014 00:27:02 -0700 (PDT), jan.de.kruyf wrote:

> >>> if Cos_Theta /= Cos_Theta then
>
> >>> Gct.Trace (Debug_Str, "cos_theta is NaN******");
>
> >>> else
>
> >>> Gct.Trace (Debug_Str, "cos_theta : " & Long_Float'Image (Cos_Theta));
>
> >>> end if;
>
> >>>
>
> >>> gives this in the log:
>
> >>>
>
> >>> [MATH3D.DEBUG] 1/372 cos_theta is NaN****** (2014-05-22 09:23:24.155)(loc: math3d.adb:129)
>
> >>>
>
> >>> Hope it helps someone;
>
> >>
>
> >> You could simply use range check:

> >> X in Long_Float'Range

> >> NaN is not a number and thus outside the range.

> > This would also return False for +/-Inf, so if the OP wants specifically
> > to check for NaN it wouldn't do. Can't think why they would, though.

> > GNAT says about "X in Long_Float'Range"
>
> > inf.adb:10:60: warning: explicit membership test may be optimized away

> Looks like a bug, it may not be optimized away if Long_Float is IEEE 754.

> > inf.adb:10:60: warning: use 'Valid attribute instead

> Hmm, reading RM 13.9.2 makes me believe that NaN's 'Valid should yield
> True.

No, I don't think so. 3.5.7(8) says "The set of values for a floating point type is the (infinite) set of rational numbers." This excludes NaN and infinities, which are not rational numbers (nor any kind of number). Therefore, if X contains an infinity or NaN, X'Valid should be false.

Unlike some languages (e.g. Java), Ada doesn't define +/- Infinity or NaN to be valid values in the language, and therefore it can't make any statements about how they're supposed to be handled. Normally, an operation that results in infinity or NaN is supposed to raise Constraint_Error. However, the language allows for implementations not to check this, by providing a Machine_Overflows attribute that is False if Constraint_Error isn't raised. As far as I can tell, however, the language doesn't say anything about what happens otherwise, except that the result is "unspecified" or "implementation-defined". Even where an implementation is required to support IEEE 754 semantics (I think this is required if an implementation claims to support Annex G), I don't believe the requirements apply to NaN or Infinity even if Machine_Overflows is False--since those aren't really valid values in the language, I don't think the language can impose any requirements on how they're handled.

In particular, that means that a condition like

if Cos_Theta /= Cos_Theta then ...

could be treated the same as

if False then ...

by the compiler. And yes, "X in Long_Float'Range" could be treated as "known to be True". Maybe it will and maybe it won't, but the thing is, you can't count on it in Ada. You may be able to count on it for a specific compiler, depending on what the compiler vendor promises. But it won't be portable. (The warning could be a GNAT bug within the context of what GNAT's documentation says the compiler should do--I don't know, I haven't read all of it--but this behavior is permissible in Ada.)

There are a few statements in the AARM that say "It is anticipated that an Ada binding to IEC 559:1989 will be developed in the future" or something similar, and those sections do discuss treating infinities and NaN's as values and anticipate that there will be language rules about how they're to be handled. However, I notice that those statements were in the Ada 95 AARM and haven't really been changed since. On Google Groups, this thread includes some posts going back to 2008 about this subject, including one by Randy about why the ARG hasn't addressed this yet.

-- Adam





Dmitry A. Kazakov

unread,
May 22, 2014, 12:31:12 PM5/22/14
to
These are not values of Long_Float. I guess that values of Long_Float are
"machine numbers" defined in the following sentence.

Why doesn't it preclude NaN returned and accepted by arithmetic operations?
Either 3.5.7 lies or the operations do.

Adam Beneschan

unread,
May 22, 2014, 7:33:50 PM5/22/14
to
On Thursday, May 22, 2014 9:31:12 AM UTC-7, Dmitry A. Kazakov wrote:

> > No, I don't think so. 3.5.7(8) says "The set of values for a floating
> > point type is the (infinite) set of rational numbers." This excludes NaN
> > and infinities, which are not rational numbers (nor any kind of number).
>
> These are not values of Long_Float. I guess that values of Long_Float are
> "machine numbers" defined in the following sentence.

I'm not sure why the RM defined the "set of values" to be an infinite set; I'm sure that this made the rest of the semantics easier to specify in some way, but I don't know what that is. The set of *machine numbers* for a type is a subset of this set of values. I think that intermediate computations can involve numbers that aren't machine numbers (if they're performed using a type with greater precision, for example); I'm not sure. In any case, though, it's clear that infinities and NaN aren't part of the "set of values", and thus they can't be part of the set of machine numbers which is a subset of the "set of values".


> Why doesn't it preclude NaN returned and accepted by arithmetic operations?
> Either 3.5.7 lies or the operations do.

I think it *does* preclude NaN, unless I don't understand what you mean. I guess you could say that the "operations lie", because if Machine_Overflows is False, an operation on two values of a floating-point type may have an invalid result. Normally, that's not supposed to happen. But we can consider Machine_Overflows=False to work somewhat similarly to a Suppress pragma in that undefined results may happen. If B is a Boolean variable whose value is True, what does B := Boolean'Succ(B) do if Suppress(Range_Check) is in effect? It will quite possibly set B to something that is not a valid Boolean value. But I'm not sure that means the 'Succ operation is lying. And I don't think that the arithmetic operations "lie" any more than 'Succ is in this example.

-- Adam

Dmitry A. Kazakov

unread,
May 23, 2014, 3:38:58 AM5/23/14
to
On Thu, 22 May 2014 16:33:50 -0700 (PDT), Adam Beneschan wrote:

> On Thursday, May 22, 2014 9:31:12 AM UTC-7, Dmitry A. Kazakov wrote:
>
>>> No, I don't think so. 3.5.7(8) says "The set of values for a floating
>>> point type is the (infinite) set of rational numbers." This excludes NaN
>>> and infinities, which are not rational numbers (nor any kind of number).
>>
>> These are not values of Long_Float. I guess that values of Long_Float are
>> "machine numbers" defined in the following sentence.
>
> I'm not sure why the RM defined the "set of values" to be an infinite set;
> I'm sure that this made the rest of the semantics easier to specify in
> some way, but I don't know what that is. The set of *machine numbers* for
> a type is a subset of this set of values. I think that intermediate
> computations can involve numbers that aren't machine numbers (if they're
> performed using a type with greater precision, for example); I'm not sure.
> In any case, though, it's clear that infinities and NaN aren't part of the
> "set of values", and thus they can't be part of the set of machine numbers
> which is a subset of the "set of values".

Yes, but NaN is certainly a machine value of IEEE 754 hardware.

My impression is that the text was written prior to wide spread of IEEE 754
hardware and was not reviewed since.

>> Why doesn't it preclude NaN returned and accepted by arithmetic operations?
>> Either 3.5.7 lies or the operations do.
>
> I think it *does* preclude NaN, unless I don't understand what you mean.
> I guess you could say that the "operations lie", because if
> Machine_Overflows is False, an operation on two values of a floating-point
> type may have an invalid result.

Yes, but an invalid result still may not be outside the set of type values!

If NaN is not a type value, then an operation returning NaN is not of the
type. It is a type error then, a compiler/language bug.

After all, floating-point types are models, there is no reason why a model
could not have ideals NaN, +/-Inf as proper values and thus arithmetic
operations were defined in terms of this extended set of values. Which is
what IEEE 754 actually is all about.

The semantics of X'Value to exclude IEEE ideals could be easily defined in
13.9.2 as a special case. (X'Succ and X'Pred are already defined correctly
as returning a machine number.)

3.5.7 could be slightly rewritten to convey that type values include
equivalents of some real numbers (machine numbers) and, possibly, of some
ideals (machine special values).

Randy Brukardt

unread,
May 23, 2014, 5:39:54 PM5/23/14
to
"Adam Beneschan" <adambe...@gmail.com> wrote in message
news:b96fb365-9061-4170...@googlegroups.com...
...
>> Why doesn't it preclude NaN returned and accepted by arithmetic
>> operations?
>> Either 3.5.7 lies or the operations do.
>
>I think it *does* preclude NaN, unless I don't understand what you mean. I
>guess you could
>say that the "operations lie", because if Machine_Overflows is False, an
>operation on two
>values of a floating-point type may have an invalid result.

Right. I have no idea what's supposed to happen if Machine_Overflows is
False. To the point that Janus/Ada simply doesn't use it; Machine_Overflows
is True and we check after every group of operations to ensure that's true.
So it's not possible to generate a NaN in Janus/Ada. I understand that the
other semantics exists, but it's a mess by any standard and I'd need a lot
more convincing ($$$$) to support something else. [That is, I see no
sensible reason for NaNs or infinities -- they're just ways of deferring
detection of bugs. I would have hoped that Ada's moved beyond that, just
like it has for integers.]

Randy.


Dmitry A. Kazakov

unread,
May 27, 2014, 4:35:29 AM5/27/14
to
On Fri, 23 May 2014 16:39:54 -0500, Randy Brukardt wrote:

> That is, I see no
> sensible reason for NaNs or infinities -- they're just ways of deferring
> detection of bugs. I would have hoped that Ada's moved beyond that, just
> like it has for integers.]

Yes, from the engineering POV IEEE 754 is a great nuisance, as we want to
report any bugs as early as possible.

But as a mathematical construct (extended numeric sets) it is very elegant,
e.g. surreal numbers:

http://en.wikipedia.org/wiki/Surreal_number

Maurizio Tomasi

unread,
May 27, 2014, 8:35:26 AM5/27/14
to
> That is, I see no sensible reason for NaNs or infinities -- they're just ways of deferring detection of bugs. I would have hoped that Ada's moved beyond that, just like it has for integers.]

Being a scientist working with large chunks of data, I find NaNs useful in a number of situations. I work in a domain (observational cosmology) where we need to deal with sky maps containing ~10^7 pixels (you can think of a "map" as a 1D vector where pixels on the sky sphere are ordered according to some rule). Not every sky direction can be sampled, because of a number of problems (in the instrument, in the observational strategy, in the data reduction pipeline, etc.)

Therefore, in my Python+NumPy codes I always mark such directions using "quiet NaNs". If I have to combine two maps in order e.g. to take their average, the usual rules for combining NaNs are be exactly what I want. Writing in Ada what I actually write in Python:

for I := 1 to N do
Average_Map(I) := 0.5 * (Map1(I) + Map2(I));
end loop;

If either Map1(I) or Map2(I) (or both) are NaN, then Average_Map(I) will be a NaN too, which is correct from the point of view of the meaning of the measurement. But without proper treatment of NaNs, one should write

for I in Map1'Range do
if not Is_NaN(Map1(I)) and not Is_NaN(Map2(I)) then
Average_Map(I) := 0.5 * (Map1(I) + Map2(I));
else
Set_To_NaN(Average_Map, I);
end if;
end loop;

If one has to run many calculations on such maps (which is indeed always the case) instead of just a plain average, the code can get quite complex. And I do not think one gets more safety from such verbosity, as what a scientist expects from a NaN number is actually what the usual rules for NaN give.

I am not an Ada export, so these are just my two cents,
Maurizio.

Adam Beneschan

unread,
May 27, 2014, 11:53:00 AM5/27/14
to
On Tuesday, May 27, 2014 5:35:26 AM UTC-7, Maurizio Tomasi wrote:
> > That is, I see no sensible reason for NaNs or infinities -- they're just ways of deferring detection of bugs. I would have hoped that Ada's moved beyond that, just like it has for integers.]
>
>
>
> Being a scientist working with large chunks of data, I find NaNs useful in a number of situations. I work in a domain (observational cosmology) where we need to deal with sky maps containing ~10^7 pixels (you can think of a "map" as a 1D vector where pixels on the sky sphere are ordered according to some rule). Not every sky direction can be sampled, because of a number of problems (in the instrument, in the observational strategy, in the data reduction pipeline, etc.)
>
>
>
> Therefore, in my Python+NumPy codes I always mark such directions using "quiet NaNs". If I have to combine two maps in order e.g. to take their average, the usual rules for combining NaNs are be exactly what I want. Writing in Ada what I actually write in Python:
>
> for I := 1 to N do
> Average_Map(I) := 0.5 * (Map1(I) + Map2(I));
> end loop;

Well, that's actually half Pascal and half Ada, but we understand what you mean.

But you don't need NaN's built into the language in order to get that sort of functionality. In Ada (or C++ or any other language that supports operator overloading), it's simple enough to define an "optional floating-point" record type consisting of a float and a Boolean, where the Boolean indicates "missing data", and define operators that produce "missing data" if either operand is missing. So you could still write mostly the same code, except that converting to or from a float, or from a floating-point literal, takes a little extra code.

-- Adam

Randy Brukardt

unread,
May 27, 2014, 6:35:48 PM5/27/14
to
"Adam Beneschan" <adambe...@gmail.com> wrote in message
news:840855a9-bda8-44b7...@googlegroups.com...
If one has
function "+" (Right : Float) return Optional_Float;

then the "extra code" is just preceeding the float value with a "+". Hardly
earth-shaking. (And the usual complaint about using "+" as a conversion
operator is a non-problem here as these are numeric types).

I much prefer this sort of solution (where the missing values are explicitly
treated) rather than using some sort of magic number (a NaN being an extreme
version of that). The name alone tells you that it doesn't belong in a
numeric type -- since when is something that is "not a number" belong in a
type defining numbers?

As usual, this is mainly a case of premature optimization (preverting the
hardware to handle something that's a rare need -- I wonder how much faster
float hardware could be if it didn't have to mess with NaNs? I know that
they impacted our software floating point quite a bit even though I made no
attempt to actually do anything useful with them.)

Randy.


Jeffrey Carter

unread,
May 27, 2014, 6:59:07 PM5/27/14
to
On 05/27/2014 03:35 PM, Randy Brukardt wrote:
>
> I much prefer this sort of solution (where the missing values are explicitly
> treated) rather than using some sort of magic number (a NaN being an extreme
> version of that). The name alone tells you that it doesn't belong in a
> numeric type -- since when is something that is "not a number" belong in a
> type defining numbers?

It's a clear violation of the software-engineering principle that a value has
only a single meaning. (Of course, returning zero from Ada.Strings.Fixed.Index
is the same error.)

--
Jeff Carter
"There's no messiah here. There's a mess all right, but no messiah."
Monty Python's Life of Brian
84

Dmitry A. Kazakov

unread,
May 28, 2014, 3:32:47 AM5/28/14
to
On Tue, 27 May 2014 17:35:48 -0500, Randy Brukardt wrote:

> As usual, this is mainly a case of premature optimization (preverting the
> hardware to handle something that's a rare need -- I wonder how much faster
> float hardware could be if it didn't have to mess with NaNs?

BTW, the poster mentioned it was in Python, which implies that performance
couldn't be any concern!

Maurizio Tomasi

unread,
May 28, 2014, 4:40:36 AM5/28/14
to
> But you don't need NaN's built into the language in order to get that sort of functionality. In Ada (or C++ or any other language that supports operator overloading), it's simple enough to define an "optional floating-point" record type consisting of a float and a Boolean, where the Boolean indicates "missing data", and define operators that produce "missing data" if either operand is missing. So you could still write mostly the same code, except that converting to or from a float, or from a floating-point literal, takes a little extra code.

Thanks a lot for your reply, I wrote my post with the hope of getting some good advice about the best way to do such things in Ada. Yours is indeed a smart idea!

Funny that I have used C++ and operator overloading for years, yet I have never realized that some sort of ad-hoc type (plus operator overloading) would be perfect here. Guess the reason is because I have used Python too much: to get a reasonable speed in such calculations, you are forced to use functions like numpy.add (http://docs.scipy.org/doc/numpy/reference/generated/numpy.add.html), which only accept basic numeric types.

Cheers,
Maurizio.

(BTW, to answer Dmitry, speed *is* a concern for my calculations, which often involve Fourier Transforms on the maps and heavy Monte Carlo simulations. But fortunately functions like numpy.add are not that slow, as they are written in C/Fortran.)
0 new messages