Я знаю, что это очень старая тема, но я думаю, что может быть полезен более общий ответ:
ADD: упущено из виду, что это должен был быть C #, поэтому здесь оно переводится:
//--Formats the number after scaling by factors of 1000, and appends a metric unit prefix (e.g. M for *1000000)
//--Mask, Prov are the standard ToString() parameters (after metric scaling has been performed)
//--MinPow10 (/Max) should be multipla of 3 and a usually a negative (/Positve) number or zero, if say +9 is used, all is in G or above (/below)
//--SwitchLimit usualy 1, but could be say 10 or 100 with few/zero decimals, The limit at which to switch prefix, if say 33 then 33000000->33M but 32900000->32900K
static string FormatMetricPrefix(double Input, String Mask ="F2", IFormatProvider Prov=null, int MinPow10 =-24, int MaxPow10 =24, int SwitchLimit =1) {
string Prefixes ="yzafpnμm KMGTPEZY";
int idx=9;
double tmp=Input;
if (Input!=0.0) {
if (+24<MaxPow10)MaxPow10=+24;
if (MinPow10<-24)MaxPow10=-24;
idx=(int)Math.Truncate(9.0+Math.Log(Math.Abs(Input/SwitchLimit))/Math.Log(1000.0));
if (idx<9+(MinPow10/3)) idx=9+(MinPow10/3); // below lower limit
if (9+(MaxPow10/3)<idx) idx=9+(MaxPow10/3); // Above upper limit
if (idx<=9)tmp *=Math.Pow(1000.0,9-idx);
if (9<idx) tmp /=Math.Pow(1000.0,idx-9);
}
if (Prov==null)Prov=CultureInfo.InvariantCulture;
return tmp.ToString(Mask,Prov)+Prefixes.Substring(idx-1,1).Trim();
}
static string FormatMetricPrefixF2DK(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("da-DK"));}
static string FormatMetricPrefixF2US(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("en-US"));}
static string FormatMetricPrefixF0DK(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("da-DK"),SwitchLimit:100);}
static string FormatMetricPrefixF0US(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("en-US"),SwitchLimit:100);}
static void Main(string[] args)
{
Console.WriteLine(FormatMetricPrefixF2US(1.234567890E+27));
Console.WriteLine(FormatMetricPrefixF2US(1234567890));
Console.WriteLine(FormatMetricPrefixF2US(0.01234567890));
Console.WriteLine(FormatMetricPrefixF2US(0.00000001234567890));
Console.WriteLine(FormatMetricPrefixF2US(1.234567890E-26));
Console.WriteLine(FormatMetricPrefixF0US(0.5));
Console.WriteLine(FormatMetricPrefixF0US(2));
Console.WriteLine(FormatMetricPrefixF0US(20000));
Console.WriteLine(FormatMetricPrefixF0US(87654321));
}
И это для SQL:
--Formats the number after scaling by factors of 1000, and appends a metric unit prefix (e.g. M for *1000000)
--@Mask, @Cult are the standard FORMAT parameters (after metric scaling has been performed)
--@MinPow10 (/Max) should be multipla of 3 and a usually a negative (/Positve) number or zero, if say +9 is used, all is in G or above (/below)
--@SwitchLimit usualy 1, but could be say 10 or 100 with few/zero decimals, The limit at which to switch prefix, if say 33 then 33000000->33M but 32900000->32900K
CREATE function FormatMetricPrefix(@Input float, @Mask Varchar(22)='F2', @Cult Varchar(9)='en-us', @MinPow10 int =-24, @MaxPow10 int =24, @SwitchLimit int=1) returns Varchar(99) as
Begin
Declare @Prefixes Varchar(17)='yzafpnμm KMGTPEZY'
Declare @idx int = 9
Declare @tmp float=@input
if @Input<>0.0
begin
if +24<@MaxPow10 set @MaxPow10=+24 --highest limit is y 10^24
if @MinPow10<-24 set @MinPow10=-24 --lowest limit is y 10^-24
set @idx=9.0+Log(Abs(@input/@SwitchLimit))/Log(1000)
If @idx<9+(@MinPow10/3) set @idx=9+(@MinPow10/3) -- below lower limit
If 9+(@MaxPow10/3)<@idx set @idx=9+(@MaxPow10/3) --above upper limit
if @idx<=9set @tmp=@tmp*POWER(1000.0,9-@idx)
if 9<@idx set @tmp=@tmp/POWER(1000.0,@idx-9)
end
Return FORMAT(@tmp,@mask,@Cult)+LTrim(Substring(@Prefixes,@idx,1))
end
GO
А затем, возможно, некоторые соответствующие функции-обертки для облегчения использования, например,
CREATE function FormatMetricPrefixF2US(@Input float) returns Varchar(99) as
begin
return dbo.FormatMetricPrefix(@Input, default,default,default,default,default)
end
GO
CREATE function FormatMetricPrefixF0US(@Input float) returns Varchar(99) as
begin
return dbo.FormatMetricPrefix(@Input, 'F0' ,default, 0 ,default, 100 )
end
GO
И куча тестов / примеров:
Select 0, dbo.FormatMetricPrefixF2US(1.234567890E+27)+'g'
union Select 1, dbo.FormatMetricPrefixF2US(1234567890)+'g'
union Select 2, dbo.FormatMetricPrefixF2US(123456789.0)+'g'
union Select 3, dbo.FormatMetricPrefixF2US(12345678.90)+'g'
union Select 4, dbo.FormatMetricPrefixF2US(1234567.890)+'g'
union Select 5, dbo.FormatMetricPrefixF2US(123456.7890)+'g'
union Select 6, dbo.FormatMetricPrefixF2US(12345.67890)+'g'
union Select 7, dbo.FormatMetricPrefixF2US(1234.567890)+'g'
union Select 8, dbo.FormatMetricPrefixF2US(123.4567890)+'g'
union Select 9, dbo.FormatMetricPrefixF2US(12.34567890)+'g'
union Select 10, dbo.FormatMetricPrefixF2US(1.234567890)+'g'
union Select 11, dbo.FormatMetricPrefixF2US(0.1234567890)+'g'
union Select 12, dbo.FormatMetricPrefixF2US(0.01234567890)+'g'
union Select 13, dbo.FormatMetricPrefixF2US(0.001234567890)+'g'
union Select 14, dbo.FormatMetricPrefixF2US(0.0001234567890)+'g'
union Select 15, dbo.FormatMetricPrefixF2US(0.00001234567890)+'g'
union Select 16, dbo.FormatMetricPrefixF2US(0.000001234567890)+'g'
union Select 17, dbo.FormatMetricPrefixF2US(0.0000001234567890)+'g'
union Select 18, dbo.FormatMetricPrefixF2US(0.00000001234567890)+'g'
union Select 19, dbo.FormatMetricPrefixF2US(1.234567890E-26)+'g'
union Select 20, dbo.FormatMetricPrefixF0US(0.5)
union Select 20, dbo.FormatMetricPrefixF0US(2)
union Select 21, dbo.FormatMetricPrefixF0US(20000)
union Select 22, dbo.FormatMetricPrefixF0US(87654321)