@@ -143,4 +143,85 @@ public static string FromDouble(double value)
143143 var mantissaHex = mantissa . ToString ( "x13" ) . TrimEnd ( '0' ) ;
144144 return $ "{ sign } 0x{ leadingDigit } .{ mantissaHex } p{ adjustedExponent : +0;-0} ";
145145 }
146+
147+ internal static string FormatDouble (
148+ double value ,
149+ int precision ,
150+ bool alternateForm ,
151+ bool upperCase
152+ )
153+ {
154+ string text ;
155+ if ( double . IsNaN ( value ) || double . IsInfinity ( value ) )
156+ {
157+ text = value . ToString ( CultureInfo . InvariantCulture ) ;
158+ }
159+ else
160+ {
161+ text = FormatFinite ( value , precision , alternateForm ) ;
162+ }
163+ return upperCase ? text . ToUpperInvariant ( ) : text ;
164+ }
165+
166+ static string FormatFinite ( double value , int precision , bool alternateForm )
167+ {
168+ const ulong fractionMask = ( 1UL << 52 ) - 1 ;
169+ var bits = BitConverter . DoubleToInt64Bits ( value ) ;
170+ var exponent = ( int ) ( ( bits >> 52 ) & 0x7ff ) ;
171+ var significand = ( ( ulong ) bits & fractionMask ) | ( exponent == 0 ? 0 : 1UL << 52 ) ;
172+ var adjustedExponent = exponent == 0 ? ( significand == 0 ? 0 : - 1022 ) : exponent - 1023 ;
173+
174+ if ( precision is >= 0 and < 13 )
175+ {
176+ var shift = 52 - precision * 4 ;
177+ var retained = significand >> shift ;
178+ var discarded = significand & ( ( 1UL << shift ) - 1 ) ;
179+ var halfway = 1UL << ( shift - 1 ) ;
180+ // Round to nearest, with ties to an even final hexadecimal digit.
181+ if ( discarded > halfway || ( discarded == halfway && ( retained & 1 ) != 0 ) )
182+ retained ++ ;
183+ significand = retained << shift ;
184+ }
185+
186+ var sign = bits < 0 ? "-" : "" ;
187+ var leadingDigit = ( char ) ( '0' + ( significand >> 52 ) ) ;
188+ var fraction = significand & fractionMask ;
189+ var digits = "" ;
190+ if ( precision != 0 && ( precision >= 0 || fraction != 0 ) )
191+ {
192+ digits = fraction . ToString ( "x13" , CultureInfo . InvariantCulture ) ;
193+ digits =
194+ precision < 0 ? digits . TrimEnd ( '0' )
195+ : precision < 13 ? digits [ .. precision ]
196+ : digits . PadRight ( precision , '0' ) ;
197+ }
198+ #if NET6_0_OR_GREATER
199+ if ( digits . Length == 0 && ! alternateForm )
200+ return string . Create (
201+ CultureInfo . InvariantCulture ,
202+ $ "{ sign } 0x{ leadingDigit } p{ adjustedExponent : +0;-0} "
203+ ) ;
204+ return string . Create (
205+ CultureInfo . InvariantCulture ,
206+ $ "{ sign } 0x{ leadingDigit } .{ digits } p{ adjustedExponent : +0;-0} "
207+ ) ;
208+ #else
209+ if ( digits . Length == 0 && ! alternateForm )
210+ return string . Format (
211+ CultureInfo . InvariantCulture ,
212+ "{0}0x{1}p{2:+0;-0}" ,
213+ sign ,
214+ leadingDigit ,
215+ adjustedExponent
216+ ) ;
217+ return string . Format (
218+ CultureInfo . InvariantCulture ,
219+ "{0}0x{1}.{2}p{3:+0;-0}" ,
220+ sign ,
221+ leadingDigit ,
222+ digits ,
223+ adjustedExponent
224+ ) ;
225+ #endif
226+ }
146227}
0 commit comments