如何将unsigned long long转换为double

时间:2014-06-03 19:54:16

标签: c

我有一个随机数生成器如下。

uint64_t s[ 2 ];

uint64_t next(void) { 
    uint64_t s1 = s[ 0 ];
    const uint64_t s0 = s[ 1 ];
    s[ 0 ] = s0;
    s1 ^= s1 << 23; // a
    return ( s[ 1 ] = ( s1 ^ s0 ^ ( s1 >> 17 ) ^ ( s0 >> 26 ) ) ) + s0; // b, c
}

实际上,我希望在范围(0,1)中获得双打。一种选择是在我的代码中执行此操作

#define M_RAN_INVM64 5.42101086242752217003726400434970855e-20
[..]
double u1;
u1 = next()*M_RAN_INVM64;
  1. 我担心我会失去精确度,而且这也取决于平台。
  2. 我不希望得到0或1的值。

  3. 一种选择是将next()转换为带符号的long long,乘以M_RAN_INVM64然后再加0.5。然后我可以添加2 ^(64)/ 2以确保我从未得到过0。

2 个答案:

答案 0 :(得分:1)

已编辑:要将范围(0,1)中的任何正unsigned long long转换为long double,您可以使用以下步骤因素:

 long double step = ((long double) 1.0) / ULLONG_MAX

其他信息在处理浮点数时,也许您可​​以考虑系统的限制。以下内容可以帮助您了解系统中的浮点数:

有一种可移植的方法来获取编译程序的系统中最小的浮点数。

这可以通过使用标准库<float.h>来实现 有了它,您可以使用以下宏常量:

 FLT_MIN    // Smallest positive float number in your system  
 DBL_MIN    // Smallest positive double number in your system  
 LDBL_MIN   // Smallest positive long double number in your system  

此外,您可以考虑类似“epsilon”的常量,它会为您提供有关给定类型的最小正数的信息,例如1.0!= 1.0 +“epsilon”。
当您尝试获得尽可能接近1.0的数字时,这可以帮助您,但仍然不同:

FLT_EPSILON  
DBL_EPSILON  
LDBL_EPSILON  

例如,请参阅:float.h (ANSI)

答案 1 :(得分:1)

接受回答后:

double个数字以对数方式分布。有double 0.25到0.5,因为有0.5到1.0 - 假设基数为2 double

假设double是IEEE binary64:...

要在[0.0到1.0]范围内获得double均匀(线性)分布,只能使用2 ^ 53个值。因此,从next()

的结果中丢弃11位
uint64_t u1 = next();
u1 >>= 11;
// or
u1 &= 0x001FFFFFFFFFFFFF;
if (u1 == 0) ThrowOutZero();

// convert to (0.0 to 1.0)
double d = u1 / 9007199254740992.0;  // Divide by 2^53