148

Lets say I have a value of 3.4679 and want 3.46, how can I truncate to two decimal places that without rounding up?

I have tried the following but all three give me 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));
}

This returns 3.46, but just seems dirty some how:

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

25 Answers25

202
value = Math.Truncate(100 * value) / 100;

Beware that fractions like these cannot be accurately represented in floating point.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 14
    Use decimal for your values and this answer will work. It is unlikely to always work in any floating point representation. – driis Jun 29 '10 at 18:39
  • 2
    That makes me wonder whether it should be possible to specify rounding direction in floating point literals. Hmmmm. –  Jun 29 '10 at 18:53
  • In this case will not work, Math.Truncate(100 * -100.999) / 100; Result -101 – Diogo Cid Sep 01 '23 at 15:21
65

It would be more useful to have a full function for real-world usage of truncating a decimal in C#. This could be converted to a Decimal extension method pretty easy if you wanted:

public decimal TruncateDecimal(decimal value, int precision)
{
    decimal step = (decimal)Math.Pow(10, precision);
    decimal tmp = Math.Truncate(step * value);
    return tmp / step;
}

If you need VB.NET try this:

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

Then use it like so:

decimal result = TruncateDecimal(0.275, 2);

or

Dim result As Decimal = TruncateDecimal(0.275, 2)
Corgalore
  • 2,486
  • 2
  • 23
  • 32
  • 5
    This will overflow on large numbers. – nightcoder May 16 '16 at 23:58
  • 1
    To add to night coder, the fact that you are using Int32 as intermediary in your function will cause overflows. You should use Int64 if you really must cast it to an Integer. The question would be why you would want to incur that extra overhead anyway since Truncate returns Decimal integrals anyway. Just do something like: decimal step = (decimal)Math.Pow(10, precision); return Math.Truncate(step * value) / step; – Sarel Esterhuizen Apr 16 '17 at 07:36
  • I dropped the cast to Integer. I left them separate lines for better readability and understanding of how the function works. – Corgalore Apr 24 '17 at 16:22
62

Universal and fast method (without Math.Pow() / multiplication) for System.Decimal:

decimal Truncate(decimal d, byte decimals)
{
    decimal r = Math.Round(d, decimals);

    if (d > 0 && r > d)
    {
        return r - new decimal(1, 0, 0, false, decimals);
    }
    else if (d < 0 && r < d)
    {
        return r + new decimal(1, 0, 0, false, decimals);
    }

    return r;
}
D. Nesterov
  • 916
  • 6
  • 6
  • 6
    I ran this through all of the tests mentioned in the other answers and it works perfectly. Surprised it doesn't have more upvotes. It is worth noting that decimals can only be between 0 and 28 (Probably OK for most people). – RichardOD Mar 22 '18 at 11:45
  • 1
    I second that. This is the best answer. +1 – Branko Dimitrijevic Jul 16 '18 at 07:36
  • 1
    Great answer, that's what i call "think outside of the box" – bruno.almeida Sep 13 '19 at 09:25
  • Good answer. This works with double data type too, if i am able to hard code the value for "new decimal(1, 0, 0, false, decimals)" ;) – Deepak Oct 14 '20 at 07:13
  • How do I have to call this method? var truncated = Truncate(decimalNumber, (byte)decimalPlaces); where decimalNumber is of type decimal and decimalPlaces is of type int. Is this correct? – thomasgalliker Dec 03 '20 at 10:24
  • @thomasgalliker it depends on how you implement it, but if you just leave it as its own method instead of an extension method then yes, that's fine. – Propagating Jan 17 '21 at 08:44
  • From some very basic benchmarking this is ~35% faster than methods using Math.Pow and division. 1.119 seconds to do 10,000,000 truncations using Math.Pow vs 0.707 seconds using this method. – Propagating Jan 17 '21 at 08:47
  • i like this one also :D – princessbubbles15 Mar 07 '21 at 04:18
41

Use the modulus operator:

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

result: 0.54

