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

时间:2013-08-11 10:34:58

标签: gcc floating-point compiler-optimization compiler-flags rtems

我在pc386系统上使用GCC O2级别的优化编译偏执浮点测试套装并获得了几次失败,但是在没有使用相同GCC进行优化的情况下编译它并得到了正确的结果。 我读到了O2中启用的标志,但似乎没有问题。可能是什么原因? 可以找到偏执狂代码here,这是采用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...

1 个答案:

答案 0 :(得分:3)

优化和-O2不是这里的主要罪魁祸首。您正在运行的测试套件在其他优化方案的C实现中可能会失败。这种情况下的主要问题似乎是偏执狂测试是测试浮点运算是否一致并且具有各种属性,但是您使用的C实现中的浮点运算不一致,因为有时它使用80位算术,有时它使用64位算术(或对它的近似,例如使用80位算术但将结果舍入到64位浮点)。

最初,测试会找到一个U1的数字,1-U11不同,1-U11之间没有可表示的值。也就是说,U1是从1到浮点格式的下一个可表示值的步长。在您的情况下,测试发现U1大约是5.4210109e-20。这个U1恰好是2 -64 。您运行的Intel处理器具有80位浮点格式,其中有效位数(浮点表示的小数部分)具有64位。这个有效数字的64位宽度负责步长为2 -64 ,因此U1为2 -64

稍后,测试会评估(1-U1)-1/2并将其与1/2进行比较。由于1-U1小于1,减去1/2应该使得产生的结果小于1/2。但是,在这种情况下,您的C实现正在使用64位算术评估1-U1,该算法具有53位有效数。使用53位有效位数时,1-U1无法准确表示。由于它非常接近1,因此1-U1的数学值在64位格式中舍入为1。然后从这1减去1/2产生1/2。此1/2不小于1/2,因此比较失败,程序报告错误。

这是您的C实现的缺陷。它实际上在一个地方评估1-U1不同于另一个地方。它在一个地方使用80位算术而在另一个地方使用64位,并且它不提供控制它的好方法。 (但是可能有开关只使用64位算术;我不知道你的GCC版本。)

虽然这是一个需要良好的浮点运算的人的标准的缺陷,但它不是根据C标准的缺陷。 C语言标准允许这种行为。

我没有检查过第一次报告后的失败。它们可能源于类似的原因。