Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> overflow и underflow 
:(
    Опции темы
DJVasek
Дата 11.12.2009, 03:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 27.10.2008

Репутация: нет
Всего: нет



Прогаю давно, но вот застрял.
Задание: 
Опишите функцию умножения двух целых, обработайте ошибку перепол-нения сверху (overflow).

Я сделал вот что:

#include <iostream>
using namespace std;

int multiply (int a, int b)
{
    int x = a*b;
    if (a>0 && b>0 || a<0 && b<0)
    {
        if(x<=0)
            throw "error";                                        
        else
            return x;
    }
    if (a>0 && b<0 || a<0 && b>0)
    {
        if(x>=0)
            throw "error";                                        
        else
            return x;
    }
}

void main()
{
    // Исключение
    int a = 45, b = a;
    try
    {
        for(;;)
        {
            a = multiply(a, a);
            cout<<b<<" * "<<b<<" = "<<a<<endl;
            b = a;
        }
    }

    catch (char*)
    {
        cout<<b<<" * "<<b<<" = "<<a*a<<" - Overflow!";
    }

    cout<<endl;
    system("pause");
}

вопросы:
1) Я правильно понял задание? Если нет, то объясни что тут имелось ввиду.
2) Если да, то тогда как быть в таком случае:
Опишите функцию деления двух целых, обработайте ошибку переполне-ния снизу (underflow).

Спасибо.
PM MAIL   Вверх
Леопольд
Дата 11.12.2009, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(DJVasek @  11.12.2009,  03:53 Найти цитируемый пост)
Опишите функцию умножения двух целых, обработайте ошибку перепол-нения сверху (overflow).


Для простоты предположим что у нас 8-битный процессор. В восемь битов "влезает" 256 значений, включая ноль.
200 * 3 = 400 % 256 = 88
600 не поместится в 8 битов, однако даже для целого со знаком и результат и множители будут больше ноля. Твои проверки это пропустят.

Как то надо иначе работать.
Возьмём 200 * 3 в двоичной системе: 
11001000 * 11 = 
(2^7 + 2^6 + 2^3) * (2^1 + 2^0) = 
2^(7 + 1 + 0) + 2^(6 + 1 + 0) + 2^(3 + 1 + 0) =
2^8 + 2^7 + 2^4 =             (По первому же слагаемому видно что результат выходит за границы)
110010000

Как реализовать алгоритм. "Смотрим" какие биты выставлены в единицу у меньшего из множителей и складываем их индексы, начиная с ноля. Полученную сумму запоминаем, допустим в var. Берём второй множитель и смотрим какие биты выставлены у него, походу сравниваем сумму текущего индекса и var с пороговым значением. Для 32 битных целых, не должно выходить за 31.

Код

#include <iostream>
#include <algorithm>


template<typename I>
bool checkMultyplyOverflow(I lArg, I rArg){
    enum {
        bitsPerByte = 8,
        correction = static_cast<I>(-1) > 0 ? 0 : 1, //для знаковых на один бит меньще, потому что он нужен для знака
        bound = sizeof(I) * bitsPerByte - correction
    };

    if(lArg > rArg)
        std::swap(lArg, rArg);

    std::size_t summ = 0;
    I one = 1;
    for (std::size_t i = 0; i < bound; ++i)
        if(lArg & (one << i))
            summ += i;

    for (std::size_t i = 0; i < bound; ++i)
        if(rArg & (one << i))
            if(i + summ >= bound)
                return true;
    return false;
}

int main(){
    unsigned char ulArg = 127;
    unsigned char urArg = 2;
    std::cout<<std::boolalpha<<checkMultyplyOverflow(ulArg, urArg)<<std::endl;

    char slArg = 127;
    char srArg = 2;
    std::cout<<std::boolalpha<<checkMultyplyOverflow(slArg, srArg)<<std::endl;

    return 0;
}



