如果将浮点值分配给long int,是否有任何错误(潜在的未定义行为)与下面的代码?
struct timespec t;
t.tv_nsec = (some float value < 1) * 1E9
Run Code Online (Sandbox Code Playgroud)
转换将在编译时完成.您可能会从编译器收到警告,但代码实际上没有"错误",因为初始化具有浮点常量的整数是非常常规的.
我给出的初始化只是为了保持简单.在代码中它将是这样的:
Run Code Online (Sandbox Code Playgroud)struct timespec t; t.tv_nsec = (some float value < 1) * 1E9;
纳秒进入tv_nsec; 有趣,但不应该有任何重大问题.实践中的双精度具有足够的精度,您不会遇到太多麻烦,尽管您可能偶尔会得到与预期不同的值,因为当您没有预料到时,分数会被截断.可能值得检查一下; 这取决于它对你有多重要.
我做了一个快速的程序,看看是否有问题.请记住,这是运行时计算而不是编译时计算,但结果可能与您类似:
#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;
}
Run Code Online (Sandbox Code Playgroud)
它打印出小数值与整数值不匹配的值.一小部分的大量输出是:
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
Run Code Online (Sandbox Code Playgroud)
虽然并非所有价值都存在问题,但我wc -l在1,000,000,000个值(或约1.7%的值)中记录(带)17075,957,但存在差异.那是在Mac OS X 10.7.4上的GCC 4.1.2(由Apple提供).我用GCC 4.7.0获得了相同的结果.生成数据大约需要30秒.
我最喜欢的Kernighan和Plauger的"编程风格元素"之一是:
这很好地证明了这个问题.
请注意,一个微不足道的更改会将错误率降低到0:
long r = d * 1E9 + 0.5;
Run Code Online (Sandbox Code Playgroud)
也许你应该使用一个宏:
#define NANOSECONDS(x) ((x) * 1E9 + 0.5)
long r = NANOSECONDS(d);
Run Code Online (Sandbox Code Playgroud)
您可以使用较小的附加常数; 0.1还将错误率降低到0.