浮点限制代码不能产生正确的结果

时间:2013-02-18 02:49:11

标签: c++ floating-point rounding

我正在绞尽脑汁想弄清楚为什么这段代码没有得到正确的结果。我正在寻找浮点正负溢出/下溢水平的十六进制表示。该代码基于此网站和Wikipedia entry

7f7fffff≈3.44028234×10 38 (最大单精度) - 来自维基百科条目,对应正溢出

以下是代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>

using namespace std;

int main(void) {

    float two = 2;
    float twentyThree = 23;
    float one27 = 127;
    float one49 = 149;


    float posOverflow, negOverflow, posUnderflow, negUnderflow;

    posOverflow = two - (pow(two, -twentyThree) * pow(two, one27));
    negOverflow = -(two - (pow(two, one27) * pow(two, one27)));


    negUnderflow = -pow(two, -one49);
    posUnderflow = pow(two, -one49);


    cout << "Positive overflow occurs when value greater than: " << hex << *(int*)&posOverflow << endl;


    cout << "Neg overflow occurs when value less than: " << hex << *(int*)&negOverflow << endl;


    cout << "Positive underflow occurs when value greater than: " << hex << *(int*)&posUnderflow << endl;


    cout << "Neg overflow occurs when value greater than: " << hex << *(int*)&negUnderflow << endl;

}

输出结果为:

  

当值大于:f3800000时,会发生正溢出   值小于:7f800000时发生否溢出   当值大于:1时,会发生正下溢   当值大于:80000001

时,会发生负溢出

要获取浮点的十六进制表示,我使用的是here描述的方法:

为什么代码不起作用?我知道如果积极溢出= 7f7f ffff,它会起作用。

3 个答案:

答案 0 :(得分:3)

你表达最高可表示的正浮动是错误的。您关联的网页使用(2-pow(2, -23)) * pow(2, 127),您有2 - (pow(2, -23) * pow(2, 127))。同样,对于最小的可表示负浮动。

然而,您的下溢表达式看起来是正确的,它们的十六进制输出也是如此。

请注意,posOverflownegOverflow只是+FLT_MAX-FLT_MAX。但请注意,您的posUnderflownegUnderflow实际上小于而不是FLT_MIN(因为它们是非正规的,FLT_MIN是最小的正正常浮动)。

答案 1 :(得分:2)

随着数字变大,浮点失去精度。当你加2时,数量为2 127 的数量不会改变。

除此之外,我并没有真正关注你的代码。使用单词拼出数字使我很难阅读。

以下是获取机器浮点限制的标准方法:

#include <limits>
#include <iostream>
#include <iomanip>

std::ostream &show_float( std::ostream &s, float f ) {
    s << f << " = ";
    std::ostream s_hex( s.rdbuf() );
    s_hex << std::hex << std::setfill( '0' );
    for ( char const *c = reinterpret_cast< char const * >( & f );
          c != reinterpret_cast< char const * >( & f + 1 );
          ++ c ) {
        s_hex << std::setw( 2 ) << ( static_cast< unsigned int >( * c ) & 0xff );
    }
    return s;
}

int main() {
    std::cout << std::hex;
    std::cout << "Positive overflow occurs when value greater than: ";
    show_float( std::cout, std::numeric_limits< float >::max() ) << '\n';
    std::cout << "Neg overflow occurs when value less than: ";
    show_float( std::cout, - std::numeric_limits< float >::max() ) << '\n';
    std::cout << "Positive underflow occurs when value less than: ";
    show_float( std::cout, std::numeric_limits< float >::denormal_min() ) << '\n';
    std::cout << "Neg underflow occurs when value greater than: ";
    show_float( std::cout, - std::numeric_limits< float >::min() ) << '\n';
}

输出:

Positive overflow occurs when value greater than: 3.40282e+38 = ffff7f7f
Neg overflow occurs when value less than: -3.40282e+38 = ffff7fff
Positive underflow occurs when value less than: 1.17549e-38 = 00008000
Neg underflow occurs when value greater than: -1.17549e-38 = 00008080

输出取决于机器的字节顺序。由于little-endian顺序,这里的字节被反转。

注意,在这种情况下,“下溢”不是灾难性的零结果,而只是逐渐降低精度的非规范化。 (但这可能对性能造成灾难性影响。)您也可以检查生成numeric_limits< float >::denorm_min()的{​​{1}}。

答案 2 :(得分:1)

你的代码假定整数与浮点数相同(所以除了你链接的页面上的一些帖子之外,btw。)你可能想要一些类似的东西:

for (size_t s = 0; s < sizeof(myVar); ++s) {
    unsigned char *byte = reinterpret_cast<unsigned char*>(myVar)[s];
    //sth byte is byte
}

即类似于该页面上的模板化代码。

您的编译器可能没有使用那些特定的IEEE 754类型。您需要查看其文档。

另外,请考虑使用std::numeric_limits<float>.min() / max()cfloat FLT_常量来确定其中一些值。