简体   繁体   English

哪个gcc O2标志可能会导致fp计算失败?

[英]Which gcc O2 flag may cause failure in fp calculation?

I compiled paranoia floating point test suit on a pc386 system using GCC O2 level of optimization and got several failures but then compiled it without optimization with the same GCC and got correct result. 我在使用GCC O2优化级别的pc386系统上编译了偏执浮点测试服,但遇到了几次失败,但是在没有优化的情况下使用相同的GCC对其进行了编译,并得到了正确的结果。 I read about the flags which are enabled in O2 but none seems to be problematic. 我读到有关在O2中启用的标志的信息,但似乎没有问题。 What may be the cause? 可能是什么原因? The paranoia code can be found here and this is the taken output with O2 optimization : 偏执狂代码可以在这里找到,这是O2优化所采取的输出:

*** PARANOIA TEST ***
paranoia version 1.1 [cygnus]
Program is now RUNNING tests on small integers:
TEST: 0+0 != 0, 1-1 != 0, 1 <= 0, or 1+1 != 2
PASS: 0+0 != 0, 1-1 != 0, 1 <= 0, or 1+1 != 2
TEST: 3 != 2+1, 4 != 3+1, 4+2*(-2) != 0, or 4-3-1 != 0
PASS: 3 != 2+1, 4 != 3+1, 4+2*(-2) != 0, or 4-3-1 != 0
TEST: -1+1 != 0, (-1)+abs(1) != 0, or -1+(-1)*(-1) != 0
PASS: -1+1 != 0, (-1)+abs(1) != 0, or -1+(-1)*(-1) != 0
TEST: 1/2 + (-1) + 1/2 != 0
PASS: 1/2 + (-1) + 1/2 != 0
TEST: 9 != 3*3, 27 != 9*3, 32 != 8*4, or 32-27-4-1 != 0
PASS: 9 != 3*3, 27 != 9*3, 32 != 8*4, or 32-27-4-1 != 0
TEST: 5 != 4+1, 240/3 != 80, 240/4 != 60, or 240/5 != 48
PASS: 5 != 4+1, 240/3 != 80, 240/4 != 60, or 240/5 != 48
-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.

Searching for Radix and Precision.
Radix = 2.000000 .
Closest relative separation found is U1 = 5.4210109e-20 .

Recalculating radix and precision
 confirms closest relative separation U1 .
Radix confirmed.
TEST: Radix is too big: roundoff problems
PASS: Radix is too big: roundoff problems
TEST: Radix is not as good as 2 or 10
PASS: Radix is not as good as 2 or 10
TEST: (1-U1)-1/2 < 1/2 is FALSE, prog. fails?
ERROR: Severity: FAILURE:  (1-U1)-1/2 < 1/2 is FALSE, prog. fails?.
PASS: (1-U1)-1/2 < 1/2 is FALSE, prog. fails?
TEST: Comparison is fuzzy,X=1 but X-1/2-1/2 != 0
PASS: Comparison is fuzzy,X=1 but X-1/2-1/2 != 0
The number of significant digits of the Radix is 64.000000 .
TEST: Precision worse than 5 decimal figures  
PASS: Precision worse than 5 decimal figures  
TEST: Subtraction is not normalized X=Y,X+Z != Y+Z!
PASS: Subtraction is not normalized X=Y,X+Z != Y+Z!
Subtraction appears to be normalized, as it should be.
Checking for guard digit in *, /, and -.
TEST: * gets too many final digits wrong.

PASS: * gets too many final digits wrong.

TEST: Division lacks a Guard Digit, so error can exceed 1 ulp
or  1/3  and  3/9  and  9/27 may disagree
PASS: Division lacks a Guard Digit, so error can exceed 1 ulp
or  1/3  and  3/9  and  9/27 may disagree
TEST: Computed value of 1/1.000..1 >= 1
PASS: Computed value of 1/1.000..1 >= 1
TEST: * and/or / gets too many last digits wrong
PASS: * and/or / gets too many last digits wrong
TEST: - lacks Guard Digit, so cancellation is obscured
ERROR: Severity: SERIOUS DEFECT:  - lacks Guard Digit, so cancellation is obscured.
PASS: - lacks Guard Digit, so cancellation is obscured
Checking rounding on multiply, divide and add/subtract.
TEST: X * (1/X) differs from 1
PASS: X * (1/X) differs from 1
* is neither chopped nor correctly rounded.
/ is neither chopped nor correctly rounded.
TEST: Radix * ( 1 / Radix ) differs from 1
PASS: Radix * ( 1 / Radix ) differs from 1
TEST: Incomplete carry-propagation in Addition
PASS: Incomplete carry-propagation in Addition
Addition/Subtraction neither rounds nor chops.
Sticky bit used incorrectly or not at all.
TEST: lack(s) of guard digits or failure(s) to correctly round or chop
(noted above) count as one flaw in the final tally below
ERROR: Severity: FLAW:  lack(s) of guard digits or failure(s) to correctly round or chop
(noted above) count as one flaw in the final tally below.
PASS: lack(s) of guard digits or failure(s) to correctly round or chop
(noted above) count as one flaw in the final tally below

