Arithmetic properties of HUGE_VAL and errno

P

pete

On my system, the following five expressions are true:

(HUGE_VAL == HUGE_VAL / 2)
(1 / HUGE_VAL == 0)
(sqrt(HUGE_VAL) == HUGE_VAL)
(sqrt(-1) == HUGE_VAL)
(sqrt(-HUGE_VAL) == HUGE_VAL)

and

sqrt(HUGE_VAL) doesn't set errno, but sqrt(-1) and sqrt(-HUGE_VAL) do.

Does that all seem right?
 
R

robertwessel2

pete said:
On my system, the following five expressions are true:

(HUGE_VAL == HUGE_VAL / 2)
(1 / HUGE_VAL == 0)
(sqrt(HUGE_VAL) == HUGE_VAL)
(sqrt(-1) == HUGE_VAL)
(sqrt(-HUGE_VAL) == HUGE_VAL)

and

sqrt(HUGE_VAL) doesn't set errno, but sqrt(-1) and sqrt(-HUGE_VAL) do.

Does that all seem right?


Your implementation apparently defines HUGE_VAL as a positive infinity,
which is legitimate. All the rest flows pretty obviously from there.
 
M

Martin Ambuhl

pete said:
On my system, the following five expressions are true:

(HUGE_VAL == HUGE_VAL / 2)
(1 / HUGE_VAL == 0)
(sqrt(HUGE_VAL) == HUGE_VAL)
(sqrt(-1) == HUGE_VAL)
(sqrt(-HUGE_VAL) == HUGE_VAL)

and

sqrt(HUGE_VAL) doesn't set errno, but sqrt(-1) and sqrt(-HUGE_VAL) do.

Does that all seem right?

If HUGE_VAL and HUGE_VALF are INFINITY, as they are in my
implementation, that would explain much. Your question has led me to
discover that HUGE_VALL is broken on my implementation (it is an
unnormalized NaN).
 
E

Eric Sosman

Martin said:
If HUGE_VAL and HUGE_VALF are INFINITY, as they are in my
implementation, that would explain much. Your question has led me to
discover that HUGE_VALL is broken on my implementation (it is an
unnormalized NaN).

An "unnormalized" NaN? I'm having trouble with
the concept; can you explain in more detail?
 
P

pete

Your implementation apparently
defines HUGE_VAL as a positive infinity,
which is legitimate. All the rest flows pretty obviously from there.

Thank you. I have more questions.
What other options are there besides positive infinity?
Could sqrt(HUGE_VAL) be undefined?
Is it allowed for sqrt(HUGE_VAL) to set errno to errange
if it returns HUGE_VAL?
Are any of the above 5 expressions
guaranteed to be true by the standard,
or is it merely the case that they are allowed to be true?

Suppose I want to write a 100% portable function for C89 and C99
that does exactly what log2 does. Could it be written this way?:

double l_og2(double x)
{
return log(x) / log(2);
}

The point being, Can I really on any funky values like HUGE_VAL,
which might be returned by log(x),
to not be altered by being divided by log(2)?
Or would this be more portable?:

double l_og2(double x)
{
return x > 0 && DBL_MAX >= x ? log(x) / log(2) : log(x);
}


It seems that most settings of errno to ERANGE are optional,
but for exp, it says that you do get them when the magnitude of x
is too large, not x, but the magnitude of x.
Is setting errno to ERANGE optional or mandatory for exp(-DBL_MAX)?
I think it would be a case of underflow.
On a system like mine, where HUGE_VAL is an infinity,
Is setting errno to ERANGE optional or mandatory for exp(-HUGE_VAL)?
 
K

kuyper

pete said:
Thank you. I have more questions.
What other options are there besides positive infinity?

HUGE_VAL is required to expand into a positive double constant
expression (7.12p3). However, the C standard places no other
requirements on it, unless __STDC_IEC_559__ is #defined by the
implementation, in which case it's required to expand into an
expression with a value of positive infinity (F.9p2). As far as I can
see, if __STDC_IEC_559__ is not #defined, then it would be perfectly
legal to #define HUGE_VAL as DBL_MIN.
Could sqrt(HUGE_VAL) be undefined?

HUGE_VAL must be positive, and there's no positive number for which
sqrt() is undefined.
Is it allowed for sqrt(HUGE_VAL) to set errno to errange
if it returns HUGE_VAL?

According to 7.5p3, "The value of errno may be set to nonzero by a
library function call whether or not there is an error, provided the
use of errno is not documented in the description of the function in
this International Standard."

I could find no mention of errno in 7.12.7.5, which describes sqrt(),
so errno can be set to anything it wants. I'm not sure if that's the
intent; other parts of 7.12 describe the setting of errno in contexts
that apply to sqrt() - but that's not "in the description of the
function".

In particular, errno must be set to ERANGE if sqrt(HUGE_VAL) overflows
and math_errhandling & MATH_ERRNO is true. sqrt(HUGE_VAL) will
overflow, if and only HUGE_VAL is positive infinity.
Are any of the above 5 expressions
guaranteed to be true by the standard,
or is it merely the case that they are allowed to be true?

