SORU
4 Mayıs 2015, PAZARTESİ


Şubesiz K-anlamına gelir (ya da diğer iyileştirme)

Not: yaklaşım ve çözümler bu tür değil, çözümün kendisi için nasıl bir rehber daha memnun olurum.

Benim sistemi bir dizi belirli bağlamlarda bir profil noktasal gösteren oyuncu-çok kritik bir işlevi var. K-demek bir yineleme (zaten çok iş parçacıklı işlem için bir paralel kullanarak alt aralıklar her bir işçi olarak puan thread) ortasında.

ClusterPoint& pt = points[j];
pt.min_index = -1;
pt.min_dist = numeric_limits<float>::max();
for (int i=0; i < num_centroids;   i)
{
    const ClusterCentroid& cent = centroids[i];
    const float dist = ...;
    if (dist < pt.min_dist) // <-- #1 hotspot
    {
        pt.min_dist = dist;
        pt.min_index = i;
    }
}

Zaman kodu bu bölümde, işlem için gerekli tüm birikimleri çoğu zaman beraberinde bir sürü işe yaramaz oldum çok önemli sayar. Dışarıda denir döngü koyarak değer, örneğin, ve belirli bir ağırlık merkezi için paralel noktaları arasında yinelemek olabilir. Küme sayısı hava masasında; çarpışma sayısı binlerce yayılmış olsa milyonlarca burada yayılan puan. Algoritmanın yineleme bir avuç (genellikle 10 altında) için uygulanır. İstikrar, sadece biraz mantıklı yaklaşım./mükemmel yakınsama aramazlar

Herhangi bir fikir takdir, ama gerçekten keşfetmek için can atıyorum ne varsa bu kodu SIMD bir sürüm için izin vermesi gibi şubesiz yapılabilir. Görmedim gerçekten gelişmiş bir tür zihinsel yeteneği kolayca kavramak ne kadar şubesiz çözüm: beynime başarısız pek çok şey gibi o zaman ben ilk maruz özyineleme ilk günlerde, bu yüzden bir rehber yazmayı şubesiz Kodu ve nasıl geliştirmek için uygun bir zihniyet için de yararlı olabilir.

Kısacası, ve ipuçları ve öneriler (mutlaka çözüm) hakkında herhangi bir kılavuz mikro-optimize bu kodu arıyorum. Büyük olasılıkla algoritmik iyileştirmeler için bir oda var, ama benim her zaman kör nokta-mikro optimizasyon çözümleri (ve onları daha etkili bir şekilde denize gidiyor olmadan nasıl uygulanacağını öğrenmek için merak ediyorum) olmuştur. Zaten mantık için tıknaz paralel ile sıkıca çok iş parçacıklı, çok akıllı bir algoritma olmadan salt denemek için hızlı şeylerden biri olarak mikro-optimizasyon köşeye sıkıştım. Bellek düzeni değiştirmek için tamamen özgürüz.

Algoritmik Önerilerine Yanıt olarak

Algoritmik düzeyde mikro-optimize açıkça geliştirilebilir(knm) O bir algoritma bulmaya çalışırken, yanlış bakma, ben de buna yürekten katılıyorum. Bu biraz akademik ve pratik bir aleme bu özel soru iter. Ancak, eğer ben olabilir izin bir anekdot, ben gel bir orijinal arka plan yüksek seviyeli programlama büyük önem geniş, büyük ölçekli bakış açısı, güvenlik, ve çok az üzerinde düşük seviyeli uygulama ayrıntıları. Ben zaten son zamanlarda açık projeler için bir çok farklı tür modern aromalı ve öğreniyorum her türlü yeni hileler arkadaşlarımın önbellek verimlilik, GPGPU, şubesiz teknikleri, SIMD, özel amaçlı mem yöneticileri gerçekten daha iyi performans malloc (ama belirli senaryolar), vb.

Nerede çalışıyorum yetiş ile son performans eğilimleri ve şaşırtıcı buldum bu eski veri yapıları sık sık tercih sırasında 90'lı yılların hangi arada bağlantılı/ağaç türü yapılardır aslında oldukça geride olmaktan çok daha saf, hayvani, mikro-optimize edilmiş, parallelized kodu uygulayarak ayarlı talimatları üzerine ardışık bellek blokları. Algoritmaları makine daha şimdi uydurma ve olanaklarını bu şekilde (özellikle GPGPU ile) daralması gibi hissediyorum bu yana, aynı anda biraz hayal kırıklığı.

