Add support for larger quantities, as voted for in Nov 2022 by the BIPM: https://www.bipm.org/en/cgpm-2022/resolution-3
This now allows: $ numfmt --from=si --to=iec 2000R 1.6Q * src/numfmt.c: Increase limits from 999Y to 999Q. * tests/misc/numfmt.pl: Adjust accordingly. * doc/coreutils.texi (numfmt invocation): Describe the new Ronna, Robi, Quetta, Quebi prefixes. * NEWS: Mention the improvement. --- NEWS | 3 ++ doc/coreutils.texi | 6 ++++ src/numfmt.c | 32 ++++++++++++++------ tests/misc/numfmt.pl | 72 ++++++++++++++++++++++---------------------- 4 files changed, 67 insertions(+), 46 deletions(-) diff --git a/NEWS b/NEWS index b6b5201e7..4e98e5a2d 100644 --- a/NEWS +++ b/NEWS @@ -67,6 +67,9 @@ GNU coreutils NEWS -*- outline -*- date --debug now diagnoses if multiple --date or --set options are specified, as only the last specified is significant in that case. + numfmt now supports the new Ronna, and Quetta SI prefixes, + corresponding to 10^27 and 10^30 respectively. + rm outputs more accurate diagnostics in the presence of errors when removing directories. For example EIO will be faithfully diagnosed, rather than being conflated with ENOTEMPTY. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index c801097ee..3040462d4 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -18933,6 +18933,8 @@ one of the following suffixes: @samp{E} => @math{1000^6 = 10^{18}} (Exa) @samp{Z} => @math{1000^7 = 10^{21}} (Zetta) @samp{Y} => @math{1000^8 = 10^{24}} (Yotta) +@samp{R} => @math{1000^9 = 10^{27}} (Ronna) +@samp{Q} => @math{1000^{10} = 10^{30}} (Quetta) @end example @item iec @@ -18951,6 +18953,8 @@ one of the following suffixes: @samp{E} => @math{1024^6 = 2^{60}} (Exbi) @samp{Z} => @math{1024^7 = 2^{70}} (Zebi) @samp{Y} => @math{1024^8 = 2^{80}} (Yobi) +@samp{R} => @math{1024^9 = 2^{90}} (Robi) +@samp{Q} => @math{1024^{10} = 2^{100}} (Quebi) @end example The @option{iec} option uses a single letter suffix (e.g. @samp{G}), which is @@ -18974,6 +18978,8 @@ one of the following suffixes: @samp{Ei} => @math{1024^6 = 2^{60}} (Exbi) @samp{Zi} => @math{1024^7 = 2^{70}} (Zebi) @samp{Yi} => @math{1024^8 = 2^{80}} (Yobi) +@samp{Ri} => @math{1024^9 = 2^{90}} (Robi) +@samp{Qi} => @math{1024^{10} = 2^{100}} (Quebi) @end example The @option{iec-i} option uses a two-letter suffix symbol (e.g. @samp{Gi}), diff --git a/src/numfmt.c b/src/numfmt.c index b1067d227..de34177f6 100644 --- a/src/numfmt.c +++ b/src/numfmt.c @@ -161,10 +161,10 @@ enum { DELIMITER_DEFAULT = CHAR_MAX + 1 }; enum { MAX_UNSCALED_DIGITS = LDBL_DIG }; /* Maximum number of digits we can work with. - This is equivalent to 999Y. + This is equivalent to 999Q. NOTE: 'long double' can handle more than that, but there's - no official suffix assigned beyond Yotta (1000^8). */ -enum { MAX_ACCEPTABLE_DIGITS = 27 }; + no official suffix assigned beyond Quetta (10^30). */ +enum { MAX_ACCEPTABLE_DIGITS = 33 }; static enum scale_type scale_from = scale_none; static enum scale_type scale_to = scale_none; @@ -232,7 +232,7 @@ default_scale_base (enum scale_type scale) static inline int valid_suffix (const char suf) { - static char const *valid_suffixes = "KMGTPEZY"; + static char const *valid_suffixes = "KMGTPEZYRQ"; return (strchr (valid_suffixes, suf) != NULL); } @@ -265,6 +265,12 @@ suffix_power (const char suf) case 'Y': /* yotta or 2**80. */ return 8; + case 'R': /* ronna or 2**90. */ + return 9; + + case 'Q': /* quetta or 2**100. */ + return 10; + default: /* should never happen. assert? */ return 0; } @@ -302,6 +308,12 @@ suffix_power_char (unsigned int power) case 8: return "Y"; + case 9: + return "R"; + + case 10: + return "Q"; + default: return "(error)"; } @@ -460,7 +472,7 @@ enum simple_strtod_error Returns: SSE_OK - valid number. SSE_OK_PRECISION_LOSS - if more than 18 digits were used. - SSE_OVERFLOW - if more than 27 digits (999Y) were used. + SSE_OVERFLOW - if more than 33 digits (999Q) were used. SSE_INVALID_NUMBER - if no digits were found. */ static enum simple_strtod_error simple_strtod_int (char const *input_str, @@ -525,7 +537,7 @@ simple_strtod_int (char const *input_str, Returns: SSE_OK - valid number. SSE_OK_PRECISION_LOSS - if more than 18 digits were used. - SSE_OVERFLOW - if more than 27 digits (999Y) were used. + SSE_OVERFLOW - if more than 33 digits (999Q) were used. SSE_INVALID_NUMBER - if no digits were found. */ static enum simple_strtod_error simple_strtod_float (char const *input_str, @@ -598,7 +610,7 @@ simple_strtod_float (char const *input_str, Returns: SSE_OK - valid number. SSE_OK_PRECISION_LOSS - if more than LDBL_DIG digits were used. - SSE_OVERFLOW - if more than 27 digits (999Y) were used. + SSE_OVERFLOW - if more than 33 digits (999Q) were used. SSE_INVALID_NUMBER - if no digits were found. SSE_VALID_BUT_FORBIDDEN_SUFFIX SSE_INVALID_SUFFIX @@ -830,7 +842,7 @@ unit_to_umax (char const *n_string) size_t n_len = strlen (n_string); char *end = NULL; uintmax_t n; - char const *suffixes = "KMGTPEZY"; + char const *suffixes = "KMGTPEZYRQ"; /* Adjust suffixes so K=1000, Ki=1024, KiB=invalid. */ if (n_len && ! c_isdigit (n_string[n_len - 1])) @@ -845,7 +857,7 @@ unit_to_umax (char const *n_string) { *++end = 'B'; *++end = '\0'; - suffixes = "KMGTPEZY0"; + suffixes = "KMGTPEZYRQ0"; } c_string = t_string; @@ -1224,7 +1236,7 @@ prepare_padded_number (const long double val, size_t precision) { if (inval_style != inval_ignore) error (conv_exit_code, 0, _("value too large to be printed: '%Lg'" - " (cannot handle values > 999Y)"), val); + " (cannot handle values > 999Q)"), val); return 0; } diff --git a/tests/misc/numfmt.pl b/tests/misc/numfmt.pl index 7ec04b1ef..87c27b3e4 100755 --- a/tests/misc/numfmt.pl +++ b/tests/misc/numfmt.pl @@ -116,29 +116,29 @@ my @Tests = # Test Suffix logic ['suf-1', '4000', {OUT=>'4000'}], - ['suf-2', '4Q', - {ERR => "$prog: invalid suffix in input: '4Q'\n"}, + ['suf-2', '4S', + {ERR => "$prog: invalid suffix in input: '4S'\n"}, {EXIT => '2'}], ['suf-2.1', '4M', {ERR => "$prog: rejecting suffix " . "in input: '4M' (consider using --from)\n"}, {EXIT => '2'}], ['suf-3', '--from=si 4M', {OUT=>'4000000'}], - ['suf-4', '--from=si 4Q', - {ERR => "$prog: invalid suffix in input: '4Q'\n"}, + ['suf-4', '--from=si 4S', + {ERR => "$prog: invalid suffix in input: '4S'\n"}, {EXIT => '2'}], - ['suf-5', '--from=si 4MQ', - {ERR => "$prog: invalid suffix in input '4MQ': 'Q'\n"}, + ['suf-5', '--from=si 4MS', + {ERR => "$prog: invalid suffix in input '4MS': 'S'\n"}, {EXIT => '2'}], ['suf-6', '--from=iec 4M', {OUT=>'4194304'}], ['suf-7', '--from=auto 4M', {OUT=>'4000000'}], ['suf-8', '--from=auto 4Mi', {OUT=>'4194304'}], - ['suf-9', '--from=auto 4MiQ', - {ERR => "$prog: invalid suffix in input '4MiQ': 'Q'\n"}, + ['suf-9', '--from=auto 4MiS', + {ERR => "$prog: invalid suffix in input '4MiS': 'S'\n"}, {EXIT => '2'}], - ['suf-10', '--from=auto 4QiQ', - {ERR => "$prog: invalid suffix in input: '4QiQ'\n"}, + ['suf-10', '--from=auto 4SiS', + {ERR => "$prog: invalid suffix in input: '4SiS'\n"}, {EXIT => '2'}], # characters after a white space are OK - printed as-is @@ -443,8 +443,8 @@ my @Tests = {EXIT=>2}], # INVALID_SUFFIX - ['strtod-9', '--from=si 12.2Q', - {ERR=>"$prog: invalid suffix in input: '12.2Q'\n"}, + ['strtod-9', '--from=si 12.2S', + {ERR=>"$prog: invalid suffix in input: '12.2S'\n"}, {EXIT=>2}], # VALID_BUT_FORBIDDEN_SUFFIX @@ -731,18 +731,18 @@ my @Tests = ## Check all errors again, this time with --invalid=fail ## Input will be printed without conversion, ## and exit code will be 2 - ['ign-err-1', '--invalid=fail 4Q', - {ERR => "$prog: invalid suffix in input: '4Q'\n"}, - {OUT => "4Q\n"}, + ['ign-err-1', '--invalid=fail 4S', + {ERR => "$prog: invalid suffix in input: '4S'\n"}, + {OUT => "4S\n"}, {EXIT => 2}], ['ign-err-2', '--invalid=fail 4M', {ERR => "$prog: rejecting suffix " . "in input: '4M' (consider using --from)\n"}, {OUT => "4M\n"}, {EXIT => 2}], - ['ign-err-3', '--invalid=fail --from=si 4MQ', - {ERR => "$prog: invalid suffix in input '4MQ': 'Q'\n"}, - {OUT => "4MQ\n"}, + ['ign-err-3', '--invalid=fail --from=si 4MS', + {ERR => "$prog: invalid suffix in input '4MS': 'S'\n"}, + {OUT => "4MS\n"}, {EXIT => 2}], ['ign-err-4', '--invalid=fail --suffix=Foo --to=si 7000FooF', {ERR => "$prog: invalid suffix in input: '7000FooF'\n"}, @@ -880,10 +880,10 @@ my @Limit_Tests = ['large-3.26','--to=si 76543210000000000000000000', {OUT=> "77Y"}], ['large-3.27','--to=si 876543210000000000000000000', {OUT=>"877Y"}], - # More than 27 digits is not OK - ['large-3.28','--to=si 9876543210000000000000000000', + # More than 33 digits is not OK + ['large-3.28','--to=si 9876543210000000000000000000000000', {ERR => "$prog: value too large to be converted: " . - "'9876543210000000000000000000'\n"}, + "'9876543210000000000000000000000000'\n"}, {EXIT => 2}], # Test Output @@ -941,9 +941,9 @@ my @Limit_Tests = ['large-7','--from=si --to=si 80Y', {OUT=>"80Y"}], ['large-8','--from=si --to=si 9000Z', {OUT=>"9.0Y"}], - ['large-10','--from=si --to=si 999Y', {OUT=>"999Y"}], - ['large-11','--from=si --to=iec 999Y', {OUT=>"827Y"}], - ['large-12','--from=si --round=down --to=iec 999Y', {OUT=>"826Y"}], + ['large-10','--from=si --to=si 999Q', {OUT=>"999Q"}], + ['large-11','--from=si --to=iec 999Q', {OUT=>"789Q"}], + ['large-12','--from=si --round=down --to=iec 999Q', {OUT=>"788Q"}], # units can also affect the output ['large-13','--from=si --from-unit=1000000 9P', @@ -952,15 +952,15 @@ my @Limit_Tests = {EXIT => 2}], ['large-13.1','--from=si --from-unit=1000000 --to=si 9P', {OUT=>"9.0Z"}], - # Numbers>999Y are never acceptable, regardless of scaling - ['large-14','--from=si --to=si 999Y', {OUT=>"999Y"}], - ['large-14.1','--from=si --to=si 1000Y', - {ERR => "$prog: value too large to be printed: '1e+27' " . - "(cannot handle values > 999Y)\n"}, + # Numbers>999Q are never acceptable, regardless of scaling + ['large-14','--from=si --to=si 999Q', {OUT=>"999Q"}], + ['large-14.1','--from=si --to=si 1000Q', + {ERR => "$prog: value too large to be printed: '1e+33' " . + "(cannot handle values > 999Q)\n"}, {EXIT => 2}], - ['large-14.2','--from=si --to=si --from-unit=10000 1Y', - {ERR => "$prog: value too large to be printed: '1e+28' " . - "(cannot handle values > 999Y)\n"}, + ['large-14.2','--from=si --to=si --from-unit=10000 1Q', + {ERR => "$prog: value too large to be printed: '1e+34' " . + "(cannot handle values > 999Q)\n"}, {EXIT => 2}], # intmax_t overflow when rounding caused this to fail before 8.24 @@ -999,10 +999,10 @@ my @Limit_Tests = "(consider using --to)\n"}, {OUT => "10000000000000000000\n"}, {EXIT=>2}], - ['ign-err-11','--invalid=fail --to=si 9876543210000000000000000000', + ['ign-err-11','--invalid=fail --to=si 9876543210000000000000000000000000', {ERR => "$prog: value too large to be converted: " . - "'9876543210000000000000000000'\n"}, - {OUT => "9876543210000000000000000000\n"}, + "'9876543210000000000000000000000000'\n"}, + {OUT => "9876543210000000000000000000000000\n"}, {EXIT => 2}], ); # Restrict these tests to systems with LDBL_DIG == 18 @@ -1067,7 +1067,7 @@ push @Tests, @Locale_Tests if $locale ne 'C'; ## Check all valid/invalid suffixes foreach my $suf ( 'A' .. 'Z', 'a' .. 'z' ) { - if ( $suf =~ /^[KMGTPEZY]$/ ) + if ( $suf =~ /^[KMGTPEZYRQ]$/ ) { push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf", {OUT=>"1.0$suf"}]; -- 2.26.2