Leonard Lewis
  • 503
  • 5
  • 6
  • 2
    I don't understand (read: didn't spend the time to verify) all these other fancy solutions, this does _exactly_ what I was looking for. Thank you! – Isaac Baker Jul 01 '19 at 20:12
  • 1
    Running this on .Net Fiddle [clicky](https://dotnetfiddle.net/9bPCvK) produces `0.5400`... The [answer by D. Nesterov](https://stackoverflow.com/questions/3143657/truncate-two-decimal-places-without-rounding#answer-43639947) below produced the expected `0.54`. – ttugates Aug 13 '20 at 21:11
  • 1
    You do realize, @ttugates , that 0.54 and 0.5400 are exactly the same value, right? It doesn't matter how many zeros follow unless/until it comes time to format for display—in which case, the result will be the same if formatted properly: `$"{0.54m:C}"` produces `"$0.54"` and yes, `$"{0.5400m:C}"` produces `"$0.54"`. – Leonard Lewis Aug 15 '20 at 04:05
  • This is a bit of a lazy answer, it should be updated to actually show you returning the value to two decimal places which as pointed out this code doesn't do. If we are looking at completeness and being pedantic, which well I am, this is only a partial answer granted it does answer the issue of removing the rounding component but again, not technically complete. – JoeTomks Feb 25 '21 at 16:08
  • i like this answer. simple but works very well – princessbubbles15 Mar 07 '21 at 04:17
  • 1
    Thank you @LeonardLewis for this simple answer. I just modified it a bit by wrapping it up in Math.Round() to trim off the extra 0's. – AK3800 Jul 11 '22 at 13:16
25

One issue with the other examples is they multiply the input value before dividing it. There is an edge case here that you can overflow decimal by multiplying first, an edge case, but something I have come across. It's safer to deal with the fractional part separately as follows:

    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;
    }
Tim Lloyd
  • 37,954
  • 10
  • 100
  • 130
  • I know this is old but I noticed and issue with this. The factor you have here is an int and so if you are truncating to a large number of decimal places (say 25) it will cause the end result to have precision error. I fixed it by changing the factor type to decimal. – TheKingDave Aug 19 '13 at 14:34
  • @TheKingDave: probably it's irrelevant but as factor cannot have decimals should be better to model it as long right? – Ignacio Soler Garcia Sep 23 '13 at 09:09
  • @SoMoS For me Decimal worked better because it gave me the highest storage values for factor. It still has a limitation but it is big enough for my application. Long on the other hand wasn't able to store large enough numbers for my application. For example if you do a Truncate(25) with long then there will be some inaccuracy. – TheKingDave Sep 23 '13 at 09:29
  • Updated to allow truncation to a greater number of places as per @TheKingDave suggestion, thanks. – Tim Lloyd Sep 23 '13 at 14:58
17

In .NET Core 3.0 and later Math.Round and Decimal.Round can truncate digits through the new MidpointRounding.ToZero. For positive numbers, MidpointRounding.ToNegativeInfinity has the same effect while for negative numbers the equivalent is MidpointRounding.ToPositiveInfinity.

These lines:

Console.WriteLine(Math.Round(3.4679, 2,MidpointRounding.ToZero));
Console.WriteLine(Math.Round(3.9999, 2,MidpointRounding.ToZero));
Console.WriteLine(Math.Round(-3.4679, 2,MidpointRounding.ToZero));
Console.WriteLine(Math.Round(-3.9999, 2,MidpointRounding.ToZero));

Produce :

