Пересобранный и видоизмененный conky для ОСГОС
This commit is contained in:
commit
3a48cf8c86
738 changed files with 217718 additions and 0 deletions
544
obj-x86_64-linux-gnu/3rdparty/Vc/avx_sorthelper_AVX.cpp
vendored
Normal file
544
obj-x86_64-linux-gnu/3rdparty/Vc/avx_sorthelper_AVX.cpp
vendored
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2011-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/avx/vector.h>
|
||||
#include <Vc/avx/debug.h>
|
||||
#include <Vc/avx/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
#ifdef Vc_IMPL_AVX2
|
||||
template <>
|
||||
Vc_CONST AVX2::short_v sorted<CurrentImplementation::current()>(AVX2::short_v x_)
|
||||
{
|
||||
// ab cd ef gh ij kl mn op
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮
|
||||
// ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮
|
||||
// ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮
|
||||
// 01 23 01 23 01 23 01 23
|
||||
// ⎮⎮ ⎮⎮ ╳ ⎮⎮ ⎮⎮ ╳
|
||||
// 01 23 32 10 01 23 32 10
|
||||
// ⎮⎝ ⎮⎝ ⎠⎮ ⎠⎮ ⎮⎝ ⎮⎝ ⎠⎮ ⎠⎮
|
||||
// ⎮ ╲⎮ ╳ ⎮╱ ⎮ ⎮ ╲⎮ ╳ ⎮╱ ⎮
|
||||
// ⎮ ╲╱ ╲╱ ⎮ ⎮ ╲╱ ╲╱ ⎮
|
||||
// ⎮ ╱╲ ╱╲ ⎮ ⎮ ╱╲ ╱╲ ⎮
|
||||
// ⎮ ╱⎮ ╳ ⎮╲ ⎮ ⎮ ╱⎮ ╳ ⎮╲ ⎮
|
||||
// ⎮⎛ ⎮⎛ ⎞⎮ ⎞⎮ ⎮⎛ ⎮⎛ ⎞⎮ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮
|
||||
// ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮
|
||||
// ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮
|
||||
// 01 23 01 23 01 23 01 23
|
||||
|
||||
// sort pairs (one min/max)
|
||||
auto x = AVX::lo128(x_.data());
|
||||
auto y = AVX::hi128(x_.data());
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
auto l = _mm_min_epi16(x, y);
|
||||
auto h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge left & right quads (two min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "8x2 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge quads into octs (three min/max)
|
||||
x = _mm_unpacklo_epi16(h, l);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
// Vc_DEBUG << "4x4 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X2, X3, X0, X1>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(h, l));
|
||||
y = Mem::permuteHi<X6, X7, X4, X5>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(l, h));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h) << " done?";
|
||||
|
||||
// merge octs into hexa (four min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "2x8 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi64(l, h);
|
||||
y = _mm_unpackhi_epi64(l, h);
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_castps_si128(Mem::permute<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(h), _mm_castsi128_ps(l))));
|
||||
y = _mm_castps_si128(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(l), _mm_castsi128_ps(h)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h);
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(
|
||||
Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
return AVX::concat(x, y);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::ushort_v sorted<CurrentImplementation::current()>(AVX2::ushort_v x_)
|
||||
{
|
||||
// sort pairs (one min/max)
|
||||
auto x = AVX::lo128(x_.data());
|
||||
auto y = AVX::hi128(x_.data());
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
auto l = _mm_min_epu16(x, y);
|
||||
auto h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge left & right quads (two min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "8x2 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge quads into octs (three min/max)
|
||||
x = _mm_unpacklo_epi16(h, l);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
// Vc_DEBUG << "4x4 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X2, X3, X0, X1>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(h, l));
|
||||
y = Mem::permuteHi<X6, X7, X4, X5>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(l, h));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h) << " done?";
|
||||
|
||||
// merge octs into hexa (four min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "2x8 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi64(l, h);
|
||||
y = _mm_unpackhi_epi64(l, h);
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_castps_si128(Mem::permute<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(h), _mm_castsi128_ps(l))));
|
||||
y = _mm_castps_si128(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(l), _mm_castsi128_ps(h)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h);
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(
|
||||
Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
return AVX::concat(x, y);
|
||||
}
|
||||
|
||||
template <> Vc_CONST AVX2::int_v sorted<CurrentImplementation::current()>(AVX2::int_v x_)
|
||||
{
|
||||
using namespace AVX;
|
||||
const __m256i hgfedcba = x_.data();
|
||||
const __m128i hgfe = hi128(hgfedcba);
|
||||
const __m128i dcba = lo128(hgfedcba);
|
||||
__m128i l = _mm_min_epi32(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128i h = _mm_max_epi32(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128i x = _mm_unpacklo_epi32(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128i y = _mm_unpackhi_epi32(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_epi32(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_epi32(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_epi32(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_epi32(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128i b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
__m128i a = _mm_unpackhi_epi64(x, y); // a3 >= a2 >= a1 >= a0
|
||||
|
||||
// _mm_extract_epi32 may return an unsigned int, breaking these comparisons.
|
||||
if (Vc_IS_UNLIKELY(static_cast<int>(_mm_extract_epi32(x, 2)) >= static_cast<int>(_mm_extract_epi32(y, 1)))) {
|
||||
return concat(Reg::permute<X0, X1, X2, X3>(b), a);
|
||||
} else if (Vc_IS_UNLIKELY(static_cast<int>(_mm_extract_epi32(x, 0)) >= static_cast<int>(_mm_extract_epi32(y, 3)))) {
|
||||
return concat(a, Reg::permute<X0, X1, X2, X3>(b));
|
||||
}
|
||||
|
||||
// merge
|
||||
l = _mm_min_epi32(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_epi32(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_epi32(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_epi32(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_epi32(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2) ↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_epi32(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2) ↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return concat(_mm_unpacklo_epi32(l, h), _mm_unpackhi_epi32(l, h));
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::uint_v sorted<CurrentImplementation::current()>(AVX2::uint_v x_)
|
||||
{
|
||||
using namespace AVX;
|
||||
const __m256i hgfedcba = x_.data();
|
||||
const __m128i hgfe = hi128(hgfedcba);
|
||||
const __m128i dcba = lo128(hgfedcba);
|
||||
__m128i l = _mm_min_epu32(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128i h = _mm_max_epu32(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128i x = _mm_unpacklo_epi32(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128i y = _mm_unpackhi_epi32(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_epu32(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_epu32(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_epu32(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_epu32(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128i b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
__m128i a = _mm_unpackhi_epi64(x, y); // a3 >= a2 >= a1 >= a0
|
||||
|
||||
if (Vc_IS_UNLIKELY(extract_epu32<2>(x) >= extract_epu32<1>(y))) {
|
||||
return concat(Reg::permute<X0, X1, X2, X3>(b), a);
|
||||
} else if (Vc_IS_UNLIKELY(extract_epu32<0>(x) >= extract_epu32<3>(y))) {
|
||||
return concat(a, Reg::permute<X0, X1, X2, X3>(b));
|
||||
}
|
||||
|
||||
// merge
|
||||
l = _mm_min_epu32(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_epu32(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_epu32(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_epu32(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_epu32(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2) ↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_epu32(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2) ↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return concat(_mm_unpacklo_epi32(l, h), _mm_unpackhi_epi32(l, h));
|
||||
}
|
||||
#endif // AVX2
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::float_v sorted<CurrentImplementation::current()>(AVX2::float_v x_)
|
||||
{
|
||||
__m256 hgfedcba = x_.data();
|
||||
const __m128 hgfe = AVX::hi128(hgfedcba);
|
||||
const __m128 dcba = AVX::lo128(hgfedcba);
|
||||
__m128 l = _mm_min_ps(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128 h = _mm_max_ps(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128 x = _mm_unpacklo_ps(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128 y = _mm_unpackhi_ps(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_ps(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_ps(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_ps(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_ps(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128 a = _mm_castpd_ps(_mm_unpackhi_pd(_mm_castps_pd(x), _mm_castps_pd(y))); // a3 >= a2 >= a1 >= a0
|
||||
__m128 b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
|
||||
// merge
|
||||
l = _mm_min_ps(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_ps(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_ps(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_ps(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_ps(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_ps(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_ps(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_ps(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_ps(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2),↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_ps(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2),↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return AVX::concat(_mm_unpacklo_ps(l, h), _mm_unpackhi_ps(l, h));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<> void SortHelper<double>::sort(__m256d &Vc_RESTRICT x, __m256d &Vc_RESTRICT y)
|
||||
{
|
||||
__m256d l = _mm256_min_pd(x, y); // ↓x3y3 ↓x2y2 ↓x1y1 ↓x0y0
|
||||
__m256d h = _mm256_max_pd(x, y); // ↑x3y3 ↑x2y2 ↑x1y1 ↑x0y0
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑x2y2 ↓x2y2 ↑x0y0 ↓x0y0
|
||||
y = _mm256_unpackhi_pd(l, h); // ↑x3y3 ↓x3y3 ↑x1y1 ↓x1y1
|
||||
l = _mm256_min_pd(x, y); // ↓(↑x2y2,↑x3y3) ↓x3x2y3y2 ↓(↑x0y0,↑x1y1) ↓x1x0y1y0
|
||||
h = _mm256_max_pd(x, y); // ↑x3x2y3y2 ↑(↓x2y2,↓x3y3) ↑x1x0y1y0 ↑(↓x0y0,↓x1y1)
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑(↓x2y2,↓x3y3) ↓x3x2y3y2 ↑(↓x0y0,↓x1y1) ↓x1x0y1y0
|
||||
y = _mm256_unpackhi_pd(h, l); // ↓(↑x2y2,↑x3y3) ↑x3x2y3y2 ↓(↑x0y0,↑x1y1) ↑x1x0y1y0
|
||||
l = _mm256_min_pd(x, y); // ↓(↑(↓x2y2,↓x3y3) ↓(↑x2y2,↑x3y3)) ↓x3x2y3y2 ↓(↑(↓x0y0,↓x1y1) ↓(↑x0y0,↑x1y1)) ↓x1x0y1y0
|
||||
h = _mm256_max_pd(x, y); // ↑(↑(↓x2y2,↓x3y3) ↓(↑x2y2,↑x3y3)) ↑x3x2y3y2 ↑(↑(↓x0y0,↓x1y1) ↓(↑x0y0,↑x1y1)) ↑x1x0y1y0
|
||||
__m256d a = Reg::permute<X2, X3, X1, X0>(Reg::permute128<X0, X1>(h, h)); // h0 h1 h3 h2
|
||||
__m256d b = Reg::permute<X2, X3, X1, X0>(l); // l2 l3 l1 l0
|
||||
|
||||
// a3 >= a2 >= b1 >= b0
|
||||
// b3 <= b2 <= a1 <= a0
|
||||
|
||||
// merge
|
||||
l = _mm256_min_pd(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm256_min_pd(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑a2b2 ↓a2b2 ↑a0b0 ↓a0b0
|
||||
y = _mm256_unpackhi_pd(l, h); // ↑a3b3 ↓a3b3 ↑a1b1 ↓a1b1
|
||||
l = _mm256_min_pd(x, y); // ↓(↑a2b2,↑a3b3) ↓a2b3 ↓(↑a0b0,↑a1b1) ↓a1b0
|
||||
h = _mm256_min_pd(x, y); // ↑a3b2 ↑(↓a2b2,↓a3b3) ↑a0b1 ↑(↓a0b0,↓a1b1)
|
||||
|
||||
x = Reg::permute128<Y0, X0>(l, h); // ↑a0b1 ↑(↓a0b0,↓a1b1) ↓(↑a0b0,↑a1b1) ↓a1b0
|
||||
y = Reg::permute128<Y1, X1>(l, h); // ↑a3b2 ↑(↓a2b2,↓a3b3) ↓(↑a2b2,↑a3b3) ↓a2b3
|
||||
l = _mm256_min_pd(x, y); // ↓(↑a0b1,↑a3b2) ↓(↑(↓a0b0,↓a1b1) ↑(↓a2b2,↓a3b3)) ↓(↑a0b0,↑a1b1,↑a2b2,↑a3b3) ↓b0b3
|
||||
h = _mm256_min_pd(x, y); // ↑a0a3 ↑(↓a0b0,↓a1b1,↓a2b2,↓a3b3) ↑(↓(↑a0b0,↑a1b1) ↓(↑a2b2,↑a3b3)) ↑(↓a1b0,↓a2b3)
|
||||
|
||||
x = _mm256_unpacklo_pd(l, h); // h2 l2 h0 l0
|
||||
y = _mm256_unpackhi_pd(l, h); // h3 l3 h1 l1
|
||||
}
|
||||
#endif
|
||||
template <>
|
||||
Vc_CONST AVX2::double_v sorted<CurrentImplementation::current()>(AVX2::double_v x_)
|
||||
{
|
||||
__m256d dcba = x_.data();
|
||||
/*
|
||||
* to find the second largest number find
|
||||
* max(min(max(ab),max(cd)), min(max(ad),max(bc)))
|
||||
* or
|
||||
* max(max(min(ab),min(cd)), min(max(ab),max(cd)))
|
||||
*
|
||||
const __m256d adcb = avx_cast<__m256d>(AVX::concat(_mm_alignr_epi8(avx_cast<__m128i>(dc), avx_cast<__m128i>(ba), 8), _mm_alignr_epi8(avx_cast<__m128i>(ba), avx_cast<__m128i>(dc), 8)));
|
||||
const __m256d l = _mm256_min_pd(dcba, adcb); // min(ad cd bc ab)
|
||||
const __m256d h = _mm256_max_pd(dcba, adcb); // max(ad cd bc ab)
|
||||
// max(h3, h1)
|
||||
// max(min(h0,h2), min(h3,h1))
|
||||
// min(max(l0,l2), max(l3,l1))
|
||||
// min(l3, l1)
|
||||
|
||||
const __m256d ll = _mm256_min_pd(h, Reg::permute128<X0, X1>(h, h)); // min(h3h1 h2h0 h1h3 h0h2)
|
||||
//const __m256d hh = _mm256_max_pd(h3 ll1_3 l1 l0, h1 ll0_2 l3 l2);
|
||||
const __m256d hh = _mm256_max_pd(
|
||||
Reg::permute128<X1, Y0>(_mm256_unpackhi_pd(ll, h), l),
|
||||
Reg::permute128<X0, Y1>(_mm256_blend_pd(h ll, 0x1), l));
|
||||
_mm256_min_pd(hh0, hh1
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// max(max(ac), max(bd))
|
||||
// max(max(min(ac),min(bd)), min(max(ac),max(bd)))
|
||||
// min(max(min(ac),min(bd)), min(max(ac),max(bd)))
|
||||
// min(min(ac), min(bd))
|
||||
__m128d l = _mm_min_pd(AVX::lo128(dcba), AVX::hi128(dcba)); // min(bd) min(ac)
|
||||
__m128d h = _mm_max_pd(AVX::lo128(dcba), AVX::hi128(dcba)); // max(bd) max(ac)
|
||||
__m128d h0_l0 = _mm_unpacklo_pd(l, h);
|
||||
__m128d h1_l1 = _mm_unpackhi_pd(l, h);
|
||||
l = _mm_min_pd(h0_l0, h1_l1);
|
||||
h = _mm_max_pd(h0_l0, h1_l1);
|
||||
return AVX::concat(
|
||||
_mm_min_pd(l, Reg::permute<X0, X0>(h)),
|
||||
_mm_max_pd(h, Reg::permute<X1, X1>(l))
|
||||
);
|
||||
// extract: 1 cycle
|
||||
// min/max: 4 cycles
|
||||
// unpacklo/hi: 2 cycles
|
||||
// min/max: 4 cycles
|
||||
// permute: 1 cycle
|
||||
// min/max: 4 cycles
|
||||
// insert: 1 cycle
|
||||
// ----------------------
|
||||
// total: 17 cycles
|
||||
|
||||
/*
|
||||
__m256d cdab = Reg::permute<X2, X3, X0, X1>(dcba);
|
||||
__m256d l = _mm256_min_pd(dcba, cdab);
|
||||
__m256d h = _mm256_max_pd(dcba, cdab);
|
||||
__m256d maxmin_ba = Reg::permute128<X0, Y0>(l, h);
|
||||
__m256d maxmin_dc = Reg::permute128<X1, Y1>(l, h);
|
||||
|
||||
l = _mm256_min_pd(maxmin_ba, maxmin_dc);
|
||||
h = _mm256_max_pd(maxmin_ba, maxmin_dc);
|
||||
|
||||
return _mm256_blend_pd(h, l, 0x55);
|
||||
*/
|
||||
|
||||
/*
|
||||
// a b c d
|
||||
// b a d c
|
||||
// sort pairs
|
||||
__m256d y, l, h;
|
||||
__m128d l2, h2;
|
||||
y = shuffle<X1, Y0, X3, Y2>(x, x);
|
||||
l = _mm256_min_pd(x, y); // min[ab ab cd cd]
|
||||
h = _mm256_max_pd(x, y); // max[ab ab cd cd]
|
||||
|
||||
// 1 of 2 is at [0]
|
||||
// 1 of 4 is at [1]
|
||||
// 1 of 4 is at [2]
|
||||
// 1 of 2 is at [3]
|
||||
|
||||
// don't be fooled by unpack here. It works differently for AVX pd than for SSE ps
|
||||
x = _mm256_unpacklo_pd(l, h); // l_ab h_ab l_cd h_cd
|
||||
l2 = _mm_min_pd(AVX::lo128(x), AVX::hi128(x)); // l_abcd l(h_ab hcd)
|
||||
h2 = _mm_max_pd(AVX::lo128(x), AVX::hi128(x)); // h(l_ab l_cd) h_abcd
|
||||
|
||||
// either it is:
|
||||
return AVX::concat(l2, h2);
|
||||
// or:
|
||||
// AVX::concat(_mm_unpacklo_pd(l2, h2), _mm_unpackhi_pd(l2, h2));
|
||||
|
||||
// I'd like to have four useful compares
|
||||
const __m128d dc = AVX::hi128(dcba);
|
||||
const __m128d ba = AVX::lo128(dcba);
|
||||
const __m256d adcb = avx_cast<__m256d>(AVX::concat(_mm_alignr_epi8(avx_cast<__m128i>(dc), avx_cast<__m128i>(ba), 8), _mm_alignr_epi8(avx_cast<__m128i>(ba), avx_cast<__m128i>(dc), 8)));
|
||||
|
||||
const int extraCmp = _mm_movemask_pd(_mm_cmpgt_pd(dc, ba));
|
||||
// 0x0: d <= b && c <= a
|
||||
// 0x1: d <= b && c > a
|
||||
// 0x2: d > b && c <= a
|
||||
// 0x3: d > b && c > a
|
||||
|
||||
switch (_mm256_movemask_pd(_mm256_cmpgt_pd(dcba, adcb))) {
|
||||
// impossible: 0x0, 0xf
|
||||
case 0x1: // a <= b && b <= c && c <= d && d > a
|
||||
// abcd
|
||||
return Reg::permute<X2, X3, X0, X1>(Reg::permute<X0, X1>(dcba, dcba));
|
||||
case 0x2: // a <= b && b <= c && c > d && d <= a
|
||||
// dabc
|
||||
return Reg::permute<X2, X3, X0, X1>(adcb);
|
||||
case 0x3: // a <= b && b <= c && c > d && d > a
|
||||
// a[bd]c
|
||||
if (extraCmp & 2) {
|
||||
// abdc
|
||||
return Reg::permute<X2, X3, X1, X0>(Reg::permute<X0, X1>(dcba, dcba));
|
||||
} else {
|
||||
// adbc
|
||||
return Reg::permute<X3, X2, X0, X1>(adcb);
|
||||
}
|
||||
case 0x4: // a <= b && b > c && c <= d && d <= a
|
||||
// cdab;
|
||||
return Reg::permute<X2, X3, X0, X1>(dcba);
|
||||
case 0x5: // a <= b && b > c && c <= d && d > a
|
||||
// [ac] < [bd]
|
||||
switch (extraCmp) {
|
||||
case 0x0: // d <= b && c <= a
|
||||
// cadb
|
||||
return shuffle<>(dcba, bcda);
|
||||
case 0x1: // d <= b && c > a
|
||||
case 0x2: // d > b && c <= a
|
||||
case 0x3: // d > b && c > a
|
||||
}
|
||||
case 0x6: // a <= b && b > c && c > d && d <= a
|
||||
// d[ac]b
|
||||
case 0x7: // a <= b && b > c && c > d && d > a
|
||||
// adcb;
|
||||
return permute<X1, X0, X3, X2>(permute128<X1, X0>(bcda, bcda));
|
||||
case 0x8: // a > b && b <= c && c <= d && d <= a
|
||||
return bcda;
|
||||
case 0x9: // a > b && b <= c && c <= d && d > a
|
||||
// b[ac]d;
|
||||
case 0xa: // a > b && b <= c && c > d && d <= a
|
||||
// [ac] > [bd]
|
||||
case 0xb: // a > b && b <= c && c > d && d > a
|
||||
// badc;
|
||||
return permute128<X1, X0>(dcba);
|
||||
case 0xc: // a > b && b > c && c <= d && d <= a
|
||||
// c[bd]a;
|
||||
case 0xd: // a > b && b > c && c <= d && d > a
|
||||
// cbad;
|
||||
return permute<X1, X0, X3, X2>(bcda);
|
||||
case 0xe: // a > b && b > c && c > d && d <= a
|
||||
return dcba;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
544
obj-x86_64-linux-gnu/3rdparty/Vc/avx_sorthelper_AVX2+FMA+BMI2.cpp
vendored
Normal file
544
obj-x86_64-linux-gnu/3rdparty/Vc/avx_sorthelper_AVX2+FMA+BMI2.cpp
vendored
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2011-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/avx/vector.h>
|
||||
#include <Vc/avx/debug.h>
|
||||
#include <Vc/avx/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
#ifdef Vc_IMPL_AVX2
|
||||
template <>
|
||||
Vc_CONST AVX2::short_v sorted<CurrentImplementation::current()>(AVX2::short_v x_)
|
||||
{
|
||||
// ab cd ef gh ij kl mn op
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮
|
||||
// ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮
|
||||
// ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮
|
||||
// 01 23 01 23 01 23 01 23
|
||||
// ⎮⎮ ⎮⎮ ╳ ⎮⎮ ⎮⎮ ╳
|
||||
// 01 23 32 10 01 23 32 10
|
||||
// ⎮⎝ ⎮⎝ ⎠⎮ ⎠⎮ ⎮⎝ ⎮⎝ ⎠⎮ ⎠⎮
|
||||
// ⎮ ╲⎮ ╳ ⎮╱ ⎮ ⎮ ╲⎮ ╳ ⎮╱ ⎮
|
||||
// ⎮ ╲╱ ╲╱ ⎮ ⎮ ╲╱ ╲╱ ⎮
|
||||
// ⎮ ╱╲ ╱╲ ⎮ ⎮ ╱╲ ╱╲ ⎮
|
||||
// ⎮ ╱⎮ ╳ ⎮╲ ⎮ ⎮ ╱⎮ ╳ ⎮╲ ⎮
|
||||
// ⎮⎛ ⎮⎛ ⎞⎮ ⎞⎮ ⎮⎛ ⎮⎛ ⎞⎮ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮ ⎮ ╳ ⎮
|
||||
// ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮ ⎮⎛ ⎞⎮
|
||||
// <> <> <> <> <> <> <> <>
|
||||
// ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑ ↓↑
|
||||
// ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮ ⎮⎝ ⎠⎮
|
||||
// ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮ ⎮ o ⎮
|
||||
// ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮ ⎮↓ ↑⎮
|
||||
// 01 23 01 23 01 23 01 23
|
||||
|
||||
// sort pairs (one min/max)
|
||||
auto x = AVX::lo128(x_.data());
|
||||
auto y = AVX::hi128(x_.data());
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
auto l = _mm_min_epi16(x, y);
|
||||
auto h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge left & right quads (two min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "8x2 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge quads into octs (three min/max)
|
||||
x = _mm_unpacklo_epi16(h, l);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
// Vc_DEBUG << "4x4 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X2, X3, X0, X1>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(h, l));
|
||||
y = Mem::permuteHi<X6, X7, X4, X5>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(l, h));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h) << " done?";
|
||||
|
||||
// merge octs into hexa (four min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "2x8 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi64(l, h);
|
||||
y = _mm_unpackhi_epi64(l, h);
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_castps_si128(Mem::permute<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(h), _mm_castsi128_ps(l))));
|
||||
y = _mm_castps_si128(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(l), _mm_castsi128_ps(h)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h);
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(
|
||||
Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epi16(x, y);
|
||||
h = _mm_max_epi16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
return AVX::concat(x, y);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::ushort_v sorted<CurrentImplementation::current()>(AVX2::ushort_v x_)
|
||||
{
|
||||
// sort pairs (one min/max)
|
||||
auto x = AVX::lo128(x_.data());
|
||||
auto y = AVX::hi128(x_.data());
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
auto l = _mm_min_epu16(x, y);
|
||||
auto h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge left & right quads (two min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "8x2 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
|
||||
// merge quads into octs (three min/max)
|
||||
x = _mm_unpacklo_epi16(h, l);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
// Vc_DEBUG << "4x4 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteLo<X2, X3, X0, X1>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(h, l));
|
||||
y = Mem::permuteHi<X6, X7, X4, X5>(Mem::blend<X0, X1, Y2, Y3, X4, X5, Y6, Y7>(l, h));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h));
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h) << " done?";
|
||||
|
||||
// merge octs into hexa (four min/max)
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(h, l);
|
||||
// Vc_DEBUG << "2x8 sorted xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi64(l, h);
|
||||
y = _mm_unpackhi_epi64(l, h);
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_castps_si128(Mem::permute<X1, X0, X3, X2>(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(h), _mm_castsi128_ps(l))));
|
||||
y = _mm_castps_si128(Mem::blend<X0, Y1, X2, Y3>(_mm_castsi128_ps(l), _mm_castsi128_ps(h)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(l, h);
|
||||
y = Mem::permuteLo<X1, X0, X3, X2>(
|
||||
Mem::permuteHi<X5, X4, X7, X6>(Mem::blend<X0, Y1, X2, Y3, X4, Y5, X6, Y7>(h, l)));
|
||||
// Vc_DEBUG << "xy: " << AVX::addType<short>(x) << AVX::addType<short>(y);
|
||||
l = _mm_min_epu16(x, y);
|
||||
h = _mm_max_epu16(x, y);
|
||||
// Vc_DEBUG << "lh: " << AVX::addType<short>(l) << AVX::addType<short>(h);
|
||||
x = _mm_unpacklo_epi16(l, h);
|
||||
y = _mm_unpackhi_epi16(l, h);
|
||||
return AVX::concat(x, y);
|
||||
}
|
||||
|
||||
template <> Vc_CONST AVX2::int_v sorted<CurrentImplementation::current()>(AVX2::int_v x_)
|
||||
{
|
||||
using namespace AVX;
|
||||
const __m256i hgfedcba = x_.data();
|
||||
const __m128i hgfe = hi128(hgfedcba);
|
||||
const __m128i dcba = lo128(hgfedcba);
|
||||
__m128i l = _mm_min_epi32(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128i h = _mm_max_epi32(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128i x = _mm_unpacklo_epi32(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128i y = _mm_unpackhi_epi32(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_epi32(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_epi32(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_epi32(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_epi32(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128i b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
__m128i a = _mm_unpackhi_epi64(x, y); // a3 >= a2 >= a1 >= a0
|
||||
|
||||
// _mm_extract_epi32 may return an unsigned int, breaking these comparisons.
|
||||
if (Vc_IS_UNLIKELY(static_cast<int>(_mm_extract_epi32(x, 2)) >= static_cast<int>(_mm_extract_epi32(y, 1)))) {
|
||||
return concat(Reg::permute<X0, X1, X2, X3>(b), a);
|
||||
} else if (Vc_IS_UNLIKELY(static_cast<int>(_mm_extract_epi32(x, 0)) >= static_cast<int>(_mm_extract_epi32(y, 3)))) {
|
||||
return concat(a, Reg::permute<X0, X1, X2, X3>(b));
|
||||
}
|
||||
|
||||
// merge
|
||||
l = _mm_min_epi32(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_epi32(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_epi32(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_epi32(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_epi32(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2) ↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_epi32(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2) ↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return concat(_mm_unpacklo_epi32(l, h), _mm_unpackhi_epi32(l, h));
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::uint_v sorted<CurrentImplementation::current()>(AVX2::uint_v x_)
|
||||
{
|
||||
using namespace AVX;
|
||||
const __m256i hgfedcba = x_.data();
|
||||
const __m128i hgfe = hi128(hgfedcba);
|
||||
const __m128i dcba = lo128(hgfedcba);
|
||||
__m128i l = _mm_min_epu32(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128i h = _mm_max_epu32(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128i x = _mm_unpacklo_epi32(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128i y = _mm_unpackhi_epi32(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_epu32(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_epu32(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_epu32(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_epu32(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128i b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
__m128i a = _mm_unpackhi_epi64(x, y); // a3 >= a2 >= a1 >= a0
|
||||
|
||||
if (Vc_IS_UNLIKELY(extract_epu32<2>(x) >= extract_epu32<1>(y))) {
|
||||
return concat(Reg::permute<X0, X1, X2, X3>(b), a);
|
||||
} else if (Vc_IS_UNLIKELY(extract_epu32<0>(x) >= extract_epu32<3>(y))) {
|
||||
return concat(a, Reg::permute<X0, X1, X2, X3>(b));
|
||||
}
|
||||
|
||||
// merge
|
||||
l = _mm_min_epu32(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_epu32(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_epu32(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_epu32(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_epi32(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_epi32(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_epu32(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2) ↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_epu32(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2) ↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return concat(_mm_unpacklo_epi32(l, h), _mm_unpackhi_epi32(l, h));
|
||||
}
|
||||
#endif // AVX2
|
||||
|
||||
template <>
|
||||
Vc_CONST AVX2::float_v sorted<CurrentImplementation::current()>(AVX2::float_v x_)
|
||||
{
|
||||
__m256 hgfedcba = x_.data();
|
||||
const __m128 hgfe = AVX::hi128(hgfedcba);
|
||||
const __m128 dcba = AVX::lo128(hgfedcba);
|
||||
__m128 l = _mm_min_ps(hgfe, dcba); // ↓hd ↓gc ↓fb ↓ea
|
||||
__m128 h = _mm_max_ps(hgfe, dcba); // ↑hd ↑gc ↑fb ↑ea
|
||||
|
||||
__m128 x = _mm_unpacklo_ps(l, h); // ↑fb ↓fb ↑ea ↓ea
|
||||
__m128 y = _mm_unpackhi_ps(l, h); // ↑hd ↓hd ↑gc ↓gc
|
||||
|
||||
l = _mm_min_ps(x, y); // ↓(↑fb,↑hd) ↓hfdb ↓(↑ea,↑gc) ↓geca
|
||||
h = _mm_max_ps(x, y); // ↑hfdb ↑(↓fb,↓hd) ↑geca ↑(↓ea,↓gc)
|
||||
|
||||
x = _mm_min_ps(l, Reg::permute<X2, X2, X0, X0>(h)); // 2(hfdb) 1(hfdb) 2(geca) 1(geca)
|
||||
y = _mm_max_ps(h, Reg::permute<X3, X3, X1, X1>(l)); // 4(hfdb) 3(hfdb) 4(geca) 3(geca)
|
||||
|
||||
__m128 a = _mm_castpd_ps(_mm_unpackhi_pd(_mm_castps_pd(x), _mm_castps_pd(y))); // a3 >= a2 >= a1 >= a0
|
||||
__m128 b = Reg::shuffle<Y0, Y1, X0, X1>(y, x); // b3 <= b2 <= b1 <= b0
|
||||
|
||||
// merge
|
||||
l = _mm_min_ps(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm_max_ps(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
a = _mm_unpacklo_ps(l, h); // ↑a1b1 ↓a1b1 ↑a0b0 ↓a0b0
|
||||
b = _mm_unpackhi_ps(l, h); // ↑a3b3 ↓a3b3 ↑a2b2 ↓a2b2
|
||||
l = _mm_min_ps(a, b); // ↓(↑a1b1,↑a3b3) ↓a1b3 ↓(↑a0b0,↑a2b2) ↓a0b2
|
||||
h = _mm_max_ps(a, b); // ↑a3b1 ↑(↓a1b1,↓a3b3) ↑a2b0 ↑(↓a0b0,↓a2b2)
|
||||
|
||||
a = _mm_unpacklo_ps(l, h); // ↑a2b0 ↓(↑a0b0,↑a2b2) ↑(↓a0b0,↓a2b2) ↓a0b2
|
||||
b = _mm_unpackhi_ps(l, h); // ↑a3b1 ↓(↑a1b1,↑a3b3) ↑(↓a1b1,↓a3b3) ↓a1b3
|
||||
l = _mm_min_ps(a, b); // ↓(↑a2b0,↑a3b1) ↓(↑a0b0,↑a2b2,↑a1b1,↑a3b3) ↓(↑(↓a0b0,↓a2b2),↑(↓a1b1,↓a3b3)) ↓a0b3
|
||||
h = _mm_max_ps(a, b); // ↑a3b0 ↑(↓(↑a0b0,↑a2b2),↓(↑a1b1,↑a3b3)) ↑(↓a0b0,↓a2b2,↓a1b1,↓a3b3) ↑(↓a0b2,↓a1b3)
|
||||
|
||||
return AVX::concat(_mm_unpacklo_ps(l, h), _mm_unpackhi_ps(l, h));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<> void SortHelper<double>::sort(__m256d &Vc_RESTRICT x, __m256d &Vc_RESTRICT y)
|
||||
{
|
||||
__m256d l = _mm256_min_pd(x, y); // ↓x3y3 ↓x2y2 ↓x1y1 ↓x0y0
|
||||
__m256d h = _mm256_max_pd(x, y); // ↑x3y3 ↑x2y2 ↑x1y1 ↑x0y0
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑x2y2 ↓x2y2 ↑x0y0 ↓x0y0
|
||||
y = _mm256_unpackhi_pd(l, h); // ↑x3y3 ↓x3y3 ↑x1y1 ↓x1y1
|
||||
l = _mm256_min_pd(x, y); // ↓(↑x2y2,↑x3y3) ↓x3x2y3y2 ↓(↑x0y0,↑x1y1) ↓x1x0y1y0
|
||||
h = _mm256_max_pd(x, y); // ↑x3x2y3y2 ↑(↓x2y2,↓x3y3) ↑x1x0y1y0 ↑(↓x0y0,↓x1y1)
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑(↓x2y2,↓x3y3) ↓x3x2y3y2 ↑(↓x0y0,↓x1y1) ↓x1x0y1y0
|
||||
y = _mm256_unpackhi_pd(h, l); // ↓(↑x2y2,↑x3y3) ↑x3x2y3y2 ↓(↑x0y0,↑x1y1) ↑x1x0y1y0
|
||||
l = _mm256_min_pd(x, y); // ↓(↑(↓x2y2,↓x3y3) ↓(↑x2y2,↑x3y3)) ↓x3x2y3y2 ↓(↑(↓x0y0,↓x1y1) ↓(↑x0y0,↑x1y1)) ↓x1x0y1y0
|
||||
h = _mm256_max_pd(x, y); // ↑(↑(↓x2y2,↓x3y3) ↓(↑x2y2,↑x3y3)) ↑x3x2y3y2 ↑(↑(↓x0y0,↓x1y1) ↓(↑x0y0,↑x1y1)) ↑x1x0y1y0
|
||||
__m256d a = Reg::permute<X2, X3, X1, X0>(Reg::permute128<X0, X1>(h, h)); // h0 h1 h3 h2
|
||||
__m256d b = Reg::permute<X2, X3, X1, X0>(l); // l2 l3 l1 l0
|
||||
|
||||
// a3 >= a2 >= b1 >= b0
|
||||
// b3 <= b2 <= a1 <= a0
|
||||
|
||||
// merge
|
||||
l = _mm256_min_pd(a, b); // ↓a3b3 ↓a2b2 ↓a1b1 ↓a0b0
|
||||
h = _mm256_min_pd(a, b); // ↑a3b3 ↑a2b2 ↑a1b1 ↑a0b0
|
||||
|
||||
x = _mm256_unpacklo_pd(l, h); // ↑a2b2 ↓a2b2 ↑a0b0 ↓a0b0
|
||||
y = _mm256_unpackhi_pd(l, h); // ↑a3b3 ↓a3b3 ↑a1b1 ↓a1b1
|
||||
l = _mm256_min_pd(x, y); // ↓(↑a2b2,↑a3b3) ↓a2b3 ↓(↑a0b0,↑a1b1) ↓a1b0
|
||||
h = _mm256_min_pd(x, y); // ↑a3b2 ↑(↓a2b2,↓a3b3) ↑a0b1 ↑(↓a0b0,↓a1b1)
|
||||
|
||||
x = Reg::permute128<Y0, X0>(l, h); // ↑a0b1 ↑(↓a0b0,↓a1b1) ↓(↑a0b0,↑a1b1) ↓a1b0
|
||||
y = Reg::permute128<Y1, X1>(l, h); // ↑a3b2 ↑(↓a2b2,↓a3b3) ↓(↑a2b2,↑a3b3) ↓a2b3
|
||||
l = _mm256_min_pd(x, y); // ↓(↑a0b1,↑a3b2) ↓(↑(↓a0b0,↓a1b1) ↑(↓a2b2,↓a3b3)) ↓(↑a0b0,↑a1b1,↑a2b2,↑a3b3) ↓b0b3
|
||||
h = _mm256_min_pd(x, y); // ↑a0a3 ↑(↓a0b0,↓a1b1,↓a2b2,↓a3b3) ↑(↓(↑a0b0,↑a1b1) ↓(↑a2b2,↑a3b3)) ↑(↓a1b0,↓a2b3)
|
||||
|
||||
x = _mm256_unpacklo_pd(l, h); // h2 l2 h0 l0
|
||||
y = _mm256_unpackhi_pd(l, h); // h3 l3 h1 l1
|
||||
}
|
||||
#endif
|
||||
template <>
|
||||
Vc_CONST AVX2::double_v sorted<CurrentImplementation::current()>(AVX2::double_v x_)
|
||||
{
|
||||
__m256d dcba = x_.data();
|
||||
/*
|
||||
* to find the second largest number find
|
||||
* max(min(max(ab),max(cd)), min(max(ad),max(bc)))
|
||||
* or
|
||||
* max(max(min(ab),min(cd)), min(max(ab),max(cd)))
|
||||
*
|
||||
const __m256d adcb = avx_cast<__m256d>(AVX::concat(_mm_alignr_epi8(avx_cast<__m128i>(dc), avx_cast<__m128i>(ba), 8), _mm_alignr_epi8(avx_cast<__m128i>(ba), avx_cast<__m128i>(dc), 8)));
|
||||
const __m256d l = _mm256_min_pd(dcba, adcb); // min(ad cd bc ab)
|
||||
const __m256d h = _mm256_max_pd(dcba, adcb); // max(ad cd bc ab)
|
||||
// max(h3, h1)
|
||||
// max(min(h0,h2), min(h3,h1))
|
||||
// min(max(l0,l2), max(l3,l1))
|
||||
// min(l3, l1)
|
||||
|
||||
const __m256d ll = _mm256_min_pd(h, Reg::permute128<X0, X1>(h, h)); // min(h3h1 h2h0 h1h3 h0h2)
|
||||
//const __m256d hh = _mm256_max_pd(h3 ll1_3 l1 l0, h1 ll0_2 l3 l2);
|
||||
const __m256d hh = _mm256_max_pd(
|
||||
Reg::permute128<X1, Y0>(_mm256_unpackhi_pd(ll, h), l),
|
||||
Reg::permute128<X0, Y1>(_mm256_blend_pd(h ll, 0x1), l));
|
||||
_mm256_min_pd(hh0, hh1
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// max(max(ac), max(bd))
|
||||
// max(max(min(ac),min(bd)), min(max(ac),max(bd)))
|
||||
// min(max(min(ac),min(bd)), min(max(ac),max(bd)))
|
||||
// min(min(ac), min(bd))
|
||||
__m128d l = _mm_min_pd(AVX::lo128(dcba), AVX::hi128(dcba)); // min(bd) min(ac)
|
||||
__m128d h = _mm_max_pd(AVX::lo128(dcba), AVX::hi128(dcba)); // max(bd) max(ac)
|
||||
__m128d h0_l0 = _mm_unpacklo_pd(l, h);
|
||||
__m128d h1_l1 = _mm_unpackhi_pd(l, h);
|
||||
l = _mm_min_pd(h0_l0, h1_l1);
|
||||
h = _mm_max_pd(h0_l0, h1_l1);
|
||||
return AVX::concat(
|
||||
_mm_min_pd(l, Reg::permute<X0, X0>(h)),
|
||||
_mm_max_pd(h, Reg::permute<X1, X1>(l))
|
||||
);
|
||||
// extract: 1 cycle
|
||||
// min/max: 4 cycles
|
||||
// unpacklo/hi: 2 cycles
|
||||
// min/max: 4 cycles
|
||||
// permute: 1 cycle
|
||||
// min/max: 4 cycles
|
||||
// insert: 1 cycle
|
||||
// ----------------------
|
||||
// total: 17 cycles
|
||||
|
||||
/*
|
||||
__m256d cdab = Reg::permute<X2, X3, X0, X1>(dcba);
|
||||
__m256d l = _mm256_min_pd(dcba, cdab);
|
||||
__m256d h = _mm256_max_pd(dcba, cdab);
|
||||
__m256d maxmin_ba = Reg::permute128<X0, Y0>(l, h);
|
||||
__m256d maxmin_dc = Reg::permute128<X1, Y1>(l, h);
|
||||
|
||||
l = _mm256_min_pd(maxmin_ba, maxmin_dc);
|
||||
h = _mm256_max_pd(maxmin_ba, maxmin_dc);
|
||||
|
||||
return _mm256_blend_pd(h, l, 0x55);
|
||||
*/
|
||||
|
||||
/*
|
||||
// a b c d
|
||||
// b a d c
|
||||
// sort pairs
|
||||
__m256d y, l, h;
|
||||
__m128d l2, h2;
|
||||
y = shuffle<X1, Y0, X3, Y2>(x, x);
|
||||
l = _mm256_min_pd(x, y); // min[ab ab cd cd]
|
||||
h = _mm256_max_pd(x, y); // max[ab ab cd cd]
|
||||
|
||||
// 1 of 2 is at [0]
|
||||
// 1 of 4 is at [1]
|
||||
// 1 of 4 is at [2]
|
||||
// 1 of 2 is at [3]
|
||||
|
||||
// don't be fooled by unpack here. It works differently for AVX pd than for SSE ps
|
||||
x = _mm256_unpacklo_pd(l, h); // l_ab h_ab l_cd h_cd
|
||||
l2 = _mm_min_pd(AVX::lo128(x), AVX::hi128(x)); // l_abcd l(h_ab hcd)
|
||||
h2 = _mm_max_pd(AVX::lo128(x), AVX::hi128(x)); // h(l_ab l_cd) h_abcd
|
||||
|
||||
// either it is:
|
||||
return AVX::concat(l2, h2);
|
||||
// or:
|
||||
// AVX::concat(_mm_unpacklo_pd(l2, h2), _mm_unpackhi_pd(l2, h2));
|
||||
|
||||
// I'd like to have four useful compares
|
||||
const __m128d dc = AVX::hi128(dcba);
|
||||
const __m128d ba = AVX::lo128(dcba);
|
||||
const __m256d adcb = avx_cast<__m256d>(AVX::concat(_mm_alignr_epi8(avx_cast<__m128i>(dc), avx_cast<__m128i>(ba), 8), _mm_alignr_epi8(avx_cast<__m128i>(ba), avx_cast<__m128i>(dc), 8)));
|
||||
|
||||
const int extraCmp = _mm_movemask_pd(_mm_cmpgt_pd(dc, ba));
|
||||
// 0x0: d <= b && c <= a
|
||||
// 0x1: d <= b && c > a
|
||||
// 0x2: d > b && c <= a
|
||||
// 0x3: d > b && c > a
|
||||
|
||||
switch (_mm256_movemask_pd(_mm256_cmpgt_pd(dcba, adcb))) {
|
||||
// impossible: 0x0, 0xf
|
||||
case 0x1: // a <= b && b <= c && c <= d && d > a
|
||||
// abcd
|
||||
return Reg::permute<X2, X3, X0, X1>(Reg::permute<X0, X1>(dcba, dcba));
|
||||
case 0x2: // a <= b && b <= c && c > d && d <= a
|
||||
// dabc
|
||||
return Reg::permute<X2, X3, X0, X1>(adcb);
|
||||
case 0x3: // a <= b && b <= c && c > d && d > a
|
||||
// a[bd]c
|
||||
if (extraCmp & 2) {
|
||||
// abdc
|
||||
return Reg::permute<X2, X3, X1, X0>(Reg::permute<X0, X1>(dcba, dcba));
|
||||
} else {
|
||||
// adbc
|
||||
return Reg::permute<X3, X2, X0, X1>(adcb);
|
||||
}
|
||||
case 0x4: // a <= b && b > c && c <= d && d <= a
|
||||
// cdab;
|
||||
return Reg::permute<X2, X3, X0, X1>(dcba);
|
||||
case 0x5: // a <= b && b > c && c <= d && d > a
|
||||
// [ac] < [bd]
|
||||
switch (extraCmp) {
|
||||
case 0x0: // d <= b && c <= a
|
||||
// cadb
|
||||
return shuffle<>(dcba, bcda);
|
||||
case 0x1: // d <= b && c > a
|
||||
case 0x2: // d > b && c <= a
|
||||
case 0x3: // d > b && c > a
|
||||
}
|
||||
case 0x6: // a <= b && b > c && c > d && d <= a
|
||||
// d[ac]b
|
||||
case 0x7: // a <= b && b > c && c > d && d > a
|
||||
// adcb;
|
||||
return permute<X1, X0, X3, X2>(permute128<X1, X0>(bcda, bcda));
|
||||
case 0x8: // a > b && b <= c && c <= d && d <= a
|
||||
return bcda;
|
||||
case 0x9: // a > b && b <= c && c <= d && d > a
|
||||
// b[ac]d;
|
||||
case 0xa: // a > b && b <= c && c > d && d <= a
|
||||
// [ac] > [bd]
|
||||
case 0xb: // a > b && b <= c && c > d && d > a
|
||||
// badc;
|
||||
return permute128<X1, X0>(dcba);
|
||||
case 0xc: // a > b && b > c && c <= d && d <= a
|
||||
// c[bd]a;
|
||||
case 0xd: // a > b && b > c && c <= d && d > a
|
||||
// cbad;
|
||||
return permute<X1, X0, X3, X2>(bcda);
|
||||
case 0xe: // a > b && b > c && c > d && d <= a
|
||||
return dcba;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_AVX.cpp
vendored
Normal file
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_AVX.cpp
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/sse/vector.h>
|
||||
#include <Vc/sse/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template <>
|
||||
Vc_CONST SSE::short_v sorted<CurrentImplementation::current()>(SSE::short_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::ushort_v sorted<CurrentImplementation::current()>(SSE::ushort_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::int_v sorted<CurrentImplementation::current()>(SSE::int_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
/*
|
||||
// in 16,67% of the cases the merge can be replaced by an append
|
||||
|
||||
// x = [a b c d]
|
||||
// y = [c d a b]
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
__m128i l = SSE::min_epi32(x, y); // min[ac bd ac bd]
|
||||
__m128i h = SSE::max_epi32(x, y); // max[ac bd ac bd]
|
||||
if (IS_UNLIKELY(_mm_cvtsi128_si32(h) <= l[1])) { // l[0] < h[0] < l[1] < h[1]
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
// h[0] > l[1]
|
||||
*/
|
||||
|
||||
// sort pairs
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epi32(x, y);
|
||||
__m128i h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::uint_v sorted<CurrentImplementation::current()>(SSE::uint_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epu32(x, y);
|
||||
__m128i h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::float_v sorted<CurrentImplementation::current()>(SSE::float_v x_)
|
||||
{
|
||||
__m128 x = x_.data();
|
||||
__m128 y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128 l = _mm_min_ps(x, y);
|
||||
__m128 h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_unpackhi_ps(h, l);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_movehl_ps(x, x);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
return _mm_unpacklo_ps(l, h);
|
||||
// X __m128 k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(0, 1, 1, 0));
|
||||
// X return SSE::blendv_ps(x, y, k);
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_AVX2+FMA+BMI2.cpp
vendored
Normal file
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_AVX2+FMA+BMI2.cpp
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/sse/vector.h>
|
||||
#include <Vc/sse/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template <>
|
||||
Vc_CONST SSE::short_v sorted<CurrentImplementation::current()>(SSE::short_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::ushort_v sorted<CurrentImplementation::current()>(SSE::ushort_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::int_v sorted<CurrentImplementation::current()>(SSE::int_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
/*
|
||||
// in 16,67% of the cases the merge can be replaced by an append
|
||||
|
||||
// x = [a b c d]
|
||||
// y = [c d a b]
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
__m128i l = SSE::min_epi32(x, y); // min[ac bd ac bd]
|
||||
__m128i h = SSE::max_epi32(x, y); // max[ac bd ac bd]
|
||||
if (IS_UNLIKELY(_mm_cvtsi128_si32(h) <= l[1])) { // l[0] < h[0] < l[1] < h[1]
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
// h[0] > l[1]
|
||||
*/
|
||||
|
||||
// sort pairs
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epi32(x, y);
|
||||
__m128i h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::uint_v sorted<CurrentImplementation::current()>(SSE::uint_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epu32(x, y);
|
||||
__m128i h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::float_v sorted<CurrentImplementation::current()>(SSE::float_v x_)
|
||||
{
|
||||
__m128 x = x_.data();
|
||||
__m128 y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128 l = _mm_min_ps(x, y);
|
||||
__m128 h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_unpackhi_ps(h, l);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_movehl_ps(x, x);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
return _mm_unpacklo_ps(l, h);
|
||||
// X __m128 k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(0, 1, 1, 0));
|
||||
// X return SSE::blendv_ps(x, y, k);
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_SSE2.cpp
vendored
Normal file
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_SSE2.cpp
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/sse/vector.h>
|
||||
#include <Vc/sse/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template <>
|
||||
Vc_CONST SSE::short_v sorted<CurrentImplementation::current()>(SSE::short_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::ushort_v sorted<CurrentImplementation::current()>(SSE::ushort_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::int_v sorted<CurrentImplementation::current()>(SSE::int_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
/*
|
||||
// in 16,67% of the cases the merge can be replaced by an append
|
||||
|
||||
// x = [a b c d]
|
||||
// y = [c d a b]
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
__m128i l = SSE::min_epi32(x, y); // min[ac bd ac bd]
|
||||
__m128i h = SSE::max_epi32(x, y); // max[ac bd ac bd]
|
||||
if (IS_UNLIKELY(_mm_cvtsi128_si32(h) <= l[1])) { // l[0] < h[0] < l[1] < h[1]
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
// h[0] > l[1]
|
||||
*/
|
||||
|
||||
// sort pairs
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epi32(x, y);
|
||||
__m128i h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::uint_v sorted<CurrentImplementation::current()>(SSE::uint_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epu32(x, y);
|
||||
__m128i h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::float_v sorted<CurrentImplementation::current()>(SSE::float_v x_)
|
||||
{
|
||||
__m128 x = x_.data();
|
||||
__m128 y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128 l = _mm_min_ps(x, y);
|
||||
__m128 h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_unpackhi_ps(h, l);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_movehl_ps(x, x);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
return _mm_unpacklo_ps(l, h);
|
||||
// X __m128 k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(0, 1, 1, 0));
|
||||
// X return SSE::blendv_ps(x, y, k);
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_SSE4_1.cpp
vendored
Normal file
202
obj-x86_64-linux-gnu/3rdparty/Vc/sse_sorthelper_SSE4_1.cpp
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
#include <Vc/sse/vector.h>
|
||||
#include <Vc/sse/macros.h>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
template <>
|
||||
Vc_CONST SSE::short_v sorted<CurrentImplementation::current()>(SSE::short_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = _mm_min_epi16(x, y);
|
||||
hi = _mm_max_epi16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::ushort_v sorted<CurrentImplementation::current()>(SSE::ushort_v x_)
|
||||
{
|
||||
__m128i lo, hi, y, x = x_.data();
|
||||
// sort pairs
|
||||
y = Mem::permute<X1, X0, X3, X2, X5, X4, X7, X6>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, hi);
|
||||
|
||||
// merge left and right quads
|
||||
y = Mem::permute<X3, X2, X1, X0, X7, X6, X5, X4>(x);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xcc>(lo, hi);
|
||||
y = _mm_srli_si128(x, 2);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
x = SSE::blend_epi16<0xaa>(lo, _mm_slli_si128(hi, 2));
|
||||
|
||||
// merge quads into octs
|
||||
y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
y = _mm_shufflelo_epi16(y, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
x = _mm_unpacklo_epi16(lo, hi);
|
||||
y = _mm_srli_si128(x, 8);
|
||||
lo = SSE::min_epu16(x, y);
|
||||
hi = SSE::max_epu16(x, y);
|
||||
|
||||
return _mm_unpacklo_epi16(lo, hi);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::int_v sorted<CurrentImplementation::current()>(SSE::int_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
/*
|
||||
// in 16,67% of the cases the merge can be replaced by an append
|
||||
|
||||
// x = [a b c d]
|
||||
// y = [c d a b]
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
__m128i l = SSE::min_epi32(x, y); // min[ac bd ac bd]
|
||||
__m128i h = SSE::max_epi32(x, y); // max[ac bd ac bd]
|
||||
if (IS_UNLIKELY(_mm_cvtsi128_si32(h) <= l[1])) { // l[0] < h[0] < l[1] < h[1]
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
// h[0] > l[1]
|
||||
*/
|
||||
|
||||
// sort pairs
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epi32(x, y);
|
||||
__m128i h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epi32(x, y);
|
||||
h = SSE::max_epi32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <> Vc_CONST SSE::uint_v sorted<CurrentImplementation::current()>(SSE::uint_v x_)
|
||||
{
|
||||
__m128i x = x_.data();
|
||||
__m128i y = _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128i l = SSE::min_epu32(x, y);
|
||||
__m128i h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi32(h, l);
|
||||
|
||||
// sort quads
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
x = _mm_unpacklo_epi32(l, h);
|
||||
y = _mm_unpackhi_epi64(x, x);
|
||||
|
||||
l = SSE::min_epu32(x, y);
|
||||
h = SSE::max_epu32(x, y);
|
||||
return _mm_unpacklo_epi32(l, h);
|
||||
}
|
||||
|
||||
template <>
|
||||
Vc_CONST SSE::float_v sorted<CurrentImplementation::current()>(SSE::float_v x_)
|
||||
{
|
||||
__m128 x = x_.data();
|
||||
__m128 y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128 l = _mm_min_ps(x, y);
|
||||
__m128 h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_unpackhi_ps(h, l);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
x = _mm_unpacklo_ps(l, h);
|
||||
y = _mm_movehl_ps(x, x);
|
||||
|
||||
l = _mm_min_ps(x, y);
|
||||
h = _mm_max_ps(x, y);
|
||||
return _mm_unpacklo_ps(l, h);
|
||||
// X __m128 k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
// X x = SSE::blendv_ps(x, y, k);
|
||||
// X y = _mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
// X k = _mm_cmpgt_ps(x, y);
|
||||
// X k = _mm_shuffle_ps(k, k, _MM_SHUFFLE(0, 1, 1, 0));
|
||||
// X return SSE::blendv_ps(x, y, k);
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Vc
|
||||
|
||||
// vim: foldmethod=marker
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+FMA.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+FMA.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+XOP+FMA.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+XOP+FMA.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+XOP+FMA4.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX+XOP+FMA4.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX2+FMA+BMI2.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_AVX2+FMA+BMI2.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE+XOP+FMA.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE+XOP+FMA.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE+XOP+FMA4.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE+XOP+FMA4.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE2.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE2.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE3.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE3.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE4_1.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSE4_1.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSSE3.cpp
vendored
Normal file
614
obj-x86_64-linux-gnu/3rdparty/Vc/trigonometric_SSSE3.cpp
vendored
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
/* This file is part of the Vc library. {{{
|
||||
Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the names of contributing organizations nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
}}}*/
|
||||
|
||||
// enable bit operators for easier portable bit manipulation on floats
|
||||
#define Vc_ENABLE_FLOAT_BIT_OPERATORS 1
|
||||
|
||||
#include <Vc/vector.h>
|
||||
#if defined(Vc_IMPL_SSE) || defined(Vc_IMPL_AVX)
|
||||
#include <Vc/common/macros.h>
|
||||
//#include <Vc/IO>
|
||||
|
||||
namespace Vc_VERSIONED_NAMESPACE
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Vc::Vector;
|
||||
template <typename T, typename Abi>
|
||||
using Const = typename std::conditional<std::is_same<Abi, VectorAbi::Avx>::value,
|
||||
AVX::Const<T>, SSE::Const<T>>::type;
|
||||
|
||||
template <typename V>
|
||||
using best_int_v_for =
|
||||
typename std::conditional<(V::size() <= Vector<int, VectorAbi::Best<int>>::size()),
|
||||
Vector<int, VectorAbi::Best<int>>,
|
||||
SimdArray<int, V::size()>>::type;
|
||||
template <typename Abi> using float_int_v = best_int_v_for<Vector<float, Abi>>;
|
||||
template <typename Abi> using double_int_v = best_int_v_for<Vector<double, Abi>>;
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> cosSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant< 1, 0x500000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x360800, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x2AAAAB, -5>(); // 1/4!
|
||||
return y * (x2 * x2) - .5f * x2 + 1.f;
|
||||
// alternative (appears neither faster nor more precise):
|
||||
// return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> cosSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant< 1, 0xAC00000000000, -45>(); // 1/16!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x9394000000000, -37>(); // -1/14!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1EED8C0000000, -29>(); // 1/12!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x27E4FB7400000, -22>(); // -1/10!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0xA01A01A018000, -16>(); // 1/8!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x6C16C16C16C00, -10>(); // -1/6!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x5555555555554, -5>(); // 1/4!
|
||||
return (y * x2 - .5f) * x2 + 1.f;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<float, Abi> sinSeries(const Vector<float, Abi> &x)
|
||||
{
|
||||
const Vector<float, Abi> x2 = x * x;
|
||||
Vector<float, Abi> y;
|
||||
y = Vc::Detail::floatConstant<-1, 0x4E6000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::floatConstant< 1, 0x088880, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::floatConstant<-1, 0x2AAAAB, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE Vector<double, Abi> sinSeries(const Vector<double, Abi> &x)
|
||||
{
|
||||
// x = [0, 0.7854 = pi/4]
|
||||
// x² = [0, 0.6169 = pi²/8]
|
||||
const Vector<double, Abi> x2 = x * x;
|
||||
Vector<double, Abi> y;
|
||||
y = Vc::Detail::doubleConstant<-1, 0xACF0000000000, -41>(); // -1/15!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x6124400000000, -33>(); // 1/13!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xAE64567000000, -26>(); // -1/11!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x71DE3A5540000, -19>(); // 1/9!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0xA01A01A01A000, -13>(); // -1/7!
|
||||
y = y * x2 + Vc::Detail::doubleConstant< 1, 0x1111111111110, -7>(); // 1/5!
|
||||
y = y * x2 + Vc::Detail::doubleConstant<-1, 0x5555555555555, -3>(); // -1/3!
|
||||
return y * (x2 * x) + x;
|
||||
}
|
||||
|
||||
/**\internal
|
||||
* Fold \p x into [-¼π, ¼π] and remember the quadrant it came from:
|
||||
* quadrant 0: [-¼π, ¼π]
|
||||
* quadrant 1: [ ¼π, ¾π]
|
||||
* quadrant 2: [ ¾π, 1¼π]
|
||||
* quadrant 3: [1¼π, 1¾π]
|
||||
*
|
||||
* The algorithm determines `y` as the multiple `x - y * ¼π = [-¼π, ¼π]`. Using a bitmask,
|
||||
* `y` is reduced to `quadrant`. `y` can be calculated as
|
||||
* ```
|
||||
* y = trunc(x / ¼π);
|
||||
* y += fmod(y, 2);
|
||||
* ```
|
||||
* This can be simplified by moving the (implicit) division by 2 into the truncation
|
||||
* expression. The `+= fmod` effect can the be achieved by using rounding instead of
|
||||
* truncation:
|
||||
* `y = round(x / ½π) * 2`.
|
||||
* If precision allows, `2/π * x` is better (faster).
|
||||
*/
|
||||
template <class T, class Abi> struct folded {
|
||||
Vector<T, Abi> x, quadrant;
|
||||
};
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<float, Abi> foldInput(const Vector<float, Abi> &x)
|
||||
{
|
||||
using V = Vector<float, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<float, Abi>;
|
||||
|
||||
folded<float, Abi> r;
|
||||
r.x = abs(x);
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < C::_pi_4()))) {
|
||||
r.quadrant = 0;
|
||||
} else if (Vc_IS_LIKELY(all_of(r.x < 33 * C::_pi_4()))) {
|
||||
const float _2_over_pi = Vc::Detail::floatConstant<1, 0x22F983, -1>(); // ½π
|
||||
V y = round(r.x * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // y mod 4
|
||||
r.x -= y * Vc::Detail::floatConstant<1, 0x490fe0, 0>(); // pi/2
|
||||
r.x -= y * Vc::Detail::floatConstant<-1, 0x2bbbd3, -21>(); // pi/2 remainder
|
||||
} else {
|
||||
typedef SimdArray<double, V::size()> VD;
|
||||
VD xd = simd_cast<VD>(abs(r.x));
|
||||
constexpr double _2_over_pi =
|
||||
Vc::Detail::doubleConstant<1, 0x45F306DC9C883, -1>();
|
||||
VD y = round(xd * _2_over_pi);
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3); // = y mod 4
|
||||
constexpr double pi_over_2 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, 0>();
|
||||
r.x = simd_cast<V>(xd - y * pi_over_2);
|
||||
}
|
||||
//std::cout << std::hexfloat << r.x << ' ' << r.quadrant << std::defaultfloat << '\n';
|
||||
return r;
|
||||
|
||||
/*
|
||||
More alternatives to avoid double precision calculation follow. Their main problem
|
||||
is unfortunate rounding on intermediate values of x (after subtraction):
|
||||
|
||||
if (all_of(y <= 0x1000)) {
|
||||
// 0 <= x <= 0x1.921fb6p12
|
||||
// π/4 - 12 bits precision (12 zero bits):
|
||||
//const auto _pi_4_1 = Vc::Detail::floatConstant< 1, 0x491000, -1>();
|
||||
//const auto _pi_4_2 = Vc::Detail::floatConstant<-1, 0x157000, -19>();
|
||||
//const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x6F4B9F, -32>();
|
||||
x -= y * C::_pi_4_hi();
|
||||
x -= y * C::_pi_4_rem1();
|
||||
x -= y * C::_pi_4_rem2();
|
||||
} else { //if (all_of(y <= 0x10000)) {
|
||||
// consider y = 0x1.fffep+16 / x = 0x1.921e24p+16
|
||||
// critical input: 0x1.921fb6p+12 <= x <= 0x1.921fb6p+16
|
||||
// π/4 - 8 bits precision (16 zero bits):
|
||||
const auto _pi_4_1 = Vc::Detail::floatConstant<+1, 0x490000, -1>();
|
||||
const auto _pi_4_2 = Vc::Detail::floatConstant<+1, 0x7E0000, -13>();
|
||||
const auto _pi_4_3 = Vc::Detail::floatConstant<-1, 0x2C0000, -22>();
|
||||
const auto _pi_4_4 = Vc::Detail::floatConstant<+1, 0x085A31, -31>();
|
||||
x -= y * _pi_4_1; // (x -= 0x1.91fe6ep+16) -> 0x1.fb6000p+4
|
||||
x -= y * _pi_4_2; // (x -= 0x1.fbfe04p+4) -> -0x1.3c0800p-6
|
||||
x -= y * _pi_4_3; // (x -= 0x1.57fea8p-5) -> 0x1.bf5a80p-9
|
||||
x -= y * _pi_4_4; // (x -= 0x1.10b352p-14) -> 0x1.b6e4e6p-9
|
||||
x.setQnan(y > 0x10000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <typename Abi>
|
||||
static Vc_ALWAYS_INLINE folded<double, Abi> foldInput(const Vector<double, Abi> &x)
|
||||
{
|
||||
using V = Vector<double, Abi>;
|
||||
using IV = best_int_v_for<V>;
|
||||
using C = Const<double, Abi> ;
|
||||
|
||||
folded<double, Abi> r;
|
||||
r.x = abs(x);
|
||||
constexpr double pi_over_4 = Vc::Detail::doubleConstant<1, 0x921FB54442D18, -1>();
|
||||
if (Vc_IS_UNLIKELY(all_of(r.x < pi_over_4))) {
|
||||
r.quadrant = 0;
|
||||
return r;
|
||||
}
|
||||
const V y = round(r.x / (2 * pi_over_4));
|
||||
r.quadrant = simd_cast<V>(simd_cast<IV>(y) & 3);
|
||||
|
||||
if (Vc_IS_LIKELY(all_of(r.x < 1025 * pi_over_4))) {
|
||||
// x - y * pi/2, y uses no more than 11 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x921FB54443000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<-1, 0x73DCB3B39A000, -43>();
|
||||
r.x -= y * Vc::Detail::doubleConstant< 1, 0x45C06E0E68948, -86>();
|
||||
} else if (Vc_IS_LIKELY(all_of(y <= Vc::Detail::doubleConstant<1, 0, 30>()))) {
|
||||
// x - y * pi/2, y uses no more than 29 mantissa bits
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x921FB40000000, 0>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x4442D00000000, -24>();
|
||||
r.x -= y * Vc::Detail::doubleConstant<1, 0x8469898CC5170, -48>();
|
||||
} else {
|
||||
// x - y * pi/2, y may require all mantissa bits
|
||||
const V y_hi = y & C::highMask(26);
|
||||
const V y_lo = y - y_hi;
|
||||
const auto _pi_2_1 = Vc::Detail::doubleConstant<1, 0x921FB50000000, 0>();
|
||||
const auto _pi_2_2 = Vc::Detail::doubleConstant<1, 0x110B460000000, -26>();
|
||||
const auto _pi_2_3 = Vc::Detail::doubleConstant<1, 0x1A62630000000, -54>();
|
||||
const auto _pi_2_4 = Vc::Detail::doubleConstant<1, 0x8A2E03707344A, -81>();
|
||||
/*
|
||||
std::cout << std::hexfloat;
|
||||
std::cout
|
||||
<< y_hi << '\n'
|
||||
<< y_lo << '\n'
|
||||
<< _pi_2_1 << '\n'
|
||||
<< _pi_2_2 << '\n'
|
||||
<< _pi_2_3 << '\n'
|
||||
<< y_hi * _pi_2_1 << '\n'
|
||||
<< y_hi * _pi_2_2 << '\n'
|
||||
<< y_hi * _pi_2_3 << '\n'
|
||||
<< y * _pi_2_4 << '\n'
|
||||
<< y_lo * _pi_2_1 << '\n'
|
||||
<< y_lo * _pi_2_2 << '\n'
|
||||
<< y_lo * _pi_2_3 << '\n';
|
||||
std::cout << std::defaultfloat;
|
||||
*/
|
||||
r.x = r.x
|
||||
- y_hi * _pi_2_1
|
||||
- max(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- min(y_hi * _pi_2_2, y_lo * _pi_2_1)
|
||||
- max(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- min(y_hi * _pi_2_3, y_lo * _pi_2_2)
|
||||
- max(y * _pi_2_4, y_lo * _pi_2_3)
|
||||
- min(y * _pi_2_4, y_lo * _pi_2_3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
constexpr double signmask = -0.;
|
||||
constexpr float signmaskf = -0.f;
|
||||
} // anonymous namespace
|
||||
|
||||
/*
|
||||
* algorithm for sine and cosine:
|
||||
*
|
||||
* The result can be calculated with sine or cosine depending on the π/4 section the input is
|
||||
* in.
|
||||
* sine ≈ x + x³
|
||||
* cosine ≈ 1 - x²
|
||||
*
|
||||
* sine:
|
||||
* Map -x to x and invert the output
|
||||
* Extend precision of x - n * π/4 by calculating
|
||||
* ((x - n * p1) - n * p2) - n * p3 (p1 + p2 + p3 = π/4)
|
||||
*
|
||||
* Calculate Taylor series with tuned coefficients.
|
||||
* Fix sign.
|
||||
*/
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | sinSeries
|
||||
// 1 | cosSeries
|
||||
// 2 | sinSeries, sign flip
|
||||
// 3 | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sin(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 527449))) {
|
||||
return simd_cast<V>(sin(simd_cast<Vc::double_v, 0>(x)),
|
||||
sin(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::double_v &x)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | effect
|
||||
// 0 | cosSeries, +
|
||||
// 1 | sinSeries, -
|
||||
// 2 | cosSeries, -
|
||||
// 3 | sinSeries, +
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::cos(const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
return simd_cast<V>(cos(simd_cast<Vc::double_v, 0>(x)),
|
||||
cos(simd_cast<Vc::double_v, 1>(x)));
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
return cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::double_v &x, Vc::double_v *s,
|
||||
Vc::double_v *c)
|
||||
{
|
||||
using V = Vc::double_v;
|
||||
const auto f = foldInput(x);
|
||||
// quadrant | cosine | sine
|
||||
// 0 | cosSeries, + | sinSeries
|
||||
// 1 | sinSeries, - | cosSeries
|
||||
// 2 | cosSeries, - | sinSeries, sign flip
|
||||
// 3 | sinSeries, + | cosSeries, sign flip
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmask;
|
||||
const V cos_sign = ((0.5 - f.quadrant) & (f.quadrant - 2.5)) & signmask;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
void Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::sincos(const Vc::float_v &x, Vc::float_v *s,
|
||||
Vc::float_v *c)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
if (Vc_IS_UNLIKELY(any_of(abs(x) >= 393382))) {
|
||||
Vc::double_v s0, s1, c0, c1;
|
||||
sincos(simd_cast<Vc::double_v, 0>(x), &s0, &c0);
|
||||
sincos(simd_cast<Vc::double_v, 1>(x), &s1, &c1);
|
||||
*s = simd_cast<V>(s0, s1);
|
||||
*c = simd_cast<V>(c0, c1);
|
||||
return;
|
||||
}
|
||||
const auto f = foldInput(x);
|
||||
const V sin_sign = (x ^ (1 - f.quadrant)) & signmaskf;
|
||||
const V cos_sign = ((0.5f - f.quadrant) & (f.quadrant - 2.5f)) & signmaskf;
|
||||
|
||||
const V sin_s = sinSeries(f.x);
|
||||
const V cos_s = cosSeries(f.x);
|
||||
*s = sin_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, sin_s, cos_s);
|
||||
*c = cos_sign ^ iif(f.quadrant == 0 || f.quadrant == 2, cos_s, sin_s);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::asin(const Vc::float_v &_x)
|
||||
{
|
||||
typedef Vc::float_v V;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M &negative = _x < V::Zero();
|
||||
|
||||
const V &a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M &small = a < C::smallAsinInput();
|
||||
const M >_0_5 = a > C::_1_2();
|
||||
V x = a;
|
||||
V z = a * a;
|
||||
z(gt_0_5) = (V::One() - a) * C::_1_2();
|
||||
x(gt_0_5) = sqrt(z);
|
||||
z = ((((C::asinCoeff0(0) * z
|
||||
+ C::asinCoeff0(1)) * z
|
||||
+ C::asinCoeff0(2)) * z
|
||||
+ C::asinCoeff0(3)) * z
|
||||
+ C::asinCoeff0(4)) * z * x
|
||||
+ x;
|
||||
z(gt_0_5) = C::_pi_2() - (z + z);
|
||||
z(small) = a;
|
||||
z(negative) = -z;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::asin (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M negative = _x < V::Zero();
|
||||
|
||||
const V a = abs(_x);
|
||||
const M outOfRange = a > V::One();
|
||||
const M small = a < C::smallAsinInput();
|
||||
const M large = a > C::largeAsinInput();
|
||||
|
||||
V zz = V::One() - a;
|
||||
const V r = (((C::asinCoeff0(0) * zz + C::asinCoeff0(1)) * zz + C::asinCoeff0(2)) * zz +
|
||||
C::asinCoeff0(3)) * zz + C::asinCoeff0(4);
|
||||
const V s = (((zz + C::asinCoeff1(0)) * zz + C::asinCoeff1(1)) * zz +
|
||||
C::asinCoeff1(2)) * zz + C::asinCoeff1(3);
|
||||
V sqrtzz = sqrt(zz + zz);
|
||||
V z = C::_pi_4() - sqrtzz;
|
||||
z -= sqrtzz * (zz * r / s) - C::_pi_2_rem();
|
||||
z += C::_pi_4();
|
||||
|
||||
V a2 = a * a;
|
||||
const V p = ((((C::asinCoeff2(0) * a2 + C::asinCoeff2(1)) * a2 + C::asinCoeff2(2)) * a2 +
|
||||
C::asinCoeff2(3)) * a2 + C::asinCoeff2(4)) * a2 + C::asinCoeff2(5);
|
||||
const V q = ((((a2 + C::asinCoeff3(0)) * a2 + C::asinCoeff3(1)) * a2 +
|
||||
C::asinCoeff3(2)) * a2 + C::asinCoeff3(3)) * a2 + C::asinCoeff3(4);
|
||||
z(!large) = a * (a2 * p / q) + a;
|
||||
|
||||
z(negative) = -z;
|
||||
z(small) = _x;
|
||||
z.setQnan(outOfRange);
|
||||
|
||||
return z;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan(const Vc::float_v &_x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
V x = abs(_x);
|
||||
const M >_tan_3pi_8 = x > C::atanThrsHi();
|
||||
const M >_tan_pi_8 = x > C::atanThrsLo() && !gt_tan_3pi_8;
|
||||
V y = V::Zero();
|
||||
y(gt_tan_3pi_8) = C::_pi_2();
|
||||
y(gt_tan_pi_8) = C::_pi_4();
|
||||
x(gt_tan_3pi_8) = -V::One() / x;
|
||||
x(gt_tan_pi_8) = (x - V::One()) / (x + V::One());
|
||||
const V &x2 = x * x;
|
||||
y += (((C::atanP(0) * x2
|
||||
- C::atanP(1)) * x2
|
||||
+ C::atanP(2)) * x2
|
||||
- C::atanP(3)) * x2 * x
|
||||
+ x;
|
||||
y(_x < V::Zero()) = -y;
|
||||
y.setQnan(isnan(_x));
|
||||
return y;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan (const Vc::double_v &_x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
M sign = _x < V::Zero();
|
||||
V x = abs(_x);
|
||||
M finite = isfinite(_x);
|
||||
V ret = C::_pi_2();
|
||||
V y = V::Zero();
|
||||
const M large = x > C::atanThrsHi();
|
||||
const M gt_06 = x > C::atanThrsLo();
|
||||
V tmp = (x - V::One()) / (x + V::One());
|
||||
tmp(large) = -V::One() / x;
|
||||
x(gt_06) = tmp;
|
||||
y(gt_06) = C::_pi_4();
|
||||
y(large) = C::_pi_2();
|
||||
V z = x * x;
|
||||
const V p = (((C::atanP(0) * z + C::atanP(1)) * z + C::atanP(2)) * z + C::atanP(3)) * z + C::atanP(4);
|
||||
const V q = ((((z + C::atanQ(0)) * z + C::atanQ(1)) * z + C::atanQ(2)) * z + C::atanQ(3)) * z + C::atanQ(4);
|
||||
z = z * p / q;
|
||||
z = x * z + x;
|
||||
V morebits = C::_pi_2_rem();
|
||||
morebits(!large) *= C::_1_2();
|
||||
z(gt_06) += morebits;
|
||||
ret(finite) = y + z;
|
||||
ret(sign) = -ret;
|
||||
ret.setQnan(isnan(_x));
|
||||
return ret;
|
||||
}
|
||||
template <>
|
||||
template <>
|
||||
Vc::float_v Trigonometric<Vc::Detail::TrigonometricImplementation<
|
||||
Vc::CurrentImplementation::current()>>::atan2(const Vc::float_v &y,
|
||||
const Vc::float_v &x)
|
||||
{
|
||||
using V = Vc::float_v;
|
||||
typedef Const<float, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(C::_pi(), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
template<> template<> Vc::double_v Trigonometric<Vc::Detail::TrigonometricImplementation<Vc::CurrentImplementation::current()>>::atan2 (const Vc::double_v &y, const Vc::double_v &x) {
|
||||
typedef Vc::double_v V;
|
||||
typedef Const<double, V::abi> C;
|
||||
typedef V::Mask M;
|
||||
|
||||
const M xZero = x == V::Zero();
|
||||
const M yZero = y == V::Zero();
|
||||
const M xMinusZero = xZero && isnegative(x);
|
||||
const M yNeg = y < V::Zero();
|
||||
const M xInf = !isfinite(x);
|
||||
const M yInf = !isfinite(y);
|
||||
|
||||
V a = copysign(V(C::_pi()), y);
|
||||
a.setZero(x >= V::Zero());
|
||||
|
||||
// setting x to any finite value will have atan(y/x) return sign(y/x)*pi/2, just in case x is inf
|
||||
V _x = x;
|
||||
_x(yInf) = copysign(V::One(), x);
|
||||
|
||||
a += atan(y / _x);
|
||||
|
||||
// if x is +0 and y is +/-0 the result is +0
|
||||
a.setZero(xZero && yZero);
|
||||
|
||||
// for x = -0 we add/subtract pi to get the correct result
|
||||
a(xMinusZero) += copysign(C::_pi(), y);
|
||||
|
||||
// atan2(-Y, +/-0) = -pi/2
|
||||
a(xZero && yNeg) = -C::_pi_2();
|
||||
|
||||
// if both inputs are inf the output is +/- (3)pi/4
|
||||
a(xInf && yInf) += copysign(C::_pi_4(), x ^ ~y);
|
||||
|
||||
// correct the sign of y if the result is 0
|
||||
a(a == V::Zero()) = copysign(a, y);
|
||||
|
||||
// any NaN input will lead to NaN output
|
||||
a.setQnan(isnan(y) || isnan(x));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
obj-x86_64-linux-gnu/3rdparty/toluapp/toluapp
vendored
Executable file
BIN
obj-x86_64-linux-gnu/3rdparty/toluapp/toluapp
vendored
Executable file
Binary file not shown.
8
obj-x86_64-linux-gnu/build.h
Normal file
8
obj-x86_64-linux-gnu/build.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __BUILD_H
|
||||
#define __BUILD_H
|
||||
|
||||
/* Conky build info */
|
||||
|
||||
#define BUILD_ARCH "Linux x86_64"
|
||||
|
||||
#endif /* __BUILD_H */
|
||||
152
obj-x86_64-linux-gnu/config.h
Normal file
152
obj-x86_64-linux-gnu/config.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Auto-generated header for CMake. See config.h.in if you need to modify the
|
||||
* original.
|
||||
*/
|
||||
|
||||
#ifndef _conky_config_h_
|
||||
#define _conky_config_h_
|
||||
|
||||
/* #undef DEBUG */
|
||||
|
||||
#define SYSTEM_NAME "Linux"
|
||||
#define PACKAGE_NAME "conky"
|
||||
#define VERSION "1.21.3-pre-aa7de839"
|
||||
#define SYSTEM_CONFIG_FILE "/etc/conky/conky.conf"
|
||||
#define PACKAGE_LIBDIR "/usr/lib/conky"
|
||||
#define DEFAULTNETDEV "eno1"
|
||||
#define XDG_CONFIG_FILE "$HOME/.config/conky/conky.conf"
|
||||
#define CONFIG_FILE "$HOME/.conkyrc"
|
||||
#define LOCALE_DIR "/usr/share/locale"
|
||||
#define MAX_USER_TEXT_DEFAULT 16384
|
||||
#define DEFAULT_TEXT_BUFFER_SIZE 256
|
||||
#define MAX_NET_INTERFACES 256
|
||||
#define HTTPPORT 10080
|
||||
|
||||
#define BUILD_I18N 1
|
||||
|
||||
#define HAVE_SYS_STATFS_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_INOTIFY_H 1
|
||||
#define HAVE_DIRENT_H 1
|
||||
|
||||
#define HAVE_SOME_SOUNDCARD_H 1
|
||||
#define HAVE_LINUX_SOUNDCARD_H 1
|
||||
|
||||
#define HAVE_STRNDUP 1
|
||||
|
||||
/* #undef HAVE_FOPENCOOKIE */
|
||||
/* #undef HAVE_FUNOPEN */
|
||||
|
||||
/* #undef HAVE_PIPE2 */
|
||||
#define HAVE_O_CLOEXEC 1
|
||||
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
|
||||
#define HAVE_XCB 1
|
||||
/* #undef HAVE_XCB_ERRORS */
|
||||
|
||||
/* #undef BUILD_WAYLAND */
|
||||
|
||||
#define BUILD_X11 1
|
||||
|
||||
#define OWN_WINDOW 1
|
||||
|
||||
#define BUILD_MOUSE_EVENTS 1
|
||||
|
||||
#define BUILD_XDAMAGE 1
|
||||
|
||||
#define BUILD_XINERAMA 1
|
||||
|
||||
#define BUILD_XFT 1
|
||||
|
||||
#define BUILD_XSHAPE 1
|
||||
|
||||
#define BUILD_XFIXES 1
|
||||
|
||||
/* #undef BUILD_XINPUT */
|
||||
|
||||
#define BUILD_ARGB 1
|
||||
|
||||
#define BUILD_XDBE 1
|
||||
|
||||
#define BUILD_PORT_MONITORS 1
|
||||
|
||||
/* #undef BUILD_AUDACIOUS */
|
||||
|
||||
/* #undef NEW_AUDACIOUS_FOUND */
|
||||
|
||||
#define BUILD_MPD 1
|
||||
|
||||
/* #undef BUILD_MYSQL */
|
||||
|
||||
#define BUILD_MOC 1
|
||||
|
||||
/* #undef BUILD_NVIDIA */
|
||||
|
||||
/* #undef BUILD_XMMS2 */
|
||||
|
||||
#define BUILD_HDDTEMP 1
|
||||
|
||||
/* #undef BUILD_LIBXML2 */
|
||||
|
||||
/* #undef BUILD_CURL */
|
||||
|
||||
#define BUILD_IMLIB2 1
|
||||
|
||||
#define BUILD_MATH 1
|
||||
|
||||
#define BUILD_BUILTIN_CONFIG 1
|
||||
|
||||
#define BUILD_OLD_CONFIG 1
|
||||
|
||||
#define BUILD_NCURSES 1
|
||||
/* #undef LEAKFREE_NCURSES */
|
||||
|
||||
#define BUILD_APCUPSD 1
|
||||
|
||||
#define BUILD_IOSTATS 1
|
||||
|
||||
/* #undef BUILD_IPGFREQ */
|
||||
|
||||
/* #undef BUILD_WLAN */
|
||||
|
||||
/* #undef BUILD_ICAL */
|
||||
|
||||
/* #undef BUILD_IRC */
|
||||
|
||||
/* #undef BUILD_PULSEAUDIO */
|
||||
|
||||
/* #undef BUILD_INTEL_BACKLIGHT */
|
||||
|
||||
#define BUILD_IPV6 1
|
||||
|
||||
/* #undef BUILD_HTTP */
|
||||
|
||||
#define BUILD_GUI 1
|
||||
|
||||
/* #undef BUILD_ICONV */
|
||||
|
||||
/* #undef BUILD_LUA_CAIRO */
|
||||
|
||||
/* #undef BUILD_LUA_IMLIB2 */
|
||||
|
||||
/* #undef BUILD_LUA_RSVG */
|
||||
|
||||
#define BUILD_IBM 1
|
||||
|
||||
/* #undef BUILD_RSS */
|
||||
|
||||
#define BUILD_CMUS 1
|
||||
|
||||
/* #undef BUILD_JOURNAL */
|
||||
|
||||
/* #undef BUILD_HSV_GRADIENT */
|
||||
|
||||
#define BUILD_COLOUR_NAME_MAP 1
|
||||
|
||||
#define HAVE_STATFS64 1
|
||||
#ifndef HAVE_STATFS64
|
||||
#define statfs64 statfs
|
||||
#endif
|
||||
|
||||
#endif /* _conky_config_h_ */
|
||||
754
obj-x86_64-linux-gnu/data/color-names.gperf
Normal file
754
obj-x86_64-linux-gnu/data/color-names.gperf
Normal file
|
|
@ -0,0 +1,754 @@
|
|||
struct rgb { const char *name; uint8_t red; uint8_t green; uint8_t blue; };
|
||||
%%
|
||||
alice blue, 240, 248, 255
|
||||
AliceBlue, 240, 248, 255
|
||||
antique white, 250, 235, 215
|
||||
AntiqueWhite, 250, 235, 215
|
||||
AntiqueWhite1, 255, 239, 219
|
||||
AntiqueWhite2, 238, 223, 204
|
||||
AntiqueWhite3, 205, 192, 176
|
||||
AntiqueWhite4, 139, 131, 120
|
||||
aquamarine, 127, 255, 212
|
||||
aquamarine1, 127, 255, 212
|
||||
aquamarine2, 118, 238, 198
|
||||
aquamarine3, 102, 205, 170
|
||||
aquamarine4, 69, 139, 116
|
||||
azure, 240, 255, 255
|
||||
azure1, 240, 255, 255
|
||||
azure2, 224, 238, 238
|
||||
azure3, 193, 205, 205
|
||||
azure4, 131, 139, 139
|
||||
beige, 245, 245, 220
|
||||
bisque, 255, 228, 196
|
||||
bisque1, 255, 228, 196
|
||||
bisque2, 238, 213, 183
|
||||
bisque3, 205, 183, 158
|
||||
bisque4, 139, 125, 107
|
||||
black, 0, 0, 0
|
||||
blanched almond, 255, 235, 205
|
||||
BlanchedAlmond, 255, 235, 205
|
||||
blue, 0, 0, 255
|
||||
blue violet, 138, 43, 226
|
||||
blue1, 0, 0, 255
|
||||
blue2, 0, 0, 238
|
||||
blue3, 0, 0, 205
|
||||
blue4, 0, 0, 139
|
||||
BlueViolet, 138, 43, 226
|
||||
brown, 165, 42, 42
|
||||
brown1, 255, 64, 64
|
||||
brown2, 238, 59, 59
|
||||
brown3, 205, 51, 51
|
||||
brown4, 139, 35, 35
|
||||
burlywood, 222, 184, 135
|
||||
burlywood1, 255, 211, 155
|
||||
burlywood2, 238, 197, 145
|
||||
burlywood3, 205, 170, 125
|
||||
burlywood4, 139, 115, 85
|
||||
cadet blue, 95, 158, 160
|
||||
CadetBlue, 95, 158, 160
|
||||
CadetBlue1, 152, 245, 255
|
||||
CadetBlue2, 142, 229, 238
|
||||
CadetBlue3, 122, 197, 205
|
||||
CadetBlue4, 83, 134, 139
|
||||
chartreuse, 127, 255, 0
|
||||
chartreuse1, 127, 255, 0
|
||||
chartreuse2, 118, 238, 0
|
||||
chartreuse3, 102, 205, 0
|
||||
chartreuse4, 69, 139, 0
|
||||
chocolate, 210, 105, 30
|
||||
chocolate1, 255, 127, 36
|
||||
chocolate2, 238, 118, 33
|
||||
chocolate3, 205, 102, 29
|
||||
chocolate4, 139, 69, 19
|
||||
coral, 255, 127, 80
|
||||
coral1, 255, 114, 86
|
||||
coral2, 238, 106, 80
|
||||
coral3, 205, 91, 69
|
||||
coral4, 139, 62, 47
|
||||
cornflower blue, 100, 149, 237
|
||||
CornflowerBlue, 100, 149, 237
|
||||
cornsilk, 255, 248, 220
|
||||
cornsilk1, 255, 248, 220
|
||||
cornsilk2, 238, 232, 205
|
||||
cornsilk3, 205, 200, 177
|
||||
cornsilk4, 139, 136, 120
|
||||
cyan, 0, 255, 255
|
||||
cyan1, 0, 255, 255
|
||||
cyan2, 0, 238, 238
|
||||
cyan3, 0, 205, 205
|
||||
cyan4, 0, 139, 139
|
||||
dark blue, 0, 0, 139
|
||||
dark cyan, 0, 139, 139
|
||||
dark goldenrod, 184, 134, 11
|
||||
dark gray, 169, 169, 169
|
||||
dark green, 0, 100, 0
|
||||
dark grey, 169, 169, 169
|
||||
dark khaki, 189, 183, 107
|
||||
dark magenta, 139, 0, 139
|
||||
dark olive green, 85, 107, 47
|
||||
dark orange, 255, 140, 0
|
||||
dark orchid, 153, 50, 204
|
||||
dark red, 139, 0, 0
|
||||
dark salmon, 233, 150, 122
|
||||
dark sea green, 143, 188, 143
|
||||
dark slate blue, 72, 61, 139
|
||||
dark slate gray, 47, 79, 79
|
||||
dark slate grey, 47, 79, 79
|
||||
dark turquoise, 0, 206, 209
|
||||
dark violet, 148, 0, 211
|
||||
DarkBlue, 0, 0, 139
|
||||
DarkCyan, 0, 139, 139
|
||||
DarkGoldenrod, 184, 134, 11
|
||||
DarkGoldenrod1, 255, 185, 15
|
||||
DarkGoldenrod2, 238, 173, 14
|
||||
DarkGoldenrod3, 205, 149, 12
|
||||
DarkGoldenrod4, 139, 101, 8
|
||||
DarkGray, 169, 169, 169
|
||||
DarkGreen, 0, 100, 0
|
||||
DarkGrey, 169, 169, 169
|
||||
DarkKhaki, 189, 183, 107
|
||||
DarkMagenta, 139, 0, 139
|
||||
DarkOliveGreen, 85, 107, 47
|
||||
DarkOliveGreen1, 202, 255, 112
|
||||
DarkOliveGreen2, 188, 238, 104
|
||||
DarkOliveGreen3, 162, 205, 90
|
||||
DarkOliveGreen4, 110, 139, 61
|
||||
DarkOrange, 255, 140, 0
|
||||
DarkOrange1, 255, 127, 0
|
||||
DarkOrange2, 238, 118, 0
|
||||
DarkOrange3, 205, 102, 0
|
||||
DarkOrange4, 139, 69, 0
|
||||
DarkOrchid, 153, 50, 204
|
||||
DarkOrchid1, 191, 62, 255
|
||||
DarkOrchid2, 178, 58, 238
|
||||
DarkOrchid3, 154, 50, 205
|
||||
DarkOrchid4, 104, 34, 139
|
||||
DarkRed, 139, 0, 0
|
||||
DarkSalmon, 233, 150, 122
|
||||
DarkSeaGreen, 143, 188, 143
|
||||
DarkSeaGreen1, 193, 255, 193
|
||||
DarkSeaGreen2, 180, 238, 180
|
||||
DarkSeaGreen3, 155, 205, 155
|
||||
DarkSeaGreen4, 105, 139, 105
|
||||
DarkSlateBlue, 72, 61, 139
|
||||
DarkSlateGray, 47, 79, 79
|
||||
DarkSlateGray1, 151, 255, 255
|
||||
DarkSlateGray2, 141, 238, 238
|
||||
DarkSlateGray3, 121, 205, 205
|
||||
DarkSlateGray4, 82, 139, 139
|
||||
DarkSlateGrey, 47, 79, 79
|
||||
DarkTurquoise, 0, 206, 209
|
||||
DarkViolet, 148, 0, 211
|
||||
deep pink, 255, 20, 147
|
||||
deep sky blue, 0, 191, 255
|
||||
DeepPink, 255, 20, 147
|
||||
DeepPink1, 255, 20, 147
|
||||
DeepPink2, 238, 18, 137
|
||||
DeepPink3, 205, 16, 118
|
||||
DeepPink4, 139, 10, 80
|
||||
DeepSkyBlue, 0, 191, 255
|
||||
DeepSkyBlue1, 0, 191, 255
|
||||
DeepSkyBlue2, 0, 178, 238
|
||||
DeepSkyBlue3, 0, 154, 205
|
||||
DeepSkyBlue4, 0, 104, 139
|
||||
dim gray, 105, 105, 105
|
||||
dim grey, 105, 105, 105
|
||||
DimGray, 105, 105, 105
|
||||
DimGrey, 105, 105, 105
|
||||
dodger blue, 30, 144, 255
|
||||
DodgerBlue, 30, 144, 255
|
||||
DodgerBlue1, 30, 144, 255
|
||||
DodgerBlue2, 28, 134, 238
|
||||
DodgerBlue3, 24, 116, 205
|
||||
DodgerBlue4, 16, 78, 139
|
||||
firebrick, 178, 34, 34
|
||||
firebrick1, 255, 48, 48
|
||||
firebrick2, 238, 44, 44
|
||||
firebrick3, 205, 38, 38
|
||||
firebrick4, 139, 26, 26
|
||||
floral white, 255, 250, 240
|
||||
FloralWhite, 255, 250, 240
|
||||
forest green, 34, 139, 34
|
||||
ForestGreen, 34, 139, 34
|
||||
gainsboro, 220, 220, 220
|
||||
ghost white, 248, 248, 255
|
||||
GhostWhite, 248, 248, 255
|
||||
gold, 255, 215, 0
|
||||
gold1, 255, 215, 0
|
||||
gold2, 238, 201, 0
|
||||
gold3, 205, 173, 0
|
||||
gold4, 139, 117, 0
|
||||
goldenrod, 218, 165, 32
|
||||
goldenrod1, 255, 193, 37
|
||||
goldenrod2, 238, 180, 34
|
||||
goldenrod3, 205, 155, 29
|
||||
goldenrod4, 139, 105, 20
|
||||
gray, 190, 190, 190
|
||||
gray0, 0, 0, 0
|
||||
gray1, 3, 3, 3
|
||||
gray10, 26, 26, 26
|
||||
gray100, 255, 255, 255
|
||||
gray11, 28, 28, 28
|
||||
gray12, 31, 31, 31
|
||||
gray13, 33, 33, 33
|
||||
gray14, 36, 36, 36
|
||||
gray15, 38, 38, 38
|
||||
gray16, 41, 41, 41
|
||||
gray17, 43, 43, 43
|
||||
gray18, 46, 46, 46
|
||||
gray19, 48, 48, 48
|
||||
gray2, 5, 5, 5
|
||||
gray20, 51, 51, 51
|
||||
gray21, 54, 54, 54
|
||||
gray22, 56, 56, 56
|
||||
gray23, 59, 59, 59
|
||||
gray24, 61, 61, 61
|
||||
gray25, 64, 64, 64
|
||||
gray26, 66, 66, 66
|
||||
gray27, 69, 69, 69
|
||||
gray28, 71, 71, 71
|
||||
gray29, 74, 74, 74
|
||||
gray3, 8, 8, 8
|
||||
gray30, 77, 77, 77
|
||||
gray31, 79, 79, 79
|
||||
gray32, 82, 82, 82
|
||||
gray33, 84, 84, 84
|
||||
gray34, 87, 87, 87
|
||||
gray35, 89, 89, 89
|
||||
gray36, 92, 92, 92
|
||||
gray37, 94, 94, 94
|
||||
gray38, 97, 97, 97
|
||||
gray39, 99, 99, 99
|
||||
gray4, 10, 10, 10
|
||||
gray40, 102, 102, 102
|
||||
gray41, 105, 105, 105
|
||||
gray42, 107, 107, 107
|
||||
gray43, 110, 110, 110
|
||||
gray44, 112, 112, 112
|
||||
gray45, 115, 115, 115
|
||||
gray46, 117, 117, 117
|
||||
gray47, 120, 120, 120
|
||||
gray48, 122, 122, 122
|
||||
gray49, 125, 125, 125
|
||||
gray5, 13, 13, 13
|
||||
gray50, 127, 127, 127
|
||||
gray51, 130, 130, 130
|
||||
gray52, 133, 133, 133
|
||||
gray53, 135, 135, 135
|
||||
gray54, 138, 138, 138
|
||||
gray55, 140, 140, 140
|
||||
gray56, 143, 143, 143
|
||||
gray57, 145, 145, 145
|
||||
gray58, 148, 148, 148
|
||||
gray59, 150, 150, 150
|
||||
gray6, 15, 15, 15
|
||||
gray60, 153, 153, 153
|
||||
gray61, 156, 156, 156
|
||||
gray62, 158, 158, 158
|
||||
gray63, 161, 161, 161
|
||||
gray64, 163, 163, 163
|
||||
gray65, 166, 166, 166
|
||||
gray66, 168, 168, 168
|
||||
gray67, 171, 171, 171
|
||||
gray68, 173, 173, 173
|
||||
gray69, 176, 176, 176
|
||||
gray7, 18, 18, 18
|
||||
gray70, 179, 179, 179
|
||||
gray71, 181, 181, 181
|
||||
gray72, 184, 184, 184
|
||||
gray73, 186, 186, 186
|
||||
gray74, 189, 189, 189
|
||||
gray75, 191, 191, 191
|
||||
gray76, 194, 194, 194
|
||||
gray77, 196, 196, 196
|
||||
gray78, 199, 199, 199
|
||||
gray79, 201, 201, 201
|
||||
gray8, 20, 20, 20
|
||||
gray80, 204, 204, 204
|
||||
gray81, 207, 207, 207
|
||||
gray82, 209, 209, 209
|
||||
gray83, 212, 212, 212
|
||||
gray84, 214, 214, 214
|
||||
gray85, 217, 217, 217
|
||||
gray86, 219, 219, 219
|
||||
gray87, 222, 222, 222
|
||||
gray88, 224, 224, 224
|
||||
gray89, 227, 227, 227
|
||||
gray9, 23, 23, 23
|
||||
gray90, 229, 229, 229
|
||||
gray91, 232, 232, 232
|
||||
gray92, 235, 235, 235
|
||||
gray93, 237, 237, 237
|
||||
gray94, 240, 240, 240
|
||||
gray95, 242, 242, 242
|
||||
gray96, 245, 245, 245
|
||||
gray97, 247, 247, 247
|
||||
gray98, 250, 250, 250
|
||||
gray99, 252, 252, 252
|
||||
green, 0, 255, 0
|
||||
green yellow, 173, 255, 47
|
||||
green1, 0, 255, 0
|
||||
green2, 0, 238, 0
|
||||
green3, 0, 205, 0
|
||||
green4, 0, 139, 0
|
||||
GreenYellow, 173, 255, 47
|
||||
grey, 190, 190, 190
|
||||
grey0, 0, 0, 0
|
||||
grey1, 3, 3, 3
|
||||
grey10, 26, 26, 26
|
||||
grey100, 255, 255, 255
|
||||
grey11, 28, 28, 28
|
||||
grey12, 31, 31, 31
|
||||
grey13, 33, 33, 33
|
||||
grey14, 36, 36, 36
|
||||
grey15, 38, 38, 38
|
||||
grey16, 41, 41, 41
|
||||
grey17, 43, 43, 43
|
||||
grey18, 46, 46, 46
|
||||
grey19, 48, 48, 48
|
||||
grey2, 5, 5, 5
|
||||
grey20, 51, 51, 51
|
||||
grey21, 54, 54, 54
|
||||
grey22, 56, 56, 56
|
||||
grey23, 59, 59, 59
|
||||
grey24, 61, 61, 61
|
||||
grey25, 64, 64, 64
|
||||
grey26, 66, 66, 66
|
||||
grey27, 69, 69, 69
|
||||
grey28, 71, 71, 71
|
||||
grey29, 74, 74, 74
|
||||
grey3, 8, 8, 8
|
||||
grey30, 77, 77, 77
|
||||
grey31, 79, 79, 79
|
||||
grey32, 82, 82, 82
|
||||
grey33, 84, 84, 84
|
||||
grey34, 87, 87, 87
|
||||
grey35, 89, 89, 89
|
||||
grey36, 92, 92, 92
|
||||
grey37, 94, 94, 94
|
||||
grey38, 97, 97, 97
|
||||
grey39, 99, 99, 99
|
||||
grey4, 10, 10, 10
|
||||
grey40, 102, 102, 102
|
||||
grey41, 105, 105, 105
|
||||
grey42, 107, 107, 107
|
||||
grey43, 110, 110, 110
|
||||
grey44, 112, 112, 112
|
||||
grey45, 115, 115, 115
|
||||
grey46, 117, 117, 117
|
||||
grey47, 120, 120, 120
|
||||
grey48, 122, 122, 122
|
||||
grey49, 125, 125, 125
|
||||
grey5, 13, 13, 13
|
||||
grey50, 127, 127, 127
|
||||
grey51, 130, 130, 130
|
||||
grey52, 133, 133, 133
|
||||
grey53, 135, 135, 135
|
||||
grey54, 138, 138, 138
|
||||
grey55, 140, 140, 140
|
||||
grey56, 143, 143, 143
|
||||
grey57, 145, 145, 145
|
||||
grey58, 148, 148, 148
|
||||
grey59, 150, 150, 150
|
||||
grey6, 15, 15, 15
|
||||
grey60, 153, 153, 153
|
||||
grey61, 156, 156, 156
|
||||
grey62, 158, 158, 158
|
||||
grey63, 161, 161, 161
|
||||
grey64, 163, 163, 163
|
||||
grey65, 166, 166, 166
|
||||
grey66, 168, 168, 168
|
||||
grey67, 171, 171, 171
|
||||
grey68, 173, 173, 173
|
||||
grey69, 176, 176, 176
|
||||
grey7, 18, 18, 18
|
||||
grey70, 179, 179, 179
|
||||
grey71, 181, 181, 181
|
||||
grey72, 184, 184, 184
|
||||
grey73, 186, 186, 186
|
||||
grey74, 189, 189, 189
|
||||
grey75, 191, 191, 191
|
||||
grey76, 194, 194, 194
|
||||
grey77, 196, 196, 196
|
||||
grey78, 199, 199, 199
|
||||
grey79, 201, 201, 201
|
||||
grey8, 20, 20, 20
|
||||
grey80, 204, 204, 204
|
||||
grey81, 207, 207, 207
|
||||
grey82, 209, 209, 209
|
||||
grey83, 212, 212, 212
|
||||
grey84, 214, 214, 214
|
||||
grey85, 217, 217, 217
|
||||
grey86, 219, 219, 219
|
||||
grey87, 222, 222, 222
|
||||
grey88, 224, 224, 224
|
||||
grey89, 227, 227, 227
|
||||
grey9, 23, 23, 23
|
||||
grey90, 229, 229, 229
|
||||
grey91, 232, 232, 232
|
||||
grey92, 235, 235, 235
|
||||
grey93, 237, 237, 237
|
||||
grey94, 240, 240, 240
|
||||
grey95, 242, 242, 242
|
||||
grey96, 245, 245, 245
|
||||
grey97, 247, 247, 247
|
||||
grey98, 250, 250, 250
|
||||
grey99, 252, 252, 252
|
||||
honeydew, 240, 255, 240
|
||||
honeydew1, 240, 255, 240
|
||||
honeydew2, 224, 238, 224
|
||||
honeydew3, 193, 205, 193
|
||||
honeydew4, 131, 139, 131
|
||||
hot pink, 255, 105, 180
|
||||
HotPink, 255, 105, 180
|
||||
HotPink1, 255, 110, 180
|
||||
HotPink2, 238, 106, 167
|
||||
HotPink3, 205, 96, 144
|
||||
HotPink4, 139, 58, 98
|
||||
indian red, 205, 92, 92
|
||||
IndianRed, 205, 92, 92
|
||||
IndianRed1, 255, 106, 106
|
||||
IndianRed2, 238, 99, 99
|
||||
IndianRed3, 205, 85, 85
|
||||
IndianRed4, 139, 58, 58
|
||||
ivory, 255, 255, 240
|
||||
ivory1, 255, 255, 240
|
||||
ivory2, 238, 238, 224
|
||||
ivory3, 205, 205, 193
|
||||
ivory4, 139, 139, 131
|
||||
khaki, 240, 230, 140
|
||||
khaki1, 255, 246, 143
|
||||
khaki2, 238, 230, 133
|
||||
khaki3, 205, 198, 115
|
||||
khaki4, 139, 134, 78
|
||||
lavender, 230, 230, 250
|
||||
lavender blush, 255, 240, 245
|
||||
LavenderBlush, 255, 240, 245
|
||||
LavenderBlush1, 255, 240, 245
|
||||
LavenderBlush2, 238, 224, 229
|
||||
LavenderBlush3, 205, 193, 197
|
||||
LavenderBlush4, 139, 131, 134
|
||||
lawn green, 124, 252, 0
|
||||
LawnGreen, 124, 252, 0
|
||||
lemon chiffon, 255, 250, 205
|
||||
LemonChiffon, 255, 250, 205
|
||||
LemonChiffon1, 255, 250, 205
|
||||
LemonChiffon2, 238, 233, 191
|
||||
LemonChiffon3, 205, 201, 165
|
||||
LemonChiffon4, 139, 137, 112
|
||||
light blue, 173, 216, 230
|
||||
light coral, 240, 128, 128
|
||||
light cyan, 224, 255, 255
|
||||
light goldenrod, 238, 221, 130
|
||||
light goldenrod yellow, 250, 250, 210
|
||||
light gray, 211, 211, 211
|
||||
light green, 144, 238, 144
|
||||
light grey, 211, 211, 211
|
||||
light pink, 255, 182, 193
|
||||
light salmon, 255, 160, 122
|
||||
light sea green, 32, 178, 170
|
||||
light sky blue, 135, 206, 250
|
||||
light slate blue, 132, 112, 255
|
||||
light slate gray, 119, 136, 153
|
||||
light slate grey, 119, 136, 153
|
||||
light steel blue, 176, 196, 222
|
||||
light yellow, 255, 255, 224
|
||||
LightBlue, 173, 216, 230
|
||||
LightBlue1, 191, 239, 255
|
||||
LightBlue2, 178, 223, 238
|
||||
LightBlue3, 154, 192, 205
|
||||
LightBlue4, 104, 131, 139
|
||||
LightCoral, 240, 128, 128
|
||||
LightCyan, 224, 255, 255
|
||||
LightCyan1, 224, 255, 255
|
||||
LightCyan2, 209, 238, 238
|
||||
LightCyan3, 180, 205, 205
|
||||
LightCyan4, 122, 139, 139
|
||||
LightGoldenrod, 238, 221, 130
|
||||
LightGoldenrod1, 255, 236, 139
|
||||
LightGoldenrod2, 238, 220, 130
|
||||
LightGoldenrod3, 205, 190, 112
|
||||
LightGoldenrod4, 139, 129, 76
|
||||
LightGoldenrodYellow, 250, 250, 210
|
||||
LightGray, 211, 211, 211
|
||||
LightGreen, 144, 238, 144
|
||||
LightGrey, 211, 211, 211
|
||||
LightPink, 255, 182, 193
|
||||
LightPink1, 255, 174, 185
|
||||
LightPink2, 238, 162, 173
|
||||
LightPink3, 205, 140, 149
|
||||
LightPink4, 139, 95, 101
|
||||
LightSalmon, 255, 160, 122
|
||||
LightSalmon1, 255, 160, 122
|
||||
LightSalmon2, 238, 149, 114
|
||||
LightSalmon3, 205, 129, 98
|
||||
LightSalmon4, 139, 87, 66
|
||||
LightSeaGreen, 32, 178, 170
|
||||
LightSkyBlue, 135, 206, 250
|
||||
LightSkyBlue1, 176, 226, 255
|
||||
LightSkyBlue2, 164, 211, 238
|
||||
LightSkyBlue3, 141, 182, 205
|
||||
LightSkyBlue4, 96, 123, 139
|
||||
LightSlateBlue, 132, 112, 255
|
||||
LightSlateGray, 119, 136, 153
|
||||
LightSlateGrey, 119, 136, 153
|
||||
LightSteelBlue, 176, 196, 222
|
||||
LightSteelBlue1, 202, 225, 255
|
||||
LightSteelBlue2, 188, 210, 238
|
||||
LightSteelBlue3, 162, 181, 205
|
||||
LightSteelBlue4, 110, 123, 139
|
||||
LightYellow, 255, 255, 224
|
||||
LightYellow1, 255, 255, 224
|
||||
LightYellow2, 238, 238, 209
|
||||
LightYellow3, 205, 205, 180
|
||||
LightYellow4, 139, 139, 122
|
||||
lime green, 50, 205, 50
|
||||
LimeGreen, 50, 205, 50
|
||||
linen, 250, 240, 230
|
||||
magenta, 255, 0, 255
|
||||
magenta1, 255, 0, 255
|
||||
magenta2, 238, 0, 238
|
||||
magenta3, 205, 0, 205
|
||||
magenta4, 139, 0, 139
|
||||
maroon, 176, 48, 96
|
||||
maroon1, 255, 52, 179
|
||||
maroon2, 238, 48, 167
|
||||
maroon3, 205, 41, 144
|
||||
maroon4, 139, 28, 98
|
||||
medium aquamarine, 102, 205, 170
|
||||
medium blue, 0, 0, 205
|
||||
medium orchid, 186, 85, 211
|
||||
medium purple, 147, 112, 219
|
||||
medium sea green, 60, 179, 113
|
||||
medium slate blue, 123, 104, 238
|
||||
medium spring green, 0, 250, 154
|
||||
medium turquoise, 72, 209, 204
|
||||
medium violet red, 199, 21, 133
|
||||
MediumAquamarine, 102, 205, 170
|
||||
MediumBlue, 0, 0, 205
|
||||
MediumOrchid, 186, 85, 211
|
||||
MediumOrchid1, 224, 102, 255
|
||||
MediumOrchid2, 209, 95, 238
|
||||
MediumOrchid3, 180, 82, 205
|
||||
MediumOrchid4, 122, 55, 139
|
||||
MediumPurple, 147, 112, 219
|
||||
MediumPurple1, 171, 130, 255
|
||||
MediumPurple2, 159, 121, 238
|
||||
MediumPurple3, 137, 104, 205
|
||||
MediumPurple4, 93, 71, 139
|
||||
MediumSeaGreen, 60, 179, 113
|
||||
MediumSlateBlue, 123, 104, 238
|
||||
MediumSpringGreen, 0, 250, 154
|
||||
MediumTurquoise, 72, 209, 204
|
||||
MediumVioletRed, 199, 21, 133
|
||||
midnight blue, 25, 25, 112
|
||||
MidnightBlue, 25, 25, 112
|
||||
mint cream, 245, 255, 250
|
||||
MintCream, 245, 255, 250
|
||||
misty rose, 255, 228, 225
|
||||
MistyRose, 255, 228, 225
|
||||
MistyRose1, 255, 228, 225
|
||||
MistyRose2, 238, 213, 210
|
||||
MistyRose3, 205, 183, 181
|
||||
MistyRose4, 139, 125, 123
|
||||
moccasin, 255, 228, 181
|
||||
navajo white, 255, 222, 173
|
||||
NavajoWhite, 255, 222, 173
|
||||
NavajoWhite1, 255, 222, 173
|
||||
NavajoWhite2, 238, 207, 161
|
||||
NavajoWhite3, 205, 179, 139
|
||||
NavajoWhite4, 139, 121, 94
|
||||
navy, 0, 0, 128
|
||||
navy blue, 0, 0, 128
|
||||
NavyBlue, 0, 0, 128
|
||||
old lace, 253, 245, 230
|
||||
OldLace, 253, 245, 230
|
||||
olive drab, 107, 142, 35
|
||||
OliveDrab, 107, 142, 35
|
||||
OliveDrab1, 192, 255, 62
|
||||
OliveDrab2, 179, 238, 58
|
||||
OliveDrab3, 154, 205, 50
|
||||
OliveDrab4, 105, 139, 34
|
||||
orange, 255, 165, 0
|
||||
orange red, 255, 69, 0
|
||||
orange1, 255, 165, 0
|
||||
orange2, 238, 154, 0
|
||||
orange3, 205, 133, 0
|
||||
orange4, 139, 90, 0
|
||||
OrangeRed, 255, 69, 0
|
||||
OrangeRed1, 255, 69, 0
|
||||
OrangeRed2, 238, 64, 0
|
||||
OrangeRed3, 205, 55, 0
|
||||
OrangeRed4, 139, 37, 0
|
||||
orchid, 218, 112, 214
|
||||
orchid1, 255, 131, 250
|
||||
orchid2, 238, 122, 233
|
||||
orchid3, 205, 105, 201
|
||||
orchid4, 139, 71, 137
|
||||
pale goldenrod, 238, 232, 170
|
||||
pale green, 152, 251, 152
|
||||
pale turquoise, 175, 238, 238
|
||||
pale violet red, 219, 112, 147
|
||||
PaleGoldenrod, 238, 232, 170
|
||||
PaleGreen, 152, 251, 152
|
||||
PaleGreen1, 154, 255, 154
|
||||
PaleGreen2, 144, 238, 144
|
||||
PaleGreen3, 124, 205, 124
|
||||
PaleGreen4, 84, 139, 84
|
||||
PaleTurquoise, 175, 238, 238
|
||||
PaleTurquoise1, 187, 255, 255
|
||||
PaleTurquoise2, 174, 238, 238
|
||||
PaleTurquoise3, 150, 205, 205
|
||||
PaleTurquoise4, 102, 139, 139
|
||||
PaleVioletRed, 219, 112, 147
|
||||
PaleVioletRed1, 255, 130, 171
|
||||
PaleVioletRed2, 238, 121, 159
|
||||
PaleVioletRed3, 205, 104, 137
|
||||
PaleVioletRed4, 139, 71, 93
|
||||
papaya whip, 255, 239, 213
|
||||
PapayaWhip, 255, 239, 213
|
||||
peach puff, 255, 218, 185
|
||||
PeachPuff, 255, 218, 185
|
||||
PeachPuff1, 255, 218, 185
|
||||
PeachPuff2, 238, 203, 173
|
||||
PeachPuff3, 205, 175, 149
|
||||
PeachPuff4, 139, 119, 101
|
||||
peru, 205, 133, 63
|
||||
pink, 255, 192, 203
|
||||
pink1, 255, 181, 197
|
||||
pink2, 238, 169, 184
|
||||
pink3, 205, 145, 158
|
||||
pink4, 139, 99, 108
|
||||
plum, 221, 160, 221
|
||||
plum1, 255, 187, 255
|
||||
plum2, 238, 174, 238
|
||||
plum3, 205, 150, 205
|
||||
plum4, 139, 102, 139
|
||||
powder blue, 176, 224, 230
|
||||
PowderBlue, 176, 224, 230
|
||||
purple, 160, 32, 240
|
||||
purple1, 155, 48, 255
|
||||
purple2, 145, 44, 238
|
||||
purple3, 125, 38, 205
|
||||
purple4, 85, 26, 139
|
||||
red, 255, 0, 0
|
||||
red1, 255, 0, 0
|
||||
red2, 238, 0, 0
|
||||
red3, 205, 0, 0
|
||||
red4, 139, 0, 0
|
||||
rosy brown, 188, 143, 143
|
||||
RosyBrown, 188, 143, 143
|
||||
RosyBrown1, 255, 193, 193
|
||||
RosyBrown2, 238, 180, 180
|
||||
RosyBrown3, 205, 155, 155
|
||||
RosyBrown4, 139, 105, 105
|
||||
royal blue, 65, 105, 225
|
||||
RoyalBlue, 65, 105, 225
|
||||
RoyalBlue1, 72, 118, 255
|
||||
RoyalBlue2, 67, 110, 238
|
||||
RoyalBlue3, 58, 95, 205
|
||||
RoyalBlue4, 39, 64, 139
|
||||
saddle brown, 139, 69, 19
|
||||
SaddleBrown, 139, 69, 19
|
||||
salmon, 250, 128, 114
|
||||
salmon1, 255, 140, 105
|
||||
salmon2, 238, 130, 98
|
||||
salmon3, 205, 112, 84
|
||||
salmon4, 139, 76, 57
|
||||
sandy brown, 244, 164, 96
|
||||
SandyBrown, 244, 164, 96
|
||||
sea green, 46, 139, 87
|
||||
SeaGreen, 46, 139, 87
|
||||
SeaGreen1, 84, 255, 159
|
||||
SeaGreen2, 78, 238, 148
|
||||
SeaGreen3, 67, 205, 128
|
||||
SeaGreen4, 46, 139, 87
|
||||
seashell, 255, 245, 238
|
||||
seashell1, 255, 245, 238
|
||||
seashell2, 238, 229, 222
|
||||
seashell3, 205, 197, 191
|
||||
seashell4, 139, 134, 130
|
||||
sienna, 160, 82, 45
|
||||
sienna1, 255, 130, 71
|
||||
sienna2, 238, 121, 66
|
||||
sienna3, 205, 104, 57
|
||||
sienna4, 139, 71, 38
|
||||
sky blue, 135, 206, 235
|
||||
SkyBlue, 135, 206, 235
|
||||
SkyBlue1, 135, 206, 255
|
||||
SkyBlue2, 126, 192, 238
|
||||
SkyBlue3, 108, 166, 205
|
||||
SkyBlue4, 74, 112, 139
|
||||
slate blue, 106, 90, 205
|
||||
slate gray, 112, 128, 144
|
||||
slate grey, 112, 128, 144
|
||||
SlateBlue, 106, 90, 205
|
||||
SlateBlue1, 131, 111, 255
|
||||
SlateBlue2, 122, 103, 238
|
||||
SlateBlue3, 105, 89, 205
|
||||
SlateBlue4, 71, 60, 139
|
||||
SlateGray, 112, 128, 144
|
||||
SlateGray1, 198, 226, 255
|
||||
SlateGray2, 185, 211, 238
|
||||
SlateGray3, 159, 182, 205
|
||||
SlateGray4, 108, 123, 139
|
||||
SlateGrey, 112, 128, 144
|
||||
snow, 255, 250, 250
|
||||
snow1, 255, 250, 250
|
||||
snow2, 238, 233, 233
|
||||
snow3, 205, 201, 201
|
||||
snow4, 139, 137, 137
|
||||
spring green, 0, 255, 127
|
||||
SpringGreen, 0, 255, 127
|
||||
SpringGreen1, 0, 255, 127
|
||||
SpringGreen2, 0, 238, 118
|
||||
SpringGreen3, 0, 205, 102
|
||||
SpringGreen4, 0, 139, 69
|
||||
steel blue, 70, 130, 180
|
||||
SteelBlue, 70, 130, 180
|
||||
SteelBlue1, 99, 184, 255
|
||||
SteelBlue2, 92, 172, 238
|
||||
SteelBlue3, 79, 148, 205
|
||||
SteelBlue4, 54, 100, 139
|
||||
tan, 210, 180, 140
|
||||
tan1, 255, 165, 79
|
||||
tan2, 238, 154, 73
|
||||
tan3, 205, 133, 63
|
||||
tan4, 139, 90, 43
|
||||
thistle, 216, 191, 216
|
||||
thistle1, 255, 225, 255
|
||||
thistle2, 238, 210, 238
|
||||
thistle3, 205, 181, 205
|
||||
thistle4, 139, 123, 139
|
||||
tomato, 255, 99, 71
|
||||
tomato1, 255, 99, 71
|
||||
tomato2, 238, 92, 66
|
||||
tomato3, 205, 79, 57
|
||||
tomato4, 139, 54, 38
|
||||
turquoise, 64, 224, 208
|
||||
turquoise1, 0, 245, 255
|
||||
turquoise2, 0, 229, 238
|
||||
turquoise3, 0, 197, 205
|
||||
turquoise4, 0, 134, 139
|
||||
violet, 238, 130, 238
|
||||
violet red, 208, 32, 144
|
||||
VioletRed, 208, 32, 144
|
||||
VioletRed1, 255, 62, 150
|
||||
VioletRed2, 238, 58, 140
|
||||
VioletRed3, 205, 50, 120
|
||||
VioletRed4, 139, 34, 82
|
||||
wheat, 245, 222, 179
|
||||
wheat1, 255, 231, 186
|
||||
wheat2, 238, 216, 174
|
||||
wheat3, 205, 186, 150
|
||||
wheat4, 139, 126, 102
|
||||
white, 255, 255, 255
|
||||
white smoke, 245, 245, 245
|
||||
WhiteSmoke, 245, 245, 245
|
||||
yellow, 255, 255, 0
|
||||
yellow green, 154, 205, 50
|
||||
yellow1, 255, 255, 0
|
||||
yellow2, 238, 238, 0
|
||||
yellow3, 205, 205, 0
|
||||
yellow4, 139, 139, 0
|
||||
YellowGreen, 154, 205, 50
|
||||
162
obj-x86_64-linux-gnu/data/convertconf.h
Normal file
162
obj-x86_64-linux-gnu/data/convertconf.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
const char convertconf[] =
|
||||
"#! /usr/bin/lua\n"
|
||||
"\n"
|
||||
"local usage = [[\n"
|
||||
"Usage: convert.lua old_conkyrc [new_conkyrc]\n"
|
||||
"\n"
|
||||
"Tries to convert conkyrc from the old v1.x format to the new, lua-based format.\n"
|
||||
"\n"
|
||||
"Keep in mind that there is no guarantee that the output will work correctly\n"
|
||||
"with conky, or that it will be able to convert every conkyrc. However, it\n"
|
||||
"should provide a good starting point.\n"
|
||||
"\n"
|
||||
"Although you can use this script with only 1 arg and let it overwrite the old\n"
|
||||
"config, it's suggested to use 2 args so that the new config is written in a new\n"
|
||||
"file (so that you have backup if something went wrong).\n"
|
||||
"\n"
|
||||
"Optional: Install dos2unix. We will attempt to use this if it is available\n"
|
||||
"because Conky configs downloaded from Internet sometimes are created on DOS/Windows\n"
|
||||
"machines with different line endings than Conky configs created on Unix/Linux.\n"
|
||||
"\n"
|
||||
"For more information about the new format, read the wiki page\n"
|
||||
"<https://github.com/brndnmtthws/conky/wiki>\n"
|
||||
"]];\n"
|
||||
"\n"
|
||||
"local function quote(s)\n"
|
||||
" if not s:find(\"[\\n'\\\\]\") then\n"
|
||||
" return \"'\" .. s .. \"'\";\n"
|
||||
" end;\n"
|
||||
" local q = '';\n"
|
||||
" while s:find(']' .. q .. ']', 1, true) do\n"
|
||||
" q = q .. '=';\n"
|
||||
" end;\n"
|
||||
" return string.format('[%s[\\n%s]%s]', q, s, q);\n"
|
||||
"end;\n"
|
||||
"\n"
|
||||
"local bool_setting = {\n"
|
||||
" background = true, disable_auto_reload = true, double_buffer = true, draw_borders = true,\n"
|
||||
" draw_graph_borders = true, draw_outline = true, draw_shades = true, extra_newline = true,\n"
|
||||
" format_human_readable = true, no_buffers = true, out_to_console = true,\n"
|
||||
" out_to_wayland = true,\n"
|
||||
" out_to_ncurses = true, out_to_stderr = true, out_to_x = true, override_utf8_locale = true,\n"
|
||||
" own_window = true, own_window_argb_visual = true, own_window_transparent = true,\n"
|
||||
" short_units = true, show_graph_range = true, show_graph_scale = true,\n"
|
||||
" times_in_seconds = true, top_cpu_separate = true, uppercase = true, use_xft = true,\n"
|
||||
" draw_blended = true, forced_redraw = true\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"local num_setting = {\n"
|
||||
" border_inner_margin = true, border_outer_margin = true, border_width = true,\n"
|
||||
" cpu_avg_samples = true, diskio_avg_samples = true, gap_x = true, gap_y = true,\n"
|
||||
" imlib_cache_flush_interval = true, imlib_cache_size = true,\n"
|
||||
" max_port_monitor_connections = true, max_text_width = true, max_user_text = true,\n"
|
||||
" maximum_width = true, mpd_port = true, music_player_interval = true, net_avg_samples = true,\n"
|
||||
" own_window_argb_value = true, pad_percents = true, stippled_borders = true,\n"
|
||||
" text_buffer_size = true, top_name_width = true, total_run_times = true,\n"
|
||||
" update_interval = true, update_interval_on_battery = true, xftalpha = true,\n"
|
||||
" xinerama_head = true,\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"local split_setting = {\n"
|
||||
" default_bar_size = true, default_gauge_size = true, default_graph_size = true,\n"
|
||||
" minimum_size = true\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"local colour_setting = {\n"
|
||||
" color0 = true, color1 = true, color2 = true, color3 = true, color4 = true, color5 = true,\n"
|
||||
" color6 = true, color7 = true, color8 = true, color9 = true, default_color = true,\n"
|
||||
" default_outline_color = true, default_shade_color = true, own_window_colour = true\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"local function alignment_map(value)\n"
|
||||
" local map = { m = 'middle', t = 'top', b = 'bottom', r = 'right', l = 'left' };\n"
|
||||
" if map[value] == nil then\n"
|
||||
" return value;\n"
|
||||
" else\n"
|
||||
" return map[value];\n"
|
||||
" end;\n"
|
||||
"end;\n"
|
||||
"\n"
|
||||
"local function handle(setting, value)\n"
|
||||
" setting = setting:lower();\n"
|
||||
" if setting == '' then\n"
|
||||
" return '';\n"
|
||||
" end;\n"
|
||||
" if split_setting[setting] then\n"
|
||||
" local x, y = value:match('^(%S+)%s*(%S*)$');\n"
|
||||
" local ret = setting:gsub('_size', '_width = ') .. x .. ',';\n"
|
||||
" if y ~= '' then\n"
|
||||
" ret = ret .. ' ' .. setting:gsub('_size', '_height = ') .. y .. ',';\n"
|
||||
" end;\n"
|
||||
" return '\\t' .. ret;\n"
|
||||
" end;\n"
|
||||
" if bool_setting[setting] then\n"
|
||||
" value = value:lower();\n"
|
||||
" if value == 'yes' or value == 'true' or value == '1' or value == '' then\n"
|
||||
" value = 'true';\n"
|
||||
" else\n"
|
||||
" value = 'false';\n"
|
||||
" end;\n"
|
||||
" elseif not num_setting[setting] then\n"
|
||||
" if setting == 'alignment' and value:len() == 2 then\n"
|
||||
" value = alignment_map(value:sub(1,1)) .. '_' .. alignment_map(value:sub(2,2));\n"
|
||||
" elseif colour_setting[setting] and value:match('^[0-9a-fA-F]+$') then\n"
|
||||
" value = '#' .. value;\n"
|
||||
" elseif setting == 'xftfont' then\n"
|
||||
" setting = 'font';\n"
|
||||
" end;\n"
|
||||
" value = quote(value);\n"
|
||||
" end;\n"
|
||||
" return '\\t' .. setting .. ' = ' .. value .. ',';\n"
|
||||
"end;\n"
|
||||
"\n"
|
||||
"local function convert(s)\n"
|
||||
" local setting, comment = s:match('^([^#]*)#?(.*)\\n$');\n"
|
||||
" if comment ~= '' then\n"
|
||||
" comment = '--' .. comment;\n"
|
||||
" end;\n"
|
||||
" comment = comment .. '\\n';\n"
|
||||
" return handle(setting:match('^%s*(%S*)%s*(.-)%s*$')) .. comment;\n"
|
||||
"end;\n"
|
||||
"\n"
|
||||
"local input;\n"
|
||||
"local output;\n"
|
||||
"\n"
|
||||
"if conky == nil then --> standalone program\n"
|
||||
" -- 1 arg: arg is input and outputfile\n"
|
||||
" -- 2 args: 1st is inputfile, 2nd is outputfile\n"
|
||||
" -- 0, 3 or more args: print usage to STDERR and quit\n"
|
||||
" if #arg == 1 or #arg == 2 then\n"
|
||||
" if os.execute('command -v dos2unix 2>&1 >/dev/null') == 0 then\n"
|
||||
" os.execute('dos2unix ' .. arg[1]);\n"
|
||||
" end\n"
|
||||
" input = io.input(arg[1]);\n"
|
||||
" else\n"
|
||||
" io.stderr:write(usage);\n"
|
||||
" return;\n"
|
||||
" end;\n"
|
||||
"else\n"
|
||||
" -- we are called from conky, the filename is the first argument\n"
|
||||
" input = io.open(..., 'r');\n"
|
||||
"end;\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"local config = input:read('*a');\n"
|
||||
"input:close();\n"
|
||||
"\n"
|
||||
"local settings, text = config:match('^(.-)TEXT\\n(.*)$');\n"
|
||||
"\n"
|
||||
"local converted = 'conky.config = {\\n' .. settings:gsub('.-\\n', convert) .. '};\\n\\nconky.text = ' ..\n"
|
||||
" quote(text) .. ';\\n';\n"
|
||||
"\n"
|
||||
"if conky == nil then\n"
|
||||
" if #arg == 2 then\n"
|
||||
" output = io.output(arg[2]);\n"
|
||||
" else\n"
|
||||
" output = io.output(arg[1]);\n"
|
||||
" end\n"
|
||||
" output:write(converted);\n"
|
||||
" output:close();\n"
|
||||
"else\n"
|
||||
" return assert(load(converted, 'converted config'));\n"
|
||||
"end;\n";
|
||||
105
obj-x86_64-linux-gnu/data/defconfig.h
Normal file
105
obj-x86_64-linux-gnu/data/defconfig.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
const char defconfig[] =
|
||||
"-- Определяем функцию для получения фактора масштабирования окна\n"
|
||||
"function get_window_scaling_factor()\n"
|
||||
" -- Определяем текущего пользователя\n"
|
||||
" local user_handle = io.popen(\"whoami\")\n"
|
||||
" local current_user = user_handle:read(\"*a\"):gsub(\"%s+\", \"\") -- Удаляем пробелы и символы новой строки\n"
|
||||
" user_handle:close()\n"
|
||||
"\n"
|
||||
" local scale_factor\n"
|
||||
"\n"
|
||||
" if current_user == \"root\" then\n"
|
||||
" -- Если текущий пользователь root, определяем пользователя, который запустил X-сессию\n"
|
||||
" local session_user_handle = io.popen(\"who | grep '(:0)' | awk '{print $1}'\")\n"
|
||||
" local session_user = session_user_handle:read(\"*a\"):gsub(\"%s+\", \"\") -- Удаляем пробелы и символы новой строки\n"
|
||||
" session_user_handle:close()\n"
|
||||
"\n"
|
||||
" -- Если не удалось определить пользователя, возвращаем масштаб по умолчанию\n"
|
||||
" if not session_user or session_user == \"\" then return 1 end\n"
|
||||
"\n"
|
||||
" -- Выполняем команду от имени этого пользователя\n"
|
||||
" local command = string.format(\"sudo -u %s xfconf-query -c xsettings -p /Gdk/WindowScalingFactor\", session_user)\n"
|
||||
" local handle = io.popen(command)\n"
|
||||
" scale_factor = tonumber(handle:read(\"*a\"))\n"
|
||||
" handle:close()\n"
|
||||
" else\n"
|
||||
" -- Если текущий пользователь не root, просто получаем масштабирование\n"
|
||||
" local handle = io.popen(\"xfconf-query -c xsettings -p /Gdk/WindowScalingFactor\")\n"
|
||||
" scale_factor = tonumber(handle:read(\"*a\"))\n"
|
||||
" handle:close()\n"
|
||||
" end\n"
|
||||
"\n"
|
||||
" return scale_factor or 1\n"
|
||||
"end\n"
|
||||
"\n"
|
||||
"-- Получаем текущий фактор масштаба окон\n"
|
||||
"local scale_factor = get_window_scaling_factor()\n"
|
||||
"\n"
|
||||
"-- Применяем масштаб к шрифту и элементам интерфейса\n"
|
||||
"conky.config = {\n"
|
||||
" update_interval = 1,\n"
|
||||
" cpu_avg_samples = 2,\n"
|
||||
" net_avg_samples = 2,\n"
|
||||
" out_to_console = false,\n"
|
||||
" override_utf8_locale = true,\n"
|
||||
" double_buffer = true,\n"
|
||||
" no_buffers = true,\n"
|
||||
" text_buffer_size = 32768,\n"
|
||||
" imlib_cache_size = 0,\n"
|
||||
" own_window = true,\n"
|
||||
" own_window_type = 'desktop',\n"
|
||||
" own_window_argb_value = 200,\n"
|
||||
" own_window_argb_visual = true,\n"
|
||||
" own_window_transparent = false,\n"
|
||||
" own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager', -- Новая строка для предотвращения скрытия\n"
|
||||
" border_inner_margin = 15 * scale_factor,\n"
|
||||
" border_outer_margin = 0 * scale_factor,\n"
|
||||
" xinerama_head = 1,\n"
|
||||
" alignment = 'bottom_right',\n"
|
||||
" gap_x = 80 * scale_factor,\n"
|
||||
" gap_y = 80 * scale_factor,\n"
|
||||
" draw_shades = false,\n"
|
||||
" draw_outline = false,\n"
|
||||
" draw_borders = false,\n"
|
||||
" draw_graph_borders = false,\n"
|
||||
" use_xft = true,\n"
|
||||
" font = string.format('Comfortaa:size=%d', 12 * scale_factor),\n"
|
||||
" xftalpha = 0.8,\n"
|
||||
" uppercase = false,\n"
|
||||
" default_color = 'white',\n"
|
||||
" own_window_colour = '003333',\n"
|
||||
" minimum_width = 300 * scale_factor, minimum_height = 0,\n"
|
||||
" alignment = 'top_right',\n"
|
||||
" color1 = '000000',\n"
|
||||
" stippled_border = 100 * scale_factor,\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"-- Variables: https://conky.cc/variables\n"
|
||||
"conky.text = string.format([[\n"
|
||||
" \n"
|
||||
"${voffset -10}\n"
|
||||
"${font Comfortaa:bold:size=%d}Система ${hr 2}\n"
|
||||
"${font Comfortaa:normal:size=%d}Пользователь:${alignr}${USER}\n"
|
||||
"Система:${alignr}${font Comfortaa:normal:size=%d}$sysname $kernel \n"
|
||||
"Хост:$alignr$nodename\n"
|
||||
"Время работы:$alignr$uptime\n"
|
||||
"Процессы: $alignr ${execi 1000 ps aux | wc -l}\n"
|
||||
"\n"
|
||||
"${font Comfortaa:bold:size=%d}Процессор ${hr 2}\n"
|
||||
"${font Comfortaa:normal:size=%d}${execi 1000 grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed 's/\\\\s//'}${voffset 5}\n"
|
||||
"Нагрузка: ${cpu cpu1}%% ${cpubar cpu1}${voffset 5}\n"
|
||||
"Температура: ${acpitemp}°С\n"
|
||||
"\n"
|
||||
"${font Comfortaa:bold:size=%d}Память ${hr 2}\n"
|
||||
"${font Comfortaa:normal:size=%d}Оперативная память $alignc $mem / $memmax $alignr $memperc%%${voffset 5}\n"
|
||||
"Файлы подкачки $alignc ${swap} / ${swapmax} $alignr ${swapperc}%%\n"
|
||||
"\n"
|
||||
"${font Comfortaa:bold:size=%d}Диск ${hr 2}\n"
|
||||
"${font Comfortaa:normal:size=%d}/ $alignc ${fs_used /} / ${fs_size /} $alignr ${fs_used_perc /}%%\n"
|
||||
"${fs_bar /}\n"
|
||||
"\n"
|
||||
"${font Ubuntu:bold:size=%d}Сеть ${hr 2}\n"
|
||||
"${font Comfortaa:normal:size=%d}Локальный IP:${alignr}Внешний IP:\n"
|
||||
"${execi 1000 ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \\\\/ -f1 | sed 's/[^0-9\\\\.]*//g'} ${alignr}${execi 1000 wget -q -O- http://ipecho.net/plain; echo}\n"
|
||||
"${font Comfortaa:normal:size=%d}Down: ${downspeed enp0s3} ${alignr}Up: ${upspeed enp0s3} \n"
|
||||
"]], 10 * scale_factor, 8 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor, 8 * scale_factor, 10 * scale_factor)\n";
|
||||
7
obj-x86_64-linux-gnu/install_manifest.txt
Normal file
7
obj-x86_64-linux-gnu/install_manifest.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/usr/share/applications/conky.desktop
|
||||
/usr/share/icons/hicolor/scalable/apps/conky-logomark-violet.svg
|
||||
/usr/bin/conky
|
||||
/usr/lib/libtcp-portmon.a
|
||||
/usr/share/doc/conky-1.21.3/convert.lua
|
||||
/usr/share/doc/conky-1.21.3/conky_no_x11.conf
|
||||
/usr/share/doc/conky-1.21.3/conky.conf
|
||||
1563
obj-x86_64-linux-gnu/src/colour-names.hh
Normal file
1563
obj-x86_64-linux-gnu/src/colour-names.hh
Normal file
File diff suppressed because it is too large
Load diff
BIN
obj-x86_64-linux-gnu/src/conky
Executable file
BIN
obj-x86_64-linux-gnu/src/conky
Executable file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue