Reputation: 3975
Is there anything wrong (potential undefined behavior) with the following code, were a float value gets assigned to a long int ?
struct timespec t;
t.tv_nsec = (some float value < 1) * 1E9
Upvotes: 2
Views: 439
Reputation: 753485
The conversion would be done at compile time. You might get a warning from the compiler, but there's nothing actually 'wrong' with the code, for all it is very aconventional to initialize an integer with a floating point constant.
The initialization I gave was just to keep it simple. In the code it will be something like:
struct timespec t; t.tv_nsec = (some float value < 1) * 1E9;
Nanoseconds into tv_nsec
; interesting, but there shouldn't be any major issues. A double in practice has enough precision that you won't run into much trouble, though you might occasionally get a different value from what you expected because the fraction is truncated down when you didn't expect it. It might be worth checking that; it depends how crucial it would be to you.
I did a quick program to see whether there might be a problem. Bear in mind that this is run time calculation and not compile time calculation, but the results might be similar for you:
#include <stdio.h>
int main(void)
{
for (long l = 0; l < 1000000000; l++)
{
double d = l / 1.0E9;
long r = d * 1E9;
if (r != l)
printf("%.9ld: %12.9f != %ld\n", l, d, r);
}
return 0;
}
It prints out values where the fractional value does not match the integer value. A small section of some voluminous output is:
031890838: 0.031890838 != 31890837
031890839: 0.031890839 != 31890838
031890840: 0.031890840 != 31890839
031890851: 0.031890851 != 31890850
031890852: 0.031890852 != 31890851
031890853: 0.031890853 != 31890852
031890864: 0.031890864 != 31890863
031890865: 0.031890865 != 31890864
031890866: 0.031890866 != 31890865
031890877: 0.031890877 != 31890876
031890878: 0.031890878 != 31890877
031890879: 0.031890879 != 31890878
031890890: 0.031890890 != 31890889
While it is by no means every value that has problems, I record (with wc -l
) 17,075,957 out of 1,000,000,000 values (or about 1.7% of the values) with a discrepancy. That was with GCC 4.1.2 on Mac OS X 10.7.4 (as supplied by Apple). I got the same result with GCC 4.7.0. It took about 30 seconds to generate the data.
One of my favourite quotes from 'The Elements of Programming Style' by Kernighan and Plauger is:
This demonstrates the issue quite well.
Note that a trivial change reduces the error rate to 0:
long r = d * 1E9 + 0.5;
Maybe you should use a macro:
#define NANOSECONDS(x) ((x) * 1E9 + 0.5)
long r = NANOSECONDS(d);
You can use a smaller additive constant; 0.1 also reduced the error rate to 0.
Upvotes: 5