summaryrefslogtreecommitdiff
path: root/tests/tmul.c
blob: 66025addc9a9a653ef3f5163234ebb5c701f80b8 (plain)
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
96
97
#include <stdio.h>
#include <stdlib.h>
#include "gmp.h"
#include "mpfr.h"
#include "mpfr-impl.h"

#define MINNORM 2.2250738585072013831e-308 /* 2^(-1022), smallest normalized */

/* checks that x*y gives the same results in double
   and with mpfr with 53 bits of precision */
void check(double x, double y, unsigned int rnd_mode, unsigned int px, 
unsigned int py, unsigned int pz, double res)
{
  double z1,z2; mpfr_t xx,yy,zz;

  mpfr_init2(xx, px);
  mpfr_init2(yy, py);
  mpfr_init2(zz, pz);
  mpfr_set_d(xx, x, rnd_mode);
  mpfr_set_d(yy, y, rnd_mode);
  mpfr_mul(zz, xx, yy, rnd_mode);
  mpfr_set_machine_rnd_mode(rnd_mode);
  z1 = (res==0.0) ? x*y : res;
  z2 = mpfr_get_d(zz);
  if (px==53 && py==53 && pz==53) res=1.0;
  if (res!=0.0 && z1!=z2 && (z1>=MINNORM || z1<=-MINNORM)) {
    printf("expected product is %1.20e, got %1.20e\n",z1,z2);
    printf("mpfr_mul failed for x=%1.20e y=%1.20e with rnd_mode=%u\n",x,y,rnd_mode);
mpfr_print_raw(zz); putchar('\n');
    exit(1);
  }
  mpfr_clear(xx); mpfr_clear(yy); mpfr_clear(zz);
}

/* check sign of result */
void check_sign()
{
  mpfr_t a, b;

  mpfr_init2(a, 53); mpfr_init2(b, 53);
  mpfr_set_d(a, -1.0, GMP_RNDN);
  mpfr_set_d(b, 2.0, GMP_RNDN);
  mpfr_mul(a, b, b, GMP_RNDN);
  if (mpfr_get_d(a) != 4.0) {
    fprintf(stderr,"2.0*2.0 gives %1.20e\n", mpfr_get_d(a)); exit(1);
  }
  mpfr_clear(a); mpfr_clear(b);
}

int main(argc,argv) int argc; char *argv[];
{
  double x,y,z; int i,prec,rnd_mode;

  check(6.9314718055994530941514e-1, 0.0, GMP_RNDZ, 53, 53, 53, 0.0);
  check(0.0, 6.9314718055994530941514e-1, GMP_RNDZ, 53, 53, 53, 0.0);
  prec = (argc<2) ? 53 : atoi(argv[1]);
  rnd_mode = (argc<3) ? -1 : atoi(argv[2]);
  check_sign();
  check(-4.165000000e4, -0.00004801920768307322868063274915, GMP_RNDN, 
	53, 53, 53, 2.0); 
  check(2.71331408349172961467e-08, -6.72658901114033715233e-165,
	GMP_RNDZ, 53, 53, 53, 0.0);
  x=0.31869277231188065; y=0.88642843322303122;
  check(x, y, GMP_RNDZ, 53, 53, 53, 0.0);
  x=8.47622108205396074254e-01; y=3.24039313247872939883e-01;
  check(x, y, GMP_RNDU, 28, 45, 1, 0.5);
  x=2.63978122803639081440e-01; 
  y=5736014.0/8388608.0; /* 6.83786096444222835089e-01; */
  check(x, y, GMP_RNDN, 34, 23, 31, 0.180504585267044603);
  x=9.84891017624509146344e-01; /* rounded to 1.0 with prec=6 */
  x=1.0;
  y=1.18351709358762491320e-01;
  check(x, y, GMP_RNDU, 6, 41, 36, 0.1183517093595583);
  /* the following checks that rounding to nearest sets the last
     bit to zero in case of equal distance */
  check(67108865.0, 134217729.0, GMP_RNDN, 53, 53, 53, 0.0);
  x=1.37399642157394197284e-01; y=2.28877275604219221350e-01;
  check(x, y, GMP_RNDN, 49, 15, 32, 0.0314472340833162888);
  x=4.03160720978664954828e-01; y=5.85483042917246621073e-01;
  check(x, y, GMP_RNDZ, 51, 22, 32, 0.2360436821472831);
  x=3.90798504668055102229e-14; y=9.85394674650308388664e-04;
  check(x, y, GMP_RNDN, 46, 22, 12, 0.385027296503914762e-16);
  x=4.58687081072827851358e-01; y=2.20543551472118792844e-01;
  check(x, y, GMP_RNDN, 49, 3, 1, 0.125);
  for (i=0;i<1000000;) {
    x = drand();
    y = drand();
    z = x*y; if (z<0) z=-z;
    if (z<1e+308 && z>1e-308) /* don't test overflow/underflow for now */
      { i++;
      check(x, y, (rnd_mode==-1) ? lrand48()%4 : rnd_mode, 
	    prec, prec, prec, 0.0);
      }
  } 
  return 0;
}