None of them are required by the standard unless __STDC_IEC_559__ is
#defined, in which case they are required in order to conform with IEC
559.
Suppose I want to write a 100% portable function for C89 and C99
that does exactly what log2 does. Could it be written this way?:

double l_og2(double x)
{
return log(x) / log(2);
}

The point being, Can I really on any funky values like HUGE_VAL,
which might be returned by log(x),
to not be altered by being divided by log(2)?
No.

Or would this be more portable?:

double l_og2(double x)
{
return x > 0 && DBL_MAX >= x ? log(x) / log(2) : log(x);
}

That looks good to me; but I might have missed some tricky detail.
It seems that most settings of errno to ERANGE are optional,

As, for instance, whenever 7.12p3 applies.
but for exp, it says that you do get them when the magnitude of x
is too large, not x, but the magnitude of x.
Is setting errno to ERANGE optional or mandatory for exp(-DBL_MAX)?
I think it would be a case of underflow.
On a system like mine, where HUGE_VAL is an infinity,
Is setting errno to ERANGE optional or mandatory for exp(-HUGE_VAL)?

If math_errhandling & MATH_ERRNO is true, then setting ERANGE is
mandatory for overflows and for cases where the exact value of a
function is infinite (7.12.1p4).
 
F

Fred J. Tydeman

pete said:
On my system, the following five expressions are true:

(HUGE_VAL == HUGE_VAL / 2)
(1 / HUGE_VAL == 0)
(sqrt(HUGE_VAL) == HUGE_VAL)

Those are true if HUGE_VAL is +infinity (which it will be if IEEE-754
floating-point is being used).
(sqrt(-1) == HUGE_VAL)
(sqrt(-HUGE_VAL) == HUGE_VAL)

Those should be false. sqrt(negative) should be a NaN (Not-a-Number)
if IEEE-754 style floating-point is supported. And a NaN does not
compare equal to anything. In the general case, a domain error can
return any value, so +infinity is allowed.
and

sqrt(HUGE_VAL) doesn't set errno, but sqrt(-1) and sqrt(-HUGE_VAL) do.

Those are correct.
---
Fred J. Tydeman Tydeman Consulting
(e-mail address removed) Testing, numerics, programming
+1 (775) 358-9748 Vice-chair of J11 (ANSI "C")
Sample C99+FPCE tests: http://www.tybor.com
Savers sleep well, investors eat well, spenders work forever.
 
P

pete

pete wrote:
As far as I can
see, if __STDC_IEC_559__ is not #defined, then it would be perfectly
legal to #define HUGE_VAL as DBL_MIN.

Thank you.
Hmm...


I'm also attempting e_xp, to do what exp does,
under the same rules as l_og2, for academic purposes.
I've replaced some alogorithms with library function calls
to simplify the appearence of the code.
My exp algorithm only works on nonnegative input.

I had written it this way:

double e_xp(double x)
{
unsigned negative;
double e;

if (0 > x) {
x = -x;
negative = 1;
} else {
negative = 0;
}
if (log(DBL_MAX) >= x) {
exp(x);
} else {
errno = ERANGE;
e = HUGE_VAL;
}
return negative ? 1 / e : e;
}

But if HUGE_VAL can be small,
then I think this way might be more better:

double e_xp(double x)
{
unsigned negative;
double e;

if (0 > x) {
x = -x;
negative = 1;
} else {
negative = 0;
}
if (log(DBL_MAX) >= x) {
exp(x);
if (negative) {
e = 1 / e;
}
} else {
errno = ERANGE;
e = negative ? 0.0 : HUGE_VAL;
}
return e;
}

Because I wouldn't want e_xp to return a large positive number
for large negative x.

Followup set to c.l.c
 
P

pete

Fred said:
Those are true if HUGE_VAL is +infinity (which it will be if IEEE-754
floating-point is being used).


Those should be false. sqrt(negative) should be a NaN (Not-a-Number)
if IEEE-754 style floating-point is supported. And a NaN does not
compare equal to anything. In the general case, a domain error can
return any value, so +infinity is allowed.


Those are correct.

Thank you.

For academic purposes,
I was hoping to be able to write a source code for a function sq_rt,
that would do exactly sqrt was supposed to do,
and have it be portable for C89 and C99.
Some standard functions like are easy to write like that,
like isdigit:

int is_digit(int c)
{
return c >= '0' && '9' >= c;
}

But, the math functions seem more complicated to write
portably because of the various macros in C99 which may
or may not be defined.

This is what I have so far:

double sq_rt(double x)
{
if (DBL_MAX >= x) {
if (x > 0) {
x = sqrt(x);
/*
** I've replaced my sqrt algortihm with the call to sqrt
** to simplify the appearence of the code
*/
} else {
if (0 > x) {
errno = EDOM;

#ifdef __STDC_IEC_559__
x = NAN;
#else
x = HUGE_VAL;
#endif

}
}
} else {
errno = ERANGE;
}
return x;
}

Does that seem about right?
Is this complicated enough enough
that I should try to acquire the standard for IEEE-754
if I want to do it right?


