Using type prefixes with floating point constants

I

Ioannis Vranos

ISO/IEC 9899:1990/1995 says (from K&R2):

“A6.4

When a less precise floating value is converted to an equally or more
precise floating type, the value is unchanged.

==> When a more precise floating value is converted to a less precise floating type, and the value is within
representable range, the result may be either the next higher or the next lower representable value.

If the result is out of range, the behavior is undefined”.


Question: Does the above mean that it is a good practice or *always*
needed to use the appropriate type suffixes with floating point constants?


An example of this:


#include <stdio.h>


int main(void)
{
float f1 = 0.33439F;

float f2= 0.33439f;

printf("\nf1= %f, f2= %f\n", f1, f2);


double d1= 0.33439;

double d2= 0.33439;

printf("\nd1= %f, d2= %f\n", d1, d2);


/* It doesn't work with MINGW, compiler is broken regarding long double. */
long double ld1= 0.33439L;

long double ld2= 0.33439l; /* 'l' is the lower case 'L'. */

printf("\nld1= %Lf, ld2= %Lf\n\n", ld1, ld2);


return 0;
}
 
B

Barry Schwarz

ISO/IEC 9899:1990/1995 says (from K&R2):

“A6.4

When a less precise floating value is converted to an equally or more
precise floating type, the value is unchanged.

==> When a more precise floating value is converted to a less precise floating type, and the value is within
representable range, the result may be either the next higher or the next lower representable value.

If the result is out of range, the behavior is undefined”.


Question: Does the above mean that it is a good practice or *always*
needed to use the appropriate type suffixes with floating point constants?


An example of this:


#include <stdio.h>


int main(void)
{
float f1 = 0.33439F;

If 0.33439 can be represented exactly in a float, it can also be
represented exactly in a double. In that case, the above code has the
same effect whether the F is present or not.

If 0.33439 cannot be represented exactly in a float, the constant on
the right hand side will be the appropriate float approximation (the
next higher or the next lower representable value). If the F were not
present, the constant on the right hand side would be the appropriate
double approximation (or possibly the exact representation) and when
it is assigned to f1 it will be adjusted to the next higher or the
next lower representable value. I imagine it is possible that a
perverse compiler could choose the lower approximation when the F is
present and the higher approximation when the F is not present.

About the only real benefit for the F is that without it some
compilers (and probably some lint tools) will issue diagnostics
regarding the possible loss of significance.

On the other hand,
float f1 = 0.123456; /*with or without the F*/
float f2 = f1 +0.33439F;
will perform the arithmetic on floats but without the F on the
constant would perform the arithmetic on doubles. This could impact
performance. More importantly, at the edges of significance it could
result is slightly different results.

On the third hand, almost all floating point values are approximations
and should be treated as such.
 
I

Ioannis Vranos

Barry said:
If 0.33439 can be represented exactly in a float, it can also be
represented exactly in a double. In that case, the above code has the
same effect whether the F is present or not.

If 0.33439 cannot be represented exactly in a float, the constant on
the right hand side will be the appropriate float approximation (the
next higher or the next lower representable value). If the F were not
present, the constant on the right hand side would be the appropriate
double approximation (or possibly the exact representation) and when
it is assigned to f1 it will be adjusted to the next higher or the
next lower representable value. I imagine it is possible that a
perverse compiler could choose the lower approximation when the F is
present and the higher approximation when the F is not present.

About the only real benefit for the F is that without it some
compilers (and probably some lint tools) will issue diagnostics
regarding the possible loss of significance.

On the other hand,
float f1 = 0.123456; /*with or without the F*/
float f2 = f1 +0.33439F;
will perform the arithmetic on floats but without the F on the
constant would perform the arithmetic on doubles. This could impact
performance. More importantly, at the edges of significance it could
result is slightly different results.

On the third hand, almost all floating point values are approximations
and should be treated as such.



Thank you for your answer, the discussion is continued in thread:

"Corrected: Using type suffixes with floating point constants"

where I will forward your answer.
 
D

Dik T. Winter

> If 0.33439 cannot be represented exactly in a float, the constant on
> the right hand side will be the appropriate float approximation (the
> next higher or the next lower representable value). If the F were not
> present, the constant on the right hand side would be the appropriate
> double approximation (or possibly the exact representation) and when
> it is assigned to f1 it will be adjusted to the next higher or the
> next lower representable value. I imagine it is possible that a
> perverse compiler could choose the lower approximation when the F is
> present and the higher approximation when the F is not present.

A compiler need not be perverse if this happens. It can occur with standard
IEEE arithmetic. In the first case there is only one rounding involved:
round to float, in the second case there are two roundings involved, first
to double and next to float. It is well known that the two do not necessarily
give the same result.
 
K

Keith Thompson

Ioannis Vranos said:
Thank you for your answer, the discussion is continued in thread:

"Corrected: Using type suffixes with floating point constants"

where I will forward your answer.

It would have been good to indicate just what you were correcting.
Apparently you just changed "prefixes" to "suffixes" in the subject
header, but I didn't take the time to compare the two articles to see
if anything eles changed.

Since killing a thread is extremely difficult, starting a new thread
on the same topic is rarely a good idea. In this case, it would have
been better to post a correction on the original thread and live with
the incorrect subject line.
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top