How to truncate a decimal without rounding

How to truncate a decimal without rounding

Introduction

Lately I had this odd requirement to truncate decimal places without actually rounding them. Microsoft provides a Math.Truncate() method, which seems to do the trick, but doesn't take any input paramters to configure the places to cut off.

This where the solutions that came to mind, most of them not being practical:

Format to string and back to decimal

var value = 1.23456M;
var shortenedValue = Convert.ToDecimal(value.ToString("0.###"));

Assert.Equals(shortenedValue, 1.234);

Okay, this actually works, but is kinda clunky approach and also lacks flexibility.

Use Math.Truncate()

This works by shifting places to the left via a multiplier.

public static decimal TruncateDigits(this decimal value, int places)
{
    if (places <= 0)
    {
        throw new InvalidOperationException("Places to shift must be greater then zero!");
    }

    var multiplier = (decimal)Math.Pow(10, places);

    return Math.Truncate(value * multiplier) / multiplier;
}

There is one issue with this solution, as an overflow could happen in case value * multiplier becomes bigger then decimal.Max resuling in an overflow.

So a safer approach would be to handle the integral and fractional part seperatly

public static decimal TruncateDigits(this decimal value, int places)
{
    var integral = Math.Truncate(value);
    var fraction = value - integralValue;

    var multiplier = (decimal)Math.Pow(10, places);
    var truncatedFraction = Math.Truncate(fraction * multiplier) / multiplier;

    return integral + truncatedFraction;
}

Use a modulus operation

Even another approach would be to use a modulus operation as follows

public static decimal TruncateDigits(this decimal value, int places)
{
    if (places <= 0)
    {
        throw new InvalidOperationException("Should be bigger then 0");
    }

    var divisor = (decimal)Math.Pow(10, -1 * places);

    return (value - (value % divisor));
}
Show Comments