LINUX.ORG.RU

[C]Проверка на переполнение int

 


0

0

Какой способ проверки на переполнение int (а также long int и т.д.) самое труЪ? Кроме откровенно быдлокодерских, пока на ум пришло следующее: 1) Не использовать unsigned и проверять смену знака 2) Проверять флаг переполнения asm'ом

Какой способ используют эксперты ЛОРа? Интересует минимальное падение скорости и переносимость хотябы в рамках x86. Примеры кода с асмрм приветствуются.

★★★★★

проверять регистр состояния процессора?

dimon555 ★★★★★
()
Ответ на: комментарий от balodja

>http://www.fefe.de/intof.html

Суть метода на странице по ссылке состоит в проверке "а влезет ли?". Именно такую стратегию я отмёл как быдлокодерскую, в частности из-за падения производительности.

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

> Суть метода на странице по ссылке состоит в проверке "а влезет ли?". Именно такую стратегию я отмёл как быдлокодерскую, в частности из-за падения производительности.

Тут как бы немного вариантов: либо проверка "а влезет ли", либо писать на ассемблере и проверять флаг переполнения. Первый вариант кроссплатформенный, но медленный, второй прибит гвоздями к конкретной архитектуре и конкретному компилятору.

Можешь посмотреть ещё класс SafeInt (для C++): http://msdn.microsoft.com/en-us/library/ms972705.aspx, http://www.codeplex.com/SafeInt.

Deleted
()
Ответ на: комментарий от Deleted

> Можешь посмотреть ещё класс SafeInt (для C++): http://msdn.microsoft.com/en-us/library/ms972705.aspx, http://www.codeplex.com/SafeInt.

Только сразу предупреждаю: там злой исходник под не менее злой лицензией "как бы opensource" от M$. Так что слабонервным, беременным женщинам и детям лучше не смотреть =).

Deleted
()
Ответ на: комментарий от Deleted

Фу. Как будто невозможно сколотить свой тип SafeInt под реальную задачу без МСДНа; при этом совместимый со встроенным, и предоставляющий необходимые фичи по обработке переполнения.

зы: но все плюсофобы здесь сразу же идут лесом, ага.

d_a ★★★★★
()

"СамогоЪ" варианта нет, т.к. всё зависит от задачи.

Самый "правильный" вариант (ты его назвал быдлокодерским) - заранее знать, влезет или нет. Например, умножая 15-битное целое на 15-битное, можешь не сомневаться, что результат влезет в 31-битное.

Для сложения часто лучше просто переформулировать выражение так, чтобы переполнения не возникало. Классика - усреднить два неотрицательных целых числа. (a+b)/2 может переполниться и дать неверный (отрицательный!) результат; а вот a+(b-a)/2 вычислится правильно всегда.

Для умножения можешь сделать "проверку делением" ;-)

Из "прочих" универсальных подоходов ещё можно отметить выполнение расчётов в арифметике заведомо достаточной разрядности (обычно для int32 хватает int64).

alexsaa
()
Ответ на: комментарий от d_a

> SafeInt

если не считать производительности, это очень даже удобное решение. Но только непонятно, а что дальше делать в случае переполнения? В кору вываливаться?

alexsaa
()
Ответ на: комментарий от alexsaa

float и double генерируют исключения при переполнении (и, ЕМНИП, потери значимости ("underflow") тоже).

Я просто хочу, чтобы целые тоже генерировали исключение. Вся необходимая информация — флаг переполнения — есть. Надо только проверить. Думаю, это наилучший по производительности вариант. Си (и си++) отчего-то не предоставляет такой возможности напрямую.

Ассемблера я не знаю (и синтаксис встраивания у него какой-то мутный), поэтому проверить флаг у меня пока не получилось. Но может есть другой путь? Может какие-нибудь опции компилятора предусмотрены?

legolegs ★★★★★
() автор топика
Ответ на: комментарий от alexsaa

>Но только непонятно, а что дальше делать в случае переполнения? В кору вываливаться?

Поймать исключение и обработать: юзеру нажаловаться или рухнуть.

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

> юзеру нажаловаться или рухнуть.

