In ACM, accuracy issues are very common. Where the calculation of the geometric headache is generally the size of the code and the accuracy of the problem, code, as long as the usual attention to accumulate template is not a problem. Accuracy problem is not good to say, sometimes a precision problem may become a bottleneck, so you debug half a day can not find the error.
1. Why do floating point numbers have precision problems:
Floating-point numbers (in C + +), generally used more is the float, double.
&NBSP, |
number of bytes |
|
decimal precision number of digits |
float |
4 |
-3.4e-38~3.4e38 |
6~7 |
double |
8 |
-1.7e-308~1.7e308 |
14~15 |
If the memory is not very tight or the accuracy requirement is not very low, the general choice is double. The 14-bit precision (which is a valid digit bit, not the number of digits after the decimal point) is usually sufficient. Note that the problem comes, the number of data precision digits reached 14 bits, but some floating-point operations result in precision and can not reach such a high, may be accurate results only 10~12 bit around. What about the lower one? Nature is an unexpected figure. This brings us to the question that even theoretically the same values, because they are obtained by different computational processes, are likely to be different (in general) for the lower number. This phenomenon does not seem to have much impact, but it can have a deadly effect on an operation: = =. Well, the judgment is equal. Note that the = = = of floating-point numbers in C + + requires exactly the same to return true. Consider the following example:
#include <stdio.h>#include<math.h>intMain () {DoubleA = ASIN (SQRT (2.0) /2) *4.0; Doubleb = ACOs (-1.0 ); printf ("A =%.20lf\n", a); printf ("B =%.20lf\n", B); printf ("A-B =%.20lf\n"Ab); printf ("A = = b =%d\n", A = =b); return 0;}
Output:
A = 3.14159265358979360000
b = 3.14159265358979310000
A-B = 0.00000000000000044409
A = = b = 0
Our solution is to introduce EPS to assist in judging the equality of floating-point numbers.
2. eps
EPS is abbreviated from Epsilon, which represents a small amount, but this small quantity also ensures that the uncertainty is much larger than the result of floating-point arithmetic. The most common value of EPS is about 1e-8. After introducing EPS, we determine that two floating-point numbers A and B are equal in the following way:
Define the three exit functions as follows: Int SGN (double a) {return a <-eps? -1:a < EPS 0:1;}
The calculation of the size of various judgments should be corrected as follows:
Traditional meaning |
Correction notation 1 |
Correction Notation 2 |
A = = B |
SGN (A-b) = = 0 |
Fabs (a–b) < EPS |
A! = B |
SGN (A-b)! = 0 |
Fabs (a–b) > EPS |
A < b |
SGN (A-B) < 0 |
A–b <-eps |
A <= b |
SGN (A-B) <= 0 |
A–b < EPS |
A > B |
SGN (A-B) > 0 |
A–b > EPS |
A >= b |
SGN (A-B) >= 0 |
A–b >-eps |
In this way, we can judge the difference between the floating points which are very close to each other, and the number of the difference between the different values and the EPS is unequal.
PS: Develop good habits and try not to judge floating-point numbers. For example, my amendment does not appear in the 2. = =.
3. Function out-of-bounds for EPS
If sqrt (a), ASIN (a), and a in ACOs (a) are calculated and passed in, you have to be careful.
If a is supposed to be 0, because of a floating-point error, it may actually be a very small negative number (such as 1e-12), so that sqrt (a) deserves 0, directly because a does not define the domain and error.
Similarly, if a is supposed to be ±1, then ASIN (a), ACOs (a) can also be faulted.
Therefore, for this function, a must be corrected beforehand.
4. Output Trap I
This section, as in the next section, is caused by problems that require output floating-point numbers. And it's all about rounding.
When it comes to rounding, just a little bit more about it, as far as I know there are three common methods:
1. printf ("%.3lf", a); Three decimal places reserved for a, rounded by fourth bit
2. (int) A; Rounding A by 0
3. Ceil (a); Floor (a); As the name implies, up forensics, down rounding. It is important to note that both functions return a double, not an int
The first of these is very common in the output (nonsense ...).
Now consider a situation where the topic requires output to retain two decimal places. The exact value of the correct answer to a case is 0.005, which is supposed to output 0.01, but your result may be 0.005000000001 (congratulations), or 0.004999999999 (tragedy), if you output according to printf ("%.2lf", a), Then your encounter will be the same as the words in parentheses.
The workaround is that if a is positive, the output is a+eps, otherwise the output a-eps
Typical case: POJ2826
5. Output Trap II
ICPC topic output has an unwritten rule (sometimes written), do not output: 0.000
Let's start by figuring out when to press printf ("%.3lf\n", a) output to show this result.
Give the result directly: A∈ ( -0.000499999 ...,-0.000 ...). 1)
So, if you find that a falls within this range, please output 0.000 directly. A more insured approach is to use sprintf to directly determine whether the output is not-0.000 to be processed again.
Typical case: UVA746
6. Range out of bounds
This is strictly not a category of precision, but dine is still possible. Note that although a double can represent a large range of numbers, it is not a poor size, which says the maximum is 1e308. So there are times when you have to be careful, like when you are connected, you need to change the logarithm when necessary.
Typical case: HDU3558
7. About Set<t>
Sometimes we may have this need to insert a floating-point number and query for an operation that has been inserted. The handwritten hash table is a method (the hash function should be carefully designed), but the set is not more convenient. But the set seems to be weighed by = =? Looks like it won't work. After observation, set is not by = = To judge the equality, is through <, specifically, as long as the a<b and B<a are not established, it is considered equal to A and B, can be found,
If the smaller is defined as: BOOL operator < (const dat DAT) Const{return val < dat.val-eps;} can solve the problem. (the base type cannot overload the operator, so it is encapsulated)
8. Input value fluctuation is too large
This is not a common situation, but it can help you become more familiar with EPS. If a question input says, give a float number A, 1e-20 < a < 1e20. Do you dare to use 1e-8 EPS? It is reasonable to scale the EPS to the appropriate size according to the input scale.
Typical case: Hustoj 1361
9. Some recommendations
The functions that are prone to large floating-point errors are ASIN and ACOS. Please use atan2 as much as possible.
In addition, if the data is clearly stated to be an integer, and the range is small, using int or long long instead of double is an excellent choice, so there is no floating-point error.
Floating-point precision processing in ACM