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

Preferred Style Question

85 views
Skip to first unread message

Mike Copeland

unread,
Sep 25, 2012, 12:39:22 PM9/25/12
to
What are some accepted ways to do the following calculation - and
avoid the compiler warnings that expose conversion data loss? (I'm
trying to compute the total time in seconds that a person has to
complete an event, based on a stated pace.) TIA

double dDistance = 6.214;
time_t tPace = 600;
time_t tEstTime;

tEstTime = tPace * dDistance;

Paavo Helde

unread,
Sep 25, 2012, 1:17:11 PM9/25/12
to
mrc...@cox.net (Mike Copeland) wrote in news:MPG.2acb8c25ec554b6e989719
@news.eternal-september.org:
This is an example of meaningless or misleading use of Hungarian notation
(depending on what exactly the 'd' and 't' prefixes are supposed to
mean). If they mean 'double' and 'time_t', then they are meaningless as
the C++ compiler and the IDE hovering tooltips know this anyway. If they
mean 'distance' and 'time', they are misleading - how comes that when I
multiply time by distance, I get again time?

A potentially more useful Hungarian notation would be to encode physical
units in names. It is more natural to put them in suffixes than in
prefixes:

double distance_m = 6.214; // distance in meters
time_t pace_s_m = 600; // pace, in seconds per meter
time_t estTime_s = distance_m * pace_s_m; // estimated time in seconds

Now you immediately see that the datatype for Pace is wrong - why it
should be time_t if it is not in seconds? It should be double as well.

OTOH, in this kind of code one can see immediately that the units are
used correctly. Whenever you see something like esTime_s = distance_m *
pace_hour_km you know there is a bug.

The conversion warning comes because you want to squeeze the floating-
point result into an integer, losing precision. If there are no other
prevailing reasons, I would say that precision loss should be avoided. As
we have now got rid of meaningless type prefixes, it is easy to change
the datatype:

double distance_m = 6.214; // distance in meters
double pace_s_m = 600; // pace, in seconds per meter
double estTime_s = distance_m * pace_s_m; // estimated time in seconds

hth
Paavo

Mike Copeland

unread,
Sep 25, 2012, 3:06:19 PM9/25/12
to
In article <XnsA0D9CE5D36A8Em...@216.196.109.131>,
myfir...@osa.pri.ee says...
> > What are some accepted ways to do the following calculation - and
> > avoid the compiler warnings that expose conversion data loss? (I'm
> > trying to compute the total time in seconds that a person has to
> > complete an event, based on a stated pace.) TIA
> >
> > double dDistance = 6.214;
> > time_t tPace = 600;
> > time_t tEstTime;
> >
> > tEstTime = tPace * dDistance;
>
> Now you immediately see that the datatype for Pace is wrong - why it
> should be time_t if it is not in seconds? It should be double as well.

No, it's a computed "seconds mile", derived from a prompted value
that's in "minutes per mile". That is, the user is asked for "pace",
and the user responds in minutes. After that, the "seconds" value is
calculated and used for numerous calculations and displays.
>
> OTOH, in this kind of code one can see immediately that the units are
> used correctly. Whenever you see something like esTime_s = distance_m *
> pace_hour_km you know there is a bug.

That may be, but I must determine a value that is compared to a
presented scalar value that's in "seconds". The purpose of this derived
value is to place the user's estimate into one of 30 "slots" to
establish groupings. I want the processing to be precise (and not use
f/p comparisons), and I used to use "int". Now I'm trying to use a more
appropriate "time_t" for all "seconds-based" calculations and displays.
>
> The conversion warning comes because you want to squeeze the floating-
> point result into an integer, losing precision. If there are no other
> prevailing reasons, I would say that precision loss should be avoided. As
> we have now got rid of meaningless type prefixes, it is easy to change
> the datatype:
>
> double distance_m = 6.214; // distance in meters
> double pace_s_m = 600; // pace, in seconds per meter
> double estTime_s = distance_m * pace_s_m; // estimated time in seconds

Since I have to work in seconds throughout my processing, use of
"double" isn't going to help here. I really want to produce "time_t"
values and work from them.

Rui Maciel

unread,
Sep 25, 2012, 4:42:30 PM9/25/12
to
As the type of dDistance is double and the typeof tPace is time_t, the
expression "tPace * dDistance" is evaluated to an object of type double.
Then, the result of that expression is assigned to tEstTime, which is
another object of type time_t.

The thing with time_t is that it is an unsigned integer type. If the
expression "tPace*dDistance" returns a negative value then maybe all sorts
of hell will breaks loose, as this behavior is left undefind in the
standard.