тогда, подозреваю, у тебя приложение типа "простенький калькулятор" (иначе либо ты знаешь разрядность - в специализированном приложении, либо ты хочешь арифметику неограниченной точности - в универсальном калькуляторе). Но для приложения "простенький калькулятор" производительность обычно не важна.

alexsaa
()
Ответ на: комментарий от alexsaa

>тогда, подозреваю, у тебя приложение типа "простенький калькулятор"

Нет. Я уже давно не пишу простельких калькуляторов. Мне просто интересно как люди решают сабжевую задачу.

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

>Мне просто интересно как люди решают сабжевую задачу.

люди не парятся)

если серьезно, то там, где (условием задачи) допускается возникновение больших чисел (размер файла), надо либо увеличивать разрядность до 64-х (на данный момент этого хватает практически для всех задач), либо (если не хватает посчитать факториал 2009-ти, например) использовать строковую арифметику.

xydo ★★
()
Ответ на: комментарий от xydo

>люди не парятся)

Неспортивно :)

>увеличивать разрядность до 64-х

Медленно (на 32хбитных системах). В моих задачах 32х бит хватает почти всегда, но лучше вывалиться с ошибкой, чем дать неверный результат.

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

>Медленно (на 32хбитных системах).

ничуть не медленней, чем с пред-проверкой.

пост-проверка на асме всё одно быстрее...

xydo ★★
()
Ответ на: комментарий от xydo

>пост-проверка на асме всё одно быстрее...

Воот. Так может есть готовый код проверки? Желательно кроссплатформенный (макросом, само собой) и такой, чтобы само арифметическое действие было за пределами ассемблерной вставки.

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

>чтобы само арифметическое действие было за пределами ассемблерной вставки.

а вот это уже не безопасно. кто знает, что может случится с регистром флага.

всё равно на асме надо писать всё это дело...

xydo ★★
()
Ответ на: комментарий от xydo

В общем пока как-то так.

Асм я знаю очень плохо, так что ещё дорабатывать и дорабатывать.

>кто знает, что может случится с регистром флага.

Большинство операций его не сбрасывают, как оказалось.

#define CHECK_OVERFLOW(flag) asm (\
        "jno nooverflow;"\
        "mov $0x1,%0;"\
        "nooverflow :"\
        : "=r" (flag) : "0" (flag) )
/******************************************      0      */
template <class RetVal, typename T>
RetVal average_0(const std::vector<T> & data)
{
  bool overflow = false;
  unsigned  int m = 0;
  for (unsigned i = 0;i < data.size();i++)
  {
    m += data[i];
    CHECK_OVERFLOW(overflow);
  }
  if (overflow)
     // throw (Exception(__FILE__,__LINE__,__PRETTY_FUNCTION__, "integer overflow"));
     std::cout << Exception(__FILE__,__LINE__,__PRETTY_FUNCTION__, "integer overflow") << std::endl;
  return (RetVal)m / data.size();
}

legolegs ★★★★★
() автор топика
Ответ на: комментарий от legolegs

> Так может есть готовый код проверки? Желательно кроссплатформенный (макросом, само собой) и такой, чтобы само арифметическое действие было за пределами ассемблерной вставки.

Короткий ответ - нет.

Чтобы было быстро, это надо делать на уровне языка (т.к. надо дружить с компилятором, чтобы тот нужные проверки правильно отследил во время оптимизации). Но в большинстве языков это не предусмотрено (честно говоря, я даже не знаю, где это предусмотрено). Решили, что не надо ;)

А на уровне надстроек оптимально и универсально ты вряд ли сможешь сделать - проверить переполнение займёт примерно столько же времени, что и само сложение int'ов.

Для сравнения - в FPU всё гораздо более computing-friendly: там и бесконечности, и неопределённости - и чтобы всё это отработать, тебе вовсе не нужно ни поток вычислений прерывать, ни прерывания (сигналы) генерировать, ни в каждой операции предусматривать условный переход в случае ошибки. :) Да вдобавок ещё, по стандарту, правила округления могут настраиваться на рантайме (правда, не знаю, как этим управлять в сях).

Но что-то в целых числах всё-таки есть - это ошибка деления на ноль. Так что, видимо, люди над этим уже внимательно подумали и решили, что этого в большинстве случаев достаточно.

Хочешь быстро - анализируй, что будет происходить. Хочешь просто - плати производительностью.

alexsaa
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.