diff options
author | HowJmay <yuanyanghau@gmail.com> | 2021-05-01 11:20:20 +0800 |
---|---|---|
committer | HowJmay <yuanyanghau@gmail.com> | 2021-05-02 15:30:36 +0800 |
commit | 238f4e5984a4e668dac70a05b6b4f49dabf239ba (patch) | |
tree | 105caf852bb8e0e1a58f3defc2add0d6ff4f23a6 /numpy | |
parent | c2dd42fda4d30d307aa4f38abf5536e18f58b639 (diff) | |
download | numpy-238f4e5984a4e668dac70a05b6b4f49dabf239ba.tar.gz |
ENH: Add min values comparison for floating point
Add the similar implementation for minimum value comparison.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/_simd/_simd.dispatch.c.src | 14 | ||||
-rw-r--r-- | numpy/core/src/common/simd/avx2/math.h | 19 | ||||
-rw-r--r-- | numpy/core/src/common/simd/avx512/math.h | 17 | ||||
-rw-r--r-- | numpy/core/src/common/simd/neon/math.h | 20 | ||||
-rw-r--r-- | numpy/core/src/common/simd/sse/math.h | 19 | ||||
-rw-r--r-- | numpy/core/src/common/simd/vsx/math.h | 9 | ||||
-rw-r--r-- | numpy/core/tests/test_simd.py | 30 |
7 files changed, 119 insertions, 9 deletions
diff --git a/numpy/core/src/_simd/_simd.dispatch.c.src b/numpy/core/src/_simd/_simd.dispatch.c.src index d5984009e..3e82c28a4 100644 --- a/numpy/core/src/_simd/_simd.dispatch.c.src +++ b/numpy/core/src/_simd/_simd.dispatch.c.src @@ -388,8 +388,11 @@ SIMD_IMPL_INTRIN_1(@intrin@_@sfx@, v@sfx@, v@sfx@) #endif #if @fp_only@ -SIMD_IMPL_INTRIN_2(max_@sfx@, v@sfx@, v@sfx@, v@sfx@) -SIMD_IMPL_INTRIN_2(maxp_@sfx@, v@sfx@, v@sfx@, v@sfx@) +/**begin repeat1 + * #intrin = max, maxp, min, minp# + */ +SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@) +/**end repeat1**/ #endif /*************************** @@ -613,8 +616,11 @@ SIMD_INTRIN_DEF(@intrin@_@sfx@) #endif #if @fp_only@ -SIMD_INTRIN_DEF(max_@sfx@) -SIMD_INTRIN_DEF(maxp_@sfx@) +/**begin repeat1 + * #intrin = max, maxp, min, minp# + */ +SIMD_INTRIN_DEF(@intrin@_@sfx@) +/**end repeat1**/ #endif /*************************** diff --git a/numpy/core/src/common/simd/avx2/math.h b/numpy/core/src/common/simd/avx2/math.h index 84ab024d0..19e770ebf 100644 --- a/numpy/core/src/common/simd/avx2/math.h +++ b/numpy/core/src/common/simd/avx2/math.h @@ -56,4 +56,23 @@ NPY_FINLINE npyv_f64 npyv_maxp_f64(npyv_f64 a, npyv_f64 b) return _mm256_blendv_pd(a, max, nn); } +// Minimum, natively mapping with no guarantees to handle NaN. +#define npyv_min_f32 _mm256_min_ps +#define npyv_min_f64 _mm256_min_pd +// Minimum, supports IEEE floating-point arithmetic (IEC 60559), +// - If one of the two vectors contains NaN, the equivalent element of the other vector is set +// - Only if both corresponded elements are NaN, NaN is set. +NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b) +{ + __m256 nn = _mm256_cmp_ps(b, b, _CMP_ORD_Q); + __m256 min = _mm256_min_ps(a, b); + return _mm256_blendv_ps(a, min, nn); +} +NPY_FINLINE npyv_f64 npyv_minp_f64(npyv_f64 a, npyv_f64 b) +{ + __m256d nn = _mm256_cmp_pd(b, b, _CMP_ORD_Q); + __m256d min = _mm256_min_pd(a, b); + return _mm256_blendv_pd(a, min, nn); +} + #endif diff --git a/numpy/core/src/common/simd/avx512/math.h b/numpy/core/src/common/simd/avx512/math.h index 668362298..da94faaeb 100644 --- a/numpy/core/src/common/simd/avx512/math.h +++ b/numpy/core/src/common/simd/avx512/math.h @@ -63,4 +63,21 @@ NPY_FINLINE npyv_f64 npyv_maxp_f64(npyv_f64 a, npyv_f64 b) return _mm512_mask_max_pd(a, nn, a, b); } +// Minimum, natively mapping with no guarantees to handle NaN. +#define npyv_min_f32 _mm512_min_ps +#define npyv_min_f64 _mm512_min_pd +// Minimum, supports IEEE floating-point arithmetic (IEC 60559), +// - If one of the two vectors contains NaN, the equivalent element of the other vector is set +// - Only if both corresponded elements are NaN, NaN is set. +NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b) +{ + __mmask16 nn = _mm512_cmp_ps_mask(b, b, _CMP_ORD_Q); + return _mm512_mask_min_ps(a, nn, a, b); +} +NPY_FINLINE npyv_f64 npyv_minp_f64(npyv_f64 a, npyv_f64 b) +{ + __mmask8 nn = _mm512_cmp_pd_mask(b, b, _CMP_ORD_Q); + return _mm512_mask_min_pd(a, nn, a, b); +} + #endif diff --git a/numpy/core/src/common/simd/neon/math.h b/numpy/core/src/common/simd/neon/math.h index 09b7bbc9e..c99ef3299 100644 --- a/numpy/core/src/common/simd/neon/math.h +++ b/numpy/core/src/common/simd/neon/math.h @@ -103,4 +103,24 @@ NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a) #define npyv_maxp_f64 vmaxnmq_f64 #endif // NPY_SIMD_F64 +// Minimum, natively mapping with no guarantees to handle NaN. +#define npyv_min_f32 vminq_f32 +#define npyv_min_f64 vminq_f64 +// Minimum, supports IEEE floating-point arithmetic (IEC 60559), +// - If one of the two vectors contains NaN, the equivalent element of the other vector is set +// - Only if both corresponded elements are NaN, NaN is set. +#ifdef NPY_HAVE_ASIMD + #define npyv_minp_f32 vminnmq_f32 +#else + NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b) + { + npyv_u32 nn_a = vceqq_f32(a, a); + npyv_u32 nn_b = vceqq_f32(b, b); + return vminq_f32(vbslq_f32(nn_a, a, b), vbslq_f32(nn_b, b, a)); + } +#endif +#if NPY_SIMD_F64 + #define npyv_minp_f64 vminnmq_f64 +#endif // NPY_SIMD_F64 + #endif // _NPY_SIMD_SSE_MATH_H diff --git a/numpy/core/src/common/simd/sse/math.h b/numpy/core/src/common/simd/sse/math.h index 15e9f7e44..e43c41167 100644 --- a/numpy/core/src/common/simd/sse/math.h +++ b/numpy/core/src/common/simd/sse/math.h @@ -56,4 +56,23 @@ NPY_FINLINE npyv_f64 npyv_maxp_f64(npyv_f64 a, npyv_f64 b) return npyv_select_f64(_mm_castpd_si128(nn), max, a); } +// Minimum, natively mapping with no guarantees to handle NaN. +#define npyv_min_f32 _mm_min_ps +#define npyv_min_f64 _mm_min_pd +// Minimum, supports IEEE floating-point arithmetic (IEC 60559), +// - If one of the two vectors contains NaN, the equivalent element of the other vector is set +// - Only if both corresponded elements are NaN, NaN is set. +NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b) +{ + __m128 nn = _mm_cmpord_ps(b, b); + __m128 min = _mm_min_ps(a, b); + return npyv_select_f32(_mm_castps_si128(nn), min, a); +} +NPY_FINLINE npyv_f64 npyv_minp_f64(npyv_f64 a, npyv_f64 b) +{ + __m128d nn = _mm_cmpord_pd(b, b); + __m128d min = _mm_min_pd(a, b); + return npyv_select_f64(_mm_castpd_si128(nn), min, a); +} + #endif diff --git a/numpy/core/src/common/simd/vsx/math.h b/numpy/core/src/common/simd/vsx/math.h index 11bacd703..7c5301032 100644 --- a/numpy/core/src/common/simd/vsx/math.h +++ b/numpy/core/src/common/simd/vsx/math.h @@ -42,4 +42,13 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a) #define npyv_maxp_f32 vec_max #define npyv_maxp_f64 vec_max +// Minimum, natively mapping with no guarantees to handle NaN. +#define npyv_min_f32 vec_min +#define npyv_min_f64 vec_min +// Minimum, supports IEEE floating-point arithmetic (IEC 60559), +// - If one of the two vectors contains NaN, the equivalent element of the other vector is set +// - Only if both corresponded elements are NaN, NaN is set. +#define npyv_minp_f32 vec_min +#define npyv_minp_f64 vec_min + #endif // _NPY_SIMD_VSX_MATH_H diff --git a/numpy/core/tests/test_simd.py b/numpy/core/tests/test_simd.py index fb7dd88cf..6c1575971 100644 --- a/numpy/core/tests/test_simd.py +++ b/numpy/core/tests/test_simd.py @@ -317,11 +317,6 @@ class _SIMD_FP(_Test_Utility): assert square == data_square def test_max(self): - """ - Test intrinics: - npyv_max_##SFX - npyv_maxp_##SFX - """ data_a = self._data() data_b = self._data(self.nlanes) vdata_a, vdata_b = self.load(data_a), self.load(data_b) @@ -346,6 +341,31 @@ class _SIMD_FP(_Test_Utility): _max = self.max(vdata_a, vdata_b) assert _max == data_max + def test_min(self): + data_a = self._data() + data_b = self._data(self.nlanes) + vdata_a, vdata_b = self.load(data_a), self.load(data_b) + data_min = [min(a, b) for a, b in zip(data_a, data_b)] + _min = self.min(vdata_a, vdata_b) + assert _min == data_min + minp = self.minp(vdata_a, vdata_b) + assert minp == data_min + # test IEEE standards + pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan() + min_cases = ((nan, nan, nan), (nan, 10, 10), (10, nan, 10), + (pinf, pinf, pinf), (pinf, 10, 10), (10, pinf, 10), + (ninf, ninf, ninf), (ninf, 10, ninf), (10, ninf, ninf)) + for case_operand1, case_operand2, desired in min_cases: + data_min = [desired]*self.nlanes + vdata_a = self.setall(case_operand1) + vdata_b = self.setall(case_operand2) + minp = self.minp(vdata_a, vdata_b) + assert minp == pytest.approx(data_min, nan_ok=True) + if nan in (case_operand1, case_operand2, desired): + continue + _min = self.min(vdata_a, vdata_b) + assert _min == data_min + def test_reciprocal(self): pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan() data = self._data() |