Çok komik bir şey mikro-optimize edilmiş, hızlı bir dizi işlem kodu bu tür daha önce kullanıyordum karmaşık algoritmalar ve veri yapıları daha korumak için daha kolay buluyorum. Bir başlangıç için, genelleme yapmak daha kolaydır. Ayrıca, arkadaşlarımın genelde bir bölgede belirli bir yavaşlama hakkında müşteri şikayeti almak, sadece paralel ve muhtemelen bir SIMD tokat ve iyi bir hız ile yapılan arama yapabilirsiniz. Algoritmik geliştirmeler olabilir sık sık teklif oldukça fazla, ama çok hızlı ve olmayan intrusiveness olan bu mikro-optimizasyon uygulanabilir beni isteyen daha fazla bilgi edinmek için bu alanı okuma kağıtları algoritmaları daha iyi bir zaman olarak gerektiren daha kapsamlı değişiklikler). Bana da öyle atlama mikro-optimizasyon çoğunluğa biraz daha son zamanlarda, belki de biraz fazla bu özel durum, ama merakımı hakkında daha fazla genişleyen aralığı Olası çözümler için herhangi bir senaryo.

Demontaj

Not: ben gerçekten, gerçekten kötü kurulda bu yüzden ben genellikle ayarlanmış şeyler daha çok bir deneme yanılma biraz şekilde geliyor biraz eğitimli tahminler hakkında neden bir sıcak nokta gösterilen vtune olabilir darboğaz daha deneyip bazı şeyleri görmek için bu kez geliştirmek varsayarak tahmin biraz ipucu gerçeği ise bu kez geliştirmek veya tamamen cevapsız işareti yok.

000007FEEE3FB8A1  jl          thread_partition 70h (7FEEE3FB780h) 
    {
        ClusterPoint& pt = points[j];
        pt.min_index = -1;
        pt.min_dist = numeric_limits<float>::max();
        for (int i = 0; i < num_centroids;   i)
000007FEEE3FB8A7  cmp         ecx,r10d 
000007FEEE3FB8AA  jge         thread_partition 1F4h (7FEEE3FB904h) 
000007FEEE3FB8AC  lea         rax,[rbx rbx*2] 
000007FEEE3FB8B0  add         rax,rax 
000007FEEE3FB8B3  lea         r8,[rbp rax*8 8] 
        {
            const ClusterCentroid& cent = centroids[i];
            const float x = pt.pos[0] - cent.pos[0];
            const float y = pt.pos[1] - cent.pos[1];
000007FEEE3FB8B8  movss       xmm0,dword ptr [rdx] 
            const float z = pt.pos[2] - cent.pos[2];
000007FEEE3FB8BC  movss       xmm2,dword ptr [rdx 4] 
000007FEEE3FB8C1  movss       xmm1,dword ptr [rdx-4] 
000007FEEE3FB8C6  subss       xmm2,dword ptr [r8] 
000007FEEE3FB8CB  subss       xmm0,dword ptr [r8-4] 
000007FEEE3FB8D1  subss       xmm1,dword ptr [r8-8] 
            const float dist = x*x   y*y   z*z;
000007FEEE3FB8D7  mulss       xmm2,xmm2 
000007FEEE3FB8DB  mulss       xmm0,xmm0 
000007FEEE3FB8DF  mulss       xmm1,xmm1 
000007FEEE3FB8E3  addss       xmm2,xmm0 
000007FEEE3FB8E7  addss       xmm2,xmm1 

            if (dist < pt.min_dist)
// VTUNE HOTSPOT
000007FEEE3FB8EB  comiss      xmm2,dword ptr [rdx-8] 
000007FEEE3FB8EF  jae         thread_partition 1E9h (7FEEE3FB8F9h) 
            {
                pt.min_dist = dist;
000007FEEE3FB8F1  movss       dword ptr [rdx-8],xmm2 
                pt.min_index = i;
000007FEEE3FB8F6  mov         dword ptr [rdx-10h],ecx 
000007FEEE3FB8F9  inc         ecx  
000007FEEE3FB8FB  add         r8,30h 
000007FEEE3FB8FF  cmp         ecx,r10d 
000007FEEE3FB902  jl          thread_partition 1A8h (7FEEE3FB8B8h) 
    for (int j = *irange.first; j < *irange.last;   j)
000007FEEE3FB904  inc         edi  
000007FEEE3FB906  add         rdx,20h 
000007FEEE3FB90A  cmp         edi,dword ptr [rsi 4] 
000007FEEE3FB90D  jl          thread_partition 31h (7FEEE3FB741h) 
000007FEEE3FB913  mov         rbx,qword ptr [irange] 
            }
        }
    }
}

