c/c++语言开发共享为什么isnormal()说值不正常?

#include  #include  #include  #include  void PrintBytes( const float value ) { const char* const byte = ( const char* )&value ; for( size_t i = 0 ; i < sizeof( value ) ; i++ ) { printf( "%02hhx" , byte[i] ); } } int main(void) { float value = FLT_MIN; while( 1 ) { printf( "%e %d " , value , isnormal( value ) ); PrintBytes( value ); puts( "" ); if( !isnormal( value ) ) { break; } value /= 2.0F; } return 0; } 

输出是:

 1.175494e-038 1 00008000 5.877472e-039 1 00004000 2.938736e-039 1 00002000 1.469368e-039 1 00001000 7.346840e-040 1 00000800 3.673420e-040 1 00000400 1.836710e-040 1 00000200 9.183550e-041 1 00000100 4.591775e-041 1 00800000 2.295887e-041 1 00400000 1.147944e-041 1 00200000 5.739719e-042 1 00100000 2.869859e-042 1 00080000 1.434930e-042 1 00040000 7.174648e-043 1 00020000 3.587324e-043 1 00010000 1.793662e-043 1 80000000 8.968310e-044 1 40000000 4.484155e-044 1 20000000 2.242078e-044 1 10000000 1.121039e-044 1 08000000 5.605194e-045 1 04000000 2.802597e-045 1 02000000 1.401298e-045 1 01000000 0.000000e+000 0 00000000 

显然,第二个值5.877472e-039是次正规的,因为它的指数变为00004000

Ideone产生正确的结果:

 1.175494e-38 1 00008000 5.877472e-39 0 00004000 

我在Windows上使用gcc(MinGW-w64)编译我的代码。

    这在其他平台上可以正常工作(例如,在ideone上 ),因此它可能是您正在使用的gcc /标准库版本的问题。

    最可能的原因是isnormal的参数被转换为double。

    这似乎是具有32位目标的MinGW-w64中的错误。

    我的输出:


    看看MinGW-W64标题:

     #define isnormal(x) (fpclassify(x) == FP_NORMAL) 

    然后我们有:

     #define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x)  : sizeof (x) == sizeof (double) ? __fpclassify (x)  : __fpclassifyl (x)) 

    __fpclassifyf函数实现是:

      __CRT_INLINE int __cdecl __fpclassifyf (float x) { #ifdef __x86_64__ __mingw_flt_type_t hlp; hlp.x = x; hlp.val &= 0x7fffffff; if (hlp.val == 0) return FP_ZERO; if (hlp.val < 0x800000) return FP_SUBNORMAL; if (hlp.val >= 0x7f800000) return (hlp.val > 0x7f800000 ? FP_NAN : FP_INFINITE); return FP_NORMAL; #else unsigned short sw; __asm__ __volatile__ ("fxam; fstsw %%ax;" : "=a" (sw): "t" (x)); return sw & (FP_NAN | FP_NORMAL | FP_ZERO ); #endif } 

    由于x64版似乎可以工作,但i686版本没有,我想我们应该归咎于上面的fxam; fstsw fxam; fstsw线。 我为这个问题开了一个新线程 ; 到目前为止,已经回答fxam确实测试了一个扩展到80位精度的版本。

    在破坏版本中生成的-O1组件是:

      call ___main flds LC1 fstps 24(%esp) L7: flds 24(%esp) /APP # 484 "F:/Prog/mingw-w64/i686-4.9.2-win32-dwarf-rt_v4-rev2/mingw32/i686-w64-mingw32/include/math.h" 1 fxam; fstsw %ax; # 0 "" 2 /NO_APP andw $17664, %ax cmpw $1024, %ax sete %al movzbl %al, %eax movl %eax, 12(%esp) fstpl 4(%esp) movl $LC2, (%esp) call _printf flds 24(%esp) fstps (%esp) call _PrintBytes movl $LC3, (%esp) call _puts flds 24(%esp) /APP # 484 "F:/Prog/mingw-w64/i686-4.9.2-win32-dwarf-rt_v4-rev2/mingw32/i686-w64-mingw32/include/math.h" 1 fxam; fstsw %ax; # 0 "" 2 /NO_APP andw $17664, %ax cmpw $1024, %ax jne L6 fmuls LC4 fstps 24(%esp) jmp L7 L6: fstp %st(0) movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc LFE41: .section .rdata,"dr" .align 4 LC1: .long 8388608 .align 4 LC4: .long 1056964608 

      以上就是c/c++开发分享为什么isnormal()说值不正常?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/544949.html

      (0)
      上一篇 2021年1月9日
      下一篇 2021年1月9日

      精彩推荐