Rewrite to allow different deltas for real and imaginary part of complex
[kopensolaris-gnu/glibc.git] / math / gen-libm-test.pl
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 1999 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
5 # Contributed by Andreas Jaeger <aj@suse.de>, 1999.
6
7 # The GNU C Library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Library General Public License as
9 # published by the Free Software Foundation; either version 2 of the
10 # License, or (at your option) any later version.
11
12 # The GNU C Library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Library General Public License for more details.
16
17 # You should have received a copy of the GNU Library General Public
18 # License along with the GNU C Library; see the file COPYING.LIB.  If not,
19 # write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 # Boston, MA 02111-1307, USA.
21
22 # This file needs to be tidied up
23 # Note that functions and tests share the same namespace.
24
25 # Information about tests are stored in: %results
26 # $results{$test}{"type"} is the result type, e.g. normal or complex.
27 # $results{$test}{"has_ulps"} is set if deltas exist.
28 # $results{$test}{"has_fails"} is set if exptected failures exist.
29 # In the following description $type and $float are:
30 # - $type is either "normal", "real" (for the real part of a complex number)
31 #   or "imag" (for the imaginary part # of a complex number).
32 # - $float is either of float, ifloat, double, idouble, ldouble, ildouble;
33 #   It represents the underlying floating point type (float, double or long
34 #   double) and if inline functions (the leading i stands for inline)
35 #   are used.
36 # $results{$test}{$type}{"fail"}{$float} is defined and has a 1 if 
37 # the test is expected to fail
38 # $results{$test}{$type}{"ulp"}{$float} is defined and has a delta as value
39
40
41 use Getopt::Std;
42
43 use strict;
44
45 use vars qw ($input $output);
46 use vars qw (%results);
47 use vars qw (@tests @functions);
48 use vars qw ($count);
49 use vars qw (%beautify @all_floats);
50 use vars qw ($output_dir $ulps_file);
51
52 # all_floats is sorted and contains all recognised float types
53 @all_floats = ('double', 'float', 'idouble', 
54                'ifloat', 'ildouble', 'ldouble');
55
56 %beautify =
57   ( "minus_zero" => "-0",
58     "plus_zero" => "+0",
59     "minus_infty" => "-inf",
60     "plus_infty" => "inf",
61     "nan_value" => "NaN",
62     "M_El" => "e",
63     "M_E2l" => "e^2",
64     "M_E3l" => "e^3",
65     "M_LOG10El", "log10(e)",
66     "M_PIl" => "pi",
67     "M_PI_34l" => "3/4 pi",
68     "M_PI_2l" => "pi/2",
69     "M_PI_4l" => "pi/4",
70     "M_PI_6l" => "pi/6",
71     "M_PI_34_LOG10El" => "3/4 pi*log10(e)",
72     "M_PI_LOG10El" => "pi*log10(e)",
73     "M_PI2_LOG10El" => "pi/2*log10(e)",
74     "M_PI4_LOG10El" => "pi/4*log10(e)",
75     "M_LOG_SQRT_PIl" => "log(sqrt(pi))",
76     "M_LOG_2_SQRT_PIl" => "log(2*sqrt(pi))",
77     "M_2_SQRT_PIl" => "2 sqrt (pi)",
78     "M_SQRT_PIl" => "sqrt (pi)",
79     "INVALID_EXCEPTION" => "invalid exception",
80     "DIVIDE_BY_ZERO_EXCEPTION" => "division by zero exception",
81     "INVALID_EXCEPTION_OK" => "invalid exception allowed",
82     "DIVIDE_BY_ZERO_EXCEPTION_OK" => "division by zero exception allowed",
83     "EXCEPTIONS_OK" => "exceptions allowed",
84     "IGNORE_ZERO_INF_SIGN" => "sign of zero/inf not specified",
85 "INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN" => "invalid exception and sign of zero/inf not specified"
86   );
87
88
89 # get Options
90 # Options:
91 # u: ulps-file
92 # h: help
93 # o: output-directory
94 # n: generate new ulps file
95 use vars qw($opt_u $opt_h $opt_o $opt_n);
96 getopts('u:o:nh');
97
98 $ulps_file = 'libm-test-ulps';
99 $output_dir = '';
100
101 if ($opt_h) {
102   print "Usage: gen-libm-test.pl [OPTIONS]\n";
103   print " -h         print this help, then exit\n";
104   print " -o DIR     directory where generated files will be placed\n";
105   print " -n         generate sorted file NewUlps from libm-test-ulps\n";
106   print " -u FILE    input file with ulps\n";
107   exit 0;
108 }
109
110 $ulps_file = $opt_u if ($opt_u);
111 $output_dir = $opt_o if ($opt_o);
112
113 $input = "libm-test.inc";
114 $output = "${output_dir}libm-test.c";
115
116 $count = 0;
117
118 &parse_ulps ($ulps_file);
119 &generate_testfile ($input, $output);
120 &output_ulps ("${output_dir}libm-test-ulps.h", $ulps_file);
121 &print_ulps_file ("${output_dir}NewUlps") if ($opt_n);
122
123 # Return a nicer representation
124 sub beautify {
125   my ($arg) = @_;
126   my ($tmp);
127
128   if (exists $beautify{$arg}) {
129     return $beautify{$arg};
130   }
131   if ($arg =~ /^-/) {
132     $tmp = $arg;
133     $tmp =~ s/^-//;
134     if (exists $beautify{$tmp}) {
135       return '-' . $beautify{$tmp};
136     }
137   }
138   if ($arg =~ /[0-9]L$/) {
139     $arg =~ s/L$//;
140   }
141   return $arg;
142 }
143
144 # Return a nicer representation of a complex number
145 sub build_complex_beautify {
146   my ($r, $i) = @_;
147   my ($str1, $str2);
148
149   $str1 = &beautify ($r);
150   $str2 = &beautify ($i);
151   if ($str2 =~ /^-/) {
152     $str2 =~ s/^-//;
153     $str1 .= ' - ' . $str2;
154   } else {
155     $str1 .= ' + ' . $str2;
156   }
157   $str1 .= ' i';
158   return $str1;
159 }
160
161 # Return name of a variable
162 sub get_variable {
163   my ($number) = @_;
164
165   return "x" if ($number == 1);
166   return "y" if ($number == 2);
167   return "z" if ($number == 3);
168   # return x1,x2,...
169   $number =-3;
170   return "x$number";
171 }
172
173 # Add a new test to internal data structures and fill in the
174 # ulps, failures and exception information for the C line.
175 sub new_test {
176   my ($test, $exception) = @_;
177   my $rest;
178
179   # Add ulp, xfail
180   if (exists $results{$test}{'has_ulps'}) {
181     $rest = ", DELTA$count";
182   } else {
183     $rest = ', 0';
184   }
185   if (exists $results{$test}{'has_fails'}) {
186     $rest .= ", FAIL$count";
187   } else {
188     $rest .= ', 0';
189   }
190   if (defined $exception) {
191     $rest .= ", $exception";
192   } else {
193     $rest .= ', 0';
194   }
195   $rest .= ");\n";
196   # We must increment here to keep @tests and count in sync
197   push @tests, $test;
198   ++$count;
199   return $rest;
200 }
201
202 # Treat some functions especially.
203 # Currently only sincos needs extra treatment.
204 sub special_functions {
205   my ($file, $args) = @_;
206   my (@args, $str, $test, $cline);
207
208   @args = split /,\s*/, $args;
209
210   unless ($args[0] =~ /sincos/) {
211     die ("Don't know how to handle $args[0] extra.");
212   }
213   print $file "  FUNC (sincos) ($args[1], &sin_res, &cos_res);\n";
214
215   $str = 'sincos (' . &beautify ($args[1]) . ', &sin_res, &cos_res)';
216   # handle sin
217   $test = $str . ' puts ' . &beautify ($args[2]) . ' in sin_res';
218   if ($#args == 4) {
219     $test .= " plus " . &beautify ($args[4]);
220   }
221
222   $cline = "  check_float (\"$test\", sin_res, $args[2]";
223   $cline .= &new_test ($test, $args[4]);
224   print $file $cline;
225
226   # handle cos
227   $test = $str . ' puts ' . &beautify ($args[3]) . ' in cos_res';
228   $cline = "  check_float (\"$test\", cos_res, $args[3]";
229   # only tests once for exception
230   $cline .= &new_test ($test, undef);
231   print $file $cline;
232 }
233
234 # Parse the arguments to TEST_x_y
235 sub parse_args {
236   my ($file, $descr, $args) = @_;
237   my (@args, $str, $descr_args, $descr_res, @descr);
238   my ($current_arg, $cline, $i);
239   my ($pre, $post, @special);
240   my ($extra_var, $call, $c_call);
241
242   if ($descr eq 'extra') {
243     &special_functions ($file, $args);
244     return;
245   }
246   ($descr_args, $descr_res) = split /_/,$descr, 2;
247
248   @args = split /,\s*/, $args;
249
250   $call = "$args[0] (";
251
252   # Generate first the string that's shown to the user
253   $current_arg = 1;
254   $extra_var = 0;
255   @descr = split //,$descr_args;
256   for ($i = 0; $i <= $#descr; $i++) {
257     if ($i >= 1) {
258       $call .= ', ';
259     }
260     # FLOAT, int, long int, long long int
261     if ($descr[$i] =~ /f|i|l|L/) {
262       $call .= &beautify ($args[$current_arg]);
263       ++$current_arg;
264       next;
265     }
266     # &FLOAT, &int - argument is added here
267     if ($descr[$i] =~ /F|I/) {
268       ++$extra_var;
269       $call .= '&' . &get_variable ($extra_var);
270       next;
271     }
272     # complex
273     if ($descr[$i] eq 'c') {
274       $call .= &build_complex_beautify ($args[$current_arg], $args[$current_arg+1]);
275       $current_arg += 2;
276       next;
277     }
278
279     die ("$descr[$i] is unknown");
280   }
281   $call .= ')';
282   $str = "$call == ";
283
284   # Result
285   @descr = split //,$descr_res;
286   foreach (@descr) {
287     if ($_ =~ /f|i|l|L/) {
288       $str .= &beautify ($args[$current_arg]);
289       ++$current_arg;
290     } elsif ($_ eq 'c') {
291       $str .= &build_complex_beautify ($args[$current_arg], $args[$current_arg+1]);
292       $current_arg += 2;
293     } elsif ($_ eq 'b') {
294       # boolean
295       $str .= ($args[$current_arg] == 0) ? "false" : "true";
296       ++$current_arg;
297     } elsif ($_ eq '1') {
298       ++$current_arg;
299     } else {
300       die ("$_ is unknown");
301     }
302   }
303   # consistency check
304   if ($current_arg == $#args) {
305     die ("wrong number of arguments")
306       unless ($args[$current_arg] =~ /EXCEPTION|IGNORE_ZERO_INF_SIGN/);
307   } elsif ($current_arg < $#args) {
308     die ("wrong number of arguments");
309   } elsif ($current_arg > ($#args+1)) {
310     die ("wrong number of arguments");
311   }
312
313
314   # check for exceptions
315   if ($current_arg <= $#args) {
316     $str .= " plus " . &beautify ($args[$current_arg]);
317   }
318
319   # Put the C program line together
320   # Reset some variables to start again
321   $current_arg = 1;
322   $extra_var = 0;
323   if (substr($descr_res,0,1) eq 'f') {
324     $cline = 'check_float'
325   } elsif (substr($descr_res,0,1) eq 'b') {
326     $cline = 'check_bool';
327   } elsif (substr($descr_res,0,1) eq 'c') {
328     $cline = 'check_complex';
329   } elsif (substr($descr_res,0,1) eq 'i') {
330     $cline = 'check_int';
331   } elsif (substr($descr_res,0,1) eq 'l') {
332     $cline = 'check_long';
333   } elsif (substr($descr_res,0,1) eq 'L') {
334     $cline = 'check_longlong';
335   }
336   # Special handling for some macros:
337   $cline .= " (\"$str\", ";
338   if ($args[0] =~ /fpclassify|isnormal|isfinite|signbit/) {
339     $c_call = "$args[0] (";
340   } else {
341     $c_call = " FUNC($args[0]) (";
342   }
343   @descr = split //,$descr_args;
344   for ($i=0; $i <= $#descr; $i++) {
345     if ($i >= 1) {
346       $c_call .= ', ';
347     }
348     # FLOAT, int, long int, long long int
349     if ($descr[$i] =~ /f|i|l|L/) {
350       $c_call .= $args[$current_arg];
351       $current_arg++;
352       next;
353     }
354     # &FLOAT, &int
355     if ($descr[$i] =~ /F|I/) {
356       ++$extra_var;
357       $c_call .= '&' . &get_variable ($extra_var);
358       next;
359     }
360     # complex
361     if ($descr[$i] eq 'c') {
362       $c_call .= "BUILD_COMPLEX ($args[$current_arg], $args[$current_arg+1])";
363       $current_arg += 2;
364       next;
365     }
366   }
367   $c_call .= ')';
368   $cline .= "$c_call, ";
369
370   @descr = split //,$descr_res;
371   foreach (@descr) {
372     if ($_ =~ /b|f|i|l|L/ ) {
373       $cline .= $args[$current_arg];
374       $current_arg++;
375     } elsif ($_ eq 'c') {
376       $cline .= "BUILD_COMPLEX ($args[$current_arg], $args[$current_arg+1])";
377       $current_arg += 2;
378     } elsif ($_ eq '1') {
379       push @special, $args[$current_arg];
380       ++$current_arg;
381     }
382   }
383   # Add ulp, xfail
384   $cline .= &new_test ($str, ($current_arg <= $#args) ? $args[$current_arg] : undef);
385
386   # special treatment for some functions
387   if ($args[0] eq 'frexp') {
388     if (defined $special[0] && $special[0] ne "IGNORE") {
389       my ($str) = "$call sets x to $special[0]";
390       $post = "  check_int (\"$str\", x, $special[0]";
391       $post .= &new_test ($str, undef);
392     }
393   } elsif ($args[0] eq 'gamma' || $args[0] eq 'lgamma') {
394     $pre = "  signgam = 0;\n";
395     if (defined $special[0] && $special[0] ne "IGNORE") {
396       my ($str) = "$call sets signgam to $special[0]";
397       $post = "  check_int (\"$str\", signgam, $special[0]";
398       $post .= &new_test ($str, undef);
399     }
400   } elsif ($args[0] eq 'modf') {
401     if (defined $special[0] && $special[0] ne "IGNORE") {
402       my ($str) = "$call sets x to $special[0]";
403       $post = "  check_float (\"$str\", x, $special[0]";
404       $post .= &new_test ($str, undef);
405     }
406   } elsif ($args[0] eq 'remquo') {
407     if (defined $special[0] && $special[0] ne "IGNORE") {
408       my ($str) = "$call sets x to $special[0]";
409       $post = "  check_int (\"$str\", x, $special[0]";
410       $post .= &new_test ($str, undef);
411     }
412   }
413
414   print $file $pre if (defined $pre);
415
416   print $file "  $cline";
417
418   print $file $post if (defined $post);
419 }
420
421 # Generate libm-test.c
422 sub generate_testfile {
423   my ($input, $output) = @_;
424   my ($lasttext);
425   my (@args, $i, $str);
426
427   open INPUT, $input or die ("Can't open $input: $!");
428   open OUTPUT, ">$output" or die ("Can't open $output: $!");
429
430   # Replace the special macros
431   while (<INPUT>) {
432
433     # TEST_...
434     if (/^\s*TEST_/) {
435       my ($descr, $args);
436       chop;
437       ($descr, $args) = ($_ =~ /TEST_(\w+)\s*\((.*)\)/);
438       &parse_args (\*OUTPUT, $descr, $args);
439       next;
440     }
441     # START (function)
442     if (/START/) {
443       print OUTPUT "  init_max_error ();\n";
444       next;
445     }
446     # END (function)
447     if (/END/) {
448       my ($fct, $line, $type);
449       if (/complex/) {
450         s/,\s*complex\s*//;
451         $type = 'complex';
452       } else {
453         $type = 'normal';
454       }
455       ($fct) = ($_ =~ /END\s*\((.*)\)/);
456       if ($type eq 'complex') {
457         $line = "  print_complex_max_error (\"$fct\", ";
458       } else {
459         $line = "  print_max_error (\"$fct\", ";
460       }
461       if (exists $results{$fct}{'has_ulps'}) {
462         $line .= "DELTA$fct";
463       } else {
464         $line .= '0';
465       }
466       if (exists $results{$fct}{'has_fails'}) {
467         $line .= ", FAIL$fct";
468       } else {
469         $line .= ', 0';
470       }
471       $line .= ");\n";
472       print OUTPUT $line;
473       push @functions, $fct;
474       next;
475     }
476     print OUTPUT;
477   }
478   close INPUT;
479   close OUTPUT;
480 }
481
482
483
484 # Parse ulps file
485 sub parse_ulps {
486   my ($file) = @_;
487   my ($test, $type, $float, $eps);
488
489   # $type has the following values:
490   # "normal": No complex variable
491   # "real": Real part of complex result
492   # "imag": Imaginary part of complex result
493   open ULP, $file  or die ("Can't open $file: $!");
494   while (<ULP>) {
495     chop;
496     # ignore comments and empty lines
497     next if /^#/;
498     next if /^\s*$/;
499     if (/^Test/) {
500       if (/Real part of:/) {
501         s/Real part of: //;
502         $type = 'real';
503       } elsif (/Imaginary part of:/) {
504         s/Imaginary part of: //;
505         $type = 'imag';
506       } else {
507         $type = 'normal';
508       }
509       s/^.+\"(.*)\".*$/$1/;
510       $test = $_;
511       if ($type =~ /^real|imag$/) {
512         $results{$test}{'type'} = 'complex';
513       } elsif ($type eq 'normal') {
514         $results{$test}{'type'} = 'normal';
515       }
516       next;
517     }
518     if (/^Function: /) {
519       if (/\Real part of/) {
520         s/Real part of //;
521         $type = 'real';
522       } elsif (/Imaginary part of/) {
523         s/Imaginary part of //;
524         $type = 'imag';
525       } else {
526         $type = 'normal';
527       }
528       ($test) = ($_ =~ /^Function:\s*\"([a-zA-Z0-9_]+)\"/);
529       if ($type =~ /^real|imag$/) {
530         $results{$test}{'type'} = 'complex';
531       } elsif ($type eq 'normal') {
532         $results{$test}{'type'} = 'normal';
533       }
534       next;
535     }
536     if (/^i?(float|double|ldouble):/) {
537       ($float, $eps) = split /\s*:\s*/,$_,2;
538       if ($eps eq 'fail') {
539         $results{$test}{$type}{'fail'}{$float} = 1;
540         $results{$test}{'has_fails'} = 1;
541       } else {
542         $results{$test}{$type}{'ulp'}{$float} = $eps;
543         $results{$test}{'has_ulps'} = 1;
544       }
545       next;
546     }
547     print "Skipping unknown entry: `$_'\n";
548   }
549   close ULP;
550 }
551
552
553 # Clean up a floating point number
554 sub clean_up_number {
555   my ($number) = @_;
556
557   # Remove trailing zeros
558   $number =~ s/0+$//;
559   $number =~ s/\.$//;
560   return $number;
561 }
562
563 # Output a file which can be read in as ulps file.
564 sub print_ulps_file {
565   my ($file) = @_;
566   my ($test, $type, $float, $eps, $fct, $last_fct);
567
568   $last_fct = '';
569   open NEWULP, ">$file" or die ("Can't open $file: $!");
570   print NEWULP "# Begin of automatic generation\n";
571   foreach $test (sort @tests) {
572     foreach $type ('real', 'imag', 'normal') {
573       if (exists $results{$test}{$type}) {
574         if (defined $results{$test}) {
575           ($fct) = ($test =~ /^(\w+)\s/);
576           if ($fct ne $last_fct) {
577             $last_fct = $fct;
578             print NEWULP "\n# $fct\n";
579           }
580         }
581         if ($type eq 'normal') {
582           print NEWULP "Test \"$test\":\n";
583         } elsif ($type eq 'real') {
584           print NEWULP "Test \"Real part of: $test\":\n";
585         } elsif ($type eq 'imag') {
586           print NEWULP "Test \"Imaginary part of: $test\":\n";
587         }
588         foreach $float (@all_floats) {
589           if (exists $results{$test}{$type}{'ulp'}{$float}) {
590             print NEWULP "$float: ", 
591             &clean_up_number ($results{$test}{$type}{'ulp'}{$float}), 
592             "\n";
593           }
594           if (exists $results{$test}{$type}{'fail'}{$float}) {
595             print NEWULP "$float: fail\n";
596           }
597         }
598       }
599     }
600   }
601   print NEWULP "\n# Maximal error of functions:\n";
602
603   foreach $fct (sort @functions) {
604     foreach $type ('real', 'imag', 'normal') {
605       if (exists $results{$fct}{$type}) {
606         if ($type eq 'normal') {
607           print NEWULP "Function: \"$fct\":\n";
608         } elsif ($type eq 'real') {
609           print NEWULP "Function: Real part of \"$fct\":\n";
610         } elsif ($type eq 'imag') {
611           print NEWULP "Function: Imaginary part of \"$fct\":\n";
612         }
613         foreach $float (@all_floats) {
614           if (exists $results{$fct}{$type}{'ulp'}{$float}) {
615             print NEWULP "$float: ", 
616             &clean_up_number ($results{$fct}{$type}{'ulp'}{$float}), 
617             "\n";
618           }
619           if (exists $results{$fct}{$type}{'fail'}{$float}) {
620             print NEWULP "$float: fail\n";
621           }
622         }
623         print NEWULP "\n";
624       }
625     }
626   }
627   print NEWULP "# end of automatic generation\n";
628   close NEWULP;
629 }
630
631 sub get_ulps {
632   my ($test, $type, $float) = @_;
633
634   if ($type eq 'complex') {
635     my ($res);
636     # Return 0 instead of BUILD_COMPLEX (0,0)
637     if (!exists $results{$test}{'real'}{'ulp'}{$float} &&
638         !exists $results{$test}{'imag'}{'ulp'}{$float}) {
639       return "0";
640     }
641     $res = 'BUILD_COMPLEX (';
642     $res .= (exists $results{$test}{'real'}{'ulp'}{$float} 
643              ? $results{$test}{'real'}{'ulp'}{$float} : "0");
644     $res .= ', ';
645     $res .= (exists $results{$test}{'imag'}{'ulp'}{$float}
646              ? $results{$test}{'imag'}{'ulp'}{$float} : "0");
647     $res .= ')';
648     return $res;
649   }
650   return (exists $results{$test}{'normal'}{'ulp'}{$float}
651           ? $results{$test}{'normal'}{'ulp'}{$float} : "0");
652 }
653
654 sub get_failure {
655   my ($test, $type, $float) = @_;
656   if ($type eq 'complex') {
657     # return x,y
658     my ($res);
659     # Return 0 instead of BUILD_COMPLEX_INT (0,0)
660     if (!exists $results{$test}{'real'}{'ulp'}{$float} &&
661         !exists $results{$test}{'imag'}{'ulp'}{$float}) {
662       return "0";
663     }
664     $res = 'BUILD_COMPLEX_INT (';
665     $res .= (exists $results{$test}{'real'}{'fail'}{$float} 
666              ? $results{$test}{'real'}{'fail'}{$float} : "0");
667     $res .= ', ';
668     $res .= (exists $results{$test}{'imag'}{'fail'}{$float}
669              ? $results{$test}{'imag'}{'fail'}{$float} : "0");
670     $res .= ')';
671     return $res;
672   }
673   return (exists $results{$test}{'normal'}{'fail'}{$float}
674           ? $results{$test}{'normal'}{'fail'}{$float} : "0");
675
676 }
677
678 # Output the defines for a single test
679 sub output_test {
680   my ($file, $test, $name) = @_;
681   my ($ldouble, $double, $float, $ildouble, $idouble, $ifloat);
682   my ($type);
683
684   # Do we have ulps/failures?
685   if (!exists $results{$test}{'type'}) {
686     return;
687   }
688   $type = $results{$test}{'type'};
689   if (exists $results{$test}{'has_ulps'}) {
690     # XXX use all_floats (change order!)
691     $ldouble = &get_ulps ($test, $type, "ldouble");
692     $double = &get_ulps ($test, $type, "double");
693     $float = &get_ulps ($test, $type, "float");
694     $ildouble = &get_ulps ($test, $type, "ildouble");
695     $idouble = &get_ulps ($test, $type, "idouble");
696     $ifloat = &get_ulps ($test, $type, "ifloat");
697     print $file "#define DELTA$name CHOOSE($ldouble, $double, $float, $ildouble, $idouble, $ifloat)\t/* $test  */\n";
698   }
699
700   if (exists $results{$test}{'has_fails'}) {
701     $ldouble = &get_failure ($test, "ldouble");
702     $double = &get_failure ($test, "double");
703     $float = &get_failure ($test, "float");
704     $ildouble = &get_failure ($test, "ildouble");
705     $idouble = &get_failure ($test, "idouble");
706     $ifloat = &get_failure ($test, "ifloat");
707     print $file "#define FAIL$name CHOOSE($ldouble, $double, $float $ildouble, $idouble, $ifloat)\t/* $test  */\n";
708   }
709 }
710
711 # Print include file
712 sub output_ulps {
713   my ($file, $ulps_filename) = @_;
714   my ($i, $fct);
715
716   open ULP, ">$file" or die ("Can't open $file: $!");
717
718   print ULP "/* This file is automatically generated\n";
719   print ULP "   from $ulps_filename with gen-libm-test.pl.\n";
720   print ULP "   Don't change it - change instead the master files.  */\n\n";
721
722   print ULP "\n/* Maximal error of functions.  */\n";
723   foreach $fct (@functions) {
724     output_test (\*ULP, $fct, $fct);
725   }
726
727   print ULP "\n/* Error of single function calls.  */\n";
728   for ($i = 0; $i < $count; $i++) {
729     output_test (\*ULP, $tests[$i], $i);
730   }
731   close ULP;
732 }