Мой вопрос в том, что
У меня есть данные size_t, но теперь я хочу преобразовать их в double или int.
Если я сделаю что-то вроде
size_t data = 99999999;
int convertdata = data;
компилятор выдаст предупреждение. потому что это может быть переполнено.
У вас есть какой-нибудь метод, такой как повышение или другой метод для преобразования?
В ролях, как предложил Блаз Братаник:
size_t data = 99999999;
int convertdata = static_cast<int>(data);
скорее всего заставит замолчать предупреждение (хотя в принципе компилятор может предупреждать обо всем, что ему нравится, даже если есть приведение).
Но это не решает проблему, о которой говорилось в предупреждении, а именно, что преобразование из size_t
в int
действительно может переполниться.
Если это вообще возможно, разработайте свою программу так, чтобы вы не необходимость преобразовать size_t
значение для int
, Просто храните его в size_t
переменная (как вы уже сделали) и использовать это.
Преобразование в double
не приведет к переполнению, но это может привести к потере точности для очень большого size_t
значение. Опять же, не имеет большого смысла конвертировать size_t
к double
; вам все еще лучше держать значение в size_t
переменная.
(Р Саху ответ есть несколько советов, если вы не можете избежать приведения, например, выбрасывать исключение при переполнении.)
Статическое приведение:
static_cast<int>(data);
Вы можете использовать Boost numeric_cast
.
Это вызывает исключение, если исходное значение выходит за пределы диапазона целевого типа, но оно не обнаруживает потерю точности при преобразовании в double
,
Независимо от того, какую функцию вы используете, вы должны решить, что вы хотите, чтобы произошло в случае, когда значение в size_t
больше, чем INT_MAX
, Если вы хотите обнаружить это, используйте numeric_cast
или напишите свой собственный код для проверки. Если вы как-то знаете, что это не может произойти, вы можете использовать static_cast
подавить предупреждение без затрат на проверку времени выполнения, но в большинстве случаев стоимость все равно не имеет значения.
Если ваш код готов справиться с ошибками переполнения, вы можете вызвать исключение, если data
слишком велик
size_t data = 99999999;
if ( data > INT_MAX )
{
throw std::overflow_error("data is larger than INT_MAX);
}
int convertData = static_cast<int>(data);
Предполагая, что программа не может быть переработана, чтобы избежать приведения (см. Ответ кита томсона):
Для приведения типа size_t к int необходимо убедиться, что size_t не превышает максимальное значение типа int. Это можно сделать с помощью СТД :: 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);
}
Если вам нужно привести от size_t к удвоению, и вам нужно убедиться, что вы не теряете точность, я думаю, вы можете использовать узкое приведение (см. Страуструп: Язык программирования C ++, четвертое издание):
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;
}
Я проверил использование узкого приведения для преобразований size_t-double, проверив пределы максимальных целых чисел, представляющих числа с плавающей точкой (код использует 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);
}
То есть, если N — это число цифр в мантиссе, для двойных чисел, меньших или равных 2 ^ N, целые числа могут быть точно представлены. Для двойных чисел от 2 ^ N до 2 ^ (N + 1) любое другое целое число может быть точно представлено. Для двойных чисел от 2 ^ (N + 1) до 2 ^ (N + 2) каждое четвертое целое число может быть точно представлено, и так далее.