@@ -220,7 +220,10 @@ pub struct Float {
220220 pub width : usize ,
221221 pub positive_sign : PositiveSign ,
222222 pub alignment : NumberAlignment ,
223- pub precision : usize ,
223+ // For float, the default precision depends on the format, usually 6,
224+ // but something architecture-specific for %a. Set this to None to
225+ // use the default.
226+ pub precision : Option < usize > ,
224227}
225228
226229impl Default for Float {
@@ -232,7 +235,7 @@ impl Default for Float {
232235 width : 0 ,
233236 positive_sign : PositiveSign :: None ,
234237 alignment : NumberAlignment :: Left ,
235- precision : 6 ,
238+ precision : None ,
236239 }
237240 }
238241}
@@ -315,8 +318,8 @@ impl Formatter<&ExtendedBigDecimal> for Float {
315318 } ;
316319
317320 let precision = match precision {
318- Some ( CanAsterisk :: Fixed ( x) ) => x ,
319- None => 6 , // Default float precision (C standard)
321+ Some ( CanAsterisk :: Fixed ( x) ) => Some ( x ) ,
322+ None => None ,
320323 Some ( CanAsterisk :: Asterisk ) => return Err ( FormatError :: WrongSpecType ) ,
321324 } ;
322325
@@ -360,8 +363,13 @@ fn format_float_non_finite(e: &ExtendedBigDecimal, case: Case) -> String {
360363 s
361364}
362365
363- fn format_float_decimal ( bd : & BigDecimal , precision : usize , force_decimal : ForceDecimal ) -> String {
366+ fn format_float_decimal (
367+ bd : & BigDecimal ,
368+ precision : Option < usize > ,
369+ force_decimal : ForceDecimal ,
370+ ) -> String {
364371 debug_assert ! ( !bd. is_negative( ) ) ;
372+ let precision = precision. unwrap_or ( 6 ) ; // Default %f precision (C standard)
365373 if precision == 0 {
366374 let ( bi, scale) = bd. as_bigint_and_scale ( ) ;
367375 if scale == 0 && force_decimal != ForceDecimal :: Yes {
@@ -376,11 +384,12 @@ fn format_float_decimal(bd: &BigDecimal, precision: usize, force_decimal: ForceD
376384
377385fn format_float_scientific (
378386 bd : & BigDecimal ,
379- precision : usize ,
387+ precision : Option < usize > ,
380388 case : Case ,
381389 force_decimal : ForceDecimal ,
382390) -> String {
383391 debug_assert ! ( !bd. is_negative( ) ) ;
392+ let precision = precision. unwrap_or ( 6 ) ; // Default %e precision (C standard)
384393 let exp_char = match case {
385394 Case :: Lowercase => 'e' ,
386395 Case :: Uppercase => 'E' ,
@@ -421,11 +430,12 @@ fn format_float_scientific(
421430
422431fn format_float_shortest (
423432 bd : & BigDecimal ,
424- precision : usize ,
433+ precision : Option < usize > ,
425434 case : Case ,
426435 force_decimal : ForceDecimal ,
427436) -> String {
428437 debug_assert ! ( !bd. is_negative( ) ) ;
438+ let precision = precision. unwrap_or ( 6 ) ; // Default %g precision (C standard)
429439
430440 // Note: Precision here is how many digits should be displayed in total,
431441 // instead of how many digits in the fractional part.
@@ -503,11 +513,23 @@ fn format_float_shortest(
503513
504514fn format_float_hexadecimal (
505515 bd : & BigDecimal ,
506- precision : usize ,
516+ precision : Option < usize > ,
507517 case : Case ,
508518 force_decimal : ForceDecimal ,
509519) -> String {
510520 debug_assert ! ( !bd. is_negative( ) ) ;
521+ // Default precision for %a is supposed to be sufficient to represent the
522+ // exact value. This is platform specific, GNU coreutils uses a `long double`,
523+ // which can be equivalent to a f64, f128, or an x86(-64) specific "f80".
524+ // We have arbitrary precision in base 10, so we can't always represent
525+ // the value exactly (e.g. 0.1 is c.ccccc...).
526+ //
527+ // Emulate x86(-64) behavior, where 64 bits are printed in total, that's
528+ // 16 hex digits, including 1 before the decimal point (so 15 after).
529+ //
530+ // TODO: Make this configurable? e.g. arm64 value would be 28 (f128),
531+ // arm value 13 (f64).
532+ let precision = precision. unwrap_or ( 15 ) ;
511533
512534 let ( prefix, exp_char) = match case {
513535 Case :: Lowercase => ( "0x" , 'p' ) ,
@@ -706,7 +728,8 @@ mod test {
706728 #[ test]
707729 fn decimal_float ( ) {
708730 use super :: format_float_decimal;
709- let f = |x| format_float_decimal ( & BigDecimal :: from_f64 ( x) . unwrap ( ) , 6 , ForceDecimal :: No ) ;
731+ let f =
732+ |x| format_float_decimal ( & BigDecimal :: from_f64 ( x) . unwrap ( ) , Some ( 6 ) , ForceDecimal :: No ) ;
710733 assert_eq ! ( f( 0.0 ) , "0.000000" ) ;
711734 assert_eq ! ( f( 1.0 ) , "1.000000" ) ;
712735 assert_eq ! ( f( 100.0 ) , "100.000000" ) ;
@@ -717,11 +740,23 @@ mod test {
717740 assert_eq ! ( f( 1.999_999_5 ) , "1.999999" ) ;
718741 assert_eq ! ( f( 1.999_999_6 ) , "2.000000" ) ;
719742
720- let f = |x| format_float_decimal ( & BigDecimal :: from_f64 ( x) . unwrap ( ) , 0 , ForceDecimal :: Yes ) ;
743+ let f = |x| {
744+ format_float_decimal (
745+ & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
746+ Some ( 0 ) ,
747+ ForceDecimal :: Yes ,
748+ )
749+ } ;
721750 assert_eq ! ( f( 100.0 ) , "100." ) ;
722751
723752 // Test arbitrary precision: long inputs that would not fit in a f64, print 24 digits after decimal point.
724- let f = |x| format_float_decimal ( & BigDecimal :: from_str ( x) . unwrap ( ) , 24 , ForceDecimal :: No ) ;
753+ let f = |x| {
754+ format_float_decimal (
755+ & BigDecimal :: from_str ( x) . unwrap ( ) ,
756+ Some ( 24 ) ,
757+ ForceDecimal :: No ,
758+ )
759+ } ;
725760 assert_eq ! ( f( "0.12345678901234567890" ) , "0.123456789012345678900000" ) ;
726761 assert_eq ! (
727762 f( "1234567890.12345678901234567890" ) ,
@@ -737,7 +772,11 @@ mod test {
737772 // TODO: Enable after https://github.com/akubera/bigdecimal-rs/issues/144 is fixed,
738773 // as our workaround is in .fmt.
739774 let f = |digits, scale| {
740- format_float_decimal ( & BigDecimal :: from_bigint ( digits, scale) , 6 , ForceDecimal :: No )
775+ format_float_decimal (
776+ & BigDecimal :: from_bigint ( digits, scale) ,
777+ Some ( 6 ) ,
778+ ForceDecimal :: No ,
779+ )
741780 } ;
742781 assert_eq ! ( f( 0 . into( ) , 0 ) , "0.000000" ) ;
743782 assert_eq ! ( f( 0 . into( ) , -10 ) , "0.000000" ) ;
@@ -750,7 +789,7 @@ mod test {
750789 let f = |x| {
751790 format_float_scientific (
752791 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
753- 6 ,
792+ None ,
754793 Case :: Lowercase ,
755794 ForceDecimal :: No ,
756795 )
@@ -766,7 +805,7 @@ mod test {
766805 let f = |x| {
767806 format_float_scientific (
768807 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
769- 6 ,
808+ Some ( 6 ) ,
770809 Case :: Uppercase ,
771810 ForceDecimal :: No ,
772811 )
@@ -778,7 +817,7 @@ mod test {
778817 let f = |digits, scale| {
779818 format_float_scientific (
780819 & BigDecimal :: from_bigint ( digits, scale) ,
781- 6 ,
820+ Some ( 6 ) ,
782821 Case :: Lowercase ,
783822 ForceDecimal :: No ,
784823 )
@@ -795,7 +834,7 @@ mod test {
795834 let f = |x| {
796835 format_float_scientific (
797836 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
798- 0 ,
837+ Some ( 0 ) ,
799838 Case :: Lowercase ,
800839 ForceDecimal :: No ,
801840 )
@@ -811,7 +850,7 @@ mod test {
811850 let f = |x| {
812851 format_float_scientific (
813852 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
814- 0 ,
853+ Some ( 0 ) ,
815854 Case :: Lowercase ,
816855 ForceDecimal :: Yes ,
817856 )
@@ -831,7 +870,7 @@ mod test {
831870 let f = |x| {
832871 format_float_shortest (
833872 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
834- 6 ,
873+ None ,
835874 Case :: Lowercase ,
836875 ForceDecimal :: No ,
837876 )
@@ -853,7 +892,7 @@ mod test {
853892 let f = |x| {
854893 format_float_shortest (
855894 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
856- 6 ,
895+ None ,
857896 Case :: Lowercase ,
858897 ForceDecimal :: Yes ,
859898 )
@@ -875,7 +914,7 @@ mod test {
875914 let f = |x| {
876915 format_float_shortest (
877916 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
878- 0 ,
917+ Some ( 0 ) ,
879918 Case :: Lowercase ,
880919 ForceDecimal :: No ,
881920 )
@@ -894,7 +933,7 @@ mod test {
894933 let f = |x| {
895934 format_float_shortest (
896935 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
897- 0 ,
936+ Some ( 0 ) ,
898937 Case :: Lowercase ,
899938 ForceDecimal :: Yes ,
900939 )
@@ -920,7 +959,7 @@ mod test {
920959 let f = |x| {
921960 format_float_hexadecimal (
922961 & BigDecimal :: from_str ( x) . unwrap ( ) ,
923- 6 ,
962+ Some ( 6 ) ,
924963 Case :: Lowercase ,
925964 ForceDecimal :: No ,
926965 )
@@ -935,7 +974,7 @@ mod test {
935974 let f = |x| {
936975 format_float_hexadecimal (
937976 & BigDecimal :: from_str ( x) . unwrap ( ) ,
938- 0 ,
977+ Some ( 0 ) ,
939978 Case :: Lowercase ,
940979 ForceDecimal :: No ,
941980 )
@@ -947,7 +986,7 @@ mod test {
947986 let f = |x| {
948987 format_float_hexadecimal (
949988 & BigDecimal :: from_str ( x) . unwrap ( ) ,
950- 0 ,
989+ Some ( 0 ) ,
951990 Case :: Lowercase ,
952991 ForceDecimal :: Yes ,
953992 )
@@ -959,7 +998,7 @@ mod test {
959998 let f = |x| {
960999 format_float_hexadecimal (
9611000 & BigDecimal :: from_str ( x) . unwrap ( ) ,
962- 6 ,
1001+ Some ( 6 ) ,
9631002 Case :: Uppercase ,
9641003 ForceDecimal :: No ,
9651004 )
@@ -971,7 +1010,7 @@ mod test {
9711010 let f = |digits, scale| {
9721011 format_float_hexadecimal (
9731012 & BigDecimal :: from_bigint ( digits, scale) ,
974- 6 ,
1013+ Some ( 6 ) ,
9751014 Case :: Lowercase ,
9761015 ForceDecimal :: No ,
9771016 )
@@ -1001,7 +1040,7 @@ mod test {
10011040 let f = |x| {
10021041 format_float_shortest (
10031042 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
1004- 6 ,
1043+ None ,
10051044 Case :: Lowercase ,
10061045 ForceDecimal :: No ,
10071046 )
@@ -1019,7 +1058,7 @@ mod test {
10191058 let f = |x| {
10201059 format_float_shortest (
10211060 & BigDecimal :: from_f64 ( x) . unwrap ( ) ,
1022- 6 ,
1061+ None ,
10231062 Case :: Lowercase ,
10241063 ForceDecimal :: No ,
10251064 )
0 commit comments