Skip to content

Commit ee0f5b5

Browse files
committed
8301392: Port fdlibm log1p to Java
Reviewed-by: bpb
1 parent f696785 commit ee0f5b5

File tree

4 files changed

+409
-15
lines changed

4 files changed

+409
-15
lines changed

src/java.base/share/classes/java/lang/FdLibm.java

+169-6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
class FdLibm {
6161
// Constants used by multiple algorithms
6262
private static final double INFINITY = Double.POSITIVE_INFINITY;
63+
private static final double TWO54 = 0x1.0p54; // 1.80143985094819840000e+16
6364

6465
private FdLibm() {
6566
throw new UnsupportedOperationException("No FdLibm instances for you.");
@@ -779,11 +780,10 @@ public static double compute(double x) {
779780
* shown.
780781
*/
781782
static class Log10 {
782-
private static double two54 = 0x1.0p54; // 1.80143985094819840000e+16;
783-
private static double ivln10 = 0x1.bcb7b1526e50ep-2; // 4.34294481903251816668e-01
783+
private static final double ivln10 = 0x1.bcb7b1526e50ep-2; // 4.34294481903251816668e-01
784784

785-
private static double log10_2hi = 0x1.34413509f6p-2; // 3.01029995663611771306e-01;
786-
private static double log10_2lo = 0x1.9fef311f12b36p-42; // 3.69423907715893078616e-13;
785+
private static final double log10_2hi = 0x1.34413509f6p-2; // 3.01029995663611771306e-01;
786+
private static final double log10_2lo = 0x1.9fef311f12b36p-42; // 3.69423907715893078616e-13;
787787

788788
private Log10() {
789789
throw new UnsupportedOperationException();
@@ -799,13 +799,13 @@ public static double compute(double x) {
799799
k=0;
800800
if (hx < 0x0010_0000) { /* x < 2**-1022 */
801801
if (((hx & 0x7fff_ffff) | lx) == 0) {
802-
return -two54/0.0; /* log(+-0)=-inf */
802+
return -TWO54/0.0; /* log(+-0)=-inf */
803803
}
804804
if (hx < 0) {
805805
return (x - x)/0.0; /* log(-#) = NaN */
806806
}
807807
k -= 54;
808-
x *= two54; /* subnormal number, scale up x */
808+
x *= TWO54; /* subnormal number, scale up x */
809809
hx = __HI(x);
810810
}
811811

@@ -822,4 +822,167 @@ public static double compute(double x) {
822822
return z + y * log10_2hi;
823823
}
824824
}
825+
826+
/**
827+
* Returns the natural logarithm of the sum of the argument and 1.
828+
*
829+
* Method :
830+
* 1. Argument Reduction: find k and f such that
831+
* 1+x = 2^k * (1+f),
832+
* where sqrt(2)/2 < 1+f < sqrt(2) .
833+
*
834+
* Note. If k=0, then f=x is exact. However, if k!=0, then f
835+
* may not be representable exactly. In that case, a correction
836+
* term is need. Let u=1+x rounded. Let c = (1+x)-u, then
837+
* log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
838+
* and add back the correction term c/u.
839+
* (Note: when x > 2**53, one can simply return log(x))
840+
*
841+
* 2. Approximation of log1p(f).
842+
* Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
843+
* = 2s + 2/3 s**3 + 2/5 s**5 + .....,
844+
* = 2s + s*R
845+
* We use a special Reme algorithm on [0,0.1716] to generate
846+
* a polynomial of degree 14 to approximate R The maximum error
847+
* of this polynomial approximation is bounded by 2**-58.45. In
848+
* other words,
849+
* 2 4 6 8 10 12 14
850+
* R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
851+
* (the values of Lp1 to Lp7 are listed in the program)
852+
* and
853+
* | 2 14 | -58.45
854+
* | Lp1*s +...+Lp7*s - R(z) | <= 2
855+
* | |
856+
* Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
857+
* In order to guarantee error in log below 1ulp, we compute log
858+
* by
859+
* log1p(f) = f - (hfsq - s*(hfsq+R)).
860+
*
861+
* 3. Finally, log1p(x) = k*ln2 + log1p(f).
862+
* = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
863+
* Here ln2 is split into two floating point number:
864+
* ln2_hi + ln2_lo,
865+
* where n*ln2_hi is always exact for |n| < 2000.
866+
*
867+
* Special cases:
868+
* log1p(x) is NaN with signal if x < -1 (including -INF) ;
869+
* log1p(+INF) is +INF; log1p(-1) is -INF with signal;
870+
* log1p(NaN) is that NaN with no signal.
871+
*
872+
* Accuracy:
873+
* according to an error analysis, the error is always less than
874+
* 1 ulp (unit in the last place).
875+
*
876+
* Constants:
877+
* The hexadecimal values are the intended ones for the following
878+
* constants. The decimal values may be used, provided that the
879+
* compiler will convert from decimal to binary accurately enough
880+
* to produce the hexadecimal values shown.
881+
*
882+
* Note: Assuming log() return accurate answer, the following
883+
* algorithm can be used to compute log1p(x) to within a few ULP:
884+
*
885+
* u = 1+x;
886+
* if(u==1.0) return x ; else
887+
* return log(u)*(x/(u-1.0));
888+
*
889+
* See HP-15C Advanced Functions Handbook, p.193.
890+
*/
891+
static class Log1p {
892+
private static final double ln2_hi = 0x1.62e42feep-1; // 6.93147180369123816490e-01
893+
private static final double ln2_lo = 0x1.a39ef35793c76p-33; // 1.90821492927058770002e-10
894+
private static final double Lp1 = 0x1.5555555555593p-1; // 6.666666666666735130e-01
895+
private static final double Lp2 = 0x1.999999997fa04p-2; // 3.999999999940941908e-01
896+
private static final double Lp3 = 0x1.2492494229359p-2; // 2.857142874366239149e-01
897+
private static final double Lp4 = 0x1.c71c51d8e78afp-3; // 2.222219843214978396e-01
898+
private static final double Lp5 = 0x1.7466496cb03dep-3; // 1.818357216161805012e-01
899+
private static final double Lp6 = 0x1.39a09d078c69fp-3; // 1.531383769920937332e-01
900+
private static final double Lp7 = 0x1.2f112df3e5244p-3; // 1.479819860511658591e-01
901+
902+
public static double compute(double x) {
903+
double hfsq, f=0, c=0, s, z, R, u;
904+
int k, hx, hu=0, ax;
905+
906+
hx = __HI(x); /* high word of x */
907+
ax = hx & 0x7fff_ffff;
908+
909+
k = 1;
910+
if (hx < 0x3FDA_827A) { /* x < 0.41422 */
911+
if (ax >= 0x3ff0_0000) { /* x <= -1.0 */
912+
if (x == -1.0) /* log1p(-1)=-inf */
913+
return -INFINITY;
914+
else
915+
return Double.NaN; /* log1p(x < -1) = NaN */
916+
}
917+
918+
if (ax < 0x3e20_0000) { /* |x| < 2**-29 */
919+
if (TWO54 + x > 0.0 /* raise inexact */
920+
&& ax < 0x3c90_0000) /* |x| < 2**-54 */
921+
return x;
922+
else
923+
return x - x*x*0.5;
924+
}
925+
926+
if (hx > 0 || hx <= 0xbfd2_bec3) { /* -0.2929 < x < 0.41422 */
927+
k=0;
928+
f=x;
929+
hu=1;
930+
}
931+
}
932+
933+
if (hx >= 0x7ff0_0000) {
934+
return x + x;
935+
}
936+
937+
if (k != 0) {
938+
if (hx < 0x4340_0000) {
939+
u = 1.0 + x;
940+
hu = __HI(u); /* high word of u */
941+
k = (hu >> 20) - 1023;
942+
c = (k > 0)? 1.0 - (u-x) : x-(u-1.0); /* correction term */
943+
c /= u;
944+
} else {
945+
u = x;
946+
hu = __HI(u); /* high word of u */
947+
k = (hu >> 20) - 1023;
948+
c = 0;
949+
}
950+
hu &= 0x000f_ffff;
951+
if (hu < 0x6_a09e) {
952+
u = __HI(u, hu | 0x3ff0_0000); /* normalize u */
953+
} else {
954+
k += 1;
955+
u = __HI(u, hu | 0x3fe0_0000); /* normalize u/2 */
956+
hu = (0x0010_0000 - hu) >> 2;
957+
}
958+
f = u - 1.0;
959+
}
960+
961+
hfsq = 0.5*f*f;
962+
if (hu == 0) { /* |f| < 2**-20 */
963+
if (f == 0.0) {
964+
if (k == 0) {
965+
return 0.0;
966+
} else {
967+
c += k * ln2_lo;
968+
return k * ln2_hi + c;
969+
}
970+
}
971+
R = hfsq * (1.0 - 0.66666666666666666*f);
972+
if (k == 0) {
973+
return f - R;
974+
} else {
975+
return k * ln2_hi - ((R-(k * ln2_lo+c)) - f);
976+
}
977+
}
978+
s = f/(2.0 + f);
979+
z = s * s;
980+
R = z * (Lp1 + z * (Lp2 + z * (Lp3 + z * (Lp4 + z * (Lp5 + z * (Lp6 + z*Lp7))))));
981+
if (k == 0) {
982+
return f - (hfsq - s*(hfsq + R));
983+
} else {
984+
return k * ln2_hi - ((hfsq - (s*(hfsq + R) + (k * ln2_lo+c))) - f);
985+
}
986+
}
987+
}
825988
}

src/java.base/share/classes/java/lang/StrictMath.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -2124,7 +2124,9 @@ public static double hypot(double x, double y) {
21242124
* log of {@code x}&nbsp;+&nbsp;1
21252125
* @since 1.5
21262126
*/
2127-
public static native double log1p(double x);
2127+
public static double log1p(double x) {
2128+
return FdLibm.Log1p.compute(x);
2129+
}
21282130

21292131
/**
21302132
* Returns the first floating-point argument with the sign of the

test/jdk/java/lang/StrictMath/FdlibmTranslit.java

+151
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ public static double log10(double x) {
8282
return Log10.compute(x);
8383
}
8484

85+
public static double log1p(double x) {
86+
return Log1p.compute(x);
87+
}
88+
8589
/**
8690
* cbrt(x)
8791
* Return cube root of x
@@ -460,4 +464,151 @@ public static double compute(double x) {
460464
return z+y*log10_2hi;
461465
}
462466
}
467+
468+
/**
469+
* Returns the natural logarithm of the sum of the argument and 1.
470+
*
471+
* Method :
472+
* 1. Argument Reduction: find k and f such that
473+
* 1+x = 2^k * (1+f),
474+
* where sqrt(2)/2 < 1+f < sqrt(2) .
475+
*
476+
* Note. If k=0, then f=x is exact. However, if k!=0, then f
477+
* may not be representable exactly. In that case, a correction
478+
* term is need. Let u=1+x rounded. Let c = (1+x)-u, then
479+
* log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
480+
* and add back the correction term c/u.
481+
* (Note: when x > 2**53, one can simply return log(x))
482+
*
483+
* 2. Approximation of log1p(f).
484+
* Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
485+
* = 2s + 2/3 s**3 + 2/5 s**5 + .....,
486+
* = 2s + s*R
487+
* We use a special Reme algorithm on [0,0.1716] to generate
488+
* a polynomial of degree 14 to approximate R The maximum error
489+
* of this polynomial approximation is bounded by 2**-58.45. In
490+
* other words,
491+
* 2 4 6 8 10 12 14
492+
* R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
493+
* (the values of Lp1 to Lp7 are listed in the program)
494+
* and
495+
* | 2 14 | -58.45
496+
* | Lp1*s +...+Lp7*s - R(z) | <= 2
497+
* | |
498+
* Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
499+
* In order to guarantee error in log below 1ulp, we compute log
500+
* by
501+
* log1p(f) = f - (hfsq - s*(hfsq+R)).
502+
*
503+
* 3. Finally, log1p(x) = k*ln2 + log1p(f).
504+
* = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
505+
* Here ln2 is split into two floating point number:
506+
* ln2_hi + ln2_lo,
507+
* where n*ln2_hi is always exact for |n| < 2000.
508+
*
509+
* Special cases:
510+
* log1p(x) is NaN with signal if x < -1 (including -INF) ;
511+
* log1p(+INF) is +INF; log1p(-1) is -INF with signal;
512+
* log1p(NaN) is that NaN with no signal.
513+
*
514+
* Accuracy:
515+
* according to an error analysis, the error is always less than
516+
* 1 ulp (unit in the last place).
517+
*
518+
* Constants:
519+
* The hexadecimal values are the intended ones for the following
520+
* constants. The decimal values may be used, provided that the
521+
* compiler will convert from decimal to binary accurately enough
522+
* to produce the hexadecimal values shown.
523+
*
524+
* Note: Assuming log() return accurate answer, the following
525+
* algorithm can be used to compute log1p(x) to within a few ULP:
526+
*
527+
* u = 1+x;
528+
* if(u==1.0) return x ; else
529+
* return log(u)*(x/(u-1.0));
530+
*
531+
* See HP-15C Advanced Functions Handbook, p.193.
532+
*/
533+
static class Log1p {
534+
private static double ln2_hi = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */
535+
private static double ln2_lo = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */
536+
private static double two54 = 1.80143985094819840000e+16; /* 43500000 00000000 */
537+
private static double Lp1 = 6.666666666666735130e-01; /* 3FE55555 55555593 */
538+
private static double Lp2 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */
539+
private static double Lp3 = 2.857142874366239149e-01; /* 3FD24924 94229359 */
540+
private static double Lp4 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */
541+
private static double Lp5 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */
542+
private static double Lp6 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
543+
private static double Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
544+
private static double zero = 0.0;
545+
546+
public static double compute(double x) {
547+
double hfsq,f=0,c=0,s,z,R,u;
548+
int k,hx,hu=0,ax;
549+
550+
hx = __HI(x); /* high word of x */
551+
ax = hx&0x7fffffff;
552+
553+
k = 1;
554+
if (hx < 0x3FDA827A) { /* x < 0.41422 */
555+
if(ax>=0x3ff00000) { /* x <= -1.0 */
556+
/*
557+
* Added redundant test against hx to work around VC++
558+
* code generation problem.
559+
*/
560+
if(x==-1.0 && (hx==0xbff00000)) /* log1p(-1)=-inf */
561+
return -two54/zero;
562+
else
563+
return (x-x)/(x-x); /* log1p(x<-1)=NaN */
564+
}
565+
if(ax<0x3e200000) { /* |x| < 2**-29 */
566+
if(two54+x>zero /* raise inexact */
567+
&&ax<0x3c900000) /* |x| < 2**-54 */
568+
return x;
569+
else
570+
return x - x*x*0.5;
571+
}
572+
if(hx>0||hx<=((int)0xbfd2bec3)) {
573+
k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */
574+
}
575+
if (hx >= 0x7ff00000) return x+x;
576+
if(k!=0) {
577+
if(hx<0x43400000) {
578+
u = 1.0+x;
579+
hu = __HI(u); /* high word of u */
580+
k = (hu>>20)-1023;
581+
c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
582+
c /= u;
583+
} else {
584+
u = x;
585+
hu = __HI(u); /* high word of u */
586+
k = (hu>>20)-1023;
587+
c = 0;
588+
}
589+
hu &= 0x000fffff;
590+
if(hu<0x6a09e) {
591+
u = __HI(u, hu|0x3ff00000); /* normalize u */
592+
} else {
593+
k += 1;
594+
u = __HI(u, hu|0x3fe00000); /* normalize u/2 */
595+
hu = (0x00100000-hu)>>2;
596+
}
597+
f = u-1.0;
598+
}
599+
hfsq=0.5*f*f;
600+
if(hu==0) { /* |f| < 2**-20 */
601+
if(f==zero) { if(k==0) return zero;
602+
else {c += k*ln2_lo; return k*ln2_hi+c;}}
603+
R = hfsq*(1.0-0.66666666666666666*f);
604+
if(k==0) return f-R; else
605+
return k*ln2_hi-((R-(k*ln2_lo+c))-f);
606+
}
607+
s = f/(2.0+f);
608+
z = s*s;
609+
R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
610+
if(k==0) return f-(hfsq-s*(hfsq+R)); else
611+
return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
612+
}
613+
}
463614
}

0 commit comments

Comments
 (0)