Geldik zorla içine hedefleme SSE 2 -- biraz arkasında bizim kez, ama kullanıcı tabanı aslında takıldı bir kere ne zaman farz ettiğimiz bile SSE 4 oldu Tamam bir dakika gereksinimi (kullanıcı vardı bazı prototip Intel makinesi).

Tek Başına Test ile güncelleştirmesi: ~5.6 saniye

Tüm yardımı sunuluyor, sana minnettarım! Kod ve kod karmaşık tetiklenmesi için koşullar (sistem olayları birden çok iş parçacığı üzerinde tetiklenen) oldukça geniş olduğundan, biraz deneysel değişiklikler yapmak ve onları profil için her zaman kullanışsız. Diğerleri de çalıştırmak ve böylece denemek nezaketle sunulan tüm bu çözümleri deneme olabilir bağımsız bir uygulama olarak tarafında yüzeysel bir test hazırladım.

#define _SECURE_SCL 0
#include <iostream>
#include <fstream>
#include <vector>
#include <limits>
#include <ctime>
#if defined(_MSC_VER)
    #define ALIGN16 __declspec(align(16))
#else
    #include <malloc.h>
    #define ALIGN16 __attribute__((aligned(16)))
#endif

using namespace std;

// Aligned memory allocation (for SIMD).
static void* malloc16(size_t amount)
{
    #ifdef _MSC_VER
        return _aligned_malloc(amount, 16);
    #else
        void* mem = 0;
        posix_memalign(&mem, 16, amount);
        return mem;
    #endif
}
template <class T>
static T* malloc16_t(size_t num_elements)
{
    return static_cast<T*>(malloc16(num_elements * sizeof(T)));
}

// Aligned free.
static void free16(void* mem)
{
    #ifdef _MSC_VER
        return _aligned_free(mem);
    #else
        free(mem);
    #endif
}

// Test parameters.
enum {num_centroids = 512};
enum {num_points = num_centroids * 2000};
enum {num_iterations = 5};
static const float range = 10.0f;

class Points
{
public:
    Points(): data(malloc16_t<Point>(num_points))
    {
        for (int p=0; p < num_points;   p)
        {
            const float xyz[3] =
            {
                range * static_cast<float>(rand()) / RAND_MAX,
                range * static_cast<float>(rand()) / RAND_MAX,
                range * static_cast<float>(rand()) / RAND_MAX
            };
            init(p, xyz);
        }
    }
    ~Points()
    {
        free16(data);
    }
    void init(int n, const float* xyz)
    {
        data[n].centroid = -1;
        data[n].xyz[0] = xyz[0];
        data[n].xyz[1] = xyz[1];
        data[n].xyz[2] = xyz[2];
    }
    void associate(int n, int new_centroid)
    {
        data[n].centroid = new_centroid;
    }
    int centroid(int n) const
    {
        return data[n].centroid;
    }
    float* operator[](int n)
    {
        return data[n].xyz;
    }

private:
    Points(const Points&);
    Points& operator=(const Points&);
    struct Point
    {
        int centroid;
        float xyz[3];
    };
    Point* data;
};

class Centroids
{
public:
    Centroids(Points& points): data(malloc16_t<Centroid>(num_centroids))
    {
        // Naive initial selection algorithm, but outside the 
        // current area of interest.
        for (int c=0; c < num_centroids;   c)
            init(c, points[c]);
    }
    ~Centroids()
    {
        free16(data);
    }
    void init(int n, const float* xyz)
    {
        data[n].count = 0;
        data[n].xyz[0] = xyz[0];
        data[n].xyz[1] = xyz[1];
        data[n].xyz[2] = xyz[2];
    }
    void reset(int n)
    {
        data[n].count = 0;
        data[n].xyz[0] = 0.0f;
        data[n].xyz[1] = 0.0f;
        data[n].xyz[2] = 0.0f;
    }
    void sum(int n, const float* pt_xyz)
    {
        data[n].xyz[0]  = pt_xyz[0];
        data[n].xyz[1]  = pt_xyz[1];
        data[n].xyz[2]  = pt_xyz[2];
          data[n].count;
    }
    void average(int n)
    {
        if (data[n].count > 0)
        {
            const float inv_count = 1.0f / data[n].count;
            data[n].xyz[0] *= inv_count;
            data[n].xyz[1] *= inv_count;
            data[n].xyz[2] *= inv_count;
        }
    }
    float* operator[](int n)
    {
        return data[n].xyz;
    }
    int find_nearest(const float* pt_xyz) const
    {
        float min_dist_squared = numeric_limits<float>::max();
        int min_centroid = -1;
        for (int c=0; c < num_centroids;   c)
        {
            const float* cen_xyz = data[c].xyz;
            const float x = pt_xyz[0] - cen_xyz[0];
            const float y = pt_xyz[1] - cen_xyz[1];
            const float z = pt_xyz[2] - cen_xyz[2];
            const float dist_squared = x*x   y*y * z*z;

            if (min_dist_squared > dist_squared)
            {
                min_dist_squared = dist_squared;
                min_centroid = c;
            }
        }
        return min_centroid;
    }

private:
    Centroids(const Centroids&);
    Centroids& operator=(const Centroids&);
    struct Centroid
    {
        int count;
        float xyz[3];
    };
    Centroid* data;
};

