代码之家  ›  专栏  ›  技术社区  ›  Prix Winteroo

解析小数并在右边过滤多余的0?

  •  15
  • Prix Winteroo  · 技术社区  · 15 年前

    从一个XML文件中,我接收到以下格式的小数:

    1.132000
    6.000000
    

    当前我使用的是十进制。按如下方式分析:

    decimal myDecimal = Decimal.Parse(node.Element("myElementName").Value, System.Globalization.CultureInfo.InvariantCulture);
    
    • 如何将mydecimal打印到字符串 如下所示?

      1.132
      6
      
    5 回复  |  直到 13 年前
        1
  •  30
  •   Jon Skeet    15 年前

    我不认为有任何标准的数字格式字符串会总是忽略后面不重要的零,我担心。

    您可以尝试编写自己的十进制规范化方法,但这可能非常棘手。与 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());
            }
        }
    }
    
        2
  •  6
  •   shamp00    13 年前

    这将从小数中删除所有尾随的零,然后您只需使用 ToString() .

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

    或者,如果需要精确的精度,比如说5个小数位,首先是normalize(),然后乘以1.00000m。

        3
  •  4
  •   jcolebrand    15 年前

    这符合给出的示例,但效果不佳。(我认为)

    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

        4
  •  4
  •   LukeH    15 年前

    如果您只需要对显示进行此操作,那么使用自定义格式字符串如何?

    // 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
    
        5
  •  1
  •   Brann    14 年前

    用什么呢 ToScript(“G29”) 在你的小数点上? 这正是你想要达到的目标!