2015-08-04 6 views
5

Sto cercando di creare un decodificatore veloce per BPSK utilizzando gli intrinseci AVX di Intel. Ho una serie di numeri complessi che sono rappresentati come galleggianti intercalati, ma a causa della modulazione BPSK sono necessari solo la parte reale (o i float indicizzati pari). Ogni floatviene mappato su 0, quando x < 0 e su 1 se x >= 0. Questa operazione viene eseguita utilizzando la seguente procedura:Confronto con NaN utilizzando AVX

static inline void 
normalize_bpsk_constellation_points(int32_t *out, const complex_t *in, size_t num) 
{ 
    static const __m256    _min_mask = _mm256_set1_ps(-1.0); 
    static const __m256    _max_mask = _mm256_set1_ps(1.0); 
    static const __m256    _mul_mask = _mm256_set1_ps(0.5); 

    __m256       res; 
    __m256i       int_res; 

    size_t i; 
    gr_complex      temp; 
    float       real; 

    for(i = 0; i < num; i += COMPLEX_PER_AVX_REG){ 
      res = _mm256_load_ps((float *)&in[i]); 

      /* clamp them to avoid segmentation faults due to indexing */ 
      res = _mm256_max_ps(_min_mask, _mm256_min_ps(_max_mask, res)); 

      /* Scale accordingly for proper indexing -1->0, 1->1 */ 
      res = _mm256_add_ps(res, _max_mask); 
      res = _mm256_mul_ps(res, _mul_mask); 

      /* And then round to the nearest integer */ 
      res = _mm256_round_ps(res, _MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC); 

      int_res = _mm256_cvtps_epi32(res); 

      _mm256_store_si256((__m256i *) &out[2*i], int_res); 
    } 
} 

primo luogo, morsetto tutti i galleggianti ricevuti nell'intervallo [-1, 1]. Quindi, dopo un corretto ridimensionamento, il risultato viene arrotondato al numero intero più vicino. Questo mapperà tutti i galleggianti sopra 0.5 a 1 e tutti galleggiano sotto 0.5 a 0.

La procedura funziona correttamente se i valori di inserimento sono normali. Tuttavia, a causa di alcune situazioni nelle fasi precedenti, esiste la possibilità che alcuni valori di inserimento siano NaN o -NaN. In questo caso, i numeri "NaN" vengono propagati attraverso lo _mm256_max_ps(), _mm256_min_ps() e tutte le altre funzioni AVX risultanti in un mapping intero di -2147483648 che, naturalmente, causa il blocco del mio programma a causa di indicizzazione non valida.

Esiste una soluzione alternativa per evitare questo problema o almeno impostare NaN su 0 utilizzando AVX?

+0

'(float *) e in [i]' 'getta una complessa *' a 'float *'. Invito a comportamento indefinito. – Olaf

+0

No, 'complex_t' punta a un'area di memoria con float interlacciati che rappresentano un numero complesso. – Manos

+0

Ancora un problema di aliasing imo. E il layout di complex_t è definito dall'implementazione. – Olaf

risposta

4

Si potrebbe fare il modo più semplice per cominciare, confrontare e la maschera: (non testato)

res = _mm256_cmp_ps(res, _mm256_setzero_ps(), _CMP_NLT_US); 
ires = _mm256_srl_epi32(_mm256_castps_si256(res), 31); 

o Maiusc e XOR: (anche non testato)

ires = _mm256_srl_epi32(_mm256_castps_si256(res), 31); 
ires = _mm256_xor_epi32(ires, _mm256_set1_epi32(1)); 

questa versione sarà si preoccupa anche del segno di NaN (e ignora la NaN-ness).

alternativa per nessun AVX2 (non testato)

res = _mm256_cmp_ps(res, _mm256_setzero_ps(), _CMP_NLT_US); 
res = _mm256_and_ps(res, _mm256_set1_ps(1.0f)); 
ires = _mm256_cvtps_epi32(res); 
+0

Hmm Penso che tu abbia ragione. Controllerò la versione 'AVX' e tornerò per i risultati;) – Manos

+0

@Manos oh aspetta, ho appena notato, volevi * numero intero * 0 e 1? Cambierò il codice – harold

+0

sì, ma ho capito il tuo punto. – Manos

3

Harold ha registrato una buona soluzione per la questione si stava realmente chiedendo, ma voglio chiarire che l'eliminazione valori NaN mentre bloccaggio è del tutto semplice. Se uno degli argomenti è un NaN, MINPS e MAXPS restituiscono semplicemente il secondo argomento. Quindi tutto ciò che devi fare è scambiare l'ordine degli argomenti e anche i NaN verranno bloccati. Ad esempio, la seguente sarebbe fissare NaNs a _min_mask:

res = _mm256_max_ps(_mm256_min_ps(_max_mask, res), _min_mask);