|
33 | 33 | import jdk.internal.math.FloatingDecimal; |
34 | 34 | import jdk.internal.math.DoubleConsts; |
35 | 35 | import jdk.internal.math.DoubleToDecimal; |
| 36 | +import jdk.internal.util.DecimalDigits; |
36 | 37 | import jdk.internal.vm.annotation.IntrinsicCandidate; |
37 | 38 |
|
38 | 39 | /** |
@@ -707,51 +708,71 @@ public static String toHexString(double d) { |
707 | 708 | // For infinity and NaN, use the decimal output. |
708 | 709 | return Double.toString(d); |
709 | 710 | else { |
710 | | - // Initialized to maximum size of output. |
711 | | - StringBuilder answer = new StringBuilder(24); |
712 | | - |
713 | | - if (Math.copySign(1.0, d) == -1.0) // value is negative, |
714 | | - answer.append("-"); // so append sign info |
715 | | - |
716 | | - answer.append("0x"); |
717 | | - |
| 711 | + // Handle sign |
| 712 | + boolean negative = Math.copySign(1.0, d) == -1.0; |
718 | 713 | d = Math.abs(d); |
719 | 714 |
|
720 | | - if(d == 0.0) { |
721 | | - answer.append("0.0p0"); |
| 715 | + if (d == 0.0) { |
| 716 | + return negative ? "-0x0.0p0" : "0x0.0p0"; |
722 | 717 | } else { |
| 718 | + // Check if the value is subnormal (less than the smallest normal value) |
723 | 719 | boolean subnormal = (d < Double.MIN_NORMAL); |
724 | 720 |
|
725 | 721 | // Isolate significand bits and OR in a high-order bit |
726 | | - // so that the string representation has a known |
727 | | - // length. |
| 722 | + // so that the string representation has a known length. |
728 | 723 | long signifBits = (Double.doubleToLongBits(d) |
729 | | - & DoubleConsts.SIGNIF_BIT_MASK) | |
730 | | - 0x1000000000000000L; |
| 724 | + & DoubleConsts.SIGNIF_BIT_MASK) | |
| 725 | + 0x1000000000000000L; |
| 726 | + |
| 727 | + // Calculate the number of trailing zeros in the significand (in groups of 4 bits) |
| 728 | + // This is used to remove trailing zeros from the hex representation |
| 729 | + int trailingZeros = Math.min(12, ((Long.numberOfTrailingZeros(signifBits) & 0xFC) >> 2)); |
| 730 | + |
| 731 | + // Determine the exponent value based on whether the number is subnormal or normal |
| 732 | + int exp = subnormal ? Double.MIN_EXPONENT : Math.getExponent(d); |
| 733 | + |
| 734 | + // Calculate the total length of the resulting string |
| 735 | + int charlen = (negative ? 1 : 0) // sign character |
| 736 | + + 4 // "0x1." or "0x0." |
| 737 | + + 13 - trailingZeros // hex digits (13 max, minus trailing zeros) |
| 738 | + + 1 // "p" |
| 739 | + + DecimalDigits.stringSize(exp) // exponent |
| 740 | + ; |
| 741 | + |
| 742 | + // Create a byte array to hold the result characters |
| 743 | + byte[] chars = new byte[charlen]; |
| 744 | + int index = 0; |
| 745 | + |
| 746 | + // Add the sign character if the number is negative |
| 747 | + if (negative) { // value is negative |
| 748 | + chars[index++] = '-'; |
| 749 | + } |
| 750 | + |
| 751 | + // Add the prefix and the implicit bit ('1' for normal, '0' for subnormal) |
| 752 | + // Subnormal values have a 0 implicit bit; normal values have a 1 implicit bit. |
| 753 | + chars[index] = '0'; |
| 754 | + chars[index + 1] = 'x'; |
| 755 | + chars[index + 2] = (byte) (subnormal ? '0' : '1'); |
| 756 | + chars[index + 3] = '.'; |
| 757 | + index += 4; |
| 758 | + |
| 759 | + // Convert significand to hex digits manually to avoid creating temporary strings |
| 760 | + // Extract the 13 hex digits (52 bits) from signifBits |
| 761 | + // We need to extract bits 48-51, 44-47, ..., 0-3 (13 groups of 4 bits) |
| 762 | + for (int i = 0, end = 13 - trailingZeros; i < end; i++) { |
| 763 | + // Extract 4 bits at a time from left to right |
| 764 | + // Shift right by (12 - i) * 4 positions and mask with 0xF |
| 765 | + chars[index++] = Integer.digits[((int)(signifBits >> ((12 - i) << 2))) & 0xF]; |
| 766 | + } |
731 | 767 |
|
732 | | - // Subnormal values have a 0 implicit bit; normal |
733 | | - // values have a 1 implicit bit. |
734 | | - answer.append(subnormal ? "0." : "1."); |
| 768 | + // Add the exponent indicator |
| 769 | + chars[index] = 'p'; |
735 | 770 |
|
736 | | - // Isolate the low-order 13 digits of the hex |
737 | | - // representation. If all the digits are zero, |
738 | | - // replace with a single 0; otherwise, remove all |
739 | | - // trailing zeros. |
740 | | - String signif = Long.toHexString(signifBits).substring(3,16); |
741 | | - answer.append(signif.equals("0000000000000") ? // 13 zeros |
742 | | - "0": |
743 | | - signif.replaceFirst("0{1,12}$", "")); |
| 771 | + // Append the exponent value to the character array |
| 772 | + DecimalDigits.uncheckedGetCharsLatin1(exp, charlen, chars); |
744 | 773 |
|
745 | | - answer.append('p'); |
746 | | - // If the value is subnormal, use the E_min exponent |
747 | | - // value for double; otherwise, extract and report d's |
748 | | - // exponent (the representation of a subnormal uses |
749 | | - // E_min -1). |
750 | | - answer.append(subnormal ? |
751 | | - Double.MIN_EXPONENT: |
752 | | - Math.getExponent(d)); |
| 774 | + return String.newStringWithLatin1Bytes(chars); |
753 | 775 | } |
754 | | - return answer.toString(); |
755 | 776 | } |
756 | 777 | } |
757 | 778 |
|
|
0 commit comments