Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

Переполнение типа double при вычислении математических функций

#cpp #double


Помогите разобраться. У меня есть код, в котором я подключаю проверку на переполнение
типа double с помощью функции _finite() относительно математических операций, а не
через присваивание переменных. В консоли для z выводит ошибку OVERFLOW error. Возможно
ли в этом случае обойтись без обработки исключений? Компилятор - C++Builder 6. Буду
очень благодарен.
#include 
#include 
#include 
using namespace std;

int main (void)
{
    double x = 10E200;
    double y = 10E400;
    double z = pow(x, 2);
    if(_finite(x) != 0)
    {
        cout << "This is finite number: " << x << endl;
    }
    else cout << "This is infinity: " << x << endl;
    if(_finite(y) != 0)
    {
        cout << "This is finite number: " << y << endl;
    }
    else cout << "This is infinity: " << y << endl;
    if(_finite(z) != 0)
    {
        cout << "This is finite number: " << z << endl;
    }
    else cout << "This is infinity: " << z << endl;
    system("pause");
}

Update: Это моя вина, многие не поняли, чего я хотел, поэтому добавлю второй пример.
Через pow() или x * x выводит ошибку о переполнении. Как мне корректно проверить условие,
чтобы не выводило ошибку?
#include 
#include 
#include 
using namespace std;

int main (void)
{
    double x;
    char str[] = "Введите число, которое мы будем возводить в степень: ";
    CharToOem(str,str);
    cout << str;
    cin >> x;
    int check = 0; // флаг переполнения
    do
    {
        if(_finite(pow(x, 2)) != 0)
        {
            x = pow(x, 2);
            cout << x << endl;
        }
        else check = 1;
    }
    while(check == 0);
    system("pause");
}
    


Ответы

Ответ 1



Через pow() или x * x выводит ошибку о переполнении. Как мне корректно проверить условие, чтобы не выводило ошибку? Если я ничего не путаю: ( a * e ^ x ) * ( b * e ^ y ) = c * e ^ ( x + y + z ), где z - экспонента получаемая при перемножении a на b, а c - остаточная мантисса от этой операции. Т.е. чтобы определить, будет ли переполнение, можно просто умножить целочисленную экспоненту на n (показатель степени - второй параметр функции pow) и проверить, выходит ли это значение за пределы используемого диапазона ( для double - это 1024). Если не выходит, нужно выделить остаточную экспоненту от квадрата мантиссы, добавить к ней вычисленное ранее произведение и проверить на выход за границы снова. Вобщем - достаточно муторно, но не смертельно. Чтобы выделить остаточную экспоненту, нужно выполнить целочисленное умножение 64-битных мантисс. Предварительно, нужно маской удалить из них экспоненту (те самые 11 бит) и привести обратным кодом в натуральный диапазон. После умножения - обнулить старший бит, и посчитать число правых сдвигов результата до того момента, пока эти 11 бит не обнулятся. Число этих сдвигов и дают остаточную экспоненту. p.s.: экспоненты - тоже знаковые, это следует учитывать при их сложении, вернее - при проверке на выход за пределы границ диапазона (для этого, надо перевести 11-битную экспоненту в short, заполняя оставшиеся 5 старших бит значением старшего бита этой экспоненты).

Комментариев нет:

Отправить комментарий