我想以人性化的方式在C#中打印我的小数字,例如:
30µ
的{p> 3E-5
或456.789n
的{{1}}。
我知道C中BSD的Humanize_number()函数,但只与bit int兼容,而不是浮点数和双精度数。在C#中是否有支持那些的等价物?
此外,在显示数字时应保持一定的精确度,例如:
0.000000456789
应显示为0.003596
,而不是3.596µ
(或更糟,3.6µ
)。
这里可能的答案是:Formatting Large Numbers with .NET但是针对负log10进行了修改,将数字截断为逗号后的1位数。在我看来,这远未完成。
我想如何表达事物的例子:
4µ
我无法在SO中提出我的问题以找到相关的答案,所以如果问题已经得到解答,请开火!
答案 0 :(得分:7)
试试这个:
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
答案 1 :(得分: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();
}
}
答案 2 :(得分:0)
你能用DllImport来使用Humanize_Number函数吗?有关详细信息,请参见此处:
答案 3 :(得分:0)
为什么不乘以10 ^(十进制后的计数)?您可以在小数点后使用相同的数字计数来确定要显示的单位。它比导入整个库要好得多。