On Thu, 17 Oct 2024 23:11:07 GMT, Joe Darcy <da...@openjdk.org> wrote:
> Port of Float16 from java.lang in the lworld+fp16 branch to > jdk.incubabor.vector. Add as contributors other engineers who worked on Float16 on the lworld+fp16 branch in Valhalla. To ease review, diffs of corresponding files from the current, at time of writing, state of files in lworld+fp16 vs a port to jdk.incubator.vector, starting with Float16: $ diff src/java.base/share/classes/java/lang/Float16.java ~/jdk24/open/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java 26c26 < package java.lang; --- > package jdk.incubator.vector; 28a29 > import java.math.BigInteger; 30,31c31,32 < import jdk.internal.math.*; < import jdk.internal.vm.annotation.IntrinsicCandidate; --- > // import jdk.internal.math.*; > // import jdk.internal.vm.annotation.IntrinsicCandidate; 37c38 < * The {@code Float16} is a primitive value class holding 16-bit data --- > * The {@code Float16} is a class holding 16-bit data 46,48d46 < * <p>This is a <a href="https://openjdk.org/jeps/401">primitive value class</a> and its objects are < * identity-less non-nullable value objects. < * 52a51,56 > * <p>This is a <a > href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> > * class; programmers should treat instances that are > * {@linkplain #equals(Object) equal} as interchangeable and should not > * use instances for synchronization, or unpredictable behavior may > * occur. For example, in a future release, synchronization may fail. > * 62,64d65 < * < * @author Jatin Bhateja < * @since 20.00 69,70c70,71 < @jdk.internal.MigratedValueClass < @jdk.internal.ValueBased --- > // @jdk.internal.MigratedValueClass > //@jdk.internal.ValueBased 213c214,215 < return FloatToDecimal.toString(f16.floatValue()); --- > return Float.toString(f16.floatValue()); > // return FloatToDecimal.toString(f16.floatValue()); 420d421 < * @see BigDecimal#float16Value() 423c424,539 < return v.float16Value(); --- > return BigDecimalConversion.float16Value(v); > } > > private class BigDecimalConversion { > /* > * Let l = log_2(10). > * Then, L < l < L + ulp(L) / 2, that is, L = roundTiesToEven(l). > */ > private static final double L = 3.321928094887362; > > private static final int P_F16 = PRECISION; // 11 > private static final int Q_MIN_F16 = MIN_EXPONENT - (P_F16 - 1); // > -24 > private static final int Q_MAX_F16 = MAX_EXPONENT - (P_F16 - 1); // 5 > > /** > * Powers of 10 which can be represented exactly in {@code > * Float16}. > */ > private static final Float16[] FLOAT16_10_POW = { > Float16.valueOf(1), Float16.valueOf(10), Float16.valueOf(100), > Float16.valueOf(1_000), Float16.valueOf(10_000) > }; > > public static Float16 float16Value(BigDecimal bd) { > // int scale = bd.scale(); > // BigInteger unscaledValue = bd.unscaledValue(); > > // if > (unscaledValue.abs().compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) { > // long intCompact = bd.longValue(); > // Float16 v = Float16.valueOf(intCompact); > // if (scale == 0) { > // return v; > // } > // /* > // * The discussion for the double case also applies here. > That is, > // * the following test is precise for all long values, but > here > // * Long.MAX_VALUE is not an issue. > // */ > // if (v.longValue() == intCompact) { > // if (0 < scale && scale < FLOAT16_10_POW.length) { > // return Float16.divide(v, FLOAT16_10_POW[scale]); > // } > // if (0 > scale && scale > -FLOAT16_10_POW.length) { > // return Float16.multiply(v, FLOAT16_10_POW[-scale]); > // } > // } > // } > return fullFloat16Value(bd); > } > > private static BigInteger bigTenToThe(int scale) { > return BigInteger.TEN.pow(scale); > } > > private static Float16 fullFloat16Value(BigDecimal bd) { > if (BigDecimal.ZERO.compareTo(bd) == 0) { > return Float16.valueOf(0); > } > BigInteger w = bd.unscaledValue().abs(); > int scale = bd.scale(); > long qb = w.bitLength() - (long) Math.ceil(scale * L); > Float16 signum = Float16.valueOf(bd.signum()); > if (qb < Q_MIN_F16 - 2) { // qb < -26 > return Float16.multiply(signum, Float16.valueOf(0)); > } > if (qb > Q_MAX_F16 + P_F16 + 1) { // qb > 17 > return Float16.multiply(signum, Float16.POSITIVE_INFINITY); > } > if (scale < 0) { > return Float16.multiply(signum, > valueOf(w.multiply(bigTenToThe(-scale)))); > } > if (scale == 0) { > return Float16.multiply(signum, valueOf(w)); > } > int ql = (int) qb - (P_F16 + 3); > BigInteger pow10 = bigTenToThe(scale); > BigInteger m, n; > if (ql <= 0) { > m = w.shiftLeft(-ql); > n = pow10; > } else { > m = w; > n = pow10.shiftLeft(ql); > } > BigInteger[] qr = m.divideAndRemainder(n); > /* > * We have > * 2^12 = 2^{P+1} <= i < 2^{P+5} = 2^16 > * Contrary to the double and float cases, where we use long and > int, resp., > * here we cannot simply declare i as short, because P + 5 < > Short.SIZE > * fails to hold. > * Using int is safe, though. > * > * Further, as Math.scalb(Float16) does not exists, we fall back > to > * Math.scalb(double). > */ > int i = qr[0].intValue(); > int sb = qr[1].signum(); > int dq = (Integer.SIZE - (P_F16 + 2)) - > Integer.numberOfLeadingZeros(i); > int eq = (Q_MIN_F16 - 2) - ql; > if (dq >= eq) { > return Float16.valueOf(bd.signum() * Math.scalb((double) (i | > sb), ql)); > } > int mask = (1 << eq) - 1; > int j = i >> eq | (Integer.signum(i & mask)) | sb; > return Float16.valueOf(bd.signum() * Math.scalb((double) j, > Q_MIN_F16 - 2)); > } > > public static Float16 valueOf(BigInteger bi) { > int signum = bi.signum(); > return (signum == 0 || bi.bitLength() <= 31) > ? Float16.valueOf(bi.longValue()) // might return infinities > : signum > 0 > ? Float16.POSITIVE_INFINITY > : Float16.NEGATIVE_INFINITY; > } 577,578c693 < * according to the IEEE 754 floating-point binary16 bit layout, < * preserving Not-a-Number (NaN) values. --- > * according to the IEEE 754 floating-point binary16 bit layout. 591,607d705 < * Returns a representation of the specified floating-point value < * according to the IEEE 754 floating-point binary16 bit layout. < * < * @param fp16 a {@code Float16} floating-point number. < * @return the bits that represent the floating-point number. < * < * @see Float#floatToIntBits(float) < * @see Double#doubleToLongBits(double) < */ < public static short float16ToShortBits(Float16 fp16) { < if (!isNaN(fp16)) { < return float16ToRawShortBits(fp16); < } < return 0x7e00; < } < < /** 694c792 < @IntrinsicCandidate --- > // @IntrinsicCandidate 714c812 < @IntrinsicCandidate --- > // @IntrinsicCandidate 783c881 < @IntrinsicCandidate --- > // @IntrinsicCandidate 806c904 < @IntrinsicCandidate --- > // @IntrinsicCandidate 829c927 < @IntrinsicCandidate --- > // @IntrinsicCandidate 852c950 < @IntrinsicCandidate --- > // @IntrinsicCandidate 873c971 < @IntrinsicCandidate --- > // @IntrinsicCandidate 907c1005 < @IntrinsicCandidate --- > // @IntrinsicCandidate 1109c1207 < @IntrinsicCandidate --- > // @IntrinsicCandidate 1131c1229 < @IntrinsicCandidate --- > // @IntrinsicCandidate 1319a1418 > int DoubleConsts_EXP_BIAS = 1023; 1328c1427 < * Double.longBitsToDouble((long) (scaleFactor + DoubleConsts.EXP_BIAS) << Double.PRECISION - 1)); --- > * Double.longBitsToDouble((long) (scaleFactor + > DoubleConsts_EXP_BIAS) << Double.PRECISION - 1)); 1330d1428 < 1374d1471 < $ diff src/java.base/share/classes/jdk/internal/math/Float16Consts.java ~/jdk24/open/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Consts.java 26c26 < package jdk.internal.math; --- > package jdk.incubator.vector; 28,30c28,30 < import static java.lang.Float16.MIN_EXPONENT; < import static java.lang.Float16.PRECISION; < import static java.lang.Float16.SIZE; --- > import static jdk.incubator.vector.Float16.MIN_EXPONENT; > import static jdk.incubator.vector.Float16.PRECISION; > import static jdk.incubator.vector.Float16.SIZE; 37c37 < public class Float16Consts { --- > class Float16Consts { $ diff test/jdk/java/lang/Float16/BasicFloat16ArithTests.java ~/jdk24/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java 26c26,27 < * @bug 8329817 8334432 8339076 --- > * @bug 8329817 8334432 8339076 8341260 > * @modules jdk.incubator.vector 30c31,32 < import static java.lang.Float16.*; --- > import jdk.incubator.vector.Float16; > import static jdk.incubator.vector.Float16.*; $ diff test/jdk/java/math/BigDecimal/DoubleFloatValueTests.java ~/jdk24/test/jdk/java/math/BigDecimal/DoubleFloatValueTests.java 26c26 < * @bug 8205592 8339252 --- > * @bug 8205592 8339252 8341260 27a28 > * @modules jdk.incubator.vector 37a39 > import jdk.incubator.vector.Float16; 110c112 < Float16 res = bv.float16Value(); --- > Float16 res = Float16.valueOf(bv); // bv.float16Value(); ------------- PR Comment: https://git.openjdk.org/jdk/pull/21574#issuecomment-2420835843 PR Comment: https://git.openjdk.org/jdk/pull/21574#issuecomment-2420843492 PR Comment: https://git.openjdk.org/jdk/pull/21574#issuecomment-2420846567 PR Comment: https://git.openjdk.org/jdk/pull/21574#issuecomment-2420850283