Страницы

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

вторник, 14 мая 2019 г.

Переполнение типа 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"); }


Ответ

Через 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 старших бит значением старшего бита этой экспоненты).

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

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