Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ENH: Add SIMD sin/cos implementation with numpy-simd-routines#29699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
seiko2plus wants to merge4 commits intonumpy:main
base:main
Choose a base branch
Loading
fromseiko2plus:brings_npsr
Open
Show file tree
Hide file tree
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
SIMD, TST: Apply Marten’s suggestions
- Extend the C++ doc scope to better explain precision control, which is chosen based on the data type.- Add test cases for sine/cosine facts—for example, `cos(0) == 1`.
  • Loading branch information
@seiko2plus
seiko2plus committedDec 19, 2025
commite16efa5be3354a1da5e4dbf0806ed7361a953394

Some comments aren't visible on the classic Files Changed page.

21 changes: 16 additions & 5 deletionsnumpy/_core/src/common/simd/simd.hpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -76,17 +76,25 @@ namespace sr = npsr::HWY_NAMESPACE;
/// Default precision configrations for NumPy SIMD Routines
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Might be good here to tell what low and high imply (or at least where to look it up)

// TODO: Allow user to configure the default precision at build time.
namespace detail {
using PreciseHigh = decltype(npsr::Precise{});
using PreciseLow = decltype(npsr::Precise{npsr::kLowAccuracy});
// `npsr::Precise` is a meta-RAII class responsible for managing the floating-point environment at runtime
// and holding compile-time configurations for intrinsic floating-point behavior.
// Default configurations are set to the highest IEEE compliance intent.
// For more information, see:
// https://github.com/numpy/numpy-simd-routines/blob/1acd14571b9f58072d1f7f17886945000d78b56a/npsr/precise.h#L93
// However, when float64 SIMD is not available or disabled, we define a dummy type to avoid
// clearing floating-point exceptions within its destructor.
struct PresiceDummy {};

template <typename T>
struct PreciseByType {};
template <>
struct PreciseByType<float> { using Type = PreciseLow; };
struct PreciseByType<float> {
using Type = decltype(npsr::Precise{npsr::kLowAccuracy});
};
template <>
struct PreciseByType<double> {
#if NPY_HWY_F64
using Type =PreciseHigh;
using Type =decltype(npsr::Precise{});
#else
// If float64 SIMD isn’t available, use a dummy type.
// The scalar path will run, but `Type` must still be defined.
Expand All@@ -96,9 +104,12 @@ struct PreciseByType<double> {
#endif
};
} // namespace detail

/// `npsr::Precise<...>` for the given type `T`.
/// If `T` is `float`, it uses the low-accuracy configuration by default.
/// If `T` is `double`, it uses the high-accuracy configuration by default(if float64 SIMD is available).
template <typename T>
using Precise = typename detail::PreciseByType<T>::Type;

#endif
#include "simd.inc.hpp"
} // namespace simd
Expand Down
48 changes: 48 additions & 0 deletionsnumpy/_core/tests/test_umath.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1592,6 +1592,54 @@ def test_sincos_overlaps(self, callable, dtype, stride):
callable(x[::stride], out=x[:M])
assert_equal(x[:M], y)

@pytest.mark.parametrize("func", [np.sin, np.cos])
@pytest.mark.parametrize("dtype", ["f", "d"])
def test_trig_facts(self, dtype, func):
atol, max_ulp = (1e-6, 3) if dtype == "f" else (1e-15, 1)
test_data = {
np.sin: [
(0, 0),
(np.pi, 0),
(-np.pi, 0),
(2 * np.pi, 0),
(-2 * np.pi, 0),
(np.pi / 2, 1),
(-np.pi / 2, -1),
(3 * np.pi / 2, -1),
(-3 * np.pi / 2, 1),
(np.pi / 6, 0.5),
(5 * np.pi / 6, 0.5),
(-np.pi / 6, -0.5),
(-5 * np.pi / 6, -0.5),
],
np.cos: [
(0, 1),
(np.pi, -1),
(-np.pi, -1),
(2 * np.pi, 1),
(-2 * np.pi, 1),
(np.pi / 2, 0),
(-np.pi / 2, 0),
(3 * np.pi / 2, 0),
(-3 * np.pi / 2, 0),
(np.pi / 3, 0.5),
(5 * np.pi / 3, 0.5),
(-np.pi / 3, 0.5),
(-5 * np.pi / 3, 0.5),
],
}[func]
for s_x, s_expected in test_data:
x = np.array([s_x] * (128 + 1), dtype=dtype)
result = func(x)
# Check that all results are identical, to catch issues with
# vectorization
assert np.all(result == result[0])
expected = np.array([s_expected] * (128 + 1), dtype=dtype)
if s_expected == 0:
assert_allclose(result, expected, atol=atol, rtol=0)
else:
assert_array_max_ulp(result, expected, maxulp=max_ulp)

@pytest.mark.parametrize('dt', ['e', 'f', 'd', 'g'])
def test_sqrt_values(self, dt):
with np.errstate(all='ignore'):
Expand Down
Loading

[8]ページ先頭

©2009-2026 Movatter.jp