C ++移动浮点位表示?

时间:2013-03-08 18:44:23

标签: c++ floating-point portability ieee-754 bit-representation

是否有符合C ++标准的方法来确定“浮动”,“双重”和“长”双重结构的结构。在编译时(或运行时,作为替代)?

如果我假设std::numeric_limits< T >::is_iec559 == truestd::numeric_limits< T >::radix == 2,我怀疑可以通过以下规则:

  • 第一个X位是有效数字。
  • 下一个Y位是指数。
  • 最后1位是符号位。

用以下表达式模糊地说:

  • size_t num_significand_bits = std::numeric_limits< T >::digits;
  • size_t num_exponent_bits = log2( 2 * std::numeric_limits< T >::max_exponent );
  • size_t num_sign_bits = 1u;

除了我知道

  • std::numeric_limits< T >::digits包含&#34;整数位&#34;,无论格式是否实际明确代表它,所以我不知道如何以编程方式检测并调整此格式。
  • 我猜std::numeric_limits< T >::max_exponent总是2^(num_exponent_bits)/2

背景:我试图轻易克服两个问题:

  • 设置/获取有效数字中的哪些位。
  • 确定&#39; long double&#39;是的,所以我知道不要读取隐含的填充位,它们会有未初始化的内存。

3 个答案:

答案 0 :(得分:4)

简而言之,没有。如果std::numeric_limits<T>::is_iec559,那么你 知道T的格式,或多或少:你仍然需要 确定字节顺序。除此之外,所有赌注都已关闭。 (我知道其他仍然使用的格式不均匀 基础2:例如,IBM大型机使用基数16 IEC浮点的“标准”排列有标志 高阶位,然后是指数,以及尾数 低阶位;如果你能成功地将其视为一个 例如uint64_t(通过memcpyreinterpret_castunion - `memcpy保证可以正常工作,但更少 效率高于其他两个),那么:

代表double

uint64_t tmp;
memcpy( &tmp, &theDouble, sizeof( double ) );
bool isNeg = (tmp & 0x8000000000000000) != 0;
int  exp   = (int)( (tmp & 0x7FF0000000000000) >> 52 ) - 1022 - 53;
long mant  = (tmp & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;

表示`float:

uint32_t tmp;
memcpy( &tmp, &theFloat, sizeof( float ) );
bool isNeg = (tmp & 0x80000000) != 0;
int  exp   = (int)( (tmp & 0x7F800000) >> 23 ) - 126 - 24 );
long mant  = (tmp & 0x007FFFFF) | 0x00800000;

关于long double,情况更糟,因为不同 编译器对它的处理方式不同,即使是在同一台机器上。 名义上,它是十个字节,但出于对齐原因,它可能在 事实上是12或16.或者只是double的同义词。 如果那就是 超过10个字节,我你可以指望它被打包 进入前10个字节,以便&myLongDouble给出 10字节值的地址。但总的来说,我会避免 long double

答案 1 :(得分:1)

我想说唯一可移植的方法是将数字存储为字符串。这不依赖于“解释位模式”

即使您知道有多少位,也不意味着它具有相同的表示 - 指数从零开始或有偏差。尾数前面有一个看不见的1吗?这同样适用于该号码的所有其他部分。 BCD编码或“十六进制”浮点数变得更糟 - 这些在一些架构中可用......

如果您担心结构(类,数组等)中未初始化的位,则使用memset将整个结构设置为零[或其他一些已知值]。

答案 2 :(得分:0)

对于子孙后代,这就是我最终要做的事情。

为了生成并测试我的IEEE-754信令-NAN值,我将此模式用于'float'和'double'。

#include <cstdint> // uint32_t, uint64_t
#include <limits> // numeric_limits

union IEEE754_Float_Union
{
    float value;
    uint32_t bits;
};

float generate_IEEE754_float()
{
    IEEE754_Float_Union u = { -std::numeric_limits< float >::signaling_NaN() };
    size_t const num_significand_bits_to_set = std::numeric_limits< float >::digits
                                               - 1 // implicit "integer-bit"
                                               - 1; // the "signaling-bit"
    u.bits |= ( static_cast< uint32_t >( 1 ) << num_significand_bits_to_set ) - 1;
    return u.value;
}

bool test_IEEE754_float( float const& a_r_val )
{
    IEEE754_Float_Union const u = { a_r_val };
    IEEE754_Float_Union const expected_u = { generate_IEEE754_float() };
    return u.bits == expected_u.bits;
}

对于'long double',我使用'double'函数进行强制转换。具体来说,我生成'double'值并在返回之前将其转换为'long double',然后通过转换为'double'然后测试该值来测试'long double'。我的想法是,虽然'long double'格式可以变化,但是将'double'转换为'long double',然后将其转换回'double'应该是一致的(即不要丢失任何信息。)< / p>