coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] numfmt: support new ronna, quetta SI prefixes


From: Pádraig Brady
Subject: [PATCH] numfmt: support new ronna, quetta SI prefixes
Date: Tue, 29 Nov 2022 18:25:45 +0000

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]