C-32位计算机上的无符号长到双精度

C-32位计算机上的无符号长到双精度,c,double,unsigned,primitive,C,Double,Unsigned,Primitive,嗨,我有两个问题: uint64\u t vs double,哪一个覆盖正数的范围限制更高 如果只需要double的整数部分,如何将double转换为uint64\t 由于double的定义,直接铸造显然不起作用 很抱歉给您带来任何困惑,我说的是32位机器上的64位双精度C 例如: //operation for convertion I used: double sampleRate = ( (union { double i; uint64_t s

嗨,我有两个问题:

  • uint64\u t vs double,哪一个覆盖正数的范围限制更高

  • 如果只需要double的整数部分,如何将double转换为uint64\t

  • 由于double的定义,直接铸造显然不起作用


    很抱歉给您带来任何困惑,我说的是32位机器上的64位双精度C

    例如:

    //operation for convertion I used:
    double sampleRate = (
                          (union { double i; uint64_t sampleRate; })
                          { .i = r23u.outputSampleRate}
                        ).sampleRate;
    
    //the following are printouts on command line
    //         double                               uint64_t
    //printed by   %.16llx                           %.16llx
    outputSampleRate  0x41886a0000000000      0x41886a0000000000 sampleRate
    
    //printed by   %f                                    %llu
    outputSampleRate  51200000.000000        4722140757530509312 sampleRate
    
    因此,这两个数字保持相同的位模式,但当以小数形式输出时,uint64_t是完全错误的。
    谢谢。

    由于8字节IEEE 754的值范围为4.94065645841246544e-324d到1.79769313486231570e+308d(正或负),所以双精度
    可以容纳比
    uint64\u t
    大得多的数字。但是,如果在该范围内添加较小的值,您会感到意外,因为在某些点上,精度将无法表示例如1的加法,并将向下舍入到较低的值,基本上使循环稳定地增加1

    此代码例如:

    #include <stdio.h>
    2 int main()
    3 {
    4     for (double i = 100000000000000000000000000000000.0; i < 1000000000000000000000000000000000000000000000000.0; ++i)
    5         printf("%lf\n", i);
    6     return 0;
    7 }
    
    #包括
    2 int main()
    3 {
    4表示(双i=1000000000000000000000000.0;i<10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    5 printf(“%lf\n”,i);
    6返回0;
    7 }
    
    给我一个100000000000000536162204393472.000000的恒定输出。这也是为什么我们在数学中有nextafter和nexttoward函数。您还可以在那里找到ceil和floor函数,理论上,这将允许您解决第二个问题:删除分数部分

    然而,如果您真的需要保存大量的数字,您应该转而考虑bigint实现,例如。bigint被设计用来对非常大的整数进行运算,像一个加法这样的运算,即使对于非常大的值,也会真正增加数字

    uint64\u t vs double,哪一个覆盖正数的范围限制更高

    uint64\u t
    ,在支持的情况下,具有64个值位、无填充位和无符号位。它可以表示0和264-1之间的所有整数(包括0和264-1)

    实际上,所有现代C实现都以IEEE-754 64位二进制格式表示
    double
    ,但C不要求也不认可该格式。然而,这种情况非常普遍,因此假设这种格式是相当安全的,并且可能只是针对定义FP特性的宏进行一些编译时检查。为了平衡这个答案,我将假设C实现确实使用了这种表示


    IEEE-754二进制双精度提供53位尾数,因此它可以表示0到253-1之间的所有整数。但是,它是一种浮点格式,具有11位二进制指数。它所能代表的最大数字是(253-1)*21023,或接近21077。从这个意义上说,
    double
    的范围比
    uint64_t
    大得多,但是0与其最大值之间的绝大多数整数不能精确表示为
    double
    s,包括几乎所有可以由
    uint64_t
    精确表示的数字

    如果只需要double的整数部分,如何将double转换为uint64\t

    您可以简单地赋值(转换是隐式的),也可以显式地强制转换(如果您想明确转换发生):

    double my_double = 1.2345678e48;
    uint64_t my_uint;
    uint64_t my_other_uint;
    
    my_uint = my_double;
    my_other_uint = (uint64_t) my_double;
    
    double
    值的任何小数部分都将被截断。如果整数部分可表示为
    uint64\u t
    ,则整数部分将被精确保留;否则,行为是未定义的


    您介绍的代码使用一个并集来覆盖
    双精度
    uint64\u t
    的存储。这并不是天生的错误,但它不是在两种类型之间转换的有用技术。强制转换是C进行所有非隐式值转换的机制。

    您是指C中指定的
    double
    ,还是ieee754 binary64浮点中指定的
    double
    ?对于#2,您是否尝试只分配给double变量?您所说的“直接强制转换显然不起作用”是什么意思?它怎么不起作用?举一个数字的例子,当你将它转换为double时,你得到了什么,以及你如何检查它的值。
    double
    有一个更大的“最大值”。但是“掩护”?它的精度与该值的对数成正比。因此,在某一点上,即使是“整个”部分也会受到不精确的影响。“在32位机器上使用C双精度”-这并不能澄清任何问题!C11标准草案n1570 6.3.1.4实浮点和整数1当实浮点类型的有限值转换为除_Bool以外的整数类型时,小数部分被丢弃(即,该值被截断为零)。如果整数部分的值不能用整数类型表示,则行为未定义。@EOF,谢谢您的更正。我已经更新了我的答案。