2

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

但实际的问题是如何从头开始实现截断,用户将能够指定要保留多少位数字?将一个数字乘以 100 然后除以相同的数量就足够了吗?还是有更好的实现方式?

就像是:

Truncate(12.3456789, 3);
// returns 12.345
4

5 回答 5

2

您可能想查看 IEEE 浮点整数。

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

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

至于“为什么”:我不知道,尽管共享源 CLI可能会提供线索。我的猜测是这可能是因为性能优化。

于 2012-07-02T14:50:06.513 回答
2

经典方式:

var x = 1.2345678;
var tr = 4;

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

将给出 1.2345;

于 2012-07-02T14:51:20.217 回答
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 然后除以相同的数量就足够了吗?

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

于 2012-07-02T14:56:35.873 回答
0
var result = Math.Round(12.3456789, 3);

Math.Round 方法 (Double, Int32)

于 2012-07-02T14:39:37.113 回答
-1

目前尚不清楚您认为 Truncate 应该保留十进制值的原因。

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

d的整数部分;也就是说,在任何小数位被丢弃后剩余的数字。

似乎您想要使用的是格式化双精度/十进制值的输出字符串和/或改用 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方法来保留数字的十进制值,而默认的内置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) { return Decimal.Floor(d); }

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

于 2012-07-02T14:45:01.197 回答