Разобрать десятичную дробь и отфильтровать лишние 0 справа? - PullRequest
15 голосов
/ 28 ноября 2010

Из XML-файла я получаю десятичные дроби в формате:

1.132000
6.000000

В настоящее время я использую десятичную дробь.вывести myDecimal в строку, чтобы она выглядела следующим образом?

1.132
6

Ответы [ 5 ]

30 голосов
/ 28 ноября 2010

Я не думаю, что есть какие-либо строки стандартного числового формата, которые, я боюсь, всегда пропускают завершающие незначительные нули.

Вы можете попробовать написать свой собственный метод десятичной нормализации, но это может быть довольносложно.С классом BigInteger из .NET 4 это было бы разумно выполнимо, но без этого (или чего-то подобного) это было бы действительно очень сложно.

РЕДАКТИРОВАТЬ: Хорошо, я думаю, это то, что вы хотите:

using System;
using System.Numerics;

public static class DecimalExtensions
{
    // Avoiding implicit conversions just for clarity
    private static readonly BigInteger Ten = new BigInteger(10);
    private static readonly BigInteger UInt32Mask = new BigInteger(0xffffffffU);

    public static decimal Normalize(this decimal input)
    {
        unchecked
        {
            int[] bits = decimal.GetBits(input);
            BigInteger mantissa = 
                new BigInteger((uint) bits[0]) +
                (new BigInteger((uint) bits[1]) << 32) +
                (new BigInteger((uint) bits[2]) << 64);

            int sign = bits[3] & int.MinValue;            
            int exponent = (bits[3] & 0xff0000) >> 16;

            // The loop condition here is ugly, because we want
            // to do both the DivRem part and the exponent check :(
            while (exponent > 0)
            {
                BigInteger remainder;
                BigInteger divided = BigInteger.DivRem(mantissa, Ten, out remainder);
                if (remainder != BigInteger.Zero)
                {
                    break;
                }
                exponent--;
                mantissa = divided;
            }
            // Okay, now put it all back together again...
            bits[3] = (exponent << 16) | sign;
            // For each 32 bits, convert the bottom 32 bits into a uint (which won't
            // overflow) and then cast to int (which will respect the bits, which
            // is what we want)
            bits[0] = (int) (uint) (mantissa & UInt32Mask);
            mantissa >>= 32;
            bits[1] = (int) (uint) (mantissa & UInt32Mask);
            mantissa >>= 32;
            bits[2] = (int) (uint) (mantissa & UInt32Mask);

            return new decimal(bits);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Check(6.000m);
            Check(6000m);
            Check(6m);
            Check(60.00m);
            Check(12345.00100m);
            Check(-100.00m);
        }

        static void Check(decimal d)
        {
            Console.WriteLine("Before: {0}  -  after: {1}", d, d.Normalize());
        }
    }
}
6 голосов
/ 09 января 2013

Это удалит все завершающие нули из десятичной дроби, а затем вы можете просто использовать ToString().

public static class DecimalExtensions
{
    public static Decimal Normalize(this Decimal value)
    {
        return value / 1.000000000000000000000000000000000m;
    }
}

Или, в качестве альтернативы, если вам нужна точная величина точности, скажем 5 десятичных знаков, сначала Normalize (), а затем умножьте на 1,00000 м.

4 голосов
/ 29 ноября 2010

Если вам нужно сделать это только для отображения, то как насчет использования строки пользовательского формата?

// decimal has 28/29 significant digits so 30 "#" symbols should be plenty
public static readonly string TrimmedDecimal = "0." + new string('#', 30);

// ...

decimal x = 1.132000m;
Console.WriteLine(x.ToString() + " - " + x.ToString(TrimmedDecimal));  // 1.132

decimal y = 6.000000m;
Console.WriteLine(y.ToString() + " - " + y.ToString(TrimmedDecimal));  // 6
4 голосов
/ 28 ноября 2010

Это соответствует приведенному примеру, но Плохо.(Я ДУМАЮ)

myDecimal.ToString("#.######") 

Какие еще требования существуют?Собираетесь ли вы манипулировать значениями и показывать манипулируемые значения с этим количеством десятичных дробей?

Альтернативный ответ включает в себя рекурсивность, например так:

  //use like so:
  myTextbox.Text = RemoveTrailingZeroes( myDecimal.ToString() );

private string RemoveTrailingZeroes(string input) {
  if ( input.Contains( "." ) && input.Substring( input.Length - 1 ) == "0" ) { //test the last character == "0"
    return RemoveTrailingZeroes( input.Substring( 0, input.Length - 2 ) ) 
    //drop the last character and recurse again
  }
  return input; //else return the original string
}

А если вам нужен метод расширения, тогдаэто опция

  //use like so:
  myTextbox.Text = myDecimal.ToString().RemoveTrailingZeroes();

private string RemoveTrailingZeroes(this string input) {
  if ( input.Contains( "." ) &&  input.Substring( input.Length - 1 ) == "0" ) { //test the last character == "0"
    return RemoveTrailingZeroes( input.Substring( 0, input.Length - 2 ) ) 
    //drop the last character and recurse again
  }
  return input; //else return the original string
}

Добавлено input.Contains( "." ) && за комментарий от Джона Скита, но имейте в виду, что это сделает это невероятно медленным.Если вы знаете, что у вас всегда будет десятичный знак, а не регистр, такой как myDecimal = 6000;, тогда вы можете отказаться от этого теста, или вы можете превратить его в класс и иметь несколько закрытых методов, основанных на том, содержит ли ввод десятичное число и т. Д.собирался для самого простого и "это работает" вместо Enterprise FizzBuzz

1 голос
/ 05 апреля 2012

А как насчет использования toString ("G29") для вашего десятичного числа? это именно то, что вы пытаетесь достичь!

...