Блог пользователя DontLookBack

Автор DontLookBack, история, 6 лет назад, По-английски

This problem : https://mirror.codeforces.com/problemset/problem/514/B, gives different verdicts according to different change in epsilon values used for comparing two double quantities. Why is this so? For example it passes for epsilon from 1e-9 to 1e-13.

During contest how am I supposed to know which epsilon value will pass?

Solution:


#include <bits/stdc++.h> using namespace std; #define fast ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); #define ll long long #define ld long double #define all(v) v.begin(),v.end() #define ff first #define ss second #define pb push_back #define mp make_pair #define pi pair<int,int> const ll maxn=1e3+50; const ll mod=1e9+7; const double epsilon=1e-12; bool deq(double a, double b) { return std::abs(a - b) < epsilon; } int main() { fast; int n,x,y,u,v,i,j; cin>>n>>x>>y; pi p[n]; for(i=0;i<n;i++){ cin>>u>>v; p[i]={u,v}; } bool mark[n]; memset(mark,false,sizeof(mark)); int ans=0; for(i=0;i<n;i++){ if(mark[i]) continue; double del,f=0; if((x-p[i].ff)!=0) del=(1.0*(y-p[i].ss))/(x-p[i].ff); else{ f=1; } for(j=i;j<n;j++){ if(mark[j]) continue; if((x-p[j].ff)!=0){ if(deq(del,(1.0*(y-p[j].ss))/(x-p[j].ff))) mark[j]=true; } else if(f) mark[j]=true; } ++ans; } cout<<ans; }

Please dont downvote unnecessarily.

Any help will be appreciated.

  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

»
6 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Use standard one depending on the floating data type (FLT_EPSILON, DBL_EPSILON and so on).

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    It does not work, I tried both of them, it gives wrong answer on test 10 and test 13 respectively.

  • »
    »
    6 лет назад, скрыть # ^ |
    Rev. 4  
    Проголосовать: нравится +8 Проголосовать: не нравится

    The best epsilon to use depends very much on the the calculations that you've done. DBL_EPSILON and related macros aren't some magic epsilon values that will work everywhere. They're defined as the difference between 1 and the next greater representable value. If you have numbers that are much greater than 1, the error can be much greater than DBL_EPSILON. If you're doing more than one operation, the error can be even bigger. You need to analyze your code to determine the amount of error that you can expect, and set an epsilon appropriately.

    Directly using DBL_EPSILON fails even in the simplest cases:

    #include <iostream>
    #include <cfloat>
    #include <cmath>
    using namespace std;
    
    bool almostequal(double a, double b)
    {
        return abs(a - b) <= DBL_EPSILON;
    }
    
    int main()
    {
        cout << almostequal(3.1 + 4.2, 7.3) << '\n';
    }
    

    Output: 0

»
6 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

This prob is not supposed to be solved with floating point arithmetic. Instead you should divide the coordinates by the gcd of them and then compare the results.

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится

My C++ edition of Donald Knuth's thoughts:

bool less(double a, double b)
{
    if (abs(a) < abs(b))
        return b - a > abs(b);

    return b - a > numeric_limits<double>::epsilon() * abs(a);
}

bool equal(double a, double b)
{
    return !less(a, b) && !less(b, a);
}