If, instead, the "tPace*dDistance" expression is evaluated to a positive
number then the assignment will truncate the resulting value towards zero.
There's not much that can be done about it, other than making sure that,
instead of truncating it, we make sure the value is rounded. There are some
simple[¹] and convoluted[2] suggestions floating around, but, at least since
C99, it's possible to avoid all that with a simple call to
nearbyint(tPace*dDistance).

Another detail which is rarely mentioned is the possibility of a floating
point operation having been raised, which includes the possibility of
dDistance ending up storing an invalid value, such as NaN or divide-by-zero.
Checking the floating point exception flags can save some headaches.

So, data will be lost either way. You just need to make sure that dDistance
stores a valid positive value and then assign it to tEstTime. If you can
ensure that then it's safe to assume that the only conversion loss that can
happen is the loss of the fractional part of your floating point value.
Having done that then you will probably get rid of those warnings about
conversion loss once you cast the result back to time_t. And that's about
it.


Hope this helps,
Rui Maciel


[¹] http://c-faq.com/fp/round.html
[2] http://www.cs.tut.fi/~jkorpela/round.html

Paavo Helde

unread,
Sep 25, 2012, 5:06:10 PM9/25/12
to
mrc...@cox.net (Mike Copeland) wrote in
news:MPG.2acbae91e...@news.eternal-september.org:

> I want the processing to be precise (and not
> use f/p comparisons), and I used to use "int".

What you mean by "precise"? Double typetype is quite precise (ca 10^-16).
If a floating-point algorithm using double does not yield the same
results to at least 10 decimal places on all platforms, then the
algorithm is arguably broken.

If you fear floating-point equality comparisons, then just don't use
them.

> Now I'm trying to use
> a more appropriate "time_t" for all "seconds-based" calculations and
> displays.

But pace is not measured in seconds; it is measured in seconds per mile.
Why do you think time_t is more appropriate than int? For me time_t is
more confusing as the thing is not measured in seconds.

Anyway, you cannot have "precise" computations if your distance is a
double. To have it "precise", you will have to quantice the distance as
well in some suitable units and store as an integer. Beware that discrete
(integral) mathematics can sometimes be much more tricky than floating-
point.

> Since I have to work in seconds throughout my processing, use of
> "double" isn't going to help here.

Why not? A floating-point type can measure seconds with no problem. The
decision whether to use an integer or a floating-point datatype should be
dictated by the functional requirements, not by some (questionable) style
guidelines. So far the only justification for using an integral type was
'I used to use "int"'.

BTW, are you aware that time_t is just a typedef, and you can easily
define another, e.g.

typedef double ftime_t;

> I really want to produce "time_t"
> values and work from them.

It might be that I have misunderstood your problem. If you already have
decided all variables in your program must be time_t, where is the
problem?

Cheers
Paavo

Luca Risolia

unread,
Sep 25, 2012, 8:42:56 PM9/25/12
to
#include <chrono>
#include <ratio>
#include <iostream>

typedef long double meters;
meters operator"" _m(const long double x) { return x; }
meters operator"" _km(const long double x) { return x * 1000; }

std::chrono::seconds operator"" _s_per_m(unsigned long long x) {
return std::chrono::seconds(x);
}

template<typename V, typename R>
std::ostream& operator << (std::ostream& o,
const std::chrono::duration<V, R>& d) {
return o << d.count() << " ticks of "
<< R::num << '/' << R::den << " seconds";
}

int main() {
auto distance = 6.214_m;
auto pace = 600_s_per_m;
auto estTime = pace * distance;
std::cout << estTime << '\n';
// 3728.4 ticks of 1/1 seconds (= 3728,4 seconds)
}

Nick Keighley

unread,
Sep 26, 2012, 5:18:48 AM9/26/12
to
On Sep 25, 8:06 pm, mrc2...@cox.net (Mike Copeland) wrote:
> In article <XnsA0D9CE5D36A8Emyfirstnameosapr...@216.196.109.131>,
> myfirstn...@osa.pri.ee says...


> > >    What are some accepted ways to do the following calculation - and
> > > avoid the compiler warnings that expose conversion data loss?  (I'm
> > > trying to compute the total time in seconds that a person has to
> > > complete an event, based on a stated pace.)  TIA
>
> > >   double dDistance = 6.214;
> > >   time_t tPace     = 600;
> > >   time_t tEstTime;
>
> > >   tEstTime = tPace * dDistance;
>
> > Now you immediately see that the datatype for Pace is wrong - why it
> > should be time_t if it is not in seconds? It should be double as well.
>
>    No, it's a computed "seconds mile", derived from a prompted value
> that's in "minutes per mile".  That is, the user is asked for "pace",
> and the user responds in minutes.  After that, the "seconds" value is
> calculated and used for numerous calculations and displays.
>
> > OTOH, in this kind of code one can see immediately that the units are
> > used correctly. Whenever you see something like esTime_s = distance_m *
> > pace_hour_km you know there is a bug.
>
>    That may be, but I must determine a value that is compared to a
> presented scalar value that's in "seconds".  The purpose of this derived
> value is to place the user's estimate into one of 30 "slots" to
> establish groupings.  I want the processing to be precise (and not use
> f/p comparisons),

this makes no sense. How does cramming the result into one of 30
integral bins make the result "precise"? There's a floating point
value in there so the result is going to be a floating point value.

> and I used to use "int".  Now I'm trying to use a more
> appropriate "time_t" for all "seconds-based" calculations and displays.
>
> > The conversion warning comes because you want to squeeze the floating-
> > point result into an integer, losing precision. If there are no other
> > prevailing reasons, I would say that precision loss should be avoided. As
> > we have now got rid of meaningless type prefixes, it is easy to change
> > the datatype:
>
> > double distance_m = 6.214; // distance in meters
> > double pace_s_m = 600; // pace, in seconds per meter
> > double estTime_s = distance_m * pace_s_m; // estimated time in seconds
>
>    Since I have to work in seconds throughout my processing, use of
> "double" isn't going to help here.  I really want to produce "time_t"
> values and work from them.

why?

Scott Lurndal

unread,
Sep 26, 2012, 10:05:28 AM9/26/12
to
Paavo Helde <myfir...@osa.pri.ee> writes:
>mrc...@cox.net (Mike Copeland) wrote in
>news:MPG.2acbae91e...@news.eternal-september.org:
>
>> I want the processing to be precise (and not
>> use f/p comparisons), and I used to use "int".
>
>What you mean by "precise"? Double typetype is quite precise (ca 10^-16).
>If a floating-point algorithm using double does not yield the same
>results to at least 10 decimal places on all platforms, then the
>algorithm is arguably broken.

Actually, one cannot represent 0.1 in binary floating point with exact
precision - the binary version is a non-terminating, infinite expansion;
rounded to 24 bits, it's 0.100000001490116119384765625 in decimal.

The new decimal floating point supported by the latest C standard
(and implemented in gcc) should provide more accurate and precise
calculations (albiet much more slowly).

IEEE compliant hardware will ensure that a binary floating result will
be accurate within 0.5 of the "unit in the last place".

Paavo Helde

unread,
Sep 26, 2012, 11:04:50 AM9/26/12
to
sc...@slp53.sl.home (Scott Lurndal) wrote in
news:IYD8s.183055$qL.1...@fed01.iad:
>
> The new decimal floating point supported by the latest C standard
> (and implemented in gcc) should provide more accurate and precise
> calculations (albiet much more slowly).

I am not familiar with this, but from the naming "decimal floating point" I
suspect this gives more accuracy only when dealing with inherently decimal
numbers (financy, etc).

>
> IEEE compliant hardware will ensure that a binary floating result will
> be accurate within 0.5 of the "unit in the last place".

This is for a single number. If you have a complex algorithm then the
errors start to accumulate. Depending on the quality of the algorithm the
accuracy of the final result may be significantly worse.

Cheers
Paavo

Nick Keighley

unread,
Sep 27, 2012, 5:56:54 AM9/27/12
to
On Sep 26, 3:05 pm, sc...@slp53.sl.home (Scott Lurndal) wrote:
> Paavo Helde <myfirstn...@osa.pri.ee> writes:
> >mrc2...@cox.net (Mike Copeland) wrote in
> >news:MPG.2acbae91e...@news.eternal-september.org:
>
> >> I want the processing to be precise (and not
> >> use f/p comparisons), and I used to use "int".
>
> >What you mean by "precise"? Double typetype is quite precise (ca 10^-16).
> >If a  floating-point algorithm using double does not yield the same
> >results to at least 10 decimal places on all platforms, then the
> >algorithm is arguably broken.
>
> Actually, one cannot represent 0.1 in binary floating point with exact
> precision - the binary version is a non-terminating, infinite expansion;
> rounded to 24 bits, it's 0.100000001490116119384765625 in decimal.

actually you *can* represent 0.1 to at least 10 decimal places, which
is what he said. Which sounds plenty to me. Do runners really time
themselves to the nearest millisecond?

