是否有用于圆形功能的 ARM Neon 指令?
Are there are ARM Neon instructions for round function?
我正在尝试使用 ARM Neon 内部函数实现轮函数。
这个函数看起来像这样:
float roundf(float x) {
return signbit(x) ? ceil(x - 0.5) : floor(x + 0.5);
}
有没有办法使用 Neon 内在函数来做到这一点?如果没有,如何使用Neon intrinsics来实现这个功能?
已编辑
计算两个浮点数的乘积后,调用roundf(在armv7和armv8上)。
我的编译器是 clang。
这可以通过 vrndaq_f32
完成:https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]&q=vrndaq_f32 for armv8.
如何在 armv7 上执行此操作?
已编辑
我的实现
// input: float32x4_t arg
float32x4_t vector_zero = vdupq_n_f32(0.f);
float32x4_t neg_half = vdupq_n_f32(-0.5f);
float32x4_t pos_half = vdupq_n_f32(0.5f);
uint32x4_t mask = vcgeq_f32(arg, vector_zero);
uint32x4_t mask_neg = vandq_u32(mask, neg_half);
uint32x4_t mask_pos = vandq_u32(mask, pos_half);
arg = vaddq_f32(arg, (float32x4_t)mask_pos);
arg = vaddq_f32(arg, (float32x4_t)mask_neg);
int32x4_t arg_int32 = vcvtq_s32_f32(arg);
arg = vcvtq_f32_s32(arg_int32);
有没有更好的实现方式?
确定您真正想要的 哪种 舍入形式很重要。请参阅 Wikipedia 了解有多少舍入选项。
从您的代码片段中,您要求 commercial 或 symmetric 舍入,这是从零舍入的关系。对于 ARMv8 / ARM64,vrndaq_f32
应该这样做。
The SSE4 _mm_round_ps
and ARMv8 ARM-NEON vrndnq_f32
do bankers rounding i.e. round-to-nearest (even).
您的解决方案在周期计数和寄存器利用率方面都非常昂贵。
如果-(2^30) <= arg < (2^30)
,您可以执行以下操作:
int32x4_t argi = vcvtq_n_s32_f32(arg, 1);
argi = vsraq_n_s32(argi, argi, 31);
argi = vrshrq_n_s32(argi, 1);
arg = vcvtq_f32_s32(argi);
除了 arg
本身不需要任何其他寄存器,只需 4 条廉价指令即可完成。它适用于 aarch32
和 aarch64
我正在尝试使用 ARM Neon 内部函数实现轮函数。
这个函数看起来像这样:
float roundf(float x) {
return signbit(x) ? ceil(x - 0.5) : floor(x + 0.5);
}
有没有办法使用 Neon 内在函数来做到这一点?如果没有,如何使用Neon intrinsics来实现这个功能?
已编辑
计算两个浮点数的乘积后,调用roundf(在armv7和armv8上)。
我的编译器是 clang。
这可以通过 vrndaq_f32
完成:https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]&q=vrndaq_f32 for armv8.
如何在 armv7 上执行此操作?
已编辑
我的实现
// input: float32x4_t arg
float32x4_t vector_zero = vdupq_n_f32(0.f);
float32x4_t neg_half = vdupq_n_f32(-0.5f);
float32x4_t pos_half = vdupq_n_f32(0.5f);
uint32x4_t mask = vcgeq_f32(arg, vector_zero);
uint32x4_t mask_neg = vandq_u32(mask, neg_half);
uint32x4_t mask_pos = vandq_u32(mask, pos_half);
arg = vaddq_f32(arg, (float32x4_t)mask_pos);
arg = vaddq_f32(arg, (float32x4_t)mask_neg);
int32x4_t arg_int32 = vcvtq_s32_f32(arg);
arg = vcvtq_f32_s32(arg_int32);
有没有更好的实现方式?
确定您真正想要的 哪种 舍入形式很重要。请参阅 Wikipedia 了解有多少舍入选项。
从您的代码片段中,您要求 commercial 或 symmetric 舍入,这是从零舍入的关系。对于 ARMv8 / ARM64,vrndaq_f32
应该这样做。
The SSE4
_mm_round_ps
and ARMv8 ARM-NEONvrndnq_f32
do bankers rounding i.e. round-to-nearest (even).
您的解决方案在周期计数和寄存器利用率方面都非常昂贵。
如果-(2^30) <= arg < (2^30)
,您可以执行以下操作:
int32x4_t argi = vcvtq_n_s32_f32(arg, 1);
argi = vsraq_n_s32(argi, argi, 31);
argi = vrshrq_n_s32(argi, 1);
arg = vcvtq_f32_s32(argi);
除了 arg
本身不需要任何其他寄存器,只需 4 条廉价指令即可完成。它适用于 aarch32
和 aarch64