【问题标题】:Save float16 max number in float32在 float32 中保存 float16 最大数量
【发布时间】:2019-11-21 12:11:26
【问题描述】:

如何以 float32 (https://en.wikipedia.org/wiki/Single-precision_floating-point_format) 格式保存 float16 (https://en.wikipedia.org/wiki/Half-precision_floating-point_format) 最大值?

我想要一个可以将 0x7bff 转换为 65504 的函数。0x7bff 是可以用浮点半精度表示的最大值:

0 11110 1111111111 -> decimal value: 65504 

我想让 0x7bff 代表我程序中的实际位。

float fp16_max = bit_cast(0x7bff); 
# want "std::cout << fp16_max" to be 65504

我试图实现这样的功能,但它似乎不起作用:

float bit_cast (uint32_t fp16_bits) {
    float i;
    memcpy(&i, &fp16_bits, 4);
    return i; 
}    
float test = bit_cast(0x7bff);
# print out test: 4.44814e-41

【问题讨论】:

  • 不要使用memcpy,而是重新分配。浮点格式大相径庭。
  • 我很确定@tadman 是正确的。您为规避该分配而尝试做的任何事情都可能会减慢或破坏它。
  • @Lemon 我不确定,但我认为你把事情搞混了。我也这样做,所以这可能不准确:float a 是你的lvalue 接收0x7bff 的结果,它是一个整数。这个文字将被编译器翻译成它可以做到的最好的(31743 点),适合你的floatfloats 无法表示每个整数。如果我退后一步,看看你的问题,看看“保存”。您需要将此保存的数据带到任何地方吗?它是否只需要在您保存它的同一台计算机上进行解释?如果是这样,那就有点简单了。
  • 很抱歉给您带来了困惑。它发生在同一台计算机上,无需前往任何地方。

标签: c++ floating-point


【解决方案1】:
#include <cmath>
#include <cstdio>


/*  Decode the IEEE-754 binary16 encoding into a floating-point value.
    Details of NaNs are not handled.
*/
static float InterpretAsBinary16(unsigned Bits)
{
    //  Extract the fields from the binary16 encoding.
    unsigned SignCode        = Bits >> 15;
    unsigned ExponentCode    = Bits >> 10 & 0x1f;
    unsigned SignificandCode = Bits       & 0x3ff;

    //  Interpret the sign bit.
    float Sign = SignCode ? -1 : +1;

    //  Partition into cases based on exponent code.

    float Significand, Exponent;

    //  An exponent code of all ones denotes infinity or a NaN.
    if (ExponentCode == 0x1f)
        return Sign * (SignificandCode == 0 ? INFINITY : NAN);

    //  An exponent code of all zeros denotes zero or a subnormal.
    else if (ExponentCode == 0)
    {
        /*  Subnormal significands have a leading zero, and the exponent is the
            same as if the exponent code were 1.
        */
        Significand = 0 + SignificandCode * 0x1p-10;
        Exponent    = 1 - 0xf;
    }

    //  Other exponent codes denote normal numbers.
    else
    {
        /*  Normal significands have a leading one, and the exponent is biased
            by 0xf.
        */
        Significand = 1 + SignificandCode * 0x1p-10;
        Exponent    = ExponentCode - 0xf;
    }

    //  Combine the sign, significand, and exponent, and return the result.
    return Sign * std::ldexp(Significand, Exponent);
}


int main(void)
{
    unsigned Bits = 0x7bff;
    std::printf(
        "Interpreting the bits 0x%x as an IEEE-754 binary16 yields %.99g.\n",
        Bits,
        InterpretAsBinary16(Bits));
}

【讨论】:

    【解决方案2】:

    通过 float fp16_max 的声明,您的值已经是 32 位浮点数;无需在这里投射。我想你可以简单地:

    float i = fp16_max;
    

    这里的假设是您的“魔术”bit_cast 函数已经正确返回了 32 位浮点数。由于您没有向我们展示 bit-cast 的作用或实际返回的内容,因此我假设它确实返回了正确的 float 值。

    【讨论】:

      【解决方案3】:

      如何将float16最大数保存为float32格式?

      65504

      您可以简单地将整数转换为浮点数:

      float half_max = 65504;
      

      如果要计算值,可以使用ldexpf

      float half_max = (2 - ldexpf(1, -10)) * ldexpf(1, 15)
      

      或者一般来说,对于任何 IEEE 浮点数:

      // in case of half float
      int bits = 16;
      int man_bits = 10;
      
      // the calculation
      int exp_bits = bits - man_bits - 1;
      int exp_max = (1 << (exp_bits - 1)) - 1;
      long double max = (2 - ldexp(1, -1 * man_bits)) * ldexp(1, exp_max);
      

      位转换 0x7bff 不起作用,因为 0x7bff 是 binary16 格式(在某些字节序中)的表示,而不是 binary32 格式的表示。您不能对相互冲突的表示进行位转换。

      【讨论】:

      • 酷。我真的很想在我的程序中保留 0x7bff。有没有办法使用 ldexpf 实现 bit_conversion 函数?
      • @Lemon 您可以编写一个函数,将半浮点数转换为另一种表示形式(例如float)。然后std::memcpy0x7bff 到用于表示半浮点数的存储(注意字节序)。然后使用你的函数转换为float
      猜你喜欢
      • 2018-03-24
      • 2020-09-12
      • 2019-11-03
      • 2018-03-18
      • 2015-03-12
      • 2021-04-19
      • 2012-05-23
      • 2017-08-16
      • 2021-12-14
      相关资源
      最近更新 更多