Fred Zwarts (KVI)

unread,
Sep 27, 2012, 8:04:31 AM9/27/12
to
"Scott Lurndal" wrote in message news:IYD8s.183055$qL.1...@fed01.iad...
>
>Paavo Helde <myfir...@osa.pri.ee> writes:
>>mrc...@cox.net (Mike Copeland) wrote in
>>news:MPG.2acbae91e...@news.eternal-september.org:
>>
>>> I want the processing to be precise (and not
>>> use f/p comparisons), and I used to use "int".
>>
>>What you mean by "precise"? Double typetype is quite precise (ca 10^-16).
>>If a floating-point algorithm using double does not yield the same
>>results to at least 10 decimal places on all platforms, then the
>>algorithm is arguably broken.
>
>Actually, one cannot represent 0.1 in binary floating point with exact
>precision - the binary version is a non-terminating, infinite expansion;
>rounded to 24 bits, it's 0.100000001490116119384765625 in decimal.

Note that the approximation of 0.1 with an binary integer type is much less
accurate.

Scott Lurndal

unread,
Sep 27, 2012, 10:52:35 AM9/27/12
to
"Fred Zwarts \(KVI\)" <F.Zw...@KVI.nl> writes:
>"Scott Lurndal" wrote in message =
>news:IYD8s.183055$qL.1...@fed01.iad...
>>
>>Paavo Helde <myfir...@osa.pri.ee> writes:
>>>mrc...@cox.net (Mike Copeland) wrote in
>>>news:MPG.2acbae91e...@news.eternal-september.org:
>>>
>>>> I want the processing to be precise (and not
>>>> use f/p comparisons), and I used to use "int".
>>>
>>>What you mean by "precise"? Double typetype is quite precise (ca =
>10^-16).
>>>If a floating-point algorithm using double does not yield the same
>>>results to at least 10 decimal places on all platforms, then the
>>>algorithm is arguably broken.
>>
>>Actually, one cannot represent 0.1 in binary floating point with exact
>>precision - the binary version is a non-terminating, infinite =
>expansion;
>>rounded to 24 bits, it's 0.100000001490116119384765625 in decimal.
>
>Note that the approximation of 0.1 with an binary integer type is much =
>less=20
>accurate.=20
>


Not if you scale it by, say 100.

scott

Fred Zwarts (KVI)

unread,
Sep 27, 2012, 11:27:39 AM9/27/12
to
"Scott Lurndal" wrote in message news:TKZ8s.85461$HY4....@fed04.iad...
If you scale it, then also the floating point representation will be exact.

Fred Zwarts (KVI)

unread,
Sep 28, 2012, 4:30:30 AM9/28/12
to
"Mike Copeland" wrote in message
news:MPG.2acbae91e...@news.eternal-september.org...
>
> I want the processing to be precise (and not use >f/p comparisons),

I think that it is a misconception that floating point type are not precise.
They are as precise as integer types. One of the first computers I worked
with, had no integer arithmetic in hardware, only floating point arithmetic.
Integer arithmetic operation in high level languages were performed using
floating point operations.

Take as an example an integer type using N bits (including sign bit). Also
take a floating point type using N bits for the mantissa (including sign
bit). Then each value that can be represented by the integer type can also
be represented EXACTLY by the floating point type. Further, the arithmetic
integer operations (+, -, *, /) can be mapped to floating point operations
that yield EXACTLY the same represented value (as long as the result can
still be represented with N bits). (The most complex one is the integer
divide operation, which maps to a floating point divide followed by a
truncation.)
So, if the floating point type can map EXACTLY all the integer type values
and all integer arithmetic operations, it is simply not true that floating
point types are less precise than integer types.

Why then do we use integer and floating point types. Not because of
precision, but because of other features:

*) Integer types have other operations (like bit shifting, bit-wise logical)
that floating point types have not.

*) Floating point types yield rounded results when the result of an
operation exceeds the minimum or maximum that can be represented with N
bits, whereas an integer type will have an undefined result.

*) Floating point types have an automatic scale factor, to make it easier to
work with very big, or with very small numbers. (A problem is that this
scale factor is usually limited to powers of two.)

*) Many processors have hardware integer instructions that perform better
that the equivalent floating point instructions.

So, floating point types are as exact as integer types (given that there are
enough bits). The confusion arises because many people do not understand the
floating point representation and the corresponding floating point
operations very well. Some people think that floating point numbers can be
used to map real numbers (in some languages this is even suggested by the
name of the type), but that is not true. It is not even a very good mapping
of rational numbers.

0 new messages