Деление большого двойного на большое

Я кодирую физическое моделирование, и недавно я столкнулся с аномальными результатами. Мне удалось отладить мою программу, ошибка была в делении большого двойного на большое целое, что-то вроде:

cout << my_large_double/my_large_int << endl

с my_large_double порядка -10 ^ {9} и произведение моих двух целых чисел порядка 10 ^ {9} возвращало что-то положительное порядка 1.
Я исправил это путем наложения преобразования в удвоение в знаменателе:

cout << my_large_double/( (double)my_large_int1*my_large_int2) << endl

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

Обновление: я пропустил деталь, которая имеет значение в моем первом вопросе: int на самом деле является продуктом двух целых.

2

Решение

Это зависит от того, как именно было написано выражение.

Если вы напишите это:

my_large_double / my_large_int1 / my_large_int2

тогда это эквивалентно:

(my_large_double / my_large_int1) / my_large_int2

который должен дать вам достаточно точные результаты; my_large_int1 повышен до double до первого деления, и my_large_int2 повышен до double до второго дивизиона.

Если вы напишите это:

my_large_double / (my_large_int1 * my_large_int2)

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

Важно помнить, что в большинстве случаев каждое выражение C эффективно оценивается изолированно; его тип не зависит от контекста, в котором он появляется. Выражение my_large_int1 * my_large_int2 является целочисленным умножением, даже если результат является операндом деления с плавающей запятой или назначен переменной с плавающей запятой.

Любая операция, операнды которой являются целыми числами, является целочисленной операцией. Если один операнд double а другой int, int операнд повышен до double,

Даже это:

double temp = my_large_int1 * my_large_int2;
... my_large_double / temp ...

выполнит целочисленное умножение перед использованием результата для инициализации temp, и это:

my_large_double / (double)(my_large_int1 * my_large_int2)

имеет ту же проблему.

Как вы обнаружили, решение состоит в том, чтобы привести один или оба целочисленных операнда к double:

my_large_double / ((double)my_large_int1 * (double)my_large_int2)

(Вы могли бы также использовать их обоих, только для симметрии и ясности.)

4

Другие решения

Формат IEEE double может держать int без потери точности до 53 бит по сравнению с 31 битом, типичным для int, Ваше решение хорошее, конвертировать в double заранее, чтобы вы не столкнулись с целочисленным переполнением при умножении.

1

По вопросам рекламы [email protected]