3.46
3.99
-3.46
-3.99
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • According to the [docs](https://learn.microsoft.com/en-us/dotnet/api/system.midpointrounding?view=net-5.0), there's no need to distinguish between positive and negative with `ToZero`: 2.8 and 2.1 both truncate to 2 with it and for -2.8 and -2.1 the result is -2. – Neph Jul 28 '21 at 10:35
  • Important: You do need .NET 5.0 for this though, with version 4.0 you can only use `AwayFromZero` and `ToEven`. – Neph Jul 28 '21 at 10:42
  • @Neph this is available since .NET Core 3. There never was a .NET Core 4. .NET 5 is .NET *Core* 5. The old .NET Framework stopped at 4.8 – Panagiotis Kanavos Jul 28 '21 at 10:43
  • I'm talking about the "regular" .NET 5.0 release (not sure how it's connected to "Core",...). I mentioned this because Unity 2021 only supports the ".NET Standard 2.0" and ".NET 4.x" C# and `ToZero` or even the other two unfortunately aren't supported. – Neph Jul 28 '21 at 10:51
  • @Neph there's no "regular". .NET 5 is the current version of .NET *Core* 5. The name changed for marketing purposes. It includes almost all of the .NET Old APIs that were going to be migrated to .NET Core, so a decision was made to "unify" the platforms by ... unifying the names – Panagiotis Kanavos Jul 28 '21 at 10:52
  • @Neph check [Introducing .NET 5](https://devblogs.microsoft.com/dotnet/introducing-net-5/). The first line is `Today, we’re announcing that the next release after .NET Core 3.0 will be .NET 5. This will be the next big release in the .NET family.`. The reasoning is explained [in this Github issue](https://github.com/dotnet/core/issues/2883) - no matter what name was used, there would be trouble and confusion. I don't like the new naming either. At least, it's easier to sell a change from `.NET Framewok 4.8` to `.NET 5.0` to non-technical managers – Panagiotis Kanavos Jul 28 '21 at 11:02
  • Their naming system is quite confusing, you're right. Check the "Applies to" section in the docs I linked, all the versions that support `ToZero` are listed there. It's weird, Unity 2021's C# is ".NET Standard 2.0", which is listed but it still doesn't support that enum - I guess they're doing their own thing again and even though there are [plans](https://forum.unity.com/threads/unity-future-net-development-status.1092205/) to update to .NET 6 (they'll skip 5), it might still be a while. – Neph Jul 28 '21 at 11:19
  • @Neph The `Applies To` section applies to the type, not its values. To see what's available in different versions change the version from the `Version` dropdown at the top left. You'll see that the new values aren't available even in `.NET Standard 2.1`. – Panagiotis Kanavos Jul 28 '21 at 11:27
  • error CS0117: 'MidpointRounding' does not contain a definition for 'ToZero' – Jaider Jul 14 '22 at 00:07
  • 1
    @Jaider it does. I actually link to the enum's docs. Last option with a value of 2 is `ToZero`. All the examples in the `MidpointRounding` page use `ToZero`. Did you try to use this in .NET Framework instead of .NET Core perhaps? – Panagiotis Kanavos Jul 14 '22 at 06:10
7

I will leave the solution for decimal numbers.

Some of the solutions for decimals here are prone to overflow (if we pass a very large decimal number and the method will try to multiply it).

Tim Lloyd's solution is protected from overflow but it's not too fast.

The following solution is about 2 times faster and doesn't have an overflow problem:

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));
}
nightcoder
  • 13,149
  • 16
  • 64
  • 72
  • 2
    I don't like suffixing "Ex" to it. C# supports overloadding, your `Truncate` method will be groupped together with .net native ones, giving user a seamless experience. – Gqqnbig Nov 15 '16 at 23:47
  • 1
    Your algorithm results in some incorrect results. The default MidpointRounding mode is Banker's Rounding, which rounds 0.5 to the nearest even value. `Assert.AreEqual(1.1m, 1.12m.TruncateEx(1));` fails because of this. If you specify "normal" rounding (AwayFromZero) in the Math.Round call, then `Assert.AreEqual(0m, 0m.TruncateEx(1));` fails – Jon Senchyna Nov 30 '16 at 20:58
  • 1
    The only way this solution will work is if you use `MidpointRounding.AwayFromZero` and specifically code to handle the value 0. – Jon Senchyna Nov 30 '16 at 21:00
  • "Assert.AreEqual(1.1m, 1.12m.TruncateEx(1)); fails" - What do you mean "fails"? This code has been tested on .NET 4, 4.5.2 & 4.6.1. I use it at work and in my personal projects, and the unit test in my answer is executed every day. And it passes. Am I missing something? Could you provide a screenshot or exception details if my test fails on your machine? – nightcoder Dec 02 '16 at 02:32
  • 1
    Jon is correct: 0m.TruncateEx(0) results in -1 unless 0 is explicitly handled. Likewise -11m.TruncateEx(0) results in -10 unless MidpointRounding.AwayFromZero is used within Math.Round. Seems to work well with those modifications though. – Ho Ho Ho Feb 28 '17 at 18:23
  • 1
    Even with changes for AwayFromZero and explicit handling of 0, -9999999999999999999999999999m.TruncateEx(0) results in -9999999999999999999999999998, so it is still fallible in some cases. – Ho Ho Ho Feb 28 '17 at 18:45
