C# 截断小数点后两位而不舍入

C# 截断小数点后两位而不舍入,c#,math,rounding,C#,Math,Rounding,假设我有一个3.4679的值,想要3.46,我怎么能在不进行四舍五入的情况下截断到小数点后两位呢 我尝试过以下方法,但三种方法都给出了3.47: void Main() { Console.Write(Math.Round(3.4679, 2,MidpointRounding.ToEven)); Console.Write(Math.Round(3.4679, 2,MidpointRounding.AwayFromZero)); Console.Write(Math.Ro

假设我有一个3.4679的值,想要3.46,我怎么能在不进行四舍五入的情况下截断到小数点后两位呢

我尝试过以下方法,但三种方法都给出了3.47:

void Main()
{
    Console.Write(Math.Round(3.4679, 2,MidpointRounding.ToEven));
    Console.Write(Math.Round(3.4679, 2,MidpointRounding.AwayFromZero));
    Console.Write(Math.Round(3.4679, 2));
}
这将返回3.46,但似乎有些脏:

void Main()
{
    Console.Write(Math.Round(3.46799999999 -.005 , 2));
}

请注意,像这样的分数不能用浮点精确表示。

这对您有用吗

Console.Write(((int)(3.4679999999*100))/100.0);

long3.4679*100/100.0能满足您的需要吗?

对于实际使用C语言截断小数点更有用。如果您需要,可以很容易地将其转换为小数点扩展方法:

public decimal TruncateDecimal(decimal value, int precision)
{
    decimal step = (decimal)Math.Pow(10, precision);
    decimal tmp = Math.Truncate(step * value);
    return tmp / step;
}
如果需要VB.NET,请尝试以下操作:

Function TruncateDecimal(value As Decimal, precision As Integer) As Decimal
    Dim stepper As Decimal = Math.Pow(10, precision)
    Dim tmp As Decimal = Math.Truncate(stepper * value)
    Return tmp / stepper
End Function
然后像这样使用它:

decimal result = TruncateDecimal(0.275, 2);


其他示例的一个问题是,它们将输入值相乘后再除以。这里有一个边缘情况,你们可以通过先相乘来溢出小数,一个边缘情况,但我遇到了一些问题。按如下方式单独处理分数部分更安全:

    public static decimal TruncateDecimal(this decimal value, int decimalPlaces)
    {
        decimal integralValue = Math.Truncate(value);

        decimal fraction = value - integralValue;

        decimal factor = (decimal)Math.Pow(10, decimalPlaces);

        decimal truncatedFraction = Math.Truncate(fraction * factor) / factor;

        decimal result = integralValue + truncatedFraction;

        return result;
    }

如果您不太担心性能,并且最终结果可能是一个字符串,那么以下方法将有助于解决浮点精度问题:

string Truncate(double value, int precision)
{
    if (precision < 0)
    {
        throw new ArgumentOutOfRangeException("Precision cannot be less than zero");
    }

    string result = value.ToString();

    int dot = result.IndexOf('.');
    if (dot < 0)
    {
        return result;
    }

    int newLength = dot + precision + 1;

    if (newLength == dot + 1)
    {
        newLength--;
    }

    if (newLength > result.Length)
    {
        newLength = result.Length;
    }

    return result.Substring(0, newLength);
}

使用模数运算符:

var fourPlaces = 0.5485M;
var twoPlaces = fourPlaces - (fourPlaces % 0.01M);

结果:0.54

我将保留十进制数的解

如果我们传递一个非常大的十进制数,并且该方法将尝试将其相乘,那么这里的一些十进制解很容易溢出

Tim Lloyd的解决方案可以防止溢出,但不会太快

以下解决方案的速度约为原来的2倍,并且没有溢出问题:

public static class DecimalExtensions
{
    public static decimal TruncateEx(this decimal value, int decimalPlaces)
    {
        if (decimalPlaces < 0)
            throw new ArgumentException("decimalPlaces must be greater than or equal to 0.");

        var modifier = Convert.ToDecimal(0.5 / Math.Pow(10, decimalPlaces));
        return Math.Round(value >= 0 ? value - modifier : value + modifier, decimalPlaces);
    }
}

