Есть два целых числа типа std::intmax_t
Необходимо произвести над ними одну из следующих операций: сложение, вычитание, умножение.
Но при переполнении результата преобразовать числа в double перед операцией и вернуть double.
А если переполнения нет, то вернуть целый результат.
Можно конечно сделать double операцию, и сравнить результат с диапазоном min() max() целого. Если всё ок, то произвести целочисленную операцию.
1) ловить исключение. Стандартная библиотека это не поддерживает, но буст может:
The mathematical functions of the standard library components do not throw this exception (mathematical functions report overflow errors as specified in math_errhandling). Third-party libraries, however, use this. For example, boost.math throws std::overflow_error if boost::math::policies::throw_on_error is enabled (the default setting).
2) заморочиться с логикой на битах. Типа, если у нас сложение, и старшие биты обеих чисел нули, то можно спокойно складывать целочисленно, ну и так далее для других операций.
Патриот здравого смысла
Re: детектировать переполнения при целочисленных операциях
Здравствуйте, Sm0ke, Вы писали:
S>Они я так понимаю только в GCC доступны. Необходим портируемый способ. Я использую VS community 22.
Ну тогда давай по-сложному.
Переполнение происходит тогда и только тогда, когда сумма двух неотрицательных отрицательно либо когда сумма двух отрицательных неотрицательна. Проверяешь знаки чисел до и после операции короч
Re[3]: детектировать переполнения при целочисленных операциях
Здравствуйте, Sm0ke, Вы писали:
K>>Здравствуйте, Sm0ke, Вы писали:
K>>__builtin_add_overflow, __builtin_sub_overflow, __builtin_mul_overflow
S>Они я так понимаю только в GCC доступны. Необходим портируемый способ. Я использую VS community 22.
Здравствуйте, Sm0ke, Вы писали:
S>Какие есть ещё варианты?
Это тестовое задание? Я полагаю, тут надо какой-то алгоритмический трюк использовать, возможно с битами, чтобы понять будет ли переполнение или нет до того как выполнить операцию.
Sic luceat lux!
Re[4]: детектировать переполнения при целочисленных операциях
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, Sm0ke, Вы писали:
S>>Они я так понимаю только в GCC доступны. Необходим портируемый способ. Я использую VS community 22.
TB>Ну тогда давай по-сложному.
TB>Переполнение происходит тогда и только тогда, когда сумма двух неотрицательных отрицательно либо когда сумма двух отрицательных неотрицательна. Проверяешь знаки чисел до и после операции короч
Переполнение при операциях со знаковыми целыми — это UB.
Re[5]: детектировать переполнения при целочисленных операциях
Здравствуйте, Sm0ke, Вы писали:
S>Можно конечно сделать double операцию, и сравнить результат с диапазоном min() max() целого. Если всё ок, то произвести целочисленную операцию.
А есть гарантии, что при преобразовании в double не произойдет потери точности? А то ведь intmax_t может быть и 64, и больше бит. При преобразовании в double вы потеряете последние биты и потом схлопочете переполнение.
S>Какие есть ещё варианты?
Проверять обратными операциями. Псевдокод.
if (a ^ b < 0) //разный знак
return a + b;
if (a > 0)
if (intmax_max - a >= b)
return a + b;
else
return ((double) a) + ((double) b);
if (intmax_min - a <= b)
return a + b;
else
return ((double) a) + ((double) b);
Проверка знаков гарантирует, что при вычислении границ мы остаемся в рамках диапазона. Т.е. вычитаем из intmax_max только неотрицательные значения.
Для умножения все гораздо сложнее. Что-то вроде:
if (a == 0 || a == 1 || b == 0 || b == 1)
return a * b;
if (a > 0 && b > 0)
if (intmax_max / a >= b)
return a * b;
else
return ((double) a) * ((double) b);
if (a < 0 && b < 0)
if (a == intmax_min || b == intmax_min || (intmax_max / (-a) < (-b)))
return ((double) a) * ((double) b);
else
return a * b;
if (a > 0)
if (intmax_min / a <= b)
return a * b;
else
return ((double) a) * ((double) b);
else // b > 0
if (intmax_min / b <= a)
return a * b;
else
return ((double) a) * ((double) b);
Обратите внимание — intmax_min обрабатывается отдельно, для него отрицание плохо работает. Может быть, можно упростить делением положительного числа на отрицательное для проверки. Нужно смотреть спецификацию.
Re: детектировать переполнения при целочисленных операциях
Здравствуйте, Sm0ke, Вы писали:
S>Есть два целых числа типа std::intmax_t S>Необходимо произвести над ними одну из следующих операций: сложение, вычитание, умножение. S>Но при переполнении результата преобразовать числа в double перед операцией и вернуть double. S>А если переполнения нет, то вернуть целый результат.
S>Какие есть ещё варианты?
на асме накарячить по крайней мере для стандартных int'ов (32 bits) для x86 там можно было считать бит (после совершения операции) и по нему узнать — было ли переполнение, а также напр. при умножении результат лежит уже не в одном регистре (32-bit), а в двух ..
думаю x86-64 есть аналогичные варики для long (64 bits) ..
насчёт флагов во всяких MMX/SSE/AVX/AVX2 хз, как целочисленных возможностей последних (SSE/AVX/AVX2) — хз ..
но в любом случае, даже на x86 за счёт флага-бита переполнения можно было организовать работу с целыми числами любой разрядности — без потери точности .. (актуально для банковских приложений, переводы/счета и т.д.)
подробнее тут, "Assembler. Учебник для вузов. 2-е изд. В. И. Юров"
(для общего сведения)
[страница 165] Глава 8. Арифметические команды
(ну и собственно про сами операции с двоичными числами произвольной длины)
[страница 183] Арифметические операции над двоично-десятичными числам
P.S.:
нахрен я только в своё время голову засорял подобным ..
Здравствуйте, T4r4sB, Вы писали:
S>>Переполнение при операциях со знаковыми целыми — это UB.
TB>Ну тогда шо делать, кастануть к беззнаковым, сложить, кастануть обратно.
"Кастануть обратно" в общем случае разве не проблемно?
(в стандарте как-то сложно искать)
(и да, C++20 не всегда есть)
The God is real, unless declared integer.
Re: примерный результат (переполнения целочисленных)
Ещё добавил деление и modulo (%) — остаток от деления. При делении будет целый результат, только если делится на-цело.
Так-же учитывается int_min / (-1), при котором результат будет с плавающей точкой.
Используется std::variant, где std::monostate — это специальное состояние, математические операции с которым дают тоже monostate.
using t_mono = std::monostate;
using t_var = std::variant<t_mono, t_int, t_float>;
Здравствуйте, Sm0ke, Вы писали:
S>Есть два целых числа типа std::intmax_t S>Необходимо произвести над ними одну из следующих операций: сложение, вычитание, умножение. S>Но при переполнении результата преобразовать числа в double перед операцией и вернуть double. S>А если переполнения нет, то вернуть целый результат.
S>Можно конечно сделать double операцию, и сравнить результат с диапазоном min() max() целого. Если всё ок, то произвести целочисленную операцию.
S>Какие есть ещё варианты?
В solidity вот так делают (см https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol)
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
Может и вам подойдет
Re[5]: детектировать переполнения при целочисленных операциях
Здравствуйте, reversecode, Вы писали:
S>>Переполнение при операциях со знаковыми целыми — это UB.
R>с каких это пор, а не наоборот ? R>знаковые врапаются
Здравствуйте, cures, Вы писали:
C>Здравствуйте, Sm0ke, Вы писали:
S>>Переполнение при операциях со знаковыми целыми — это UB.
C>С простыми интами — UB, а с intmax?
если intmax знаковый то тоже https://happydapps.com/ru/article/cpp-signed-overflow