Как отличить size_t к double или int С++
Мой вопрос в том, что
У меня есть данные size_t, но теперь я хочу преобразовать его в double или int.
Если я что-то вроде
size_t data = 99999999;
int convertdata = data;
компилятор сообщит о предупреждении. потому что это может быть переполнение.
Есть ли у вас какой-то метод, например boost или какой-либо другой метод для преобразования?
Ответы
Ответ 1
Присвоение, как Блаз Братанич предложил:
size_t data = 99999999;
int convertdata = static_cast<int>(data);
вероятно, отключит предупреждение (хотя в принципе компилятор может предупредить обо всем, что ему нравится, даже если есть листинг).
Но это не решает проблему, о которой предупреждало вам предупреждение, а именно о том, что преобразование из size_t
в int
действительно может переполняться.
Если это вообще возможно, спроектируйте свою программу, поэтому вам не нужно преобразовывать значение size_t
в int
. Просто сохраните его в переменной size_t
(как вы уже сделали) и используйте это.
Преобразование в double
не приведет к переполнению, но это может привести к потере точности для очень большого значения size_t
. Опять же, нет смысла конвертировать a size_t
в double
; вам все равно лучше поддерживать значение в переменной size_t
.
Ответ 2
Статический бросок:
static_cast<int>(data);
Ответ 3
Вы можете использовать Boost numeric_cast
.
Это генерирует исключение, если исходное значение выходит за пределы целевого типа, но при преобразовании в double
оно не обнаруживает потерю точности.
Однако какую бы функцию вы ни использовали, вы должны решить, что вы хотите, в случае, когда значение в size_t
больше, чем INT_MAX
. Если вы хотите его обнаружить, используйте numeric_cast
или напишите свой собственный код для проверки. Если вы каким-то образом знаете, что это невозможно, вы можете использовать static_cast
для подавления предупреждения без затрат на проверку времени выполнения, но в большинстве случаев стоимость не имеет значения.
Ответ 4
Если ваш код готов справиться с ошибками переполнения, вы можете создать исключение, если 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);
Ответ 5
Предполагая, что программа не может быть перепроектирована, чтобы избежать приведения (ссылка Ответ Кит Томсон):
Чтобы отбрасывать из size_t в int, вам нужно убедиться, что size_t не превышает максимальное значение int. Это можно сделать, используя 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);
}
Если вам нужно отбрасывать из size_t в double, и вам нужно убедиться, что вы не потеряете точность, я думаю, вы можете использовать узкое литье (ссылка: Stroustrup: язык программирования С++, четвертое издание):
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-to-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) каждое четное целое может быть точно представлено и т.д.