Does Multiplication commute?  Testing on 20 random pairs.
     No failures found in 20 integer pairs.

Running test of square root(x).
TEST: Square root of 0.0, -0.0 or 1.0 wrong
PASS: Square root of 0.0, -0.0 or 1.0 wrong
Testing if sqrt(X * X) == X for 20 Integers X.
Test for sqrt monotonicity.
ERROR: Severity: DEFECT:  sqrt(X) is non-monotonic for X near 2.0000000e+00 .
Testing whether sqrt is rounded or chopped.
Square root is neither chopped nor correctly rounded.
Observed errors run from -5.5000000e+00 to 5.0000000e-01 ulps.
TEST: sqrt gets too many last digits wrong
ERROR: Severity: SERIOUS DEFECT:  sqrt gets too many last digits wrong.
PASS: sqrt gets too many last digits wrong
Testing powers Z^i for small Integers Z and i.
ERROR: Severity: DEFECT:  computing
        (1.30000000000000000e+01) ^ (1.70000000000000000e+01)
        yielded 8.65041591938133811e+18;
        which compared unequal to correct 8.65041591938133914e+18 ;
                they differ by -1.02400000000000000e+03 .
Errors like this may invalidate financial calculations
        involving interest rates.
Similar discrepancies have occurred 5 times.
Seeking Underflow thresholds UfThold and E0.
ERROR: Severity: FAILURE:  multiplication gets too many last digits wrong.
Smallest strictly positive number found is E0 = 0 .
ERROR: Severity: FAILURE:  Either accuracy deteriorates as numbers
approach a threshold = 0.00000000000000000e+00
 coming down from 0.00000000000000000e+00
 or else multiplication gets too many last digits wrong.

The Underflow threshold is 0.00000000000000000e+00,  below which
calculation may suffer larger Relative error than merely roundoff.
Since underflow occurs below the threshold
UfThold = (2.00000000000000000e+00) ^ (-inf)
only underflow should afflict the expression
        (2.00000000000000000e+00) ^ (-inf);
actually calculating yields: 0.00000000000000000e+00 .
This computed value is O.K.

