Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Dec 2021 09:51:51 -0800
From:      Steve Kargl <sgk@troutmask.apl.washington.edu>
To:        Mark Murray <markm@freebsd.org>
Cc:        freebsd-hackers@freebsd.org, freebsd-current@freebsd.org
Subject:   Re: What to do about tgammal?
Message-ID:  <20211218175151.GA71197@troutmask.apl.washington.edu>
In-Reply-To: <6C888EBF-1734-4EDC-8DBF-D2BA2454C37D@FreeBSD.org>
References:  <20211204185352.GA20452@troutmask.apl.washington.edu> <E5711C71-1095-4B6B-A33A-4CDFF123AB62@FreeBSD.org> <20211213022223.GA41440@troutmask.apl.washington.edu> <813F29E3-8478-4282-9518-5943DE7B5492@FreeBSD.org> <20211214215106.GA50381@troutmask.apl.washington.edu> <F63407DF-B7CF-4C7B-86AB-1D99EB6C6FC7@FreeBSD.org> <20211218035222.GA68916@troutmask.apl.washington.edu> <6C888EBF-1734-4EDC-8DBF-D2BA2454C37D@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Dec 18, 2021 at 10:41:14AM +0000, Mark Murray wrote:
> 
> Hmm. I think my understanding of ULP is missing something?
> 
> I thought that ULP could not be greater than the mantissa size
> in bits?
> 
> I.e., I thought it represents average rounding error (compared with
> "perfect rounding"), not truncation error, as the above very large
> ULPs suggest.
> 

The definition of ULP differs according which expert you
choose to follow. :-)  For me (a non-expert), ULP is measured
in the system of the "accurate answer", which is assumed to
have many more bits of precision than the "approximate answer".
>From a very old das@ email and for long double I have 

/* From a das email:
 *
 *   ulps = err * (2**(LDBL_MANT_DIG - e)), where e = ilogb(accurate).
 *
 * I use:
 *
 *   mpfr_sub(err, accurate, approximate, RNDN);
 *   mpfr_abs(err, err, RNDN);
 *   mpfr_mul_2si(ulpx, err, -mpfr_get_exp(accurate) + LDBL_MANT_DIG, RNDN);
 *   ulp = mpfr_get_d(ulpx, RNDN);
 *   if (ulp  0.506 && mpfr_cmpabs(err, ldbl_minx)  0) {
 *     print warning...;
 *   }
 */

Here, "err = |accurate - approximate|" is done in the precision
of the "accurate answer", and RNDN is round-to-nearest.  The
line 'mpfr_mul_2si(...)' is doing the scaling to manipulate the
exponent of the radix 2.

This is agreement with Goldberg.  IIRC, Jean-Michel Muller et al
have much more detailed discussion about error and ULPs in their
book "Handbook of Floating-Point Arithmetic".   

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

So, on ld80 and tgamma, I have 

% tlibm -l -x 8 -X 1755 -n 100000 -P tgamma
Interval tested for tgammal: [8,1755]
       ulp <= 0.5: 90.207%     90207 |  90.207%     90207
0.5 <  ulp <  0.6:  7.085%      7085 |  97.292%     97292
0.6 <  ulp <  0.7:  2.383%      2383 |  99.675%     99675
0.7 <  ulp <  0.8:  0.314%       314 |  99.989%     99989
0.8 <  ulp <  0.9:  0.011%        11 | 100.000%    100000
Max ulp: 0.853190 at 9.236118561185611856579e+02

The "ulp <= 0.5" line indicates the number of correctly
rounded case.  If the value of ULP exceeds 1, then you are
starting to lose more than 1 bit in the significant.  Consider
individual points.  Here's a correctly rounded case:

% tlibm -l -a 9.236118561185000000 tgamma
   xu = LD80C(0x93c72441a44a57a9,     3,  9.23611856118499999994e+00L),
libmu = LD80C(0x82f85b3fe4b36f9b,    16,  6.70567128873706962722e+04L),
mpfru = LD80C(0x82f85b3fe4b36f9b,    16,  6.70567128873706962722e+04L),
 ULP = 0.42318

Notice, ULP < 0.5 and the bits in libm and mpfr answer rounded to 
long double are all the same as is the decimal representation. Now
consider the max ULP case:

% tlibm -l -a  9.236118561185611856579e+02 tgamma
   xu = LD80C(0xe6e728a690c4fa87,     9,  9.23611856118561185658e+02L),
libmu = LD80C(0xba6bea661a7eda3c,  7762,  5.72944398777756327202e+2336L),
mpfru = LD80C(0xba6bea661a7eda3d,  7762,  5.72944398777756327245e+2336L),
 ULP = 0.85319

ULP is < 1, which is desireable.  The bits agree except for the
last place where we're off by 1, ie, 0xc vs 0xd.  The decimal
representation is of course off.

So, now on grimoirei without my patch, I have 

% ./tlibm_libm -l -a 1.59255925592559255925592559255925594e+01 tgamma
   x =  1.59255925592559255925592559255925594e+01L
libm =  1.06660136733166064453125000000000000e+12L
mpfr =  1.06660136733166211967839038834033459e+12L,
 ULP = 13932370826141802496.00000

You have 16 correct decimal digits out of 36, which is the best
you can expect from mapping tgammal to tgamma.  ULP is significant
larger than 1.  The ulp is almost guaranteed to be larger than
2**(113-53).

Now with my patch and worse case for 10000 x in [10:16]

% ./tlibm_lmath -l -a 1.59255925592559255925592559255925594e+01 tgamma
  x =  1.59255925592559255925592559255925594e+01L
libm =  1.06660136733166211967839038834033897e+12
mpfr =  1.06660136733166211967839038834033459e+12L,
 ULP = 41.40877

I don't print out the hex representation in ld128, but you see
the number of correct decimal digits is 33 digits compared to
36.

-- 
Steve



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20211218175151.GA71197>