0

First of all sorry for my english, I need a function (it can be from Math library) to truncate a decimal (not int) number.

Lets say I have a value of 4.8671 and want first 4 digit as 4.867, Lets say I have a value of 244.123456 and want first 5 digit as 244.12, how can I truncate it without rounding up?

I have tried the following but both of them give me different numbers

void Main()
{
    Console.Write(Math.Round(4.8671, 2,MidpointRounding.ToEven));
    Console.Write(Math.Round(4.8671, 2));
}

Almost all functions are rounding (2.987654) to (2.99) or floor (2). These numbers are error reason on my project.

It has to be effective way.

Is there a function for it, if there is not how can i implement ?

Mustafa Güngör
  • 73
  • 1
  • 2
  • 9
  • You could convert it to string and take the N first chars. Will have to consider the problem of the decimal separator and the lenght of the number. Maybe not the most professional way but it will work.. – MundoPeter Aug 09 '20 at 23:23
  • 1
    You keep saying [`Decimal`](https://learn.microsoft.com/en-us/dotnet/api/system.decimal) but all your examples are [`Double`](https://learn.microsoft.com/en-us/dotnet/api/system.double); which do you want? – Dour High Arch Aug 09 '20 at 23:25
  • If you know the number of decimal places that you want _after_ the decimal point, you can write a [`RoundDown()` function](https://stackoverflow.com/a/19648234/8967612). – 41686d6564 stands w. Palestine Aug 09 '20 at 23:25
  • We dont know, Decimal numbers are changing in every second via websocket @41686d6564 – Mustafa Güngör Aug 09 '20 at 23:31
  • Sorry for miswrite, i want decimal number :) @DourHighArch – Mustafa Güngör Aug 09 '20 at 23:32
  • Thanks for idea but need more effective way, if i cant find a different solution, i will try it @MundoPeter – Mustafa Güngör Aug 09 '20 at 23:33
  • 1
    @SacmaŞeyler Try for example `Math.Truncate(x * 1000) / 1000` (for 3 decimals), or `Math.Round` with `MidpointRounding.ToZero` (for positive numbers, on .NET Core 3+). – dxiv Aug 09 '20 at 23:34
  • @dxiv Math.Truncate(x * 1000) / 1000 (for 3 decimals)-- decimal numbers are variable, sometimes we need 5 decimal sometimes 7, depends on variables, i will try second one, thx – Mustafa Güngör Aug 09 '20 at 23:40
  • @dxiv, if you write MidpointRounding.ToZero function as an answer, i will accept it. It works, thx. – Mustafa Güngör Aug 09 '20 at 23:51
  • Check this out: https://stackoverflow.com/questions/3143657/truncate-two-decimal-places-without-rounding – Jamal Aug 09 '20 at 23:53
  • @SacmaŞeyler Glad it worked, though you should have mentioned .NET Core in the question, since [`MidpointRounding.ToZero`](https://learn.microsoft.com/en-us/dotnet/api/system.midpointrounding?view=netcore-3.0) is only documented for Core 3.0 and later, but not available on standard or framework. For the other/older platforms, the alternative remains the `Math.Truncate` trick, where you can replace the hardcoded constant with an appropriate `Math.Pow`. – dxiv Aug 09 '20 at 23:56
  • @Enigmativity The question is the same as the one linked as a duplicate, indeed, but the answers to the old question were written before `MidpointRounding.ToZero` was available, which I believe is relevant nowadays. – dxiv Aug 10 '20 at 00:01
  • @dxiv - You should then add that answer to the duplicate. Post a link here and I'll upvote. :-) – Enigmativity Aug 10 '20 at 00:11
  • @Enigmativity I upvoted [this answer](https://stackoverflow.com/a/62949225) instead ;-) Though I still don't think a question is technically a duplicate if the best answer *when asked* is different from the answers available many years ago. – dxiv Aug 10 '20 at 01:25

2 Answers2

0

I'm not sure if there's a better way but I wrote this function and it works:

decimal Truncate(decimal number, int decimalPlaces) {
    var x = number.ToString(CultureInfo.InvariantCulture).Split('.');
    return decimal.Parse(x[0] + "." + x[1].Substring(0, decimalPlaces), CultureInfo.InvariantCulture);
}

Or you could do this in one line:

decimal Truncate(decimal number, int decimalPlaces) {
    return (int)(number * (decimal)Math.Pow(10, decimalPlaces)) / (decimal)Math.Pow(10, decimalPlaces);
}
Frank Z.
  • 125
  • 1
  • 2
  • 12
0

I may be wrong but looks to me like you are looking for a "left cut" function, for example one like this:

public static decimal LeftCutDecimal(decimal d, int length, bool truncateInteger = false)
{
    if (d.Equals(0)) {
        return 0;
    }

    decimal newNumber = Math.Floor(d);
    int pow = 1;
    string lastString = newNumber.ToString();
    if (lastString.Length >= length)
    {
        if (truncateInteger) {
            pow = (int) Math.Pow (10, lastString.Length - length);
            return Math.Floor(newNumber / pow) * pow;
        } else {
            return newNumber;
        }
    }

    while (lastString.Length < length)
    {
        newNumber = Math.Floor(d * pow);
        pow *= 10;
        lastString = newNumber.ToString();
    }

    pow /= 10;
    return newNumber / pow;
}           
Console.WriteLine(LeftCutDecimal((decimal) 0, 3)); //outputs 0
Console.WriteLine(LeftCutDecimal((decimal) 4.3234, 2)); //outputs 4.3
Console.WriteLine(LeftCutDecimal((decimal) 4.3234, 4)); //outputs 4.323
Console.WriteLine(LeftCutDecimal((decimal) 124.3234, 4)); //outputs 124.3
Console.WriteLine(LeftCutDecimal((decimal) 1245.3234, 2)); //outputs 1245 if truncateInteger = false
Console.WriteLine(LeftCutDecimal((decimal) 1245.3234, 2, truncateInteger: true)); //outputs 1200 if truncateInteger = true
Bartosz Pachołek
  • 1,278
  • 1
  • 8
  • 17