summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorHowJmay <yuanyanghau@gmail.com>2021-05-01 11:20:20 +0800
committerHowJmay <yuanyanghau@gmail.com>2021-05-02 15:30:36 +0800
commit238f4e5984a4e668dac70a05b6b4f49dabf239ba (patch)
tree105caf852bb8e0e1a58f3defc2add0d6ff4f23a6 /numpy
parentc2dd42fda4d30d307aa4f38abf5536e18f58b639 (diff)
downloadnumpy-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.src14
-rw-r--r--numpy/core/src/common/simd/avx2/math.h19
-rw-r--r--numpy/core/src/common/simd/avx512/math.h17
-rw-r--r--numpy/core/src/common/simd/neon/math.h20
-rw-r--r--numpy/core/src/common/simd/sse/math.h19
-rw-r--r--numpy/core/src/common/simd/vsx/math.h9
-rw-r--r--numpy/core/tests/test_simd.py30
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()