1.0f vs. 1.0

V

vectorizor

Hello,

I am writing a significant amount of floating-point computational
routines as template, so float or double values can be used depending
on the accuracy needed. There are many numerical constants defined in
these routines, and they keep generating a warning in VC++ 8.0:

"warning C4244: '=' : conversion from 'double' to 'float', possible
loss of data"

This warning is obviously generated when the template is compiled with
type=float. I could get around by appending a f at the end of the
constants, i.e. "1.0f" vs "1.0", but that would lose precision when
doing computation in double. So I am looking for a workaround.

I understand that macro are not well loved around here, but is there a
way to define a macro in order to get rid of this problem?

Thanks in advance,

Alex
 
V

Victor Bazarov

vectorizor said:
I am writing a significant amount of floating-point computational
routines as template, so float or double values can be used depending
on the accuracy needed. There are many numerical constants defined in
these routines, and they keep generating a warning in VC++ 8.0:

"warning C4244: '=' : conversion from 'double' to 'float', possible
loss of data"

This warning is obviously generated when the template is compiled with
type=float. I could get around by appending a f at the end of the
constants, i.e. "1.0f" vs "1.0", but that would lose precision when
doing computation in double. So I am looking for a workaround.

I understand that macro are not well loved around here, but is there a
way to define a macro in order to get rid of this problem?

It's better to define a special contant template and specialise it for
both double and float. Something like:

template<class F> struct Constants {
static F One;
static F Pi;
static F e;
static F tenbillion;
};

template<> static Constants<float>::One = 1.0f;
template<> static Constants<double>::One = 1.0;
template<> static Constants<float>::pi = 3.141593f;
template<> static Constants<double>::pi = 3.14159265358979323846;
...

V
 
V

vectorizor

THanks for the answer, but I can't because I have entire LUTs of
constants.

Alexis
 
L

Lionel B

Hello,

I am writing a significant amount of floating-point computational
routines as template, so float or double values can be used depending on
the accuracy needed. There are many numerical constants defined in these
routines, and they keep generating a warning in VC++ 8.0:

"warning C4244: '=' : conversion from 'double' to 'float', possible loss
of data"

This warning is obviously generated when the template is compiled with
type=float. I could get around by appending a f at the end of the
constants, i.e. "1.0f" vs "1.0", but that would lose precision when
doing computation in double. So I am looking for a workaround.

If T is your floating point type template parameter I guess you could
write code like:

T x = T(1);
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hello,

I am writing a significant amount of floating-point computational
routines as template, so float or double values can be used depending
on the accuracy needed. There are many numerical constants defined in
these routines, and they keep generating a warning in VC++ 8.0:

"warning C4244: '=' : conversion from 'double' to 'float', possible
loss of data"

This warning is obviously generated when the template is compiled with
type=float. I could get around by appending a f at the end of the
constants, i.e. "1.0f" vs "1.0", but that would lose precision when
doing computation in double. So I am looking for a workaround.

It depends a bit on the constants but if all of them can be expressed
with sufficient accuracy as a float then you'll never have any loss of
precision since they'll be "up-casted" to double in if type=double. i.e.:

template<typename T>
T foo(T input) {
return input * 1.2345f;
}

Here the constant will be converted to a float before the
multiplication. Of course I have not spent a whole lot of time thinking
about this so there might be some special case where this will not apply.

If your constants can't be represented as a float you are kind of
screwed anyway but a way that will not lose the precision when working
with double (as the above would) is to use static_cast:

template<typename T>
T foo(T input) {
return input * static_cast<T>(1.234567890);
}

A third option, which might be feasible depending on the reasons you
want to be able to switch between float and double, is to perform all
calculations internally as double and cast the results to float (and
read floats as input).
 
W

Walter Bright

Victor said:
It's better to define a special contant template and specialise it for
both double and float. Something like:

template<class F> struct Constants {
static F One;
static F Pi;
static F e;
static F tenbillion;
};

template<> static Constants<float>::One = 1.0f;
template<> static Constants<double>::One = 1.0;
template<> static Constants<float>::pi = 3.141593f;
template<> static Constants<double>::pi = 3.14159265358979323846;
...

The right solution is to turn off warning C4244, as it is
counterproductive. Any warning that induces you to write all kinds of
bloated verbose workarounds is bad news.

A warning that says you lose precision by converting 1.0 to 1.0f is a
bug in the compiler, as no precision is lost.

The losing precision warning is problematical anyway, as floating point
literals are often not even representable exactly in *any* precision. An
example is 0.3. Pi, of course, is another.
 
J

James Kanze

It depends a bit on the constants but if all of them can be expressed
with sufficient accuracy as a float then you'll never have any loss of
precision since they'll be "up-casted" to double in if type=double. i.e..:
template<typename T>
T foo(T input) {
return input * 1.2345f;
}

What does "sufficient accuracy" mean in this case?

double
foo( double input )
{
return 1.2345f * input ;
}

and

double
foo( double input )
{
return 1.2345 * input ;
}

will normally return different values. If you really intended
to multiply by the real number 1.2345, the second will be closer
to the intent (more accurate, if you prefer); on most machines,
you can't even represent the real number 1.2345, much less
multiply by it.
Here the constant will be converted to a float before the
multiplication. Of course I have not spent a whole lot of time thinking
about this so there might be some special case where this will not apply.

Like any time the constant cannot be represented exactly as as
float. Like in the example above.
If your constants can't be represented as a float you are kind of
screwed anyway but a way that will not lose the precision when working
with double (as the above would) is to use static_cast:
template<typename T>
T foo(T input) {
return input * static_cast<T>(1.234567890);
}

A more accurate solution would be to do the cast after the
multiplication, i.e.:

return static_cast said:
A third option, which might be feasible depending on the reasons you
want to be able to switch between float and double, is to perform all
calculations internally as double and cast the results to float (and
read floats as input).

That's what the hardware does on many modern machines anyway.
(On an Intel, in fact, the floating point unit always works in
long double.) In practice, there's generally no reason to use
float except in objects which will be placed in large arrays.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

What does "sufficient accuracy" mean in this case?

double
foo( double input )
{
return 1.2345f * input ;
}

and

double
foo( double input )
{
return 1.2345 * input ;
}

will normally return different values. If you really intended
to multiply by the real number 1.2345, the second will be closer
to the intent (more accurate, if you prefer); on most machines,
you can't even represent the real number 1.2345, much less
multiply by it.

Sufficiently in this case would mean that either the constant can be
accurately represented or that the closest representation is
sufficiently accurate for the calculations.
 

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
473,774
Messages
2,569,598
Members
45,151
Latest member
JaclynMarl
Top