// A high-precision real timer would be nice, but we lack C  11 and
// the coarseness of the testing here should allow this to suffice.
static double sys_time()
{
    return static_cast<double>(clock()) / CLOCKS_PER_SEC;
}

static void k_means(Points& points, Centroids& centroids)
{
    // Find the closest centroid for each point.
    for (int p=0; p < num_points;   p)
    {
        const float* pt_xyz = points[p];
        points.associate(p, centroids.find_nearest(pt_xyz));
    }

    // Reset the data of each centroid.
    for (int c=0; c < num_centroids;   c)
        centroids.reset(c);

    // Compute new position sum of each centroid.
    for (int p=0; p < num_points;   p)
        centroids.sum(points.centroid(p), points[p]);

    // Compute average position of each centroid.
    for (int c=0; c < num_centroids;   c)
        centroids.average(c);
}

int main()
{
    Points points;
    Centroids centroids(points);

    cout << "Starting simulation..." << endl;
    double start_time = sys_time();
    for (int i=0; i < num_iterations;   i)
        k_means(points, centroids);
    cout << "Time passed: " << (sys_time() - start_time) << " secs" << endl;
    cout << "# Points: " << num_points << endl;
    cout << "# Centroids: " << num_centroids << endl;

    // Write the centroids to a file to give us some crude verification
    // of consistency as we make changes.
    ofstream out("centroids.txt");
    for (int c=0; c < num_centroids;   c)
        out << "Centroid " << c << ": " << centroids[c][0] << "," << centroids[c][1] << "," << centroids[c][2] << endl;
}

Yüzeysel test tehlikelerin farkındayım, ama zaten gerçek dünya önceki oturumlarında bir sıcak nokta olarak kabul olduğu için mazur umarım. Ayrıca sadece genel teknikleri mikro-optimize tür kodu ile ilgili ilgileniyorum.

Bu profil biraz farklı sonuçlar aldım. Bu kez biraz daha eşit döngü içinde dağınık ve neden emin değilim. Belki de verileri daha küçük (üye ihmal ve min_dist üye çekilir ve yerel bir değişken) yapılan içindir. Puan için hava masasında; çarpışma arasında tam oranı da biraz farklı, ama umarım yeterince yakın gelişmeler burada orijinal kodu çevirmek için. Ayrıca tek dişli bu yüzeysel test ve demontaj görünüyor oldukça farklı bu yüzden olabilir riske optimize bu yüzeysel test olmadan orijinal (bir riske girmeye hazırım almak için şimdi, ben daha fazla ilgi genişleyen bilgim teknikleri optimize olabilir bu gibi durumlarda yerine bir çözüm için bu kesin vaka).

VTune

Yohay Timmer Önerisi ile -- ~12.5 saniye güncelleştirin

Oh, anlayış montaj olmadan mikro-optimizasyon çok iyi sıkıntılarla karşı karşıyayım. Bunun yerine:

        -if (min_dist_squared > dist_squared)
        -{
        -    min_dist_squared = dist_squared;
        -    pt.centroid = c;
        -}

Bu:

         const bool found_closer = min_dist_squared > dist_squared;
         pt.centroid = bitselect(found_closer, c, pt.centroid);
         min_dist_squared = bitselect(found_closer, dist_squared, min_dist_squared);

