RFR: JDK-8301202: Port fdlibm log to Java
Raffaello Giulietti
rgiulietti at openjdk.org
Wed Feb 8 13:28:43 UTC 2023
On Wed, 8 Feb 2023 00:25:32 GMT, Joe Darcy <darcy at openjdk.org> wrote:
> Next up on the FDLIBM porting countdown, the log method.
>
> Original C vs transliteration port:
>
>
> $ diff -w Log.c Log.translit.java
> 1c1
> < /* __ieee754_log(x)
> ---
>> /**
> 51,58c51,52
> <
> < #include "fdlibm.h"
> <
> < #ifdef __STDC__
> < static const double
> < #else
> < static double
> < #endif
> ---
>> static class Log {
>> private static final double
> 70c64
> < static double zero = 0.0;
> ---
>> private static double zero = 0.0;
> 72,78c66
> < #ifdef __STDC__
> < double __ieee754_log(double x)
> < #else
> < double __ieee754_log(x)
> < double x;
> < #endif
> < {
> ---
>> static double compute(double x) {
> 81c69
> < unsigned lx;
> ---
>> /*unsigned*/ int lx;
> 98c86,87
> < __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
> ---
>> // __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
>> x =__HI(x, hx|(i^0x3ff00000)); /* normalize x or x/2 */
> 128a118
>> }
>
>
> Transliteration port vs more idiomatic port:
>
>
> $ diff -w Log.translit.java Log.fdlibm.java
> 2c2
> < * Return the logarithm of x
> ---
>> * Return the (natural) logarithm of x
> 53,62c53,54
> < ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
> < ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
> < two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
> < Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
> < Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
> < Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
> < Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
> < Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
> < Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
> < Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
> ---
>> ln2_hi = 0x1.62e42feep-1, // 6.93147180369123816490e-01
>> ln2_lo = 0x1.a39ef35793c76p-33, // 1.90821492927058770002e-10
> 64c56,64
> < private static double zero = 0.0;
> ---
>> Lg1 = 0x1.5555555555593p-1, // 6.666666666666735130e-01
>> Lg2 = 0x1.999999997fa04p-2, // 3.999999999940941908e-01
>> Lg3 = 0x1.2492494229359p-2, // 2.857142874366239149e-01
>> Lg4 = 0x1.c71c51d8e78afp-3, // 2.222219843214978396e-01
>> Lg5 = 0x1.7466496cb03dep-3, // 1.818357216161805012e-01
>> Lg6 = 0x1.39a09d078c69fp-3, // 1.531383769920937332e-01
>> Lg7 = 0x1.2f112df3e5244p-3; // 1.479819860511658591e-01
>>
>> private static final double zero = 0.0;
> 71,72c71,72
> < hx = __HI(x); /* high word of x */
> < lx = __LO(x); /* low word of x */
> ---
>> hx = __HI(x); // high word of x
>> lx = __LO(x); // low word of x
> 75,80c75,87
> < if (hx < 0x00100000) { /* x < 2**-1022 */
> < if (((hx&0x7fffffff)|lx)==0)
> < return -two54/zero; /* log(+-0)=-inf */
> < if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
> < k -= 54; x *= two54; /* subnormal number, scale up x */
> < hx = __HI(x); /* high word of x */
> ---
>> if (hx < 0x0010_0000) { // x < 2**-1022
>> if (((hx & 0x7fff_ffff) | lx) ==0) { // log(+-0) = -inf
>> return -TWO54/zero;
>> }
>> if (hx < 0) { // log(-#) = NaN
>> return (x - x)/zero;
>> }
>> k -= 54;
>> x *= TWO54; // subnormal number, scale up x
>> hx = __HI(x); // high word of x
>> }
>> if (hx >= 0x7ff0_0000) {
>> return x+x;
> 82d88
> < if (hx >= 0x7ff00000) return x+x;
> 84,87c90,92
> < hx &= 0x000fffff;
> < i = (hx+0x95f64)&0x100000;
> < // __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
> < x =__HI(x, hx|(i^0x3ff00000)); /* normalize x or x/2 */
> ---
>> hx &= 0x000f_ffff;
>> i = (hx + 0x9_5f64) & 0x10_0000;
>> x =__HI(x, hx|(i ^ 0x3ff0_0000)); // normalize x or x/2
> 90c95
> < if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
> ---
>> if ((0x000f_ffff & (2 + hx)) < 3) {// |f| < 2**-20
> 92,93c97,102
> < if (k==0) return zero;
> < else {dk=(double)k; return dk*ln2_hi+dk*ln2_lo;}
> ---
>> if (k == 0) {
>> return zero;
>> } else {
>> dk = (double)k;
>> return dk*ln2_hi + dk*ln2_lo;
>> }
> 96,97c105,110
> < if(k==0) return f-R; else {dk=(double)k;
> < return dk*ln2_hi-((R-dk*ln2_lo)-f);}
> ---
>> if (k == 0) {
>> return f - R;
>> } else {
>> dk = (double)k;
>> return dk*ln2_hi - ((R - dk*ln2_lo) - f);
>> }
> 102c115
> < i = hx-0x6147a;
> ---
>> i = hx - 0x6_147a;
> 111c124,126
> < if(k==0) return f-(hfsq-s*(hfsq+R)); else
> ---
>> if (k == 0) {
>> return f-(hfsq-s*(hfsq+R));
>> } else {
> 112a128,131
>> }
>> } else {
>> if (k == 0) {
>> return f - s*(f - R);
> 114d132
> < if(k==0) return f-s*(f-R); else
> 115a134
>> }
>
>
> The transliteration port passes the "exhausting" test of all float arguments when run against a JDK 20 build. The idiomatic port matches the transliteration port on the same test.
Both the transliteration as well as the more idiomatic versions LGTM.
There are only two decision points in the test, both powers of 2. Since there's an argument reduction step, maybe there are other good ones?
-------------
PR: https://git.openjdk.org/jdk/pull/12465
More information about the core-libs-dev
mailing list