问题
This question already has an answer here:
- Formatting Large Numbers with .NET 5 answers
I would like to print my very small numbers in C# in a human friendly way, such as:
30µ
for 3E-5
or 456.789n
for 0.000000456789
.
I know of the Humanize_number() function from BSD in C, but only compatible with bit ints, not floats and doubles. Is there the equivalent in C# that supports those?
Also, it should keep a certain amount of precision when displaying numbers, like:
0.003596
should be displayed as 3.596µ
, not 3.6µ
(or worse, 4µ
).
The possible answer here: Formatting Large Numbers with .NET but adapted for negative log10 is truncating the numbers to 1 digit after the comma. That's far from complete in my opinion.
Examples of how I'd like to present things:
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
I couldn't formulate my question to find relevant answers in SO, so if the question has been already answered, fire away!
回答1:
Try this:
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);
}
}
Test output with four significant digits:
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
回答2:
as you want the decimal to be displayed as sign and not as a lot of 0's you could as well do something like:
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();
}
}
回答3:
Could you use DllImport to use the Humanize_Number function?? See here for details :
Dynamically loading a dll in C#
回答4:
Why not multiply by 10^(count numbers after decimal)? You can use the same count of numbers after the decimal to figure out which unit to display. It's much better than importing an entire library.
来源:https://stackoverflow.com/questions/16083666/make-big-and-small-numbers-human-readable