sadece bir kez bulmak için .. ~12.5 saniye için ~5.6 saniye gelen tırmandı. Yine de, bu onun hatası değil, ne yapar elinden gelen değeri onun çözümü -- bu benim için başarısız anlamak için neler makinesi düzeyi ve bıçaklar alarak karanlıkta. Bir görünüşte cevapsız, ve görünüşe göre Ben başlangıçta düşünce olarak şube misprediction kurbanı ben değildim. Yine de, onun önerilen çözüm bu gibi durumlarda denemek için harika ve yaygın bir fonksiyonudur, ve ipuçları ve hileler benim araç eklemek için minnettarım. 2. tur için artık.

Harold SIMD Çözüm 2.496 saniye (bkz: uyarı)

Bu çözüm şaşırtıcı olabilir. Küme rep SoA dönüştürdükten sonra, bu bir ile ~2.5 saniye defa alıyorum! Ne yazık ki, bazı tür bir arıza var gibi görünüyor. Daha hafif, daha hassas farklılıklar gösteriyor son çıkış, 0 değerleri ile sonuna (arama bulunan olmadıklarını ima) yönelik bazı hava masasında; çarpışma da dahil olmak üzere çok farklı sonuçlar alıyorum. Deniyorum gitmek üzerinden SIMD mantığı ile hata ne olabilir ... olabilir sadece bir transkripsiyon hata benim, ama işte kod halinde biri olabilir nokta hata.

Eğer hata sonuçları yavaşlatmadan düzeltilmiş olabilir, bu hızlı gelişmeye hiç mikro-optimizasyon saf hayal daha fazla!

    // New version of Centroids::find_nearest (from harold's solution):
    int find_nearest(const float* pt_xyz) const
    {
        __m128i min_index = _mm_set_epi32(3, 2, 1, 0);
        __m128 xdif = _mm_sub_ps(_mm_set1_ps(pt_xyz[0]), _mm_load_ps(cen_x));
        __m128 ydif = _mm_sub_ps(_mm_set1_ps(pt_xyz[1]), _mm_load_ps(cen_y));
        __m128 zdif = _mm_sub_ps(_mm_set1_ps(pt_xyz[2]), _mm_load_ps(cen_z));
        __m128 min_dist = _mm_add_ps(_mm_add_ps(_mm_mul_ps(xdif, xdif), 
                                                _mm_mul_ps(ydif, ydif)), 
                                                _mm_mul_ps(zdif, zdif));
        __m128i index = min_index;
        for (int i=4; i < num_centroids; i  = 4) 
        {
            xdif = _mm_sub_ps(_mm_set1_ps(pt_xyz[0]), _mm_load_ps(cen_x   i));
            ydif = _mm_sub_ps(_mm_set1_ps(pt_xyz[1]), _mm_load_ps(cen_y   i));
            zdif = _mm_sub_ps(_mm_set1_ps(pt_xyz[2]), _mm_load_ps(cen_z   i));
            __m128 dist = _mm_add_ps(_mm_add_ps(_mm_mul_ps(xdif, xdif), 
                                                _mm_mul_ps(ydif, ydif)), 
                                                _mm_mul_ps(zdif, zdif));
            __m128i mask = _mm_castps_si128(_mm_cmplt_ps(dist, min_dist));
            min_dist = _mm_min_ps(min_dist, dist);
            min_index = _mm_or_si128(_mm_and_si128(index, mask), 
                                     _mm_andnot_si128(mask, min_index));
            index = _mm_add_epi32(index, _mm_set1_epi32(4));
        }

        ALIGN16 float mdist[4];
        ALIGN16 uint32_t mindex[4];
        _mm_store_ps(mdist, min_dist);
        _mm_store_si128((__m128i*)mindex, min_index);

        float closest = mdist[0];
        int closest_i = mindex[0];
        for (int i=1; i < 4; i  )
        {
            if (mdist[i] < closest) 
            {
                closest = mdist[i];
                closest_i = mindex[i];
            }
        }
        return closest_i;
    }

Harold SIMD Çözüm (Düzeltildi) - ~2.5 saniye

Düzeltmeleri uygulamak ve test sonuçları sağlam ve doğru orijinal bulunanla benzer gelişmeler işlevi!

Bunu daha iyi anlamak için arıyordum bilgisi (şubesiz SIMD) Kutsal Kase vurur bu yana, daha fazla işlem hızını iki katına çıkarmak için bazı ekstra sahne ile çözüm ödülü vereceğim. Amacım bu noktasal azaltmak için değil sadece, ama Olası çözümler benim kişisel anlayış genişletmek için onlarla başa çıkmak için bu yana ödevimi bunu anlamak için biçilmiş kaftan.