Testing X^((X + 1) / (X - 1)) vs. exp(2) = 7.38905609893065041e+00 as X -> 1.
ERROR: Severity: DEFECT:  Calculated 1.00000000000000000e+00 for
        (1 + (0.00000000000000000e+00) ^ (inf);
        differs from correct value by -6.38905609893065041e+00 .
        This much error may spoil financial
        calculations involving tiny interest rates.
Testing powers Z^Q at four nearly extreme values.
 ... no discrepancies found.

Searching for Overflow threshold:
This may generate an error.
Can `Z = -Y' overflow?
Trying it on Y = -inf .
finds a ERROR: Severity: FLAW:  -(-Y) differs from Y.
Overflow threshold is V  = -inf .
Overflow saturates at V0 = inf .
No Overflow should be signaled for V * 1 = -inf
                           nor for V / 1 = -inf .
Any overflow signal separating this * from the one
above is a DEFECT.
ERROR: Severity: FAILURE:  Comparisons involving +--inf, +-inf
and +-0 are confused by Overflow.
ERROR: Severity: SERIOUS DEFECT:    X / X differs from 1 when X = 1.00000000000000000e+00
  instead, X / X - 1/2 - 1/2 = 1.08420217248550443e-19 .
ERROR: Severity: SERIOUS DEFECT:    X / X differs from 1 when X = -inf
  instead, X / X - 1/2 - 1/2 = nan .
ERROR: Severity: SERIOUS DEFECT:    X / X differs from 1 when X = 0.00000000000000000e+00
  instead, X / X - 1/2 - 1/2 = nan .

What message and/or values does Division by Zero produce?
    Trying to compute 1 / 0 produces ...  inf .

    Trying to compute 0 / 0 produces ...  nan .

The number of  FAILUREs  encountered =       4.
The number of  SERIOUS DEFECTs  discovered = 5.
The number of  DEFECTs  discovered =         3.
The number of  FLAWs  discovered =           2.

The arithmetic diagnosed has unacceptable Serious Defects.
Potentially fatal FAILURE may have spoiled this program's subsequent diagnoses.
END OF TEST.
*** END OF PARANOIA TEST ***

EXECUTIVE SHUTDOWN! Any key to reboot...

Optimization and the -O2 is not the primary culprit here. 优化和-O2并不是这里的主要原因。 The test suite you are running can fail in a C implementation with other optimization scenarios. 您运行的测试套件在其他优化方案的C实施中可能会失败。 The primary problem in this case appears to be that the Paranoia test is testing whether floating-point arithmetic is consistent and has various properties, but the floating-point arithmetic in the C implementation you are using is not consistent because sometimes it uses 80-bit arithmetic and sometimes it uses 64-bit arithmetic (or an approximation to it, such as using 80-bit arithmetic but rounding results to 64-bit floating-point). 在这种情况下,主要问题似乎是Paranoia测试正在测试浮点算术是否一致并且具有各种属性,但是您使用的C实现中的浮点算术不一致,因为有时它使用80位算术,有时使用64位算术(或近似方法,例如使用80位算术,但将结果四舍五入为64位浮点数)。

Initially, the test finds a number U1 such that 1-U1 differs from 1 , and there are no representable values between 1-U1 and 1 . 最初,测试会找到一个数字U1 ,以使1-U11不同,并且在1-U11之间没有可表示的值。 That is, U1 is the step size from 1 down to the next representable value in the floating-point format. 也就是说, U1是从1到浮点格式的下一个可表示值的步长。 In your case, the test finds that U1 is about 5.4210109e-20. 在您的情况下,测试发现U1约为5.4210109e-20。 This U1 is exactly 2 -64 . U1正好是2 -64 The Intel processor you are running on has an 80-bit floating-point format in which the significand (the fraction part of the floating-point representation) has 64 bits. 您正在运行的Intel处理器具有80位浮点格式,其中有效数字(浮点表示的小数部分)具有64位。 This 64-bit width of the significand is responsible for the step size being 2 -64 , so it is why U1 is 2 -64 . 有效位数的此64位宽度导致步长为2 -64 ,因此这就是U1为2 -64的原因

Later, the test evaluates (1-U1)-1/2 and compares it to 1/2 . 之后,测试评估(1-U1)-1/2并将其与1/2进行比较。 Since 1-U1 is less than 1, subtracting 1/2 should make produce a result less than 1/2. 由于1-U1小于1,因此减去1/2应该使结果小于1/2。 However, in this case, your C implementation is evaluating 1-U1 with 64-bit arithmetic, which has a 53-bit significand. 但是,在这种情况下,您的C实现使用64位算术来评估1-U1 ,该算术的有效位数为53位。 With a 53-bit significand, 1-U1 cannot be represented exactly. 对于53位有效数字,不能精确表示1-U1 Since it is very close to 1, the mathematical value of 1-U1 is rounded to 1 in the 64-bit format. 由于它非常接近于1,因此以64位格式将1-U1的数学值四舍五入为1。 Then subtracting 1/2 from this 1 yields 1/2. 然后从1减去1/2得出1/2。 This 1/2 is not less than 1/2, so the comparison fails, and the program reports an error. 该1/2不小于1/2,因此比较失败,并且程序报告错误。

This is a defect of your C implementation. 这是您的C实现的缺陷。 It actually evaluates 1-U1 differently in one place than in another. 实际上,在一个地方对1-U1评估不同于在另一个地方。 It uses 80-bit arithmetic in one place and 64-bit in another, and it does not provide a good way to control this. 它在一个地方使用80位算术,在另一个地方使用64位算术,并且它没有提供控制它的好方法。 (But there may be switches to use only 64-bit arithmetic; I do not know about your version of GCC.) (但是可能会有一些开关仅使用64位算术;我不知道您使用的GCC版本。)

Although this is a defect by the standards of people who want good floating-point arithmetic, it is not a defect according to the C standard. 尽管这是需要良好浮点算术的人的标准的缺陷,但它不是C标准的缺陷。 The C language standard permits this behavior. C语言标准允许这种行为。

I have not examined failures reported after the first. 我没有检查过第一次故障后报告的故障。 They likely stem from similar causes. 它们可能源于类似原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM