Maison >développement back-end >C++ >Comment puis-je convertir efficacement entre des flottants double précision et des entiers 64 bits à l'aide des instructions SSE/AVX ?

Comment puis-je convertir efficacement entre des flottants double précision et des entiers 64 bits à l'aide des instructions SSE/AVX ?

Barbara Streisand
Barbara Streisandoriginal
2024-12-08 03:02:15466parcourir

How Can I Efficiently Convert Between Double-Precision Floats and 64-bit Integers Using SSE/AVX Instructions?

Conversions efficaces Double/int64 avec SSE/AVX

SSE2 fournit des éléments intrinsèques pour convertir des vecteurs entre des flottants simple précision et des entiers 32 bits, mais il lui manque des équivalents directs pour les entiers à virgule flottante double précision et 64 bits. AVX ne propose pas non plus ces conversions.

Méthodes de simulation des intrinsèques

1. Pour les valeurs limitées :

Si certaines limitations sont tolérées, les conversions entre doubles et int64 peuvent être effectuées avec seulement deux instructions :

  • double -> ; uint64_t :

    __m128i double_to_uint64(__m128d x){
      x = _mm_add_pd(x, _mm_set1_pd(0x0010000000000000));
      return _mm_xor_si128(
          _mm_castpd_si128(x),
          _mm_castpd_si128(_mm_set1_pd(0x0010000000000000))
      );
    }
  • double -> int64_t :

    __m128i double_to_int64(__m128d x){
      x = _mm_add_pd(x, _mm_set1_pd(0x0018000000000000));
      return _mm_sub_epi64(
          _mm_castpd_si128(x),
          _mm_castpd_si128(_mm_set1_pd(0x0018000000000000))
      );
    }
  • uint64_t -> double :

    __m128d uint64_to_double(__m128i x){
      x = _mm_or_si128(x, _mm_castpd_si128(_mm_set1_pd(0x0010000000000000)));
      return _mm_sub_pd(_mm_castsi128_pd(x), _mm_set1_pd(0x0010000000000000));
    }
  • int64_t -> double :

    __m128d int64_to_double(__m128i x){
      x = _mm_add_epi64(x, _mm_castpd_si128(_mm_set1_pd(0x0018000000000000)));
      return _mm_sub_pd(_mm_castsi128_pd(x), _mm_set1_pd(0x0018000000000000));
    }

2. Gamme complète int64 -> double :

Pour convertir la plage complète int64 en double, 5 instructions sont nécessaires pour uint64_t et 6 instructions pour int64_t :

  • uint64_t -> ; double :

    __m128d uint64_to_double_full(__m128i x){
      __m128i xH = _mm_srli_epi64(x, 32);
      xH = _mm_or_si128(xH, _mm_castpd_si128(_mm_set1_pd(19342813113834066795298816.)));          //  2^84
      __m128i xL = _mm_blend_epi16(x, _mm_castpd_si128(_mm_set1_pd(0x0010000000000000)), 0xcc);   //  2^52
      __m128d f = _mm_sub_pd(_mm_castsi128_pd(xH), _mm_set1_pd(19342813118337666422669312.));     //  2^84 + 2^52
      return _mm_add_pd(f, _mm_castsi128_pd(xL));
    }
  • int64_t -> double :

    __m128d int64_to_double_full(__m128i x){
      __m128i xH = _mm_srai_epi32(x, 16);
      xH = _mm_blend_epi16(xH, _mm_setzero_si128(), 0x33);
      xH = _mm_add_epi64(xH, _mm_castpd_si128(_mm_set1_pd(442721857769029238784.)));              //  3*2^67
      __m128i xL = _mm_blend_epi16(x, _mm_castpd_si128(_mm_set1_pd(0x0010000000000000)), 0x88);   //  2^52
      __m128d f = _mm_sub_pd(_mm_castsi128_pd(xH), _mm_set1_pd(442726361368656609280.));          //  3*2^67 + 2^52
      return _mm_add_pd(f, _mm_castsi128_pd(xL));
    }

AVX512

AVX512 offre des conversions directes vers/depuis des entiers 64 bits, signés et non signés signé. Ces conversions sont effectuées à l'aide d'intrinsèques tels que _mm512_cvtpd_epi64 et _mm256_cvtpd_epi64.

Veuillez noter que ces solutions ne sont pas fournies sous forme de code complet. Le lecteur est invité à les compléter et à les optimiser si nécessaire pour les adapter à son contexte spécifique.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn