web-dev-qa-db-fra.com

Comment convertir le size_t en double ou int C ++

Ma question est que

J'ai une taille_t données, mais maintenant je veux le convertir en double ou int.

Si je fais quelque chose comme

 size_t data = 99999999;
 int convertdata = data;

le compilateur signalera un avertissement. parce que peut-être déborder.

Avez-vous une méthode comme le boost ou une autre méthode pour convertir?

35
user2701639

Un casting, comme suggéré par Blaz Bratanic :

size_t data = 99999999;
int convertdata = static_cast<int>(data);

est susceptible de faire taire l'avertissement (bien qu'en principe un compilateur puisse avertir de tout ce qu'il veut, même s'il y a un casting).

Mais cela ne résout pas le problème évoqué par l'avertissement, à savoir qu'une conversion de size_t à int pourrait vraiment déborder.

Si possible, concevez votre programme de manière à ne pas convertir pour convertir un size_t valeur à int. Il suffit de le stocker dans un size_t variable (comme vous l'avez déjà fait) et utilisez-le.

La conversion en double ne provoquera pas de dépassement de capacité, mais cela pourrait entraîner une perte de précision pour un très grand size_t valeur. Encore une fois, il n’a pas beaucoup de sens de convertir un size_t à un double; il vaut mieux garder la valeur dans un size_t variable.

( Réponse de R Sah a quelques suggestions si vous ne pouvez pas éviter le casting, telles que le lancement d'une exception lors d'un débordement.)

51
Keith Thompson

Fonte statique:

static_cast<int>(data);
15
Blaz Bratanic

Si votre code est prêt à gérer les erreurs de débordement, vous pouvez lever une exception si data est trop volumineux.

size_t data = 99999999;
if ( data > INT_MAX )
{
   throw std::overflow_error("data is larger than INT_MAX);
}
int convertData = static_cast<int>(data);
13
R Sahu

Vous pouvez utiliser Boost numeric_cast .

Cela lève une exception si la valeur source est en dehors des limites du type de destination, mais ne détecte pas de perte de précision lors de la conversion en double.

Quelle que soit la fonction que vous utilisez, vous devez toutefois décider de ce que vous voulez qu'il se passe dans le cas où la valeur dans le size_t est supérieur à INT_MAX. Si vous voulez le détecter, utilisez numeric_cast ou écrivez votre propre code pour vérifier. Si vous savez que cela ne peut pas arriver, vous pouvez utiliser static_cast pour supprimer l'avertissement sans le coût d'une vérification de l'exécution, mais dans la plupart des cas, le coût importe peu.

9
Steve Jessop

En supposant que le programme ne puisse pas être repensé pour éviter la distribution (réf. réponse de Keith Thomson ):

Pour convertir de size_t en int, vous devez vous assurer que size_t ne dépasse pas la valeur maximale de int. Cela peut être fait en utilisant std :: numeric_limits :

int SizeTToInt(size_t data)
{
    if (data > std::numeric_limits<int>::max())
        throw std::exception("Invalid cast.");
    return std::static_cast<int>(data);
}

Si vous avez besoin de convertir de size_t en double et de ne pas perdre en précision, je pense que vous pouvez utiliser une distribution étroite (réf. Stroustrup: langage de programmation C++, quatrième édition):

template<class Target, class Source>
Target NarrowCast(Source v)
{
    auto r = static_cast<Target>(v);
    if (static_cast<Source>(r) != v)
        throw RuntimeError("Narrow cast failed.");
    return r;
}

J'ai testé l'utilisation de la conversion étroite pour les conversions taille_t-en-double en inspectant les limites du nombre entier maximal d'entiers en nombres à représenter en virgule flottante (le code utilise googletest):

EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 2 })), size_t{ IntegerRepresentableBoundary() - 2 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 1 })), size_t{ IntegerRepresentableBoundary() - 1 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() })), size_t{ IntegerRepresentableBoundary() });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 1 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 2 })), size_t{ IntegerRepresentableBoundary() + 2 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 3 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 4 })), size_t{ IntegerRepresentableBoundary() + 4 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 5 }), std::exception);

constexpr size_t IntegerRepresentableBoundary()
{
    static_assert(std::numeric_limits<double>::radix == 2, "Method only valid for binary floating point format.");
    return size_t{2} << (std::numeric_limits<double>::digits - 1);
}

Autrement dit, si N est le nombre de chiffres de la mantisse, pour les doublons inférieurs ou égaux à 2 ^ N, les entiers peuvent être représentés exactement. Pour les doubles entre 2 ^ N et 2 ^ (N + 1), un entier sur deux peut être représenté exactement. Pour les doublons entre 2 ^ (N + 1) et 2 ^ (N + 2), un entier sur quatre peut être représenté exactement, et ainsi de suite.

1
Ida