xref: /openbsd-src/gnu/usr.bin/perl/hints/t001.c (revision 256a93a44f36679bee503f12e49566c2183f6181)
1 /* Beginning of modification history */
2 /* Written 02-04-10 by Paul Green (Paul.Green@stratus.com) */
3 /* End of modification history */
4 
5 /* This test case is extracted from Perl version 5.7.3.  It is
6    in the Perl_unpack_str function of the pp_pack.c source file.
7 
8    GCC 2.95.2 improperly assumes that it can compensate for an
9    extra fsub by performing a fadd.  This would work in
10    fixed-point arithmetic, but does not work in floating-point
11    arithmetic.
12 
13    This problem has been seen on HP-UX and on Stratus VOS, both
14    of which have an HP PA-RISC target (hppa1.1).  The Stratus
15    bug number is gnu_g++-220.  */
16 
17 /* #define _POSIX_C_SOURCE 199506L -- added by Configure */
18 #include <stdio.h>
19 #include <string.h>
20 #include <math.h>
21 
test(double * result)22 void test(double *result)
23 {
24         float	afloat;
25         double	adouble;
26         int		checksum = 0;
27         unsigned	cuv = 0;
28         double	cdouble = 0.0;
29         const int	bits_in_uv = 8 * sizeof(cuv);
30 
31         checksum = 53;
32         cdouble = -1.0;
33 
34         if (checksum) {
35                 if (checksum > bits_in_uv) {
36                         double trouble;
37 
38                         adouble = (double) (1 << (checksum & 15));
39 
40                         while (checksum >= 16) {
41                                 checksum -= 16;
42                                 adouble *= 65536.0;
43                         }
44 
45                         /* At -O1, GCC 2.95.2 compiles the following loop
46                            into:
47 
48                            L$0014
49                                 fcmp,dbl,>= %fr4,%fr0
50                                 ftest
51                                 b L$0014
52                                 fadd,dbl %fr4,%fr12,%fr4
53                                 fsub,dbl %fr4,%fr12,%fr4
54 
55                                 This code depends on the floating-add and
56                                 floating-subtract retaining all of the
57                                 precision present in the operands.  There is
58                                 no such guarantee when using floating-point,
59                                 as this test case demonstrates.
60 
61                                 The code is okay at -O0.  */
62 
63                         while (cdouble < 0.0)
64                                 cdouble += adouble;
65 
66                         cdouble = modf (cdouble / adouble, &trouble) * adouble;
67                 }
68         }
69 
70         *result = cdouble;
71 }
72 
main(int argc,char ** argv)73 int main (int argc, char ** argv)
74 {
75 double	value;
76 
77         test (&value);
78 
79         if (argc == 2 && !strcmp(argv[1],"-v"))
80                 printf ("value = %.18e\n", value);
81 
82         if (value != 9.007199254740991e+15) {
83                 printf ("t001 fails!\n");
84                 return -1;
85         }
86         else {
87                 printf ("t001 works.\n");
88                 return 0;
89         }
90 }
91