【问题标题】:Make big and small numbers human-readable [duplicate]使大小数字易于阅读[重复]
【发布时间】:2013-04-11 14:38:24
【问题描述】:

我想以人性化的方式在 C# 中打印我非常小的数字,例如:

30µ3E-5456.789n0.000000456789

我知道 C 中 BSD 的 Humanize_number() 函数,但仅与位整数兼容,不兼容浮点数和双精度数。 C# 中是否有支持这些的等价物?

另外,在显示数字时应该保持一定的精度,比如:

0.003596 应该显示为3.596µ,而不是3.6µ(或更糟的是)。

这里可能的答案:Formatting Large Numbers with .NET 但适用于负 log10 将逗号后的数字截断为 1 位。在我看来,这还远远不够。

我想如何呈现事物的示例:

3000        3K
3300        3.3K
3333        3.333K
30000       30k
300000      300k
3000000     3M
3000003     3.000003M // or 3M if I specify "4 digits precision"
0.253       253m
0.0253      25.3m
0.00253     2.53m
-0.253003   -253.003m

我无法制定我的问题以在 SO 中找到相关答案,所以如果问题已经得到解答,请开火!

【问题讨论】:

标签: c# numbers human-readable humanize


【解决方案1】:

您可以使用 DllImport 来使用 Humanize_Number 函数吗?详情请看这里:

Dynamically loading a dll in C#

【讨论】:

  • 我想知道是否有“嵌入式”解决方案。我在另一种生活中使用了linux下的BSD功能:)
【解决方案2】:

为什么不乘以 10^(小数点后数)?您可以使用相同的小数点后数来确定要显示的单位。这比导入整个库要好得多。

