@@ -318,6 +318,10 @@ public static bool FromBigDec(
318318 return FromRational ( numerator , denominator , significandSize , exponentSize , out result ) ;
319319 }
320320
321+ #endregion
322+
323+ #region Validation and Parameter Checking
324+
321325 /// <summary>
322326 /// Validates that significand and exponent sizes meet minimum requirements (must be > 1)
323327 /// </summary>
@@ -360,6 +364,10 @@ private static void ValidateSizeCompatibility(BigFloat x, BigFloat y)
360364 /// </summary>
361365 private int GetActualExponent ( ) => exponent == 0 ? 1 : ( int ) exponent ;
362366
367+ #endregion
368+
369+ #region Arithmetic Helpers
370+
363371 private static ( BigInteger significand , int exponent ) PrepareOperand ( BigFloat operand , BigInteger hiddenBit )
364372 {
365373 var sig = operand . significand ;
@@ -782,6 +790,11 @@ private enum ArithmeticOperation
782790 /// </summary>
783791 /// <param name="floor">Floor (rounded towards negative infinity)</param>
784792 /// <param name="ceiling">Ceiling (rounded towards positive infinity)</param>
793+
794+ #endregion
795+
796+ #region Mathematical Operations
797+
785798 public void FloorCeiling ( out BigInteger floor , out BigInteger ceiling )
786799 {
787800 // Handle special cases
@@ -913,10 +926,6 @@ [Pure] public override int GetHashCode() =>
913926 #region String Representation
914927
915928 [ Pure ]
916- /// <summary>
917- /// Converts the BigFloat to a decimal string representation.
918- /// </summary>
919- /// <returns>A decimal string representation of the value</returns>
920929 public string ToDecimalString ( )
921930 {
922931 // Handle special values per IEEE 754-2019 Section 5.12.1
@@ -956,41 +965,69 @@ public string ToDecimalString()
956965 public override string ToString ( )
957966 {
958967 Contract . Ensures ( Contract . Result < string > ( ) != null ) ;
968+
969+ // Handle special values
959970 if ( exponent == maxExponent ) {
960971 return $ "0{ ( significand == 0 ? $ "{ ( signBit ? "-" : "+" ) } oo" : "NaN" ) } { SignificandSize } e{ ExponentSize } ";
961972 }
962973
963- // Format as hex string
974+ // Handle zero
964975 if ( IsZero ) {
965976 return $ "{ ( signBit ? "-" : "" ) } 0x0.0e0f{ SignificandSize } e{ ExponentSize } ";
966977 }
967978
968- // Get mantissa with hidden bit and actual exponent
969- var mantissa = exponent == 0 ? significand : significand | hiddenBit ;
970- var binaryExp = GetActualExponent ( ) - ( int ) bias - ( SignificandSize - 1 ) ;
979+ // Get mantissa and binary exponent
980+ var mantissa = IsSubnormal ? significand : ( significand | hiddenBit ) ;
981+ var binaryExp = IsSubnormal ? ( 1 - ( int ) bias ) : ( ( int ) exponent - ( int ) bias ) ;
982+ binaryExp -= ( SignificandSize - 1 ) ; // Adjust for mantissa bit position
971983
972- // Calculate hex alignment
973- var mantissaHex = mantissa . ToString ( "X" ) ;
974- var totalShift = binaryExp + 4 * ( mantissaHex . Length - 1 ) ;
975- var hexExp = Math . DivRem ( totalShift , 4 , out var remainder ) ;
984+ // Convert to hex representation
985+ // We want: mantissa * 2^binaryExp = hexMantissa * 16^hexExp
986+ // Since 16 = 2^4: mantissa * 2^binaryExp = hexMantissa * 2^(4*hexExp)
976987
977- // Realign if needed
978- if ( remainder != 0 ) {
979- mantissa <<= remainder > 0 ? remainder : 4 + remainder ;
980- hexExp -= remainder < 0 ? 1 : 0 ;
981- mantissaHex = mantissa . ToString ( "X" ) ;
988+ // Start with the mantissa in hex
989+ var hexStr = mantissa . ToString ( "X" ) ;
990+
991+ // Calculate initial hex exponent (divide by 4, handle remainder with bit shifts)
992+ var hexExp = binaryExp / 4 ;
993+ var bitRemainder = binaryExp % 4 ;
994+
995+ // Adjust mantissa for the bit remainder
996+ if ( bitRemainder != 0 ) {
997+ if ( bitRemainder > 0 ) {
998+ mantissa <<= bitRemainder ;
999+ } else {
1000+ // For negative remainder, shift left by (4 + remainder) and decrement hex exponent
1001+ mantissa <<= ( 4 + bitRemainder ) ;
1002+ hexExp -- ;
1003+ }
1004+ hexStr = mantissa . ToString ( "X" ) ;
9821005 }
9831006
984- // Format as x.y
985- var hex = mantissaHex . TrimStart ( '0' ) ;
986- if ( string . IsNullOrEmpty ( hex ) ) {
987- hex = "0" ;
1007+ // Handle case where mantissa became zero (shouldn't happen for valid inputs)
1008+ if ( hexStr == "0" || string . IsNullOrEmpty ( hexStr ) ) {
1009+ return $ "{ ( signBit ? "-" : "" ) } 0x0.0e0f{ SignificandSize } e{ ExponentSize } ";
9881010 }
9891011
990- var frac = hex . Length > 1 ? hex [ 1 ..] . TrimEnd ( '0' ) : "" ;
991- var formatted = $ "{ hex [ 0 ] } .{ ( string . IsNullOrEmpty ( frac ) ? "0" : frac ) } ";
1012+ // Format as H.HHH (decimal point after first hex digit)
1013+ string formattedHex ;
1014+ if ( hexStr . Length == 1 ) {
1015+ formattedHex = $ "{ hexStr } .0";
1016+ } else {
1017+ var intPart = hexStr [ ..1 ] ;
1018+ var fracPart = hexStr [ 1 ..] . TrimEnd ( '0' ) ;
1019+ if ( fracPart . Length == 0 ) {
1020+ fracPart = "0" ;
1021+ }
1022+
1023+ formattedHex = $ "{ intPart } .{ fracPart } ";
9921024
993- return $ "{ ( signBit ? "-" : "" ) } 0x{ formatted } e{ hexExp } f{ SignificandSize } e{ ExponentSize } ";
1025+ // Adjust hex exponent for decimal point placement
1026+ // Moving decimal point left by (length-1) positions = multiplying by 16^(length-1)
1027+ hexExp += hexStr . Length - 1 ;
1028+ }
1029+
1030+ return $ "{ ( signBit ? "-" : "" ) } 0x{ formattedHex } e{ hexExp } f{ SignificandSize } e{ ExponentSize } ";
9941031 }
9951032
9961033 /// <summary>
@@ -1003,6 +1040,11 @@ public override string ToString()
10031040 /// when false, follows IEEE 754 standard behavior</param>
10041041 /// <param name="result">The parsed BigFloat value if successful; default(BigFloat) otherwise</param>
10051042 /// <returns>True if the parse was successful; false otherwise</returns>
1043+
1044+ #endregion
1045+
1046+ #region String Parsing
1047+
10061048 private static bool TryParseHexFormat ( string s , int sigSize , int expSize , bool strict , out BigFloat result )
10071049 {
10081050 result = default ;
@@ -1084,7 +1126,10 @@ private static bool HandleUnderflow(bool signBit, BigInteger sig, int biasedExp,
10841126
10851127 // Calculate shift for subnormal representation
10861128 var msbPos = ( int ) sig . GetBitLength ( ) - 1 ;
1087- var shiftAmount = ( 1 - ( int ) bias ) - actualExp + msbPos ;
1129+ // Bit position 0 in subnormal represents 2^(1-bias-(sigSize-1))
1130+ // We need to shift from msbPos to the correct position for actualExp
1131+ var subnormalBase = 1 - ( int ) bias - ( sigSize - 1 ) ;
1132+ var shiftAmount = msbPos - ( actualExp - subnormalBase ) ;
10881133
10891134 // Apply shift and check result
10901135 var subnormalSig = shiftAmount > 0 ? sig >> shiftAmount : sig << ( - shiftAmount ) ;
0 commit comments