У меня есть эта строка в моем коде (ll это длинный длинный int):
ll d = (x / ( (y / 1000000) - 1) );
который, кажется, вызывает эту ошибку исключения с плавающей запятой.
Однако, когда я изменяю это на:
ll d = (1000000*x)/(y-1000000);
ошибка исчезает. Простая алгебра заставит вас поверить, что оба они — одно и то же.
Вот полный код, который для проблемы UVa 10660, продуктовый магазин. https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid = 8&категория = 643&страница = show_problem&проблема = 2177
//Problem Link: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=643&page=show_problem&problem=2177
//Problem type: Complete Search
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
#include <stdio.h>
#include <queue>
#include <set>
#include <cmath>
#include <assert.h>
#include <bitset>
#include <map>
#include <unordered_map>
#include <iomanip> //cout << setprecision(n) << fixed << num
typedef long long int ll;
using namespace std;
int main() {
//freopen("output.out", "w", stdout);
int cnt = 0;
for (int a = 1; a*4 <= 2000; a++) {
for (int b = a; a+3*b <= 2000; b++) {
for (int c = b; a+b+2*c <= 2000; c++) {
ll x = a+b+c;
ll y = a*b*c;
if (y <= 1000000) continue;
//ll d = (x / ( (y / 1000000) - 1) );
ll d = (1000000*x)/(y-1000000);
if (d < c || x + d > 2000) continue;
if ( abs( (x + d) / 100.0 - ( y * d) / 100000000.0) < 1e-8 ) {
cout << setprecision(2) << fixed << a/100.0 << " " << b/100.0 << " " << c/100.0 << " " << d/100.0 << endl;
cnt++;
}
}
}
}
cout << cnt << endl;
return 0;
}
Если я изменю это на ll d = (x / ( (y / 1000000.0f) - 1) )
однако тогда ошибка исчезает, но я получаю неправильный ответ, и число строк в выходных данных составляет всего 717, тогда как это должно быть 949 (мне пришлось найти ответ в Google, чтобы выяснить эту странную проблему: /)
Во-первых, здесь нет арифметики с плавающей точкой: все делается целыми числами (в частности, long long int
с).
Это означает, что когда y
находится между 1000000
а также 1999999
включительно, результат деления y / 1000000
будет 1
, Следовательно, вычитая 1
из этого приведет к нулевому знаменателю и делению на нулевое исключение.
Ваше второе выражение даст тот же результат только тогда, когда y
равно 1000000
, но программа будет аварийно завершать работу с тем же исключением.
Хитрость в решении таких задач состоит в том, чтобы держать числитель и знаменатель раздельно и выполнять свою математику полностью в целых числах, то есть без чисел с плавающей запятой. Создание простого класса для представления рациональных чисел должно помочь упростить ваш код.
Других решений пока нет …