xref: /openbsd-src/gnu/usr.bin/perl/hints/t001.c (revision de8cc8edbc71bd3e3bc7fbffa27ba0e564c37d8b)
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 
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 
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