6

This is an old question, but many anwsers don't perform well or overflow for big numbers. I think D. Nesterov answer is the best one: robust, simple and fast. I just want to add my two cents. I played around with decimals and also checked out the source code. From the public Decimal (int lo, int mid, int hi, bool isNegative, byte scale) constructor documentation.

The binary representation of a Decimal number consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the integer number and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10 raised to an exponent ranging from 0 to 28.

Knowing this, my first approach was to create another decimal whose scale corresponds to the decimals that I wanted to discard, then truncate it and finally create a decimal with the desired scale.

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);
    }

This method is not faster than D. Nesterov's and it is more complex, so I played around a little bit more. My guess is that having to create an auxiliar decimal and retrieving the bits twice is making it slower. On my second attempt, I manipulated the components returned by Decimal.GetBits(Decimal d) method myself. The idea is to divide the components by 10 as many times as needed and reduce the scale. The code is based (heavily) on the Decimal.InternalRoundFromZero(ref Decimal d, int decimalCount) method.

private const Int32 MaxInt32Scale = 9;
private const int ScaleMask = 0x00FF0000;
    private const int SignMask = unchecked((int)0x80000000);
    // Fast access for 10^n where n is 0-9        
    private static UInt32[] Powers10 = new UInt32[] {
        1,
        10,
        100,
        1000,
        10000,
        100000,
        1000000,
        10000000,
        100000000,
        1000000000
    };

    public static Decimal Truncate(decimal target, byte decimalPlaces)
    {
        var bits = Decimal.GetBits(target);
        int lo = bits[0];
        int mid = bits[1];
        int hi = bits[2];
        int flags = bits[3];

        var scale = (byte)((flags & (ScaleMask)) >> 16);
        int scaleDifference = scale - decimalPlaces;
        if (scaleDifference <= 0)
            return target;

        // Divide the value by 10^scaleDifference
        UInt32 lastDivisor;
        do
        {
            Int32 diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
            lastDivisor = Powers10[diffChunk];
            InternalDivRemUInt32(ref lo, ref mid, ref hi, lastDivisor);
            scaleDifference -= diffChunk;
        } while (scaleDifference > 0);


        return new Decimal(lo, mid, hi, (flags & SignMask)!=0, decimalPlaces);
    }
    private static UInt32 InternalDivRemUInt32(ref int lo, ref int mid, ref int hi, UInt32 divisor)
    {
        UInt32 remainder = 0;
        UInt64 n;
        if (hi != 0)
        {
            n = ((UInt32)hi);
            hi = (Int32)((UInt32)(n / divisor));
            remainder = (UInt32)(n % divisor);
        }
        if (mid != 0 || remainder != 0)
        {
            n = ((UInt64)remainder << 32) | (UInt32)mid;
            mid = (Int32)((UInt32)(n / divisor));
            remainder = (UInt32)(n % divisor);
        }
        if (lo != 0 || remainder != 0)
        {
            n = ((UInt64)remainder << 32) | (UInt32)lo;
            lo = (Int32)((UInt32)(n / divisor));
            remainder = (UInt32)(n % divisor);
        }
        return remainder;
    }

I haven't performed rigorous performance tests, but on a MacOS Sierra 10.12.6, 3,06 GHz Intel Core i3 processor and targeting .NetCore 2.1 this method seems to be much faster than D. Nesterov's (I won't give numbers since, as I have mentioned, my tests are not rigorous). It is up to whoever implements this to evaluate whether or not the performance gains pay off for the added code complexity.

Monticola Explorator
  • 1,188
  • 13
  • 20
3

Would ((long)(3.4679 * 100)) / 100.0 give what you want?

Frank
  • 2,628
  • 15
  • 14
2

would this work for you?

Console.Write(((int)(3.4679999999*100))/100.0);
John Boker
  • 82,559
  • 17
  • 97
  • 130
1

If you don't worry too much about performance and your end result can be a string, the following approach will be resilient to floating precision issues:

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);
}
David Airapetyan
  • 5,301
  • 4
  • 40
  • 62
  • 6
    Actually, hardcoding '.' is not a good idea, better use System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0] – David Airapetyan Aug 05 '13 at 19:48