[Test]
public void FastDecimalTruncateTest()
{
    Assert.AreEqual(-1.12m, -1.129m. TruncateEx(2));
    Assert.AreEqual(-1.12m, -1.120m. TruncateEx(2));
    Assert.AreEqual(-1.12m, -1.125m. TruncateEx(2));
    Assert.AreEqual(-1.12m, -1.1255m.TruncateEx(2));
    Assert.AreEqual(-1.12m, -1.1254m.TruncateEx(2));
    Assert.AreEqual(0m,      0.0001m.TruncateEx(3));
    Assert.AreEqual(0m,     -0.0001m.TruncateEx(3));
    Assert.AreEqual(0m,     -0.0000m.TruncateEx(3));
    Assert.AreEqual(0m,      0.0000m.TruncateEx(3));
    Assert.AreEqual(1.1m,    1.12m.  TruncateEx(1));
    Assert.AreEqual(1.1m,    1.15m.  TruncateEx(1));
    Assert.AreEqual(1.1m,    1.19m.  TruncateEx(1));
    Assert.AreEqual(1.1m,    1.111m. TruncateEx(1));
    Assert.AreEqual(1.1m,    1.199m. TruncateEx(1));
    Assert.AreEqual(1.2m,    1.2m.   TruncateEx(1));
    Assert.AreEqual(0.1m,    0.14m.  TruncateEx(1));
    Assert.AreEqual(0,      -0.05m.  TruncateEx(1));
    Assert.AreEqual(0,      -0.049m. TruncateEx(1));
    Assert.AreEqual(0,      -0.051m. TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.14m.  TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.15m.  TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.16m.  TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.19m.  TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.199m. TruncateEx(1));
    Assert.AreEqual(-0.1m,  -0.101m. TruncateEx(1));
    Assert.AreEqual(0m,     -0.099m. TruncateEx(1));
    Assert.AreEqual(0m,     -0.001m. TruncateEx(1));
    Assert.AreEqual(1m,      1.99m.  TruncateEx(0));
    Assert.AreEqual(1m,      1.01m.  TruncateEx(0));
    Assert.AreEqual(-1m,    -1.99m.  TruncateEx(0));
    Assert.AreEqual(-1m,    -1.01m.  TruncateEx(0));
}

下面是我对TRUNC函数的实现

private static object Tranc(List<Expression.Expression> p)
{
    var target = (decimal)p[0].Evaluate();

    // check if formula contains only one argument
    var digits = p.Count > 1
        ? (decimal) p[1].Evaluate()
        : 0;

    return Math.Truncate((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits);
}

下面是一个扩展方法:

public static decimal? TruncateDecimalPlaces(this decimal? value, int places)
    {
        if (value == null)
        {
            return null;
        }

        return Math.Floor((decimal)value * (decimal)Math.Pow(10, places)) / (decimal)Math.Pow(10, places);

    } // end

实际上你想要3.46和3.4679。 这只是字符的表示。因此与数学函数无关。数学函数不打算做这项工作。 只需使用以下代码

Dim str1 As String
str1=""
str1 ="3.4679" 
  Dim substring As String = str1.Substring(0, 3)

    ' Write the results to the screen.
    Console.WriteLine("Substring: {0}", substring)

Or 
    Please use the following code.
Public function result(ByVal x1 As Double) As String 
  Dim i as  Int32
  i=0
  Dim y as String
  y = ""
  For Each ch as Char In x1.ToString
    If i>3 then
     Exit For
    Else
    y + y +ch
    End if
    i=i+1
  Next
  return y
End Function
上面的代码可以修改为任何数字放在下面 按钮单击事件中的代码

这个怎么样

Function TruncateDecimal2(MyValue As Decimal) As Decimal
        Try
            Return Math.Truncate(100 * MyValue) / 100
        Catch ex As Exception
            Return Math.Round(MyValue, 2)
        End Try
End Function

除了上述解决方案之外,我们还有另一种方法可以实现

