如何在C#中实现健壮的truncate方法?

时间:2012-07-02 14:33:46

标签: c# .net math truncate

我知道.NET有一个内置但是它是一个外部调用。谁知道为什么?

但实际的问题是如何从头开始实现截断,用户可以指定要保留多少位数?将数字乘以100表示​​然后再除以相同的数量?或者是否有更好的实施?

类似的东西:

Truncate(12.3456789, 3);
// returns 12.345

5 个答案:

答案 0 :(得分:2)

您可能希望查看IEEE浮点整数。

然后,您可以使用unsafe代码修改数字,例如:

unsafe
{
    double* pValue = &value;
    var asLong = *(long*)pValue;
    do whatever you want with asLong, e.g. bit-masking it, etc.; 
}

关于'为什么':我不知道,虽然Shared Source CLI可能提供线索。我的猜测可能是因为性能优化。

答案 1 :(得分:2)

经典方式:

var x = 1.2345678;
var tr = 4;

var truncated = (int) (x * Math.Pow(10, tr)) / Math.Pow(10, tr);

会给出1.2345;

答案 2 :(得分:1)

我将如何做到这一点。在C ++中,我认为在C#中,您可以通过将其转换为整数类型来获取浮点数的整数部分。

double Truncate (double num, int dig)
{
    if (dig > 15) dig = 15; // Don't overflow
    long p = Math.Pow (10, dig);

    // Save the integer part, so that we don't overflow
    long integer_part = (long)num;

    // Fractional part * 10^dig
    double frac = (num - Convert.ToDouble(integer_part)) * p;
    long frac_trunc = (long)frac;

    // Final result
    double result = Convert.ToDouble(integer_part) + (Convert.ToDouble(frac_trunc) / p);
    return result;
}
  

将数字乘以100表示​​然后将其除以相同值   金额够吗?

这应该可行,但要小心,因为大数字或大量数字,你很容易溢出,它会给你奇怪的结果。

答案 3 :(得分:0)

var result = Math.Round(12.3456789, 3);

Math.Round Method (Double, Int32)

答案 4 :(得分:-1)

您认为Truncate应保留decmial值的原因尚不清楚。

.NET中的默认方法由以下语句描述:

  

d的组成部分;也就是说,任何之后剩下的数字   小数位已被丢弃。

看起来你想要使用的是格式化double / decmial值的输出字符串和/或使用Math.Round(double,int)函数。

你可以使用:

double num = 2.22939393; num  = Convert.ToDouble(num.ToString("#0.000")); 

从其中一个重复的问题:

public static decimal TruncateToDecimalPlace(this decimal numberToTruncate, int decimalPlaces) 
{     
       decimal power = (decimal)(Math.Pow(10.0, (double)decimalPlaces));      
       return Math.Truncate((power * numberToTruncate)) / power; 
} 

我知道这仍然使用Truncate方法。我之前只提供了此代码,因为您需要Truncate方法来保留数字的decmial值,而默认的内置Truncate方法则不会。

你总是可以使用它:

Math.Round不会从我能说出的内容中调用SplitFractionDouble

     private static unsafe double InternalRound(double value, int digits, MidpointRounding mode) {
            if (Abs(value) < doubleRoundLimit) {
                Double power10 = roundPower10Double[digits];
                value *= power10;
                if (mode == MidpointRounding.AwayFromZero) {                
                    double fraction = SplitFractionDouble(&value); 
                    if (Abs(fraction) >= 0.5d) {
                        value += Sign(fraction);
                    }
                }
                else {
                    // On X86 this can be inlined to just a few instructions
                    value = Round(value);
                }
                value /= power10;
            }
            return value;
          }           


     public static double Round(double value, int digits)
      {
           if ((digits < 0) || (digits > maxRoundingDigits))
               throw new ArgumentOutOfRangeException("digits", Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits"));
           return InternalRound(value, digits, MidpointRounding.ToEven);                     
      }

  public static double Round(double value, MidpointRounding mode) {
         return Round(value, 0, mode);
      }

      public static double Round(double value, int digits, MidpointRounding mode) {
          if ((digits < 0) || (digits > maxRoundingDigits))
              throw new ArgumentOutOfRangeException("digits", Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits"));
          if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) {            
              throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", mode, "MidpointRounding"), "mode");
          }
          return InternalRound(value, digits, mode);                           
      }

      public static Decimal Round(Decimal d) {
        return Decimal.Round(d,0);
      }

      public static Decimal Round(Decimal d, int decimals) {
        return Decimal.Round(d,decimals);
      }

      public static Decimal Round(Decimal d, MidpointRounding mode) {
        return Decimal.Round(d, 0, mode);
      }

      public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) {
        return Decimal.Round(d, decimals, mode);
      }


public static Decimal Floor(Decimal d){     返回Decimal.Floor(d);   }

[MethodImplAttribute(MethodImplOptions.InternalCall)]   public static extern double Floor(double d);