【问题标题】:Failing comparison of floats NaNs on STM32F407 CORTEX-M4 [duplicate]在 STM32F407 CORTEX-M4 上比较浮点 NaN 失败 [重复]
【发布时间】:2020-01-15 20:41:05
【问题描述】:

我正在尝试比较从 nanf("1") 返回的两个浮点数,但程序没有进入 if 块。

int main(void)
{
    volatile float f;
    volatile float ff;
    uint32_t* view1;
    uint32_t* view2;

    view1 = ((uint32_t*)&f);
    view2 = ((uint32_t*)&ff);

    f = nanf("1");
    ff = nanf("1");

    if(f == ff)
    {
        f = 0;
    }

    while(1);
}

调试器显示fff(通过view1view2)变量具有安静的NaN 值(QNaN == 0x7FC00001)。

编译器:

gcc 版本 4.8.3 20131129 (release) [ARM/embedded-4_8-branch revision 205641](用于 ARM 嵌入式处理器的 GNU 工具)

编译器标志:

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=c99 -DSTM32F407VETx -DSTM32 -DSTM32F4 -DDEBUG -O0 -g3 -Wall -fmessage-length=0 -ffunction-sections -c

链接器标志:

-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -lm

这是输出程序集(不能将其粘贴到代码块中):

if(f == ff)
080129b4:   ldr     r3, [pc, #32]   ; (0x80129d8 <main+92>)
080129b6:   vldr    s14, [r3]
080129ba:   ldr     r3, [pc, #36]   ; (0x80129e0 <main+100>)
080129bc:   vldr    s15, [r3]
080129c0:   vcmp.f32        s14, s15
080129c4:   vmrs    APSR_nzcv, fpscr
080129c8:   bne.n   0x80129d2 <main+86>

f = 0;
080129ca:   ldr     r3, [pc, #12]   ; (0x80129d8 <main+92>)
080129cc:   mov.w   r2, #0
080129d0:   str     r2, [r3, #0]

while(1);
080129d2:   b.n     0x80129d2 <main+86>

【问题讨论】:

    标签: c gcc c99 cortex-m stm32f4


    【解决方案1】:

    比较数字时,== 产生真 (1) 当且仅当两个操作数是相等的数字。 NaN 不是数字,因此它们永远不可能是相等的数字。每当xy 是NaN 时,x == y 总是产生 false (0),即使它们是相同的 NaN。

    如果需要判断两个NaN是否相同,可以比较它们表示的字节数:

    if (memcmp(&f, &ff, sizeof f) == 0)
    

    注意事项

    • memcmp&lt;string.h&gt; 中声明。
    • 您的代码view1 = ((uint32_t*)&amp;f); 表明您使用*view1 来检查f 的字节作为uint32_t。不要这样做,因为它不受 C 标准支持,并且有一些简单的支持方式。要将f 的字节作为uint32_t 进行检查,可以使用uint32_t view1; memcpy(&amp;view1, &amp;f, sizeof view1));uint32_t view1 = (union { float x; uint32_t y; }) { f } .y;
    • volatile 不需要这样做,尤其是在您停止不受支持的别名后。如果fffvolatile,那么memcmp 需要强制转换:memcmp((void *) &amp;f, (void *) &amp;ff, sizeof f)
    • 如果float 类型具有填充位,则以这种方式进行比较可能会产生误报。 (语义上相同的两个 NaN 可能具有不同的填充位。)但是,在现代 C 实现中,如果不是不存在的话,这将是不寻常的。由于您的目标是使用 32 位浮点类型的特定实现,因此如果其 C 类型为 32 位,则它不能具有填充位。

    【讨论】:

    • 感谢您的回答,但我不确定您的意思是 C 标准不支持 view1 = ((uint32_t*)&amp;f); 吗?我认为这是典型的 C 构造。
    • @Pawcio: C 2018 6.5 7 表示对象只能作为兼容类型、合格版本、签名或未签名版本、包含其中之一的聚合或联合访问,或字符类型。对于float 对象,uint32_t 不是这些。转换指针本身是可以的(如果没有对齐问题,这也可能导致标准未定义的行为),但通过该指针访问对象将违反 6.5 7.
    猜你喜欢
    • 2013-07-02
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多