提问者:小点点

如何以最大精度将uint64_t转换为 0 到 1 之间的双精度/浮点数 (C)?


我正在写一个基于无符号整数的图像类。我目前对8位和16位RGBA像素使用uint8_t和uint16_t缓冲,要从16位转换到8位,我只需将16位值除以std::numeric_limits

但是,如果我想要一个图像,每个RGBA分量都是64位无符号整数(我知道,这个数字高得离谱),我该如何在0和1之间找到一个浮点/双精度数,来表示我的像素值在0和最大uint64_t之间有多远呢?我认为转换为double是行不通的,因为double通常是64位浮点型,并且您不能在64位浮点型中捕获所有64位无符号整数值。没有转换成浮点数/双精度数的除法只能得到0或者有时是1。

查找0和1之间的浮点值的最准确方法是什么,该浮点值表示0和无符号64位值的最大值之间的距离?


共3个答案

匿名用户

查找0和1之间的浮点值的最准确方法是什么,该浮点值表示0和无符号64位值的最大值之间的距离?

可以直接将[0…264)到[0…1.0)范围内的整数值映射。

>

  • uint64_t 转换为双倍

    按264 @Mark Ransom缩放

     #define TWO63 0x8000000000000000u 
     #define TWO64f (TWO63*2.0)
    
     double map(uint64_t u) {
       double y = (double) u; 
       return y/Two64f;
     }
    

    遗嘱地图

    范围内的整数值 [263...264) 至 [0.5 ...1.0):252 种不同的双精度值。范围内的
    整数值 [262...263) 至 [0.25 ...0.5):252 种不同的双精度值。范围内的
    整数值 [261...262) 至 [0.125 ...0.25):252 个不同的双精度值。

    范围内的整数值 [252...253) 至 [2-12 ...2-11):252 种不同的双精度值。
    介于 [0...252) 到 [2-13 ...2-12):252 种不同的双精度值。

    要映射范围[0...264)到[0...1.0]比较难。(注意< code>]与< code>)。

    [2021年2月]我认为这个答案需要重新解释上边缘情况。返回的潜在值包括1.0。

  • 匿名用户

    您可以从以下代码开始Java的java.util.随机<代码>next双精度()方法。它需要53位并从中形成一个双精度:

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

    我会使用长整型中最重要的 26 位作为移位值,接下来的 27 位来填充低阶位。这将丢弃最不重要的 64-53 = 11 位输入。

    如果区分非常小的值特别重要,您也可以使用次正规数,这是< code>nextDouble()不会返回的。

    匿名用户

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

    相关问题