如何以最大精度(C ++)将uint64_t转换为0到1之间的double / float?

时间:2017-10-24 01:54:47

标签: c++ floating-point 64-bit

我正在根据无符号整数编写图像类。我目前使用uint8_t和uint16_t缓冲区用于8位和16位RGBA像素,并且要从16位转换为8位,我只需要取16位值,除以std :: numeric_limits< uint16_t> :: max()转换为double,然后乘以255。

但是,如果我想为每个RGBA组件创建一个64位无符号整数的图像(我知道,它非常高),我怎样才能找到0到1之间的浮点数/双精度值表示0和最大uint64_t之间的距离是多少?我假设转换为双精度不会起作用,因为双精度通常是64位浮点数,并且你无法捕获64位浮点数中的所有64位无符号整数值。在不转换为浮点数/双打的情况下进行划分只会给我0或有时1。

找到介于0和1之间的浮点值的最准确方法是什么,它表示0和无符号64位值之间的最大距离是多少?

3 个答案:

答案 0 :(得分:4)

  

找到介于0和1之间的浮点值的最准确方法是什么,它表示0和无符号64位值之间的最大距离是多少?

要将[0 ... 2 64 )范围内的整数值映射到[0 ... 1.0),可以直接进行。

  1. uint64_t转换为double

  2. 按2 64 @Mark Ransom

    缩放
    #define TWO63 0x8000000000000000u 
    #define TWO64f (TWO63*2.0)
    
    double map(uint64_t u) {
      double y = (double) u; 
      return y/Two64f;
    }
    
  3. 意志地图

    [2 63 ... 2 64 )至[0.5 ... 1.0)范围内的整数值:2 52 不同double值 整数值在[2 62 ... 2 63 )至[0.25 ... 0.5):2 52 不同{{1值 [2 61 ... 2 62 )至[0.125 ... 0.25)范围内的整数值:2 52 不同{{1值 ...
    整数值在[2 52 ... 2 53 )至[2 -12 ... 2 -11 < / sup>):2 52 不同的double值 整数值在[0 ... 2 52 )至[2 -13 ... 2 -12 )范围内:2 52 不同的double值。

    将[0 ... 2 64 )范围内的整数值映射到[0 ... 1.0]更加困难。 (请注意doubledouble

答案 1 :(得分:2)

您可以从Java java.util.Random nextDouble()方法的以下代码开始。它需要53位并从中形成一个双重:

   return (((long)next(26) << 27) + next(27))
     / (double)(1L << 53);

我将使用long的最重要的26位作为移位值,接下来的27位填充低位。这会丢弃输入的最低有效64-53 = 11位。

如果区分非常小的值特别重要,您还可以使用次正规数,nextDouble()不返回。

答案 2 :(得分:1)

OP要求使用C ++,所以去了: (假设编译器知道类型__int64,这很可能是Visual Studio风格的。)

double asDouble(unsigned __int64 v)
{
    return ((__int64)(v >> 11)) / (double)(1L << 53);
}

或者,如果您不介意时髦的演员表:

double asDouble(unsigned __int64 v)
{
    // the 0x3FF sets the exponent to the 0..1 range.
    unsigned __int64 vv == (v >> 11) | (0x3FFL << 53);
    return *(double*)&vv;
}