【问题标题】:double to int conversiondouble 到 int 的转换
【发布时间】:2012-05-24 02:41:53
【问题描述】:

下面的代码有什么问题(潜在的未定义行为)吗,浮点值是否被分配给 long int?

struct timespec t; 
t.tv_nsec = (some float value < 1) * 1E9

【问题讨论】:

    标签: c floating-point


    【解决方案1】:

    转换将在编译时完成。您可能会从编译器收到警告,但代码实际上并没有什么“错误”,因为使用浮点常量初始化整数是非常传统的做法。


    我给出的初始化只是为了保持简单。在代码中会是这样的:

    struct timespec t; t.tv_nsec = (some float value < 1) * 1E9;
    

    纳秒到tv_nsec;有趣,但不应该有任何重大问题。实际上,double 具有足够的精度,因此您不会遇到太多麻烦,尽管您有时可能会得到与预期不同的值,因为分数在您不期望的情况下被截断。可能值得检查一下;这取决于它对您的重要性。

    我做了一个快速程序,看看是否有问题。请记住,这是运行时计算而不是编译时计算,但您的结果可能相似:

    #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;
    }
    

    它打印出小数值与整数值不匹配的值。一些大量输出的一小部分是:

    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
    

    虽然绝不是每个值都有问题,但我记录(使用wc -l)在 1,000,000,000 个值中的 17,075,957 个(或大约 1.7% 的值)存在差异。那是在 Mac OS X 10.7.4(由 Apple 提供)上使用 GCC 4.1.2。我使用 GCC 4.7.0 得到了相同的结果。生成数据大约需要 30 秒。

    Kernighan 和 Plauger 的“编程风格的要素”中我最喜欢的一句话是:

    • 一位聪明的程序员曾经说过,'浮点数就像一小堆沙子。每次你移动一个,你就会失去一点沙子并捡起一点泥土。'

    这很好地证明了这个问题。


    请注意,微不足道的更改会将错误率降低到 0:

    long r = d * 1E9 + 0.5;
    

    也许你应该使用宏:

    #define NANOSECONDS(x) ((x) * 1E9 + 0.5)
    
    long r = NANOSECONDS(d);
    

    您可以使用较小的附加常数; 0.1 也将错误率降低到 0。

    【讨论】:

    • 谢谢。我给出的初始化只是为了保持简单。在代码中它会像.. struct timespec t; t.tv_nsec = (一些浮点值
    • 我取消了我原来的“你应该没问题”的评论,并添加了一个扩展的答案,“好吧,你将不得不决定它是否适合你”警告。
    • 谢谢。出于我的目的,这个警告是可以的..让我也更新我的问题以造福他人。
    猜你喜欢
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 2013-05-31
    • 2011-05-10
    • 1970-01-01
    相关资源
    最近更新 更多