Все работало замечательно, пока этот код не увидел VC7
warning C4146: unary minus operator applied to unsigned type, result still unsigned
Ну, думаю, это не порядок и нужно переделать. Написал:
sv=-static_cast<__int64>(usv);
Предупреждение пропало, но меня начало колбасить другое — есть гарантии что здесь нет и не будет проблем? Бинарное представление usv и sv я себе представляю, но вот как максимально корректно (с точки зрения плюсов), без нагромождения if-ов, преобразовать их друг в друга — туплю
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Когда я обрабатываю положительное число, все ясно — проверяем, что usv <= _I64_MAX. Вот когда отрицательное — затупил. Изначально был такой код: КД>
КД>Все работало замечательно, пока этот код не увидел VC7 КД>
КД>warning C4146: unary minus operator applied to unsigned type, result still unsigned
КД>
КД>Ну, думаю, это не порядок и нужно переделать. Написал: КД>
КД>sv=-static_cast<__int64>(usv);
КД>
КД>Предупреждение пропало, но меня начало колбасить другое — есть гарантии что здесь нет и не будет проблем?
За исключением случая "минус ноль" поведение кода со static_cast вполне предсказуемо:
4.7/3
If the destination type is signed, the value is unchanged if it can be represented
in the destination type (and bit-field width); otherwise, the value is implementation-defined.
ну а этот самый "минус ноль" все-таки придется проверять отдельно...
Здравствуйте, Bell, Вы писали:
КД>>Когда я обрабатываю положительное число, все ясно — проверяем, что usv <= _I64_MAX. Вот когда отрицательное — затупил. Изначально был такой код:
Тут надо было пояснить, что usv хранит модуль (отрицательного) результата...
Если usv больше этого числа, значит у знакового типа в отрицательном представлении пойдет переполнение.
B>За исключением случая "минус ноль" поведение кода со static_cast вполне предсказуемо: B>
B>4.7/3
B>If the destination type is signed, the value is unchanged if it can be represented
B>in the destination type (and bit-field width); otherwise, the value is implementation-defined.
B>
B>ну а этот самый "минус ноль" все-таки придется проверять отдельно...
Этот код возврата пересекается с ожидаемым результатом при usv == 2147352566 (на two’s complement платформе).
КД>if(usv==static_cast<unsigned __int64>(_I64_MAX))+1)
КД> return _I64_MIN;
КД>return -static_cast<__int64>(sv); // вероятно, имелось в виду (usv)?
КД>
КД> Меня параноиком не будут обзывать?
Это ещё недостаточно параноидально. Код верен только для случая, если отрицательные числа представляются как two’s complement. А стандарт C допускает также модели sign and magnitude и one’s complement, в которых -2^N тоже непредставимо.
Проверять, живём ли мы под two’s complement или под какой-нибудь симметричной моделью, думаю, можно так:
template <typename Signed, typename Unsigned>
Signed negate(Unsigned u)
{
typedef std::numeric_limits<Signed> Limits;
const Unsigned max_magnitude = static_cast<Unsigned>((Limits::max)())
+ ((Limits::min)() + (Limits::max)() == 0 ? 0U : 1U);
// max_magnitude === |Limits::min()| в терминах «настоящей» арифметикиif (u > max_magnitude) throw std::overflow_error("overflow"); // заменить обработку ошибок по вкусуif (u == max_magnitude) return (Limits::min)();
// если мы дошли сюда, то преобразование корректно, и отрицание тожеreturn -static_cast<Signed>(u);
}