    decimal val=23.5678m,finalValue;

    //take the decimal part    
     int decimalPos = val.ToString().IndexOf('.');
     string decimalPart = val.ToString().Substring(decimalPosition+1,val.ToString().Length);
    //will result.56
   string wholePart=val.ToString().Substring(0,decimalPos-1);
   //concantinate and parse for decimal.
  string truncatedValue=wholePart+decimalPart;//"23.56"
  bool isDecimal=Decimal.tryParse(truncatedValue,out finalValue);//finalValue=23.56

无需数学运算的通用快速方法。系统功率/乘法。十进制:


在某些情况下,这可能就足够了

我的十进制值是 SubCent=0.009999999999999999999m,倾向于通过字符串格式化为| SubCent:0.010000 |格式{0:N6},SubCent;以及许多其他格式选择

我的要求不是对SubCent值进行四舍五入,也不是记录每个数字

以下各项符合我的要求:

string.Format("SubCent:{0}|", 
    SubCent.ToString("N10", CultureInfo.InvariantCulture).Substring(0, 9));
返回字符串:|子部分:0.0099999|

为了适应具有整数部分的值,以下是一个开始

tmpValFmt = 567890.0099999933999229999999M.ToString("0.0000000000000000000000000000");
decPt = tmpValFmt.LastIndexOf(".");
if (decPt < 0) decPt = 0;
valFmt4 = string.Format("{0}", tmpValFmt.Substring(0, decPt + 9));

我使用此函数截断字符串变量中小数点后的值

public static string TruncateFunction(string value)
    {
        if (string.IsNullOrEmpty(value)) return "";
        else
        {
            string[] split = value.Split('.');
            if (split.Length > 0)
            {
                string predecimal = split[0];
                string postdecimal = split[1];
                postdecimal = postdecimal.Length > 6 ? postdecimal.Substring(0, 6) : postdecimal;
                return predecimal + "." + postdecimal;

            }
            else return value;
        }
    }

这是一个古老的问题,但许多Anwser的性能不好,或者对于大数字来说性能不好。我认为D.内斯特罗夫的答案是最好的:健壮、简单、快速。我只想加上我的两分钱。 我和他一起玩过,还看了一下。从公共十进制整数lo,mid,hi,bool为负,字节刻度

十进制数的二进制表示法由1位组成 符号、96位整数和用于分割 整数,并指定其小数部分。 比例因子隐式地是提升为指数的数字10 从0到28

知道了这一点,我的第一个方法是创建另一个小数,其小数位数对应于我想要丢弃的小数位数,然后截断它,最后创建一个具有所需小数位数的小数位数

private const int ScaleMask = 0x00FF0000;
    public static Decimal Truncate(decimal target, byte decimalPlaces)
    {
        var bits = Decimal.GetBits(target);
        var scale = (byte)((bits[3] & (ScaleMask)) >> 16);

        if (scale <= decimalPlaces)
            return target;

        var temporalDecimal = new Decimal(bits[0], bits[1], bits[2], target < 0, (byte)(scale - decimalPlaces));
        temporalDecimal = Math.Truncate(temporalDecimal);

        bits = Decimal.GetBits(temporalDecimal);
        return new Decimal(bits[0], bits[1], bits[2], target < 0, decimalPlaces);
    }
我没有进行过严格的性能测试,但在MacOS Sierra 10.12.6、3.06 GHz Intel Core i3处理器和targeting上进行了测试。NetCore 2.1这种方法似乎比D.Nesterov的要快得多。我不会给出数字,因为正如我提到的,我的测试并不严格。这取决于实现这一点的人来评估性能的提高是否会对增加的代码复杂性产生回报。

这就是我所做的:

