2013-04-18 3 views
19

Я хотел бы напечатать мое очень небольшое число в C# в человеческом дружественны, таких как:сделать большие и малые числа читаемым человеком

30µ для 3E-5 или 456.789n для 0.000000456789.

Я знаю о функции Humanize_number() от BSD в C, но только совместим с битовыми ints, а не плавает и удваивает. Есть ли эквивалент в 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, поэтому если вопрос уже ответил, жарь!

+3

[. нет, вы не спите] (http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-sa lutations-be-deleted-from-posts/93989 # 93989) –

+0

Прошу прощения, но ответ http://stackoverflow.com/questions/1555397/formatting-large-numbers-with-net на самом деле не помогает. Я хотел бы сохранить максимальную точность в вещах, которые я показываю. – Gui13

+6

Не похоже, что было бы ужасно сложно перенести код для 'humanize_number': http://www.opensource.apple.com/source/libutil/libutil-20/humanize_number.c –

ответ

6

Попробуйте это:

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 
+0

Это именно то, что я искал! Спасибо, ja72. – Gui13

+1

Предупреждение: когда X равно 0, у вас есть отрицательные dg и sci, которые провоцируют исключения. Я отредактировал ваш код, чтобы принять это во внимание. – Gui13

+0

Спасибо за подсказку. – ja72

0

Не могли бы вы использовать DllImport для использования функции Humanize_Number? Смотрите здесь для подробностей:

Dynamically loading a dll in C#

+0

Я предпочел бы знать, есть ли «встроенное» решение. Я использовал функцию BSD под linux в другой life :) – Gui13

0

Почему не умножать на 10^(количество чисел после десятичной системе)? Вы можете использовать один и тот же счетчик чисел после десятичного числа, чтобы выяснить, какой блок отображать. Это намного лучше, чем импорт всей библиотеки.

2

, как вы хотите десятичное отображаться как знак, а не как много 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(); 

    } 
} 
Смежные вопросы