【讨论】:

    【解决方案3】:

    由于您希望小数点显示为符号而不是很多 0,您也可以执行以下操作:

    class Program
    {
        static void Main(string[] args)
        {
            //these are your "unit precedessors"
            char[] exponentsbig = new char[] {' ', 'k', 'M', 'G', 'T', 'P', 'E' };
            char[] exponentssmall = new char[] { ' ', 'm', 'µ', 'n', 'p', 'a', 'f' };
    
            //some example numbers
            long[] numbersBig = new long[] { 3000, 3003, 30000, 300000, 300003, 1594900000000000 };
            double[] numbersSmall = new double[] { 0.0002, 0.245, 0.245003, 0.000004578 };
            //some helper vars
            int counter = 0;
            bool edited = false;
            //let's have a look at what we produce;)
            string output = "";
    
            //Big  numbers incoming!!
            for (int i = 0; i < numbersBig.Length; i++)
            {
                counter=0;
                double myNumber = Convert.ToDouble(numbersBig[i]);
                do
                {
                    edited = false;
                    //something to prevent unnecessary unit-adding and making sure you still divide by 1000
                    if (myNumber/1000>1 )
                    {
                        counter++;
                        myNumber /= 1000;
                        edited = true;
                    }
                } while (edited);
                output += numbersBig[i] + " " + myNumber + exponentsbig[counter] + "\n";
            }
    
            //small  numbers incoming!!
            for (int i = 0; i < numbersSmall.Length; i++)
            {
                counter = 0;
                double myNumber = numbersSmall[i];
                do
                {
                    edited = false;
                    //this will go to 3 digits after comma. you can make the compared smaller 
                    //to be more exact after the comma, but keep in mind you lose steps then
                    if (myNumber < 1)
                    {
                        counter++;
                        myNumber *= 1000;
                        edited = true;
                    }
                } while (edited);
                output += numbersSmall[i] + " " + myNumber + exponentssmall[counter] + "\n";
            }
            //see what we did
            Console.Write(output);
            Console.ReadKey();
    
        }
    }
    

    【讨论】:

      【解决方案4】:

      试试这个:

      static class Extensions
      {
          static string[] prefixes= { "f", "a", "p", "n", "μ", "m", string.Empty, "k", "M", "G", "T", "P", "E" };
      
          public static string Nice(this double x, int significant_digits)
          {
              //Check for special numbers and non-numbers
              if(double.IsInfinity(x)||double.IsNaN(x)||x==0||significant_digits<=0)
              {
                  return x.ToString();
              }
              // extract sign so we deal with positive numbers only
              int sign=Math.Sign(x);
              x=Math.Abs(x);
              // get scientific exponent, 10^3, 10^6, ...
              int sci= x==0? 0 : (int)Math.Floor(Math.Log(x, 10)/3)*3;
              // scale number to exponent found
              x=x*Math.Pow(10, -sci);
              // find number of digits to the left of the decimal
              int dg= x==0? 0 : (int)Math.Floor(Math.Log(x, 10))+1;
              // adjust decimals to display
              int decimals=Math.Min(significant_digits-dg, 15);
              // format for the decimals
              string fmt=new string('0', decimals);
              if(sci==0)
              {
                  //no exponent
                  return string.Format("{0}{1:0."+fmt+"}",
                      sign<0?"-":string.Empty,
                      Math.Round(x, decimals));
              }
              // find index for prefix. every 3 of sci is a new index
              int index=sci/3+6;
              if(index>=0&&index<prefixes.Length)
              {
                  // with prefix
                  return string.Format("{0}{1:0."+fmt+"}{2}",
                      sign<0?"-":string.Empty,
                      Math.Round(x, decimals),
                      prefixes[index]);
              }
              // with 10^exp format
              return string.Format("{0}{1:0."+fmt+"}·10^{2}",
                  sign<0?"-":string.Empty,
                  Math.Round(x, decimals),
                  sci);
          }
      
          // test code
          static void Main(string[] args)
          {
              double x=Math.PI/10e20;
              do
              {
                  Console.WriteLine(string.Format( "\t{0,20} = {1}", x, x.Nice(4)));
                  x*=10;
              } while(x<=Math.PI*10e20);
          }
      }
      

      四位有效数字的测试输出:

          3.14159265358979E-19 = 314.2·10^-2
           1.5707963267949E-18 = 1.571f
          7.85398163397448E-18 = 7.854f
          3.92699081698724E-17 = 39.27f
          1.96349540849362E-16 = 196.3f
           9.8174770424681E-16 = 981.7f
          4.90873852123405E-15 = 4.909a
          2.45436926061703E-14 = 24.54a
          1.22718463030851E-13 = 122.7a
          6.13592315154256E-13 = 613.6a
          3.06796157577128E-12 = 3.068p
          1.53398078788564E-11 = 15.34p
           7.6699039394282E-11 = 76.70p
           3.8349519697141E-10 = 383.5p
          1.91747598485705E-09 = 1.917n
          9.58737992428526E-09 = 9.587n
          4.79368996214263E-08 = 47.94n
          2.39684498107131E-07 = 239.7n
          1.19842249053566E-06 = 1.198µ
          5.99211245267829E-06 = 5.992µ
          2.99605622633914E-05 = 29.96µ
          0.000149802811316957 = 149.8µ
          0.000749014056584786 = 749.0µ
           0.00374507028292393 = 3.745m
            0.0187253514146196 = 18.73m
            0.0936267570730982 = 93.63m
             0.468133785365491 = 468.1m
              2.34066892682745 = 2.341
              11.7033446341373 = 11.70
              58.5167231706864 = 58.52
              292.583615853432 = 292.6
              1462.91807926716 = 1.463k
               7314.5903963358 = 7.315k
               36572.951981679 = 36.57k
              182864.759908395 = 182.9k
              914323.799541975 = 914.3k
              4571618.99770987 = 4.572M
              22858094.9885494 = 22.86M
              114290474.942747 = 114.3M
              571452374.713734 = 571.5M
              2857261873.56867 = 2.857G
              14286309367.8434 = 14.29G
              71431546839.2168 = 71.43G
              357157734196.084 = 357.2G
              1785788670980.42 = 1.786T
               8928943354902.1 = 8.929T
              44644716774510.5 = 44.64T
               223223583872552 = 223.2T
          1.11611791936276E+15 = 1.116P
          5.58058959681381E+15 = 5.581P
          2.79029479840691E+16 = 27.90P
          1.39514739920345E+17 = 139.5P
          6.97573699601726E+17 = 697.6P
          3.48786849800863E+18 = 3.488E
          1.74393424900432E+19 = 17.44E
          8.71967124502158E+19 = 87.20E
          4.35983562251079E+20 = 436.0E
           2.1799178112554E+21 = 2.180·10^21 
      

      【讨论】:

      • 这正是我想要的!谢谢 ja72。
      • 警告:当 X 为 0 时,您有负的 dg 和 sci 会引发异常。我编辑了您的代码以考虑到这一点。
      • 我编辑了代码,检查了零以及 NaN 和 Inf。
      • 我也应该在开头检查significant_digits&gt;0
      • 我修改了您的代码,使其更易于阅读:gist.github.com/bboyle1234/df47f661b531efd7386f0dbcdfbeee6f
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      • 1970-01-01
      • 2014-07-11
      • 2012-01-11
      • 1970-01-01
      相关资源
      最近更新 更多