ARM NEON 上的 float16_t 舍入

问题描述 投票:0回答:1

我正在使用 SSE 实现 X64 的 ARM float16_t 模拟;这个想法是在两个平台上都有位精确的值。我基本上完成了实现,除了一件事之外,我无法针对一组特定的输入值正确模拟 float16_t 上的 fma 操作。如下(此示例适用于 ARM,因为它可以在 ARM 和 X64 上重现):

#include <arm_fp16.h>
#include <iostream>

#pragma GCC diagnostic ignored "-Wfloat-equal"

float fma_explicit(float a, float b, float c) {
    float result;
    asm volatile(
        "fmadd %s0, %s1, %s2, %s3" // result = a * b + c
        : "=w"(result)             // output
        : "w"(a), "w"(b), "w"(c)   // inputs
    );
    return result;
}

int main() {
    float16_t x = 56.84375f;
    float16_t y = 17.90625f;
    float16_t z = 0.07940673828125f;

    float16_t res = vfmah_f16(x, y, z);
    float16_t res_emulated = static_cast<float16_t>(fma_explicit(y, z, x));

    std::cout << "Float16 result         " << res << "\n";
    std::cout << "Float32 full precision " << fma_explicit(y, z, x) << "\n";
    std::cout << "Float32 emulated       " << res_emulated << "\n";

    if (res == res_emulated) {
      std::cout << "They are same\n";
    } else {
      std::cout << "They are different\n";
    }
}

这个想法非常简单:我通过使用 32 位浮点数来模拟 float16_t。为了模拟

vfmah_f16
,我在浮点数上使用 fmadd,并在最后一步中将结果转换回 float16_t。对于输入值的特定组合,程序打印:

Float16 result         58.2813
Float32 full precision 58.2656
Float32 emulated       58.25
They are different

我不明白这是 ARM 上的硬件问题还是预期行为。要运行上述程序,您需要支持 fp16 的 ARMv8.2 芯片。

arm ieee-754 half-precision-float
1个回答
0
投票

使用二进制作为有效数并使用撇号来标记二进制16和二进制32有效数的结束,17.90625•0.07940673828125 + 56.84375的精确值为:

1.1101001000'1000000000000'12•25

如您所见,该值高于

1.11010010002•25
1.11010010012•25
之间的中点,因此四舍五入到二进制 16 应产生更大的值,
1.11010010012•25
= 58.28125。

但是,当我们四舍五入到binary32时,它会在第二个撇号处四舍五入。该数字位于两个相邻的 32 位二进制值的中间,并四舍五入到偶数低位,因此结果为

1.1101001000'10000000000002•25
。现在这个值正好是两个二进制 16 值
1.11010010002•25
1.11010010012•25
之间的中间值。因此,当四舍五入到二进制 16 时,我们四舍五入到偶数低位,得到
1.11010010002•25
= 58.25。

这表明通过执行binary32 FMA并舍入到binary16来实现binary16 FMA是不正确的。 binary32 FMA 丢失了产生正确结果所需的信息。

© www.soinside.com 2019 - 2024. All rights reserved.