您好我有两个问题:
uint64_t vs double,其覆盖正数的范围限制更高?
如果只需要double的整数部分,如何将double转换为uint64_t。
由于定义了双倍,直接投射显然不起作用。
很抱歉有任何困惑,我在谈论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完全错误。 谢谢。
答案 0 :(得分:5)
支持的uint64_t vs double,它覆盖正数的范围限制更高?
uint64_t
具有64个值位,没有填充位,没有符号位。它可以表示0到2之间的所有整数 64 - 1,包括在内。
基本上所有现代C实现都代表IEEE-754 64位二进制格式的double
,但C不要求也不支持该格式。然而,很常见的是,假设格式是相当安全的,并且可能只是对定义FP特性的宏进行一些编译时检查。我将假设这个答案的平衡,C实现确实使用了该表示。
IEEE-754二进制双精度提供53位尾数,因此它可以表示0到2之间的所有整数 53 - 1.它是浮点格式但是,使用11位二进制指数。它可以表示的最大数是(2 53 -1)* 2 1023 ,或接近2 1077 。从这个意义上说,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_t
,则将完全保留整数部分;否则,行为未定义。
您提供的代码使用联合来覆盖double
和uint64_t
的存储空间。这本身并不是错误的,但它并不是一种在这两种类型之间进行转换的有用技术。转换是所有非隐式值转换的C机制。
答案 1 :(得分:1)
double
可以容纳比uint64_t
更大的数字,因为8字节IEEE 754的值范围是4.94065645841246544e-324d到1.79769313486231570e + 308d(正面或负面)[taken from here] { {3}}。但是,如果在该范围内添加小值,则会出现意外情况,因为在某些时候精度将无法表示例如添加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 }
给我一个100000000000000005366162204393472.000000的常量输出。这也是我们在math.h中使用nextafter和nexttoward函数的原因。您还可以在那里找到ceil和floor功能,从理论上讲,它可以帮助您解决第二个问题:删除分数部分。
然而,如果你真的需要保持大数字,你应该看看bigint实现,例如[more detailed explanation]。 Bigints被设计用于对非常大的整数进行操作,并且即使对于非常大的值,添加一个操作也会真正增加数量。