Именование больших чисел
Добавлено: 29 июн 2020, 21:40
Недавно понадобилось сделать перевод больших чисел в более читабельный вид, по типу:
1 000 000 -> 1.00 Million
1 000 000 000 -> 1.00 Billion
...
На хабре есть хорошая статья https://habr.com/ru/post/314512/, но увы исходных код там не сохранился и пришлось накостылять самому
Советы по оптимизации приветствуются т.к. за 100к проходок в цикле оно жрет ~1000мс
Использование: Tools.GetPrettyNumber(1e123) -> 1.00 Quadragintillion
1 000 000 -> 1.00 Million
1 000 000 000 -> 1.00 Billion
...
На хабре есть хорошая статья https://habr.com/ru/post/314512/, но увы исходных код там не сохранился и пришлось накостылять самому
Советы по оптимизации приветствуются т.к. за 100к проходок в цикле оно жрет ~1000мс
Использование: Tools.GetPrettyNumber(1e123) -> 1.00 Quadragintillion
Синтаксис:
Используется csharp
using System;
using System.Collections.Generic;
namespace MaxUtilities
{
public static partial class Tools
{
class BigNumberPrefix
{
public enum Type
{
Units,
Tens,
Hundreds
}
public string prefix;
public string modifier;
public string correctTens;
public BigNumberPrefix(string prefix, string modifier = null)
{
this.prefix = prefix;
this.modifier = modifier;
correctTens = prefix.Remove(prefix.Length - 1) + 'i';
}
public BigNumberPrefix GetWithModifier(BigNumberPrefix unitsPrefix)
{
if (!string.IsNullOrEmpty(modifier))
{
switch (unitsPrefix.prefix)
{
case "tre":
if (modifier.Contains("S"))
return new BigNumberPrefix("tres");
break;
case "se":
if (modifier.Contains("S"))
return new BigNumberPrefix("ses");
if (modifier.Contains("X"))
return new BigNumberPrefix("sex");
break;
case "septe":
if (modifier.Contains("M"))
return new BigNumberPrefix("septem");
if (modifier.Contains("N"))
return new BigNumberPrefix("septen");
break;
case "nove":
if (modifier.Contains("M"))
return new BigNumberPrefix("novem");
if (modifier.Contains("N"))
return new BigNumberPrefix("noven");
break;
}
}
return unitsPrefix;
}
public static implicit operator bool(BigNumberPrefix prefix)
{
return prefix != null;
}
public static implicit operator string(BigNumberPrefix prefix)
{
return prefix.prefix;
}
}
static readonly string[] simpleNames = new string[]
{
"Million",
"Billion",
"Trillion",
"Quadrillion",
"Quintillion",
"Sextillion",
"Septillion",
"Octillion",
"Nonillion"
};
static readonly Dictionary<BigNumberPrefix.Type, BigNumberPrefix[]> prefixes =
new Dictionary<BigNumberPrefix.Type, BigNumberPrefix[]>()
{
{
BigNumberPrefix.Type.Units, new BigNumberPrefix[]
{
new BigNumberPrefix("un"),
new BigNumberPrefix("duo"),
new BigNumberPrefix("tre"),
new BigNumberPrefix("quattuor"),
new BigNumberPrefix("quin"),
new BigNumberPrefix("se"),
new BigNumberPrefix("septe"),
new BigNumberPrefix("octo"),
new BigNumberPrefix("nove")
}
},
{
BigNumberPrefix.Type.Tens, new BigNumberPrefix[]
{
new BigNumberPrefix("deci", "N"),
new BigNumberPrefix("viginti", "MS"),
new BigNumberPrefix("triginta", "NS"),
new BigNumberPrefix("quadraginta", "NS"),
new BigNumberPrefix("quinquaginta", "NS"),
new BigNumberPrefix("sexaginta", "N"),
new BigNumberPrefix("septuaginta", "N"),
new BigNumberPrefix("octoginta", "MX"),
new BigNumberPrefix("nonaginta")
}
},
{
BigNumberPrefix.Type.Hundreds, new BigNumberPrefix[]
{
new BigNumberPrefix("centi", "NX"),
new BigNumberPrefix("ducenti", "N"),
new BigNumberPrefix("trecenti", "NS"),
new BigNumberPrefix("quadringenti", "NS"),
new BigNumberPrefix("quingenti", "NS"),
new BigNumberPrefix("sescenti", "N"),
new BigNumberPrefix("septingenti", "N"),
new BigNumberPrefix("octingenti", "MX"),
new BigNumberPrefix("nongenti")
}
}
};
static BigNumberPrefix GetPrefix(BigNumberPrefix.Type prefixType, int value)
{
return value != 0 ? prefixes[prefixType][value - 1] : null;
}
public static string GetPrettyNumber(double number)
{
if (double.IsNaN(number) || double.IsInfinity(number) || Math.Abs(number) < 1e6)
{
return number.ToString("N2");
}
else
{
int u = 0;
int v = 0;
int n = (int)Math.Log10(Math.Abs(number));
do
{
u++;
v = n - 3 * (u + 1);
}
while (v >= 3);
number /= Math.Pow(10.0, n - v);
if (u < 10)
{
return $"{number.ToString("F2")} {simpleNames[u - 1]}";
}
else
{
int[] digits = new int[3];
for (int i = 0; i < 3; ++i)
{
digits[i] = u % 10;
u /= 10;
}
var prefixUnits = GetPrefix(BigNumberPrefix.Type.Units, digits[0]);
var prefixTens = GetPrefix(BigNumberPrefix.Type.Tens, digits[1]);
var prefixHundreds = GetPrefix(BigNumberPrefix.Type.Hundreds, digits[2]);
string result = string.Empty;
if (prefixUnits)
{
if (prefixTens)
{
prefixUnits = prefixTens.GetWithModifier(prefixUnits);
if (prefixHundreds)
{
result += prefixUnits + prefixTens + prefixHundreds;
}
else
result += prefixUnits + prefixTens.correctTens;
}
else
{
prefixUnits = prefixHundreds.GetWithModifier(prefixUnits);
result += prefixUnits + prefixHundreds;
}
}
else if (prefixTens)
{
if (prefixHundreds)
{
result += prefixTens + prefixHundreds;
}
else
result += prefixTens.correctTens;
}
else
result += prefixHundreds;
return $"{number.ToString("F2")} {char.ToUpper(result[0])}{result.Substring(1)}llion";
}
}
}
}
}
using System.Collections.Generic;
namespace MaxUtilities
{
public static partial class Tools
{
class BigNumberPrefix
{
public enum Type
{
Units,
Tens,
Hundreds
}
public string prefix;
public string modifier;
public string correctTens;
public BigNumberPrefix(string prefix, string modifier = null)
{
this.prefix = prefix;
this.modifier = modifier;
correctTens = prefix.Remove(prefix.Length - 1) + 'i';
}
public BigNumberPrefix GetWithModifier(BigNumberPrefix unitsPrefix)
{
if (!string.IsNullOrEmpty(modifier))
{
switch (unitsPrefix.prefix)
{
case "tre":
if (modifier.Contains("S"))
return new BigNumberPrefix("tres");
break;
case "se":
if (modifier.Contains("S"))
return new BigNumberPrefix("ses");
if (modifier.Contains("X"))
return new BigNumberPrefix("sex");
break;
case "septe":
if (modifier.Contains("M"))
return new BigNumberPrefix("septem");
if (modifier.Contains("N"))
return new BigNumberPrefix("septen");
break;
case "nove":
if (modifier.Contains("M"))
return new BigNumberPrefix("novem");
if (modifier.Contains("N"))
return new BigNumberPrefix("noven");
break;
}
}
return unitsPrefix;
}
public static implicit operator bool(BigNumberPrefix prefix)
{
return prefix != null;
}
public static implicit operator string(BigNumberPrefix prefix)
{
return prefix.prefix;
}
}
static readonly string[] simpleNames = new string[]
{
"Million",
"Billion",
"Trillion",
"Quadrillion",
"Quintillion",
"Sextillion",
"Septillion",
"Octillion",
"Nonillion"
};
static readonly Dictionary<BigNumberPrefix.Type, BigNumberPrefix[]> prefixes =
new Dictionary<BigNumberPrefix.Type, BigNumberPrefix[]>()
{
{
BigNumberPrefix.Type.Units, new BigNumberPrefix[]
{
new BigNumberPrefix("un"),
new BigNumberPrefix("duo"),
new BigNumberPrefix("tre"),
new BigNumberPrefix("quattuor"),
new BigNumberPrefix("quin"),
new BigNumberPrefix("se"),
new BigNumberPrefix("septe"),
new BigNumberPrefix("octo"),
new BigNumberPrefix("nove")
}
},
{
BigNumberPrefix.Type.Tens, new BigNumberPrefix[]
{
new BigNumberPrefix("deci", "N"),
new BigNumberPrefix("viginti", "MS"),
new BigNumberPrefix("triginta", "NS"),
new BigNumberPrefix("quadraginta", "NS"),
new BigNumberPrefix("quinquaginta", "NS"),
new BigNumberPrefix("sexaginta", "N"),
new BigNumberPrefix("septuaginta", "N"),
new BigNumberPrefix("octoginta", "MX"),
new BigNumberPrefix("nonaginta")
}
},
{
BigNumberPrefix.Type.Hundreds, new BigNumberPrefix[]
{
new BigNumberPrefix("centi", "NX"),
new BigNumberPrefix("ducenti", "N"),
new BigNumberPrefix("trecenti", "NS"),
new BigNumberPrefix("quadringenti", "NS"),
new BigNumberPrefix("quingenti", "NS"),
new BigNumberPrefix("sescenti", "N"),
new BigNumberPrefix("septingenti", "N"),
new BigNumberPrefix("octingenti", "MX"),
new BigNumberPrefix("nongenti")
}
}
};
static BigNumberPrefix GetPrefix(BigNumberPrefix.Type prefixType, int value)
{
return value != 0 ? prefixes[prefixType][value - 1] : null;
}
public static string GetPrettyNumber(double number)
{
if (double.IsNaN(number) || double.IsInfinity(number) || Math.Abs(number) < 1e6)
{
return number.ToString("N2");
}
else
{
int u = 0;
int v = 0;
int n = (int)Math.Log10(Math.Abs(number));
do
{
u++;
v = n - 3 * (u + 1);
}
while (v >= 3);
number /= Math.Pow(10.0, n - v);
if (u < 10)
{
return $"{number.ToString("F2")} {simpleNames[u - 1]}";
}
else
{
int[] digits = new int[3];
for (int i = 0; i < 3; ++i)
{
digits[i] = u % 10;
u /= 10;
}
var prefixUnits = GetPrefix(BigNumberPrefix.Type.Units, digits[0]);
var prefixTens = GetPrefix(BigNumberPrefix.Type.Tens, digits[1]);
var prefixHundreds = GetPrefix(BigNumberPrefix.Type.Hundreds, digits[2]);
string result = string.Empty;
if (prefixUnits)
{
if (prefixTens)
{
prefixUnits = prefixTens.GetWithModifier(prefixUnits);
if (prefixHundreds)
{
result += prefixUnits + prefixTens + prefixHundreds;
}
else
result += prefixUnits + prefixTens.correctTens;
}
else
{
prefixUnits = prefixHundreds.GetWithModifier(prefixUnits);
result += prefixUnits + prefixHundreds;
}
}
else if (prefixTens)
{
if (prefixHundreds)
{
result += prefixTens + prefixHundreds;
}
else
result += prefixTens.correctTens;
}
else
result += prefixHundreds;
return $"{number.ToString("F2")} {char.ToUpper(result[0])}{result.Substring(1)}llion";
}
}
}
}
}