long double is 80-bit on x86 Linux (Codeforces) but the same as double on MSVC — do not rely on it for correctness if the judge’s compiler is unknown.
The rules
Never compare with ==
const double EPS = 1e-9;bool eq(double a, double b) { return fabs(a - b) < EPS; }int sgn(double x) { return (x > EPS) - (x < -EPS); }
Choose ε relative to the magnitude. With values around 109, a double has absolute precision about 10−7, so ε=10−9 is smaller than the noise and will misclassify. Use a relative comparison when magnitudes vary:
bool eq(double a, double b) { return fabs(a - b) <= EPS * max(1.0, max(fabs(a), fabs(b))); }
Where precision is lost
Operation
Danger
Subtracting near-equal values
catastrophic cancellation — the killer
Adding numbers of very different magnitudes
the small one vanishes
Repeated accumulation
error grows as O(n) or O(n)
sqrt of a tiny negative (from cancellation)
NaN
acos of a value slightly outside [−1,1]
NaN
Large exponents
overflow to inf
Comparing computed values
the whole problem
The two classic rescues
Quadratic formula.2a−b+b2−4ac cancels when b>0. Use q=−21(b+sgn(b)b2−4ac),x1=q/a,x2=c/q.
Angle between vectors.acos(dot/(|a||b|)) loses precision near 0 and π and can feed acos an out-of-range value. Use
Rule: do every decision in exact arithmetic; use floating point only for the final output.
Summation accuracy
Naive summation of n values accumulates O(nε) error. Two fixes:
Kahan summation — track the lost low-order bits:
double sum = 0, c = 0;for (double x : v) { double y = x - c, t = sum + y; c = (t - sum) - y; sum = t;}
Pairwise summation — sum recursively in halves; error drops to O(εlogn) and it is what std::accumulate on a sorted range effectively achieves. Simply sorting by magnitude before summing captures most of the benefit.
Output
printf("%.10f\n", x);cout << fixed << setprecision(10) << x << "\n";
Read the statement for the required precision — usually 10−6 or 10−9 relative or absolute. Printing more digits than the computation supports is harmless; printing fewer is not.
Watch for negative zero: -0.000000 may be rejected by a strict checker. Add 0.0 or clamp tiny magnitudes to 0 before printing.
NaN propagates silently through arithmetic and makes every comparison false — which turns a sort with a NaN in the data into undefined behaviour. Guard sqrt and acos arguments.
Compiler flags to avoid
-ffast-math (implied by -Ofast) permits the compiler to reorder floating-point operations and assume no NaN/inf. It can change results and break isnan checks. Do not use it when precision matters.