C# .NET 动态尾随零?

C# .NET Dynamic Trailing Zeroes?

我正在编写一个库来格式化数字。存在一个问题,需要指定尾随零的数量。这方面的一个例子是财务数据,其中一些价格显示有超过 2 位小数,但只有前两位小数可以是尾随零。

示例(给定 2 个尾随零和精度 4):

0.10000 => 0.10

0.11100 => 0.111

0.119 => 0.119

0.11119 => 0.1112

我还想将其与 System.Globalization 提供的 "P" 和 "C" 格式结合使用。示例:

0.587 "C" => 0.587 美元

0.20 "C" => 0.20 美元

0.20001 "C" => 0.20 美元

0.48745 "C" => 0.4875 美元

0.587 "P" => 58.70%

0.20 "C" => 20.00%

0.20001 "C" => 20.00%

0.48745 "C" => 48.745%

我希望能够向库提供可变数量的尾随零。

我想利用内置功能,以便利用全球化。由于 .ToString 和 String.Format 允许指定要显示的小数位数,我想我可以使用一些奇特的对数数学来确定是否应显示小数位。我想我会看看是否有更好的解决方案。

您可以使用:

number.ToString("0.00##")

decimal.Parse(text)

例如

var inputs = new[] { "0.1000", "0.11100", "0.119", "0.11119" };

var numbers = inputs.Select(decimal.Parse);

var output = numbers.Select(x => x.ToString("0.00##"));

Console.WriteLine(String.Join(", ", output));

产出

0.10, 0.111, 0.119, 0.1112

在百分比和货币方面,我不认为有任何聪明的方法可以做到这一点,但以下可以与以上结合使用:

货币

var symbol = CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol // $
// ...
var output = numbers.Select(x => symbol + x.ToString("0.00##"));
// ...

百分比

// ...
var numbers = inputs.Select(x => decimal.Parse(x) * 100);
// ...

我最终写了一个简短的算法,可以得出适当的精度。这可以与 "PX"、"NX" 或 "CX" 结合使用,以用于全球化和内置的 .ToString 格式。它已经过各种数字的单元测试,因此非常可靠。

    /// <summary>Calculate the correct precision based on trailing zeroes and target precision
    /// </summary>
    /// <param name="number">the number to check (multiply by 100 if it is being formatted as a percent)</param>
    /// <param name="trailingZeroes">the number of trailing zeroes</param>
    /// <param name="precision">the number of decimal places to show</param>
    /// <returns>
    /// Argument Exception: trailing zero and precision cannot be less than one or greater than 99
    /// Argument Exception: trailing zeros cannot be larger than the precision
    /// </returns>
    private int CalculatePrecision(double number, int trailingZeroes, int precision)
    {
        if (trailingZeroes < 0 || trailingZeroes > 99 || precision < 0 || precision > 99)
        {
            throw new ArgumentException("Trailing Zeroes and precision must be between 0 and 99.");
        }

        // make sure trailng zeroes is not larger than precision
        trailingZeroes = Math.Min(trailingZeroes, precision);

        // a temporary value for locating decimal places
        double tempValue;

        // just the decimal places
        double allDecimalPlaces = number - Math.Floor(number);

        // the individual decimal place at a given power of 10
        double singleDecimalPlaceValue;

        // search for the zeroes in the decimal places
        for (int i = precision; i > trailingZeroes; i--)
        {
            // get just the decimal place that needs to be checked
            tempValue = allDecimalPlaces * Math.Pow(10, i - 1);
            singleDecimalPlaceValue = Math.Round((tempValue - Math.Floor(tempValue)) * 10);

            // check for a 0 decimal or a 10 value (for floating point math)
            if (singleDecimalPlaceValue != 0 && singleDecimalPlaceValue != 10)
            {
                return i;
            }
        }

        // if all zeroes are found, return trailing zeroes
        return trailingZeroes;
    }