C ++ 26'da paralel veri türleri: Uygulamadan bir örnek
Son makalemde C ++ 26'da yenilikler verdikten sonra: Veri Paralel Türleri (SIMD) C ++ 26'nın yeni işlevselliğine teorik bir giriş, bugün pratik bir örnek kullanmaya devam etmek istiyorum.
Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
Aşağıdaki giriş örneği, SIMD kütüphanesinin deneysel uygulamasından gelmektedir. Bu özellik, “Paralel Veri Türleri (SIMD)” adı ile C ++ 26 için taslağa tamamen aktarılmıştır. Programı C ++ 26 standardına getirmek için başlık yeterli olmalıdır <experimental/simd> Başından sonuna kadar <simd> ve isimlerin alanı std::experimental Başından sonuna kadar std::datapar değiştirilecek.
#include <experimental/simd>
#include <iostream>
#include <string_view>
namespace stdx = std::experimental;
void println(std::string_view name, auto const& a)
{
std::cout << name << ": ";
for (std::size_t i{}; i != std::size(a); ++i)
std::cout << a << ' ';
std::cout << 'n';
}
template<class A>
stdx::simd<int, A> my_abs(stdx::simd<int, A> x)
{
where(x < 0, x) = -x;
return x;
}
int main()
{
const stdx::native_simd<int> a = 1;
println("a", a);
const stdx::native_simd<int> b([](int i) { return i - 2; });
println("b", b);
const auto c = a + b;
println("c", c);
const auto d = my_abs(c);
println('d', d);
const auto e = d * d;
println("e", e);
const auto inner_product = stdx::reduce(e);
std::cout << "inner product: " << inner_product << "n";
const stdx::fixed_size_simd<long double, 16> x([](int i) { return i; });
println("x", x);
println("cos²(x) + sin²(x)", stdx:
ow(stdx::cos(x), 2) + stdx:
ow(stdx::sin(x), 2));
}
Programa gitmeden önce baskıyı tanıtmak istiyorum.
Örnek kodun baskısı
(Resim: Ekran görüntüsü (Rainer Grimm))
Önce işlevleri istiyorum println VE my_abs adamak. println Bir SIMD taşıyıcının adını ve içeriğini geçirir ve öğelerinden geçer. my_abs Bir SIMD taşıyıcısındaki her bir öğenin mutlak değerini tam sayılarla hesaplayın ve kullanın wherenegatif değerleri reddetmek. Bu çok daha ilginç main-İşlev.
SIMD A Taşıyıcı'da, her eleman 1 olarak ayarlanır, diğer yandan, SIMD B taşıyıcısı başlangıçta lambda işlevi tarafından dizine daha az sahip olacak şekilde başlatılır. Varsayılan değer. const stdx::native_simd<int> SSE2 Eğitmenler. Bu SIMD vektörleri 128 bittir.
Şimdi aritmetik başlıyor. C vektörü A ve B'nin elemanıdır, D, C ve taşıyıcının mutlak değerinin elemanıdır ve d karesinin elemanıdır. Sonunda geldi stdx::reduce(e) kullanılmış. Taşıyıcı toplamına indirgenir.
İfade özellikle ilginç const stdx::fixed_size_simd<long double, 16> x([](int i) { return i; }). 0 ila 15 arasında 16 uzun çift değeri olan SIMD X taşıyıcısı tarafından başlatılır. Donanım yeterince modern ise ve AVX-252'yi destekliyorsa, örneğin Intel veya AMDS ZEN-4'ün Xeon-Phi mimarisiyle desteklenir.
Çizgi eşit derecede ilginç println("cos²(x) + sin²(x)", stdx:
ow(stdx::cos(x), 2) + stdx:
ow(stdx::sin(x), 2)). Hesaplamak cos²(x) + sin²(x) Tüm elementler için pisagorun trigonometrik kimliği nedeniyle her element için 1. <cmath> Özel matematiksel işlevler hariç simd Aşırı yükler. Bunlar, örneğin, gibi temel işlevlerdir. abs,, min VEYA max. Aynı zamanda üstel, trigonometrik, hiperbolik, güç veya aralık fonksiyonları da doğrudan SIMD taşıyıcıya uygulanabilir.
Şimdi veri türünün genişliğine gitmek istiyorum simd<T> Daha yakından bak.
Simd genişliği
Veri türünün genişliği native_simd<T> derleme sırasında uygulama ile belirlenir. Aksine, geliştirici veri türünün genişliğini sağlar. fixed_size_simd<T, N> Önce.
SIMD sınıf modeli aşağıdaki ifadeye sahiptir:
template< class T, class Abi = simd_abi::compatible<T> >
class simd;
Element türü, bunu yapmadığı bulundu bool olabilir. Element sayısı ve hafızaları güne göre belirlenir.
Bu sınıf modeli için iki Aliase var:
template< class T, int N >
using fixed_size_simd = std::experimental::simd<T, std::experimental::simd_abi::fixed_size<N>>;
template< class T >
using native_simd = std::experimental::simd<T, std::experimental::simd_abi::native<T>>;
Aşağıdaki ABI etiketleri mevcuttur:
Paralel veri türlerinin ilk örneğinden sonra, bir sonraki makalede işlevsellikleriyle daha kesin bir şekilde yüzleşmek istiyorum.
(RME)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!
Son makalemde C ++ 26'da yenilikler verdikten sonra: Veri Paralel Türleri (SIMD) C ++ 26'nın yeni işlevselliğine teorik bir giriş, bugün pratik bir örnek kullanmaya devam etmek istiyorum.

Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
Aşağıdaki giriş örneği, SIMD kütüphanesinin deneysel uygulamasından gelmektedir. Bu özellik, “Paralel Veri Türleri (SIMD)” adı ile C ++ 26 için taslağa tamamen aktarılmıştır. Programı C ++ 26 standardına getirmek için başlık yeterli olmalıdır <experimental/simd> Başından sonuna kadar <simd> ve isimlerin alanı std::experimental Başından sonuna kadar std::datapar değiştirilecek.
#include <experimental/simd>
#include <iostream>
#include <string_view>
namespace stdx = std::experimental;
void println(std::string_view name, auto const& a)
{
std::cout << name << ": ";
for (std::size_t i{}; i != std::size(a); ++i)
std::cout << a << ' ';
std::cout << 'n';
}
template<class A>
stdx::simd<int, A> my_abs(stdx::simd<int, A> x)
{
where(x < 0, x) = -x;
return x;
}
int main()
{
const stdx::native_simd<int> a = 1;
println("a", a);
const stdx::native_simd<int> b([](int i) { return i - 2; });
println("b", b);
const auto c = a + b;
println("c", c);
const auto d = my_abs(c);
println('d', d);
const auto e = d * d;
println("e", e);
const auto inner_product = stdx::reduce(e);
std::cout << "inner product: " << inner_product << "n";
const stdx::fixed_size_simd<long double, 16> x([](int i) { return i; });
println("x", x);
println("cos²(x) + sin²(x)", stdx:
}
Programa gitmeden önce baskıyı tanıtmak istiyorum.

Örnek kodun baskısı
(Resim: Ekran görüntüsü (Rainer Grimm))
Önce işlevleri istiyorum println VE my_abs adamak. println Bir SIMD taşıyıcının adını ve içeriğini geçirir ve öğelerinden geçer. my_abs Bir SIMD taşıyıcısındaki her bir öğenin mutlak değerini tam sayılarla hesaplayın ve kullanın wherenegatif değerleri reddetmek. Bu çok daha ilginç main-İşlev.
SIMD A Taşıyıcı'da, her eleman 1 olarak ayarlanır, diğer yandan, SIMD B taşıyıcısı başlangıçta lambda işlevi tarafından dizine daha az sahip olacak şekilde başlatılır. Varsayılan değer. const stdx::native_simd<int> SSE2 Eğitmenler. Bu SIMD vektörleri 128 bittir.
Şimdi aritmetik başlıyor. C vektörü A ve B'nin elemanıdır, D, C ve taşıyıcının mutlak değerinin elemanıdır ve d karesinin elemanıdır. Sonunda geldi stdx::reduce(e) kullanılmış. Taşıyıcı toplamına indirgenir.
İfade özellikle ilginç const stdx::fixed_size_simd<long double, 16> x([](int i) { return i; }). 0 ila 15 arasında 16 uzun çift değeri olan SIMD X taşıyıcısı tarafından başlatılır. Donanım yeterince modern ise ve AVX-252'yi destekliyorsa, örneğin Intel veya AMDS ZEN-4'ün Xeon-Phi mimarisiyle desteklenir.
Çizgi eşit derecede ilginç println("cos²(x) + sin²(x)", stdx:
Şimdi veri türünün genişliğine gitmek istiyorum simd<T> Daha yakından bak.
Simd genişliği
Veri türünün genişliği native_simd<T> derleme sırasında uygulama ile belirlenir. Aksine, geliştirici veri türünün genişliğini sağlar. fixed_size_simd<T, N> Önce.
SIMD sınıf modeli aşağıdaki ifadeye sahiptir:
template< class T, class Abi = simd_abi::compatible<T> >
class simd;
Element türü, bunu yapmadığı bulundu bool olabilir. Element sayısı ve hafızaları güne göre belirlenir.
Bu sınıf modeli için iki Aliase var:
template< class T, int N >
using fixed_size_simd = std::experimental::simd<T, std::experimental::simd_abi::fixed_size<N>>;
template< class T >
using native_simd = std::experimental::simd<T, std::experimental::simd_abi::native<T>>;
Aşağıdaki ABI etiketleri mevcuttur:
- scalar: Tek bir elemanın arşivlenmesi
- fixed_size: Bir dizi öğenin arşivlenmesi
- compatible: ABI'nin uyumluluğunu garanti eder
- native: daha verimli
- max_fixed_size: Garantili maksimum öğe sayısı fixed_size desteklenmek
Paralel veri türlerinin ilk örneğinden sonra, bir sonraki makalede işlevsellikleriyle daha kesin bir şekilde yüzleşmek istiyorum.
(RME)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!