1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00
Files
opencv/3rdparty/hal_rvv/hal_rvv_1p0/atan.hpp
T
Liutong HAN 6eaaaa410e Merge pull request #27056 from hanliutong:rvv-hal-copyright
[RVV HAL] Add copyright and replace '#pragma once'. #27056

Add copyright and in RVV HAL, since other companies or teams may join the development and add their copyright.

And the '#pragma once' are replaced.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
2025-03-15 17:25:31 +03:00

129 lines
4.0 KiB
C++

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level
// directory of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#ifndef OPENCV_HAL_RVV_ATAN_HPP_INCLUDED
#define OPENCV_HAL_RVV_ATAN_HPP_INCLUDED
#undef cv_hal_fastAtan32f
#define cv_hal_fastAtan32f cv::cv_hal_rvv::fast_atan_32
#undef cv_hal_fastAtan64f
#define cv_hal_fastAtan64f cv::cv_hal_rvv::fast_atan_64
#include <riscv_vector.h>
#include <cfloat>
namespace cv { namespace cv_hal_rvv {
namespace detail {
// ref: mathfuncs_core.simd.hpp
static constexpr float pi = CV_PI;
struct AtanParams
{
float p1, p3, p5, p7, angle_90;
};
static constexpr AtanParams atan_params_rad {
0.9997878412794807F,
-0.3258083974640975F,
0.1555786518463281F,
-0.04432655554792128F,
90.F * (pi / 180.F)};
static constexpr AtanParams atan_params_deg {
atan_params_rad.p1 * (180 / pi),
atan_params_rad.p3 * (180 / pi),
atan_params_rad.p5 * (180 / pi),
atan_params_rad.p7 * (180 / pi),
90.F};
template <typename VEC_T>
__attribute__((always_inline)) inline VEC_T
rvv_atan(VEC_T vy, VEC_T vx, size_t vl, const AtanParams& params)
{
const auto ax = __riscv_vfabs(vx, vl);
const auto ay = __riscv_vfabs(vy, vl);
// Reciprocal Estimate (vfrec7) is not accurate enough to pass the test of cartToPolar.
const auto c = __riscv_vfdiv(__riscv_vfmin(ax, ay, vl),
__riscv_vfadd(__riscv_vfmax(ax, ay, vl), FLT_EPSILON, vl),
vl);
const auto c2 = __riscv_vfmul(c, c, vl);
// Using vfmadd only results in about a 2% performance improvement, but it occupies 3 additional
// M4 registers. (Performance test on phase32f::VectorLength::1048576: time decreased
// from 5.952ms to 5.805ms on Muse Pi)
// Additionally, when registers are nearly fully utilized (though not yet exhausted), the
// compiler is likely to fail to optimize and may introduce slower memory access (e.g., in
// cv::cv_hal_rvv::fast_atan_64).
// Saving registers can also make this function more reusable in other contexts.
// Therefore, vfmadd is not used here.
auto a = __riscv_vfadd(__riscv_vfmul(c2, params.p7, vl), params.p5, vl);
a = __riscv_vfadd(__riscv_vfmul(c2, a, vl), params.p3, vl);
a = __riscv_vfadd(__riscv_vfmul(c2, a, vl), params.p1, vl);
a = __riscv_vfmul(a, c, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(ax, ay, vl), a, a, params.angle_90, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(vx, 0.F, vl), a, a, params.angle_90 * 2, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(vy, 0.F, vl), a, a, params.angle_90 * 4, vl);
return a;
}
} // namespace detail
inline int fast_atan_32(const float* y, const float* x, float* dst, size_t n, bool angle_in_deg)
{
auto atan_params = angle_in_deg ? detail::atan_params_deg : detail::atan_params_rad;
for (size_t vl = 0; n > 0; n -= vl)
{
vl = __riscv_vsetvl_e32m4(n);
auto vy = __riscv_vle32_v_f32m4(y, vl);
auto vx = __riscv_vle32_v_f32m4(x, vl);
auto a = detail::rvv_atan(vy, vx, vl, atan_params);
__riscv_vse32(dst, a, vl);
x += vl;
y += vl;
dst += vl;
}
return CV_HAL_ERROR_OK;
}
inline int fast_atan_64(const double* y, const double* x, double* dst, size_t n, bool angle_in_deg)
{
// this also uses float32 version, ref: mathfuncs_core.simd.hpp
auto atan_params = angle_in_deg ? detail::atan_params_deg : detail::atan_params_rad;
for (size_t vl = 0; n > 0; n -= vl)
{
vl = __riscv_vsetvl_e64m8(n);
auto vy = __riscv_vfncvt_f(__riscv_vle64_v_f64m8(y, vl), vl);
auto vx = __riscv_vfncvt_f(__riscv_vle64_v_f64m8(x, vl), vl);
auto a = detail::rvv_atan(vy, vx, vl, atan_params);
__riscv_vse64(dst, __riscv_vfwcvt_f(a, vl), vl);
x += vl;
y += vl;
dst += vl;
}
return CV_HAL_ERROR_OK;
}
}} // namespace cv::cv_hal_rvv
#endif //OPENCV_HAL_RVV_ATAN_HPP_INCLUDED