Followup set to c.l.c
 
A

Anonymous 7843

An "unnormalized" NaN? I'm having trouble with
the concept; can you explain in more detail?

I'm curious also.

If my memory of IEEE-854 isn't too hazy, I think the NaN-ness
of a number is expresed by a special value of the exponent.

Martin may be referring to a situation where a HUGE_VALL
is not a NaN (NaNaN? Oy...) but is expressed with a mantissa >1.0
and an exponent such that upon normalization the exponent would
seemingly be incremented to the special exponent that NaN's have.
(Or possibly mantissa < 0.5 and exponent decremented to it).

But perhaps I am talking out of my hat.
 
D

Dik T. Winter


It makes no sense. A NaN is signalled by a specific exponent pattern.
The bits in the mantissa can be used for any purpose except the most
leading bit. If it is 0 the NaN is a signalling NaN, if it is 1 it is
a non-signalling NaN. (And if all bits are 0, it is an infinity.)
> Martin may be referring to a situation where a HUGE_VALL
> is not a NaN (NaNaN? Oy...) but is expressed with a mantissa >1.0
> and an exponent such that upon normalization the exponent would
> seemingly be incremented to the special exponent that NaN's have.
> (Or possibly mantissa < 0.5 and exponent decremented to it).

Impossible. The only numbers in IEEE format that are not normalised
are the denormals, and they are, eh, small. Forcing normalisation on
them forces them to 0.0.
 
A

Anonymous 7843

It makes no sense. A NaN is signalled by a specific exponent pattern.
The bits in the mantissa can be used for any purpose except the most
leading bit. If it is 0 the NaN is a signalling NaN, if it is 1 it is
a non-signalling NaN. (And if all bits are 0, it is an infinity.)


Impossible. The only numbers in IEEE format that are not normalised
are the denormals, and they are, eh, small. Forcing normalisation on
them forces them to 0.0.


I interpreted his comment to mean that the text of the macro was
unnormalized. For example (let's use decimal floats so I don't have to
think too hard) something like 999999E+95. In the process of being
placed into floating point representation, the exponent "rolls over"
(in odometer terms) to the same exponent that represents NaN,
something like 1.0E+101. Impossible when things are not broken,
but Martin removed that restriction.

The final decision about what Martin Ambuhl meant of course
rests with Martin Ambuhl. I am just fitting my aged brain cells
to what he said as best I can.

Perhaps we need to "normalize" Martin...
 
S

ScottD

Anonymous 7843 said:
I interpreted his comment to mean that the text of the macro was
unnormalized. For example (let's use decimal floats so I don't have to
think too hard) something like 999999E+95. In the process of being
placed into floating point representation, the exponent "rolls over"
(in odometer terms) to the same exponent that represents NaN,
something like 1.0E+101. Impossible when things are not broken,
but Martin removed that restriction.

The final decision about what Martin Ambuhl meant of course
rests with Martin Ambuhl. I am just fitting my aged brain cells
to what he said as best I can.

Perhaps we need to "normalize" Martin...

Intel has used the term 'unnormal' to describe binary floating
point number representations, although not as NaNs.

Intel describes unnormals here, for example:
ftp://download.intel.com/design/pentium/manuals/241430.htm
 
F

Fred J. Tydeman

Dik T. Winter said:
Impossible. The only numbers in IEEE format that are not normalised
are the denormals, and they are, eh, small. Forcing normalisation on
them forces them to 0.0.

The 80-bit format (double extended) on the Intel x87's has many
unusual formats, including psuedo-NaN, pseudo-infinity, and
unnormals. All are treated as signaling NaN.
---
Fred J. Tydeman Tydeman Consulting
(e-mail address removed) Testing, numerics, programming
+1 (775) 358-9748 Vice-chair of J11 (ANSI "C")
Sample C99+FPCE tests: http://www.tybor.com
Savers sleep well, investors eat well, spenders work forever.
 
C

Christian Bau

"Dik T. Winter" <[email protected]> said:
Impossible. The only numbers in IEEE format that are not normalised
are the denormals, and they are, eh, small. Forcing normalisation on
them forces them to 0.0.

In 80 bit format, there are "unnormalized" numbers. The leading bit of
the mantissa is supposed to be set except for denormalized numbers. Take
the number 1.5 in 80 bit IEEE format, for example. There are two bits
supposed to be set in the mantissa, one for 1.0 and one for 0.5. If you
clear the bit for 1.0 in the representation, you get an "unnormalized"
number. I am not at all sure how the IEEE floating point standard says
such values should be treated.
 
D

Dik T. Winter

> Intel has used the term 'unnormal' to describe binary floating
> point number representations, although not as NaNs.

What Intel calls "unnormals" is normally called "denormals".
 
T

Tim Prince

Dik said:
What Intel calls "unnormals" is normally called "denormals".
Quote from Google search:

IEEE Arithmetic
(Subnormal numbers were called denormalized numbers in IEEE Standard
754. ...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,434
Messages
2,571,691
Members
48,796
Latest member
Greg L.

Latest Threads

Top