Yine de, tüm katkıları burada çok havalı bitselect kandırmak için algoritmik öneriler için minnettarım! Tüm cevapları kabul edebilmeyi isterdim. Bir noktada hepsi çalışıyor sonunda olabilirim, ama şimdi ödevimi olmayan aritmetik bu SIMD ops biraz anlayış çıkardım.

int find_nearest_simd(const float* pt_xyz) const
{
    __m128i min_index = _mm_set_epi32(3, 2, 1, 0);
    __m128 pt_xxxx = _mm_set1_ps(pt_xyz[0]);
    __m128 pt_yyyy = _mm_set1_ps(pt_xyz[1]);
    __m128 pt_zzzz = _mm_set1_ps(pt_xyz[2]);

    __m128 xdif = _mm_sub_ps(pt_xxxx, _mm_load_ps(cen_x));
    __m128 ydif = _mm_sub_ps(pt_yyyy, _mm_load_ps(cen_y));
    __m128 zdif = _mm_sub_ps(pt_zzzz, _mm_load_ps(cen_z));
    __m128 min_dist = _mm_add_ps(_mm_add_ps(_mm_mul_ps(xdif, xdif), 
                                            _mm_mul_ps(ydif, ydif)), 
                                            _mm_mul_ps(zdif, zdif));
    __m128i index = min_index;
    for (int i=4; i < num_centroids; i  = 4) 
    {
        xdif = _mm_sub_ps(pt_xxxx, _mm_load_ps(cen_x   i));
        ydif = _mm_sub_ps(pt_yyyy, _mm_load_ps(cen_y   i));
        zdif = _mm_sub_ps(pt_zzzz, _mm_load_ps(cen_z   i));
        __m128 dist = _mm_add_ps(_mm_add_ps(_mm_mul_ps(xdif, xdif), 
                                            _mm_mul_ps(ydif, ydif)), 
                                            _mm_mul_ps(zdif, zdif));
        index = _mm_add_epi32(index, _mm_set1_epi32(4));
        __m128i mask = _mm_castps_si128(_mm_cmplt_ps(dist, min_dist));
        min_dist = _mm_min_ps(min_dist, dist);
        min_index = _mm_or_si128(_mm_and_si128(index, mask), 
                                 _mm_andnot_si128(mask, min_index));
    }

    ALIGN16 float mdist[4];
    ALIGN16 uint32_t mindex[4];
    _mm_store_ps(mdist, min_dist);
    _mm_store_si128((__m128i*)mindex, min_index);

    float closest = mdist[0];
    int closest_i = mindex[0];
    for (int i=1; i < 4; i  )
    {
        if (mdist[i] < closest) 
        {
            closest = mdist[i];
            closest_i = mindex[i];
        }
    }
    return closest_i;
}

CEVAP
4 Mayıs 2015, PAZARTESİ


Şubesiz üçlü operatördür, bitselect ( koşul ? denilen bazen kullanabilirsiniz doğru : yanlış).
Sadece 2 üyeleri için, hiçbir şey yapmadan varsaymak kullanın.
Ekstra işlemleri hakkında endişelenme, eğer deyimi dallanma kıyaslanamaz.

uygulama bitselect:

inline static int bitselect(int condition, int truereturnvalue, int falsereturnvalue)
{
    return (truereturnvalue & -condition) | (falsereturnvalue & ~(-condition)); //a when TRUE and b when FALSE
}

inline static float bitselect(int condition, float truereturnvalue, float falsereturnvalue)
{
    //Reinterpret floats. Would work because it's just a bit select, no matter the actual value
    int& at = reinterpret_cast<int&>(truereturnvalue);
    int& af = reinterpret_cast<int&>(falsereturnvalue);
    int res = (at & -condition) | (af & ~(-condition)); //a when TRUE and b when FALSE
    return  reinterpret_cast<float&>(res);
}

Ve döngü bu gibi görünmelidir:

for (int i=0; i < num_centroids;   i)
{
  const ClusterCentroid& cent = centroids[i];
  const float dist = ...;
  bool isSmaeller = dist < pt.min_dist;

  //use same value if not smaller
  pt.min_index = bitselect(isSmaeller, i, pt.min_index);
  pt.min_dist = bitselect(isSmaeller, dist, pt.min_dist);
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Ralph Phillips

    Ralph Philli

    5 Aralık 2006
  • Rugiagialia

    Rugiagialia

    1 Ocak 2008
  • Strata1000

    Strata1000

    28 EYLÜL 2009