Jerry
Ahem, I meant X'Valid for X of type Float
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
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
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
> 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
> 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
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.
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
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
> 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
> > 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
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
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.
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"
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
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
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
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
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
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
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
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.
Sorry about the cold, but if you omit the rep. clause, all of these
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
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
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
>
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
"isnan.asm" from
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=
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).
> 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...
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# ;
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).
>> 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.