s390 debug question

Greg Smith gsmith at nc.rr.com
Fri Apr 29 05:17:25 CEST 2005


Hello,

I am a developer for a s390/s390x (aka IBM mainframe) emulator.

A user who is attempting to build the CentOS linux distribution for
s390/s390x architecture has reported a problem trying to build gmp-4.1.4
from the available RHEL rpm.  The rpm enables the mpfr portion of gmp.

The error I am working on comes from mpfr/tests/tadd.c  It seems the
problem stems from adding/subtracting a very small number (vsn) to a
very big number (vbn) using 53 bit precision.

For the testcase below, we are adding (in big-endian representation)
  0e99ee563b83c5a0 + f0d038ed4fb527de
which in decimal is
  2.4888731542366126e-238 + -2.5789977198441930e+235

In both intel and s390 emulation, the answer is
  f0d038ed4fb527dd
that is, a bit changes.  I confess I do not know enough why such a nit
(vsn) added to a vbn will cause a bit to change, but it does *seem*
silly.

The problem occurs (on s390 emulation) because
 z1.f != z2.f         but
 mpfr_cmp(zz,yy)      is true, ummm, I mean 0.

That is, on intel and s390 (emulation), x+y is not the same as mpfr_add
(x,y) but on s390 mpfr_cmp() says they are equal but on intel it's not.

That the emulator has a bug is my foremost suspicion.  Good Lord knows
we've had more than one, esp. in fp arithmetic.  I can try to replicate
the problem on a real s390, but, unfortunately, this is going to require
a bit of, umm, negotiation.

What I'm looking for is some pointers or insight on how to debug the
problem... if anyone can be so kind.  I do have a rather lengthy s390
instruction trace (~50000 lines) that I will be digging in to.

Thanks,

Greg Smith

#include <stdio.h>
#include "gmp.h"
#include "mpfr.h"

void _check (double, double, double, mp_rnd_t,
             unsigned int, unsigned int, unsigned int);

typedef union {
 double f;
 unsigned long long i;
} fi;

int main()
{
 fi x, y, z1, z2;
 unsigned int p = 53;
 mp_rnd_t r = GMP_RNDZ;
 mpfr_t xx, yy, zz;
 int t;

 if (sizeof(double) != sizeof(unsigned long long)) exit(1);

 x.i = 0x0e99ee563b83c5a0ull;
 y.i = 0xf0d038ed4fb527deull;

 mpfr_init2 (xx, p);
 mpfr_init2 (yy, p);
 mpfr_init2 (zz, p);

 mpfr_set_d(xx, x.f, r);
 mpfr_set_d(yy, y.f, r);

 z1.f = x.f + y.f;
 mpfr_add(zz, xx, yy, r);
 mpfr_set_machine_rnd_mode(r);
 z2.f = mpfr_get_d1 (zz);
 mpfr_set_d (yy, z2.f, GMP_RNDN);
 t = mpfr_cmp(zz,yy);

 printf("%1.16e %1.16e = \n%1.16e + %1.16e\n",z1.f,z2.f,x.f,y.f);
 printf("%16.16llx %16.16llx = %16.16llx + %16.16llx\n",
z1.i,z2.i,x.i,y.i);
 printf("mpfr_cmp %d  z1==z2 %d\n",t,z1.f==z2.f);
}




More information about the gmp-discuss mailing list