C# Check if a decimal has more than 3 decimal places?

后端 未结 13 1784
一生所求
一生所求 2020-12-03 14:04

I have a situation that I cannot change: one database table (table A) accepts 6 decimal places, while a related column in a different table (table B) only has 3 decimal plac

相关标签:
13条回答
  • 2020-12-03 14:36

    Multiplying a number with 3 decimal places by 10 to the power of 3 will give you a number with no decimal places. It's a whole number when the modulus % 1 == 0. So I came up with this...

    bool hasMoreThanNDecimals(decimal d, int n)
    {
        return !(d * (decimal)Math.Pow(10, n) % 1 == 0);
    }
    

    Returns true when n is less than (not equal) to the number of decimal places.

    0 讨论(0)
  • 2020-12-03 14:36

    Here is my version:

    public static int CountDecimalPlaces(decimal dec)
    {
        var a = Math.Abs(dec);
        var x = a;
        var count = 1;
        while (x % 1 != 0)
        {
            x = a * new decimal(Math.Pow(10, count++));
        }
    
        var result = count - 1;
    
        return result;
    }
    

    I tried first @carlosfigueira/@Henrik Stenbæk, but their version does not work with 324000.00m

    TEST:

    Console.WriteLine(CountDecimalPlaces(0m)); //0
    Console.WriteLine(CountDecimalPlaces(0.5m)); //1
    Console.WriteLine(CountDecimalPlaces(10.51m)); //2
    Console.WriteLine(CountDecimalPlaces(10.5123456978563m)); //13
    Console.WriteLine(CountDecimalPlaces(324000.0001m)); //4
    Console.WriteLine(CountDecimalPlaces(324000.0000m)); //0
    
    0 讨论(0)
  • 2020-12-03 14:37

    All of the solutions proposed so far are not extensible ... fine if you are never going to check a value other than 3, but I prefer this because if the requirement changes the code to handle it is already written. Also this solution wont overflow.

    int GetDecimalCount(decimal val)
    {
        if(val == val*10)
        {
            return int.MaxValue; // no decimal.Epsilon I don't use this type enough to know why... this will work
        }
    
        int decimalCount = 0;
        while(val != Math.Floor(val))
        {
            val = (val - Math.Floor(val)) * 10;
            decimalCount++;
        }
        return decimalCount;
    }       
    
    0 讨论(0)
  • 2020-12-03 14:38

    One more option based on @RodH257's solution, but reworked as an extension method:

    public static bool HasThisManyDecimalPlacesOrLess(this decimal value, int noDecimalPlaces)
    {
        return (Decimal.Round(value, noDecimalPlaces) == value);
    }
    

    You can then call that as:

    If !(tableA.Qty * tableA.Unit).HasThisManyDecimalPlacesOrLess(3)) return;
    
    0 讨论(0)
  • 2020-12-03 14:42

    This works for 3 decimal places, and it can be adapted for a generic solution:

    static bool LessThan3DecimalPlaces(decimal dec)
    {
        decimal value = dec * 1000;
        return value == Math.Floor(value);
    }
    static void Test()
    {
        Console.WriteLine(LessThan3DecimalPlaces(1m * 0.00025m));
        Console.WriteLine(LessThan3DecimalPlaces(4000m * 0.00025m));
    }
    

    For a real generic solution, you'll need to "deconstruct" the decimal value in its parts - take a look at Decimal.GetBits for more information.

    Update: this is a simple implementation of a generic solution which works for all decimals whose integer part is less than long.MaxValue (you'd need something like a "big integer" for a trully generic function).

    static decimal CountDecimalPlaces(decimal dec)
    {
        Console.Write("{0}: ", dec);
        int[] bits = Decimal.GetBits(dec);
        ulong lowInt = (uint)bits[0];
        ulong midInt = (uint)bits[1];
        int exponent = (bits[3] & 0x00FF0000) >> 16;
        int result = exponent;
        ulong lowDecimal = lowInt | (midInt << 32);
        while (result > 0 && (lowDecimal % 10) == 0)
        {
            result--;
            lowDecimal /= 10;
        }
    
        return result;
    }
    
    static void Foo()
    {
        Console.WriteLine(CountDecimalPlaces(1.6m));
        Console.WriteLine(CountDecimalPlaces(1.600m));
        Console.WriteLine(CountDecimalPlaces(decimal.MaxValue));
        Console.WriteLine(CountDecimalPlaces(1m * 0.00025m));
        Console.WriteLine(CountDecimalPlaces(4000m * 0.00025m));
    }
    
    0 讨论(0)
  • 2020-12-03 14:43

    The basics is to know how to test if there are decimal places, this is done by comparing the value to its rounding

    double number;
    bool hasDecimals = number == (int) number;
    

    Then, to count 3 decimal places, you just need to do the same for your number multiplied by 1000:

    bool hasMoreThan3decimals = number*1000 != (int) (number * 1000)
    
    0 讨论(0)
提交回复
热议问题