The minimum precision digits will be kept (as defined in user profile, usually 2 digits), but higher precision will also be kept, but without useless zeros at the end of formatted result.
Example:
Your number is a decimal with the value 25.222456000 you want to show 25.222456
Your number is a decimial with the value 25.7 you want to show 25.70
The implementation is for the decimal type, but you can easely convert or duplicate it for any other floating type.
using System;
using System.Globalization;
namespace AnyNamespace
{
/// <summary>
/// Provides functionality to <c>decimal</c> data type
/// </summary>
public static class DecimalExtender
{
/// <summary>
/// Formats a decimal according to current user profile settings
/// (often called country region settings),
/// but has option to keep precision though
/// </summary>
/// <param name="input">
/// The value to format
/// </param>
/// <param name="format">
/// The value type:
/// <c>n</c> is for number,
/// <c>p</c> is for percent,
/// <c>c</c> is for currency,
/// for more infomation about format constants
/// see <see
href="https://docs.microsoft.com/de-de/dotnet/standard/base-types/standard-numeric-format-strings?view=netframework-4.7.2"/>
/// </param>
/// <param name="decimalDigitPropertyName">
/// The property on <c>NumberFormatInfo</c> type
/// to use to retrieve minimal number of digits for precision,
/// for more information see <see
cref="NumberFormatInfo"/>
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formatted number as string
/// </returns>
static string Format(decimal input, string format,
string decimalDigitPropertyName, bool keepPercision)
{
var cultureFormat = (NumberFormatInfo)CultureInfo.CurrentCulture
.NumberFormat.Clone();
/* if
PercentDecimalDigits is used,
* we need to take care of x100
multiplication
* when detecting decimal palces
...
*/
var decimalPlaces = (decimalDigitPropertyName ==
nameof(NumberFormatInfo.PercentDecimalDigits)
? (input * 100)
: input) % 1;
int requiredDecimalPlacesLength = 0;
if (decimalPlaces != 0)
{
var decimalString = Math.Abs(decimalPlaces)
.ToString(CultureInfo.InvariantCulture);
while (decimalString.Length > 2
&&
decimalString.Substring(decimalString.Length - 1) ==
0.ToString(CultureInfo.InvariantCulture))
{
decimalString =
decimalString
.Substring(0,
decimalString.Length - 1);
}
requiredDecimalPlacesLength =
decimalString.Length - 2;
}
if (keepPercision
&&
requiredDecimalPlacesLength
> (int)cultureFormat.GetType()
.GetProperty(decimalDigitPropertyName)
.GetValue(cultureFormat))
{
// extend
the precision to exact after point lenght
cultureFormat.GetType().GetProperty(decimalDigitPropertyName)
.SetValue(cultureFormat,
requiredDecimalPlacesLength);
}
string ret = input.ToString(format, cultureFormat);
return ret;
}
/// <summary>
/// Formats a number value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated number
/// </returns>
/// <remarks>
/// The method uses the <c>n</c> constant for number format formation,
/// for more information see
/// <see
href="https://docs.microsoft.com/de-de/dotnet/standard/base-types/standard-numeric-format-strings?view=netframework-4.7.2"/>
/// </remarks>
public static string FormatNumber(this decimal input, bool
keepPrecision)
{
return Format(input, "n",
nameof(NumberFormatInfo.NumberDecimalDigits), keepPrecision);
}
/// <summary>
/// Formats a percent value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated percent
/// </returns>
/// <remarks>
/// The method uses the <c>p</c> constant for percent format formation,
/// for more information see
/// <see
href="https://docs.microsoft.com/de-de/dotnet/standard/base-types/standard-numeric-format-strings?view=netframework-4.7.2"/>
/// </remarks>
public static string FormatPercent(this decimal input,
bool keepPrecision)
{
return Format(input, "p",
nameof(NumberFormatInfo.PercentDecimalDigits), keepPrecision);
}
/// <summary>
/// Formats a currency value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated currency
/// </returns>
/// The method uses the <c>c</c> constant for currency format formation,
/// for more information see
/// <see
href="https://docs.microsoft.com/de-de/dotnet/standard/base-types/standard-numeric-format-strings?view=netframework-4.7.2"/>
/// </remarks>
public static string FormatCurrency(this decimal input,
bool keepPrecision)
{
return Format(input, "c",
nameof(NumberFormatInfo.CurrencyDecimalDigits), keepPrecision);
}
/// <summary>
/// Formats a number value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated number
/// </returns>
public static string FormatNumber(this decimal? input,
bool keepPrecision)
{
return FormatNumber((decimal)input, keepPrecision);
}
/// <summary>
/// Formats a percent value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated percent
/// </returns>
public static string FormatPercent(this decimal? input,
bool keepPrecision)
{
return FormatPercent((decimal)input, keepPrecision);
}
/// <summary>
/// Formats a currency value, but keeps decimal places if required
/// </summary>
/// <param name="input">
/// The figure to format
/// </param>
/// <param name="keepPercision">
/// Keeps precision over minimal number of digits for precision
/// </param>
/// <returns>
/// The formated currency
/// </returns>
public static string FormatCurrency(this decimal? input,
bool keepPrecision)
{
return FormatCurrency((decimal)input, keepPrecision);
}
}
}
And that's how you use it:
using System;
using AnyNamespace;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
// example
when you're using en-us default culture settings
Console.WriteLine((2.5500m).FormatNumber(false));
// => to
2.55
Console.WriteLine((2.55546400m).FormatNumber(false));
// => to 2.56
Console.WriteLine((2.5500m).FormatNumber(true));
// => to
2.55
Console.WriteLine((2.55546400m).FormatNumber(true));
// => to
2.555464
Console.WriteLine((2.5500m).FormatCurrency(false));
// => to
$2.55
Console.WriteLine((2.55546400m).FormatCurrency(false));
// => to
$2.56
Console.WriteLine((2.5500m).FormatCurrency(true));
// => to
$2.55
Console.WriteLine((2.55546400m).FormatCurrency(true));
// => to
$2.555464
Console.WriteLine((2.5500m).FormatPercent(false));
// => to
255.00%
Console.WriteLine((2.55546400m).FormatPercent(false));
// => to
255.55%
Console.WriteLine((2.5500m).FormatPercent(true));
// => to
255.00%
Console.WriteLine((2.55546400m).FormatPercent(true));
// => to 255.5464%
Console.ReadKey();
}
}
}