1

Here is an extension method:

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
John Meyer
  • 2,296
  • 1
  • 31
  • 39
0

Here is my implementation of TRUNC function

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);
}
ladeangel
  • 211
  • 3
  • 5
0

what about this?

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
user2241289
  • 345
  • 2
  • 13
0

Apart from the above solutions,there is another way we can achieve .

    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
Hameed Syed
  • 3,939
  • 2
  • 21
  • 31
0

Under some conditions this may suffice.

I had a decimal value of SubCent = 0.0099999999999999999999999999M that tends to format to |SubCent:0.010000| via string.Format("{0:N6}", SubCent ); and many other formatting choices.

My requirement was not to round the SubCent value, but not log every digit either.

The following met my requirement:

string.Format("SubCent:{0}|", 
    SubCent.ToString("N10", CultureInfo.InvariantCulture).Substring(0, 9));

Which returns the string : |SubCent:0.0099999|

To accommodate the value having an integer part the following is a start.

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

Which returns the string :

valFmt4 = "567890.00999999"
kevinwaite
  • 613
  • 1
  • 8
  • 20
0

This is what i did:

        c1 = a1 - b1;
        d1 = Math.Ceiling(c1 * 100) / 100;

subtracting two inputted numbers without rounding up or down the decimals. because the other solutions does not work for me. don't know if it will work for others, i just want to share this :) Hope it works tho for those who's finding solution to a problem similar to mine. Thanks

PS: i'm a beginner so feel free to point out something on this. :D this is good if you're actually dealing with money, cause of the cents right? it only have 2 decimal places and rounding it is a no no.

Nooj
  • 3
  • 3
0
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);
        }
    }
Mr.Wang from Next Door
  • 13,670
  • 12
  • 64
  • 97
0

my favorite is

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

//additional
var valueiwant2 = myvalue.toString("0.##");
//result => "54.3" // without zero
FeelRightz
  • 2,777
  • 2
  • 38
  • 73
0

function to truncate any decimal number without rounding

public static double round(double d, byte p) 
{ 
    return Math.Truncate(d * Math.Pow(10, p)) / Math.Pow(10, p); 
}
-1

i am using this function to truncate value after decimal in a string variable

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;
        }
    }
  • 1
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Nic3500 Aug 08 '18 at 12:15
-1
        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);
Zoyeb Shaikh
  • 301
  • 1
  • 11
-1

I've done just about 0 testing on this except to make sure it handles the 0 case.

My objective was mostly branchless code (if you check source code for Math.Sign() it has a branch in it, at least in source, perhaps it's optimized out).

This has the limitation (mechanically) that it will overflow a byte if you want to round a decimal with a scale of 28 or more, however, documentation seems to indicate that would violate the structure of a decimal value anyway (or at least its accuracy limit).

My inspiration initially came from D. Nesterov's answer, so standing on some shoulders here...

decimal Truncate(decimal _input, byte _scale)
{
    //Create a decimal number which is half of the scale we want to round to
    //Ex: _input = -1.0372; scale = 2 :: myRounder = -.005
    //Technically, Math.Sign() is a branch, but boolean math isn't supported in C# without unsafe pointers
    decimal myRounder = Math.Sign(_input) * new decimal(5, 0, 0, false, ++_scale);

    //Then subtract the rounder and round the result
    return Math.Round(_input - myRounder, --_scale,MidPointRounding.AwayFromZero);
}
-2

Actually you want 3.46 from 3.4679 . This is only representation of characters.So there is nothing to do with math function.Math function is not intended to do this work. Simply use the following code.

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

The above code can be modified for any numbers Put the following code in a button click event

Dim str As String 
str= result(3.4679)
 MsgBox("The number is " & str)
-2

what about

var i = Math.Truncate(number);

var r = i + Math.Truncate((number - i) * 100) / 100;
Jacky
  • 7
  • 3