Деление посложнее будет, как мне кажется smile


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
17dufa
Дата 11.12.2009, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 324
Регистрация: 2.3.2006

Репутация: 3
Всего: 5



Леопольд, чего-то не понял насчет сложения в меньшем множителе.
пример для 8 битовых беззнаковых:
умножаю 6 * 32 = 192. влезает.
в битах 110 * 100000 
для 110 => sum = 3
для 100000 на i == 5 во втором цикле получаю: if(rArg & (one << i)) истина, i + sum = 8, т.е. if(i + summ >= bound) истина. и функция скажет, что мол переполнение.

подсмотрел тупое, но вроде работающее решение:
Код

bool MulAndTest(__int64 op1, __int64 op2, __int64 &result)
{
        result = op1 * op2;
        if( op2 ) return ( op1 == result/op2 );
        return true;
}



Это сообщение отредактировал(а) 17dufa - 11.12.2009, 17:31
PM MAIL   Вверх
Леопольд
Дата 11.12.2009, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(17dufa @  11.12.2009,  17:23 Найти цитируемый пост)
и функция скажет, что мол переполнение

Значит я что-то не продумал. Но, как мне кажется, надо работать со степенями двойки, возможно как-то иначе...

110 * 100000 = (2^2 + 2^1) * (2^5 + 2^1) = 2^(2+5) + 2^(2+1) + 2^(1+5) + 2^(1+1)

Цитата(17dufa @  11.12.2009,  17:23 Найти цитируемый пост)
Леопольд, чего-то не понял насчет сложения в меньшем множителе.

Ты прав, с суммой я перемудрил. Видимо, надо сравнивать сумму старших разрядов. Так вроде работает.

Код

#include <iostream>

template<typename I>
bool checkMultyplyOverflow(I lArg, I rArg){
    enum {
        bitsPerByte = 8,
        correction = static_cast<I>(-1) > 0 ? 0 : 1, //для знаковых на один бит меньще, потому что он нужен для знака
        bound = sizeof(I) * bitsPerByte - correction
    };

    std::size_t msb = 0; //(most significant bit) старший бит
    I one = 1;
    for (int i = bound - 1; i >= 0; --i)
        if(lArg & (one << i)){
            msb = i;
            break;
        }

    for (int i = bound - 1; i >= 0; --i)
        if(rArg & (one << i)){
            if(i + msb >= bound)
                return true;
            break;
        }
    return false;
}

int main(){
    unsigned char ulArg = 2;
    unsigned char urArg = 127;
    std::cout<<std::boolalpha<<checkMultyplyOverflow(ulArg, urArg)<<std::endl;

    ulArg = 32;
    urArg = 6;
    std::cout<<std::boolalpha<<checkMultyplyOverflow(ulArg, urArg)<<std::endl;

    char slArg = 127;
    char srArg = 2;
    std::cout<<std::boolalpha<<checkMultyplyOverflow(slArg, srArg)<<std::endl;

    return 0;
}


Это сообщение отредактировал(а) Леопольд - 11.12.2009, 18:27


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 11.12.2009, 18:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(17dufa @  11.12.2009,  17:23 Найти цитируемый пост)
подсмотрел тупое, но вроде работающее решение:
    
Код

bool MulAndTest(__int64 op1, __int64 op2, __int64 &result)
{
        result = op1 * op2;
        if( op2 ) return ( op1 == result/op2 );
        return true;
}

Вполне логичное решение.
Надо только профайлером посмотреть что быстрее...

Это сообщение отредактировал(а) Леопольд - 11.12.2009, 18:47


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
DJVasek
Дата 11.12.2009, 18:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 27.10.2008

Репутация: нет
Всего: нет



Спасиб мужыки))) Теперь понял))))

А тогда как быть с этим:
Опишите функцию деления двух целых, обработайте ошибку переполне-ния снизу (underflow)?

Это сообщение отредактировал(а) DJVasek - 11.12.2009, 22:10
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1169 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.