File: subnormal_doubles.t

package info (click to toggle)
libmath-mpfr-perl 4.45-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,716 kB
  • sloc: perl: 1,508; ansic: 517; makefile: 9
file content (95 lines) | stat: -rwxr-xr-x 2,674 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Run some checks on subnormal double-doubles and doubles.
# This script also checks some values that are Inf (or close to Inf).
# For subnormal double values and Inf we check that atodouble() and atonv() return the same value.
# We do the same for normal values - but not if the NV type is double-double.

use strict;
use warnings;
use Math::MPFR qw(:mpfr);


if(
    $Config::Config{nvtype} eq 'double' ||
    ($Config::Config{nvtype} eq 'long double' &&
    ($Config::Config{nvsize} == 8 ||  Math::MPFR::_required_ldbl_mant_dig() == 2098))
  ) {

  my $have_atodouble = MPFR_VERSION <= 196869 ? 0 : 1;

  if($have_atodouble) {

    print "1..1\n";

    my ($ok, $dmin, $inf) = (1, 2 ** - 1022, 99 ** (99 ** 99));
    my($exp, $sig, $val, $d, $nv);

    for my $it(1 .. 1500) {
      $exp = 300 + int(rand(30));
      $exp *= -1 if($it % 3);
      $sig = (1 + int(rand(9))) . '.' . int(rand(10)) . int(rand(10)) . int(rand(10)) . (1 + int(rand(9)));

      $val = "${sig}e${exp}";
      $d = atodouble($val);
      $nv = atonv($val);

      if(($d == $inf || $nv == $inf) && $d != $nv) {
        warn "\n $d != $nv\n";
        $ok = 0;
      }

      if($Math::MPFR::NV_properties{bits} != 2098) { # Check that $d == $nv for all values
        if($d != $nv) {
          warn "\n $d != $nv\n";
          $ok = 0;
        }
      }
      elsif($d <= $dmin) {            # Check that $d == $nv for subnormal values only
        if($d != $nv) {
          warn "\n $d != $nv\n";
          $ok = 0;
        }
      }

      # Additional tests for double-double builds when (and only when)
      # the exponent <= -300.
      # Specifically, the least significant double in 10 + $val should
      # be identical to $d.

      if($Config::Config{nvtype} eq 'long double' &&
         Math::MPFR::_required_ldbl_mant_dig() == 2098 &&
         $exp <= -300) {
        my $prefix = "1" . ("0" x ($exp * -1));
        my $nv = atonv($prefix . $val);

        my $hex_dd = unpack "H*", pack "D>", $nv;
        my $hex_d  = unpack "H*", pack "d>", $d;

        if($hex_dd !~ /$hex_d$/) {
          warn "\n $hex_dd !~ /$hex_d\$/\n";
          $ok = 0;
        }
      }
    }

    if($ok) {print "ok 1\n"}
    else {print "not ok 1\n"}
  }
  else { # atodouble is unavailable

    print "1..1\n";
    eval{atodouble('1234.5');};

    if($@ =~ /^The atodouble function requires mpfr-3.1.6 or later/) {print "ok 1\n"}
    else {
      warn "\n \$\@: $@\n";
      print "not ok 1\n";
    }
  }
}
else { # Not a double or double-double build
  print "1..1\n";
  warn "\n Skipping tests: NV type ( $Config::Config{nvtype} ) is neither\n  'double' nor double-double'\n";
  print "ok 1\n";
}