web-dev-qa-db-fra.com

Existe-t-il un entier de 128 bits en C++?

J'ai besoin de stocker une longueur de 128 bits UUID dans une variable. Existe-t-il un type de données 128 bits en C++? Je n'ai pas besoin d'opérations arithmétiques, je veux simplement stocker et lire la valeur très rapidement.

Une nouvelle fonctionnalité de C++ 11 conviendrait également.

50
danijar

Prise en charge de GCC et Clang __int128

29
doron

Commander Mise en œuvre de boost :

#include <boost/multiprecision/cpp_int.hpp>

using namespace boost::multiprecision;

int128_t v = 1;

C'est mieux que les chaînes et les tableaux, surtout si vous devez faire des opérations arithmétiques avec.

36
Patrik Beck

Bien que GCC fournisse __int128, il est pris en charge uniquement pour les cibles (processeurs) dont le mode entier est suffisamment large pour contenir 128 bits. Sur un système donné, sizeof () intmax_t et uintmax_t déterminent la valeur maximale prise en charge par le compilateur et la plate-forme.

26
Onkar

Votre question comporte deux parties.

1 .128-bin entier. Comme suggéré par @PatrikBeck, boost::multiprecision est un bon moyen de gérer de très grands nombres entiers.

2.Variable pour stocker UUID/GUID/CLSID ou le nom de votre choix. Dans ce cas, boost::multiprecision n'est pas une bonne idée. Vous avez besoin de la structure GUID qui est conçue à cet effet. Lorsque vous ajoutez une balise multiplate-forme, vous pouvez simplement copier cette structure dans votre code et lui donner la forme suivante:

struct GUID
{
    uint32_t Data1;
    uint16_t Data2;
    uint16_t Data3;
    uint8_t Data4[8];
};

Ce format est défini par Microsoft pour des raisons internes. Vous pouvez même le simplifier pour: 

struct GUID
{
    uint8_t Data[16];
};

Vous obtiendrez de meilleures performances grâce à une structure simple plutôt qu’à un objet capable de gérer un tas de choses différentes. Quoi qu'il en soit, vous n'avez pas besoin de faire de calcul avec GUIDS, vous n'avez donc besoin d'aucun objet de fantaisie.

7
ST3

Il n'y a pas d'entier 128 bits dans Visual-C++, car la convention d'appel de Microsoft autorise uniquement le renvoi de 2 valeurs 32 bits dans la paire RAX: EAX. La présente un mal de tête constant, car lorsque vous multipliez deux entiers avec le résultat est un entier de deux mots. La plupart des machines Load-and-Store prennent en charge l'utilisation de deux unités entières de la taille d'un mot, mais opérer avec 4 requiert un piratage logiciel. Un processeur 32 bits ne peut donc pas traiter les entiers 128 bits et les processeurs 8 et 16 bits ne peuvent pas le faire. -bits entiers sans piratage logiciel assez coûteux. Les processeurs 64 bits peuvent fonctionner régulièrement avec 128 bits, car si vous multipliez deux entiers 64 bits, vous obtenez un entier de 128 bits. Par conséquent, la version 4.6 de GCC prend en charge les entiers de 128 bits. Cela pose un problème avec l'écriture de code portable car vous devez effectuer un piratage laid en retournant un mot 64 bits dans le registre de retour et en laissant passer l'autre en utilisant une référence. Par exemple, pour imprimer rapidement un nombre à virgule flottante avec Gris , nous utilisons la multiplication non signée sur 128 bits comme suit:

#include <cstdint>
#if defined(_MSC_VER) && defined(_M_AMD64)
#define USING_VISUAL_CPP_X64 1
#include <intrin.h>
#include <intrin0.h>
#pragma intrinsic(_umul128)
#Elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
#define USING_GCC 1
#if defined(__x86_64__)
#define COMPILER_SUPPORTS_128_BIT_INTEGERS 1
#endif
#endif

#if USING_VISUAL_CPP_X64
    UI8 h;
    UI8 l = _umul128(f, rhs_f, &h);
    if (l & (UI8(1) << 63))  // rounding
      h++;
    return TBinary(h, e + rhs_e + 64);
#Elif USING_GCC
    UIH p = static_cast<UIH>(f) * static_cast<UIH>(rhs_f);
    UI8 h = p >> 64;
    UI8 l = static_cast<UI8>(p);
    if (l & (UI8(1) << 63))  // rounding
      h++;
    return TBinary(h, e + rhs_e + 64);
#else
    const UI8 M32 = 0xFFFFFFFF;
    const UI8 a = f >> 32;
    const UI8 b = f & M32;
    const UI8 c = rhs_f >> 32;
    const UI8 d = rhs_f & M32;
    const UI8 ac = a * c;
    const UI8 bc = b * c;
    const UI8 ad = a * d;
    const UI8 bd = b * d;
    UI8 tmp = (bd >> 32) + (ad & M32) + (bc & M32);
    tmp += 1U << 31;  /// mult_round
    return TBinary(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs_e + 64);
#endif
  }
2
Cale McCollough

utilisez le modèle TBigInteger et définissez une plage de bits dans le tableau de modèles, comme TBigInt <128, true> pour qu'il s'agisse d'un entier signé 128 bits ou TBigInt <128, false> pour un entier non signé 128 bits. J'espère que cela aide peut-être une réponse tardive et que quelqu'un d'autre a déjà trouvé cette méthode.

0
Silanus

Je recommanderais d'utiliser std::bitset<128> (vous pouvez toujours faire quelque chose comme using UUID = std::bitset<128>;). Sa structure de mémoire sera probablement similaire à celle de la structure personnalisée proposée dans les autres réponses, mais vous n’aurez pas à définir vos propres opérateurs de comparaison, hachage, etc.

0
Mikhail Vasilyev