        c1 = a1 - b1;
        d1 = Math.Ceiling(c1 * 100) / 100;
减去两个输入的数字,但不向上或向下舍入小数。 因为其他解决方案对我不起作用。 不知道它是否适用于其他人,我只想与大家分享: 希望它对那些正在寻找类似于我的问题的解决方案的人有效。谢谢

附:我是初学者,所以请随意指出这方面的内容D 这是好的,如果你真的在处理钱,因为美分的原因,对吗?它只有两个小数位,四舍五入是一个数字。

怎么样

var i = Math.Truncate(number);

var r = i + Math.Truncate((number - i) * 100) / 100;
我最喜欢的是

var myvalue = 54.301012345;
var valueiwant = myvalue.toString("0.00");
//result => "54.30"

//additional
var valueiwant2 = myvalue.toString("0.##");
//result => "54.3" // without zero

在.NETCore3.1及更高版本的Math.Round和Decimal.Round中,可以通过新模式截断数字

这些线路:

Console.WriteLine(Math.Round(3.4679, 2,MidpointRounding.ToNegativeInfinity));
Console.WriteLine(Math.Round(3.9999, 2,MidpointRounding.ToNegativeInfinity));
制作:

3.46
3.99
要处理负数,应使用中点舍入.ToPositiveInfinity

可以使用一种方法处理正数和负数:

public static Truncate(Decimal d,int decimals)
{
    var mode=d>0
       ? MidpointRounding.ToNegativeInfinity 
       : MidpointRounding.ToPositiveInfinity);
    return Math.Round(d,decimals,mode);
}

public static Truncate(Double d,int decimals)
{
    var mode=d>0
       ? MidpointRounding.ToNegativeInfinity 
       : MidpointRounding.ToPositiveInfinity);
    return Math.Round(d,decimals,mode);
}


用十进制表示你的值,这个答案就行了。它不可能总是在任何浮动中工作

ng点表示法。这让我想知道是否可以在浮点文本中指定舍入方向。嗯,必须有某种方法告诉程序员,假设一个数字可以存储308个以上的数字进行计算是非常不合适的。双人间只能储存15个。溢出是这里的一个非常重要的功能,溢出相当严重。对不起,我以为值是十进制的。实际上,硬编码“.”不是一个好主意,最好使用System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]我知道这很旧,但我注意到了这一点,并提出了问题。这里的因子是一个int,因此,如果要截断到大量的小数点,比如说25位,则会导致最终结果出现精度错误。我通过将因子类型更改为decimal来修复它。@TheKingDave:可能这不相关,但因为因子不能有小数,所以应该更好地对其进行建模,对吗?@SoMoS For me decimal工作得更好,因为它为因子提供了最高的存储值。它仍然有一个限制,但它对于我的应用程序来说已经足够大了。另一方面,Long无法为我的应用程序存储足够大的数字。例如,如果使用long执行截断25,则会出现一些不准确的情况。根据@TheKingDave的建议,更新以允许截断到更多的位置,谢谢。这将导致大量数字溢出。要添加到night coder,在函数中使用Int32作为中介的事实将导致溢出。如果确实必须将其强制转换为整数,则应使用Int64。问题是,既然Truncate返回十进制积分,为什么还要产生额外的开销呢。只需执行以下操作:decimalstep=decimalMath.Pow10,精度;返回Math.Truncatestep*值/步长;我把演员阵容改为整数。为了更好的可读性和对函数如何工作的理解,我把它们分开了几行。我不喜欢给它加后缀Ex。C支持重载,您的Truncate方法将与.net本机方法组合在一起,为用户提供无缝体验。您的算法会导致一些不正确的结果。默认中点舍入模式为银行家舍入,将0.5舍入为最接近的偶数值。Assert.AreEqual1.1m,1.12m.TruncateEx1;因此失败。如果在Math.Round调用中指定从零开始的正常舍入,则Assert.AreEqual0m,0m.TruncateEx1;失败此解决方案唯一有效的方法是使用MidpointRounding.AwayFromZero并专门编码来处理值0。Jon是正确的:除非显式处理0,否则0m.TruncateEx0将导致-1。同样,除非在Math.Round中使用middpointrounding.AwayFromZero,否则-11m.TruncateEx0将导致-10。虽然这些修改似乎效果很好。即使对AwayFromZero进行了更改,并显式处理了0,-9999999999999999999999999999m.TruncateEx0的结果是-999999999999999999999999998,因此在某些情况下仍然容易出错。我在其他答案中提到的所有测试中都使用了该选项,并且效果非常好。很惊讶它没有更多的选票。值得注意的是,小数只能在0到28之间,对大多数人来说可能还可以。我支持这一点。这是最好的答案+1好答案,这就是我所说的开箱思考好答案。这也适用于双精度数据类型,如果我能够硬编码新小数1、0、0、false、小数的值;我必须如何调用此方法?var truncated=截断的CIMALNumber,bytedecimalPlaces;其中,decimalNumber是decimal类型,decimalPlaces是int类型。这是否正确?虽然这段代码可能会回答这个问题,但提供有关如何和/或为什么解决问题的附加上下文将提高答案的长期价值。我不理解read:没有花时间验证所有其他奇特的解决方案,这正是我想要的。非常感谢。在.NETFiddle上运行此命令可生成0.5400。。。下面给出了预期的0.54。你知道,@ttugates,0.54和0.5400是完全相同的值,对吗?不管后面跟多少个零,除非/直到格式化显示时,如果格式化正确,结果是一样的:${0.54m:C}产生$0.54,是的,${0.5400m:C}产生$0.54。这是一个有点懒惰的答案,它应该被更新,以实际显示您将值返回到小数点后两位,正如本代码所指出的那样,这是不允许的。如果我们看的是完整性和迂腐,我就是,这只是一个部分答案,尽管它确实回答了删除舍入部分的问题,但从技术上讲,它并不完整。我喜欢这个答案。简单但效果很好,因为所有的想法和努力,我不得不投票。你把内斯特罗夫的作为一个基准,并不断地脱帽致敬。
        c1 = a1 - b1;
        d1 = Math.Ceiling(c1 * 100) / 100;
var i = Math.Truncate(number);

var r = i + Math.Truncate((number - i) * 100) / 100;
        public static void ReminderDigints(decimal? number, out decimal? Value,  out decimal? Reminder)
        {
            Reminder = null;
            Value = null;
            if (number.HasValue)
            {
                Value = Math.Floor(number.Value);
                Reminder = (number - Math.Truncate(number.Value));
            }
        }



        decimal? number= 50.55m;             
        ReminderDigints(number, out decimal? Value, out decimal? Reminder);
public static decimal TruncateDecimalPlaces(this decimal value, int precision)
    {
        try
        {
            step = (decimal)Math.Pow(10, precision);
            decimal tmp = Math.Truncate(step * value);
            return tmp / step;
        }
        catch (OverflowException)
        {
            step = (decimal)Math.Pow(10, -1 * precision);
            return value - (value % step);
        }
    }
var myvalue = 54.301012345;
var valueiwant = myvalue.toString("0.00");
//result => "54.30"

//additional
var valueiwant2 = myvalue.toString("0.##");
//result => "54.3" // without zero
Console.WriteLine(Math.Round(3.4679, 2,MidpointRounding.ToNegativeInfinity));
Console.WriteLine(Math.Round(3.9999, 2,MidpointRounding.ToNegativeInfinity));
3.46
3.99
public static Truncate(Decimal d,int decimals)
{
    var mode=d>0
       ? MidpointRounding.ToNegativeInfinity 
       : MidpointRounding.ToPositiveInfinity);
    return Math.Round(d,decimals,mode);
}

public static Truncate(Double d,int decimals)
{
    var mode=d>0
       ? MidpointRounding.ToNegativeInfinity 
       : MidpointRounding.ToPositiveInfinity);
    return Math.Round(d,decimals,mode);
}