У меня есть несколько полей, возвращаемых коллекцией как
2.4200
2.0044
2.0000
Я хочу результаты как
2.42
2.0044
2
Я пытался с String.Format
, но он возвращает 2.0000
и установка его N0
округляет и другие значения.
Разве это не так просто, если вход является строкой? Вы можете использовать один из них:
string.Format("{0:G29}", decimal.Parse("2.0044"))
decimal.Parse("2.0044").ToString("G29")
2.0m.ToString("G29")
Это должно работать для всех входных данных.
Обновление Проверьте стандартные числовые форматы. Мне пришлось явно установить спецификатор точности равным 29, поскольку документы четко указывают:
Однако, если число является десятичным, а спецификатор точности опущен, запись с фиксированной запятой всегда используется и конечные нули сохраняются
Обновление Конрада указано в комментариях:
Следите за значениями, такими как 0,000001. Формат G29 представит их в кратчайшем виде, поэтому он переключится на экспоненциальную запись.
string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))
даст "1E-08" в результате.
Я столкнулся с той же проблемой, но в случае, когда у меня нет контроля над выводом в строку, о котором позаботилась библиотека. Изучив детали реализации типа Decimal (см. Http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ), я придумал хитрый трюк (здесь как расширение метод):
public static decimal Normalize(this decimal value)
{
return value/1.000000000000000000000000000000000m;
}
Экспонента десятичной части сводится к тому, что нужно. Вызов ToString () для выходного десятичного числа запишет число без запаздывания 0. Например
1.200m.Normalize().ToString();
1
которыми следуют 33 0
, но это создает точно такой же decimal
экземпляр, как число с 29 цифрами, одной 1
и 28-ми 0
. Так же, как @ThomasMaterna сказал в своем комментарии. Не System.Decimal
может содержать более 29 цифр (цифры с начальными цифрами больше, чем 79228...
могут иметь только 28 цифр). Если вы хотите больше конечных нулей, умножьте на 1.000...m
вместо деления. Также Math.Round
можно отрубить несколько нулей, например, Math.Round(27.40000m, 2)
дает 27.40m
, так что остался только один ноль.
На мой взгляд, безопаснее использовать строки произвольного числового формата .
decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13
Я использую этот код, чтобы избежать научной нотации "G29":
public static string DecimalToString(this decimal dec)
{
string strdec = dec.ToString(CultureInfo.InvariantCulture);
return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}
РЕДАКТИРОВАТЬ: используя систему CultureInfo.NumberFormat.NumberDecimalSeparator:
public static string DecimalToString(this decimal dec)
{
string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string strdec = dec.ToString(CultureInfo.CurrentCulture);
return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}
Culture.NumberFormat.NumberDecimalSeparator
Используйте #
символ hash ( ), чтобы отображать только завершающие нули, когда это необходимо. Смотрите тесты ниже.
decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;
num1.ToString("0.##"); //13.15%
num2.ToString("0.##"); //49.1%
num3.ToString("0.##"); //30%
num1.ToString("0.##")
должен вернуть 13.1534545765
(без изменений), потому что нет никаких завершающих нулей.
Я нашел элегантное решение от http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/
В принципе
decimal v=2.4200M;
v.ToString("#.######"); // Will return 2.42. The number of # is how many decimal digits you support.
v
есть 0m
, результатом вашего кода будет пустая строка, а не "0"
.
Подход очень низкого уровня, но я верю, что это был бы наиболее эффективный способ, используя только быстрые целочисленные вычисления (без медленного анализа строк и чувствительных к культуре методов):
public static decimal Normalize(this decimal d)
{
int[] bits = decimal.GetBits(d);
int sign = bits[3] & (1 << 31);
int exp = (bits[3] >> 16) & 0x1f;
uint a = (uint)bits[2]; // Top bits
uint b = (uint)bits[1]; // Middle bits
uint c = (uint)bits[0]; // Bottom bits
while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
{
uint r;
a = DivideBy10((uint)0, a, out r);
b = DivideBy10(r, b, out r);
c = DivideBy10(r, c, out r);
exp--;
}
bits[0] = (int)c;
bits[1] = (int)b;
bits[2] = (int)a;
bits[3] = (exp << 16) | sign;
return new decimal(bits);
}
private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
ulong total = highBits;
total <<= 32;
total = total | (ulong)lowBits;
remainder = (uint)(total % 10L);
return (uint)(total / 10L);
}
a
и b
) в каждой итерации , а если они все равны нулю , так или иначе. Однако затем я нашел это удивительно простое решение, которое также легко превосходит то, что мы с вами придумали в отношении производительности .
Это будет работать:
decimal source = 2.4200m;
string output = ((double)source).ToString();
Или если ваше начальное значение string
:
string source = "2.4200";
string output = double.Parse(source).ToString();
Обратите внимание на этот комментарий .
double.ToString
по умолчанию удаляет завершающие нули.
Это просто
decimal decNumber = Convert.ToDecimal(value);
return decNumber.ToString("0.####");
Проверено.
Ура :)
Зависит от того, что представляет ваше число и как вы хотите управлять значениями: это валюта, вам нужно округление или усечение, вам нужно это округление только для отображения?
Если для отображения рассмотрим форматирование чисел x.ToString ("")
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx и
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
Если это просто округление, используйте перегрузку Math.Round, для которой требуется перегрузка MidPointRounding.
http://msdn.microsoft.com/en-us/library/ms131274.aspx )
Если вы получаете свое значение из базы данных, рассмотрите приведение вместо преобразования: double value = (decimal) myRecord ["columnName"];
Вы можете просто установить как:
decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));
Если вы хотите сохранить десятичное число, попробуйте следующий пример:
number = Math.Floor(number * 100000000) / 100000000;
Попытка сделать более дружественное решение DecimalToString ( https://stackoverflow.com/a/34486763/3852139 ):
private static decimal Trim(this decimal value)
{
var s = value.ToString(CultureInfo.InvariantCulture);
return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
: value;
}
private static decimal? Trim(this decimal? value)
{
return value.HasValue ? (decimal?) value.Value.Trim() : null;
}
private static void Main(string[] args)
{
Console.WriteLine("=>{0}", 1.0000m.Trim());
Console.WriteLine("=>{0}", 1.000000023000m.Trim());
Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}
Вывод:
=>1
=>1.000000023
=>1.000000023
=>
Очень простой ответ - использовать TrimEnd (). Вот результат,
double value = 1.00;
string output = value.ToString().TrimEnd('0');
Выходное значение равно 1 Если мое значение равно 1,01, то выходное значение будет 1,01
value = 100
?
Следующий код может быть использован, чтобы не использовать строковый тип:
int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
decimalResult = decimalResult / 10;
}
return decimalResult;
Возвращает 789,5
Обрезать конечные нули очень просто, решите с помощью дуплексного приведения:
decimal mydecimal = decimal.Parse("1,45000000"); //(I)
decimal truncate = (decimal)(double)mydecimal; //(II)
(I) -> Разобрать десятичное значение из любого источника строки.
(II) -> Во-первых: приведение к удвоению удаляет завершающие нули. Второе: другие приводятся к десятичному типу, потому что не существует неявного преобразования из десятичного в двойное и наоборот)
попробуйте этот код:
string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');
попробуй вот так
string s = "2.4200";
s = s.TrimStart('0').TrimEnd('0', '.');
а затем преобразовать это, чтобы плавать
subString()
метод для этого, но в соответствии с вопросом, размещенным здесь, я не вижу каких-либо требований, как это =)
"12300.00"
будет урезан "123"
. Другой эффект, который кажется нежелательным, заключается в том, что некоторые числа, подобные "0.00"
, обрезаются до пустой строки ""
(хотя это число является особым случаем целочисленного значения, кратного 10,0).
String.Format()
с «G» должен получить то, что вы хотите .. я обновил свой ответ со ссылкой на стандартные числовые форматы. Очень удобно.double
, и значениеToString
по умолчанию для двойного испускает завершающие нули. Прочитайте этоToString
.