Round a decimal number to the first decimal position that is not zero

后端 未结 5 556
粉色の甜心
粉色の甜心 2021-01-17 08:19

I want to shorten a number to the first significant digit that is not 0. The digits behind should be rounded.

Examples:

0.001 -> 0.001
0.00367 -&g         


        
相关标签:
5条回答
  • 2021-01-17 08:49

    Another approach

        decimal RoundToFirstNonNullDecimal(decimal value)
        {
            var nullDecimals = value.ToString().Split('.').LastOrDefault()?.TakeWhile(c => c == '0').Count();
            var roundTo = nullDecimals.HasValue && nullDecimals >= 1 ? nullDecimals.Value + 1 : 2;
            return Math.Round(value, roundTo);
        }
    

    Result

            Console.WriteLine(RoundToFirstNonNullDecimal(0.001m));                0.001
            Console.WriteLine(RoundToFirstNonNullDecimal(0.00367m));              0.004
            Console.WriteLine(RoundToFirstNonNullDecimal(0.000000564m));          0.0000006
            Console.WriteLine(RoundToFirstNonNullDecimal(0.00000432907543029m));  0.000004
            Console.WriteLine(RoundToFirstNonNullDecimal(0.12m));                 0.12
            Console.WriteLine(RoundToFirstNonNullDecimal(1.232m));                1.23
            Console.WriteLine(RoundToFirstNonNullDecimal(7));                     7.00
    
    0 讨论(0)
  • 2021-01-17 08:53

    I would declare precision variable and use a iteration multiplies that variable by 10 with the original value it didn't hit, that precision will add 1.

    then use precision variable be Math.Round second parameter.

    static decimal RoundFirstSignificantDigit(decimal input) {
        int precision = 0;
        var val = input;
        while (Math.Abs(val) < 1)
        {
            val *= 10;
            precision++;
        }
        return Math.Round(input, precision);
    }
    

    I would write an extension method for this function.

    public static class FloatExtension
    {
        public static decimal RoundFirstSignificantDigit(this decimal input)
        {
            int precision = 0;
            var val = input;
            while (Math.Abs(val) < 1)
            {
                val *= 10;
                precision++;
            }
            return Math.Round(input, precision);
        }
    }
    

    then use like

    decimal input = 0.00001;
    input.RoundFirstSignificantDigit();
    

    c# online

    Result

    (-0.001m).RoundFirstSignificantDigit()                  -0.001
    (-0.00367m).RoundFirstSignificantDigit()                -0.004
    (0.000000564m).RoundFirstSignificantDigit()             0.0000006
    (0.00000432907543029m).RoundFirstSignificantDigit()     0.000004
    
    0 讨论(0)
  • 2021-01-17 09:03

    code is from R but the algo should be obvious

    > x = 0.0004932
    > y = log10(x)
    > z = ceiling(y)
    > a = round(10^(y-z),1)
    > finally = a*10^(z)
    > finally
    [1] 5e-04
    

    the following was basically already provided by Benjamin K

    At the risk of being labelled a complete wacko, I would cheerfully announce that regexp is your friend. Convert your number to a char string, search for the location of the first char that is neither "." nor "0" , grab the char at that location and the next char behind it, convert them to a number, round, and (because you were careful), multiply the result by $10^{-(number of zeros you found between "." and the first number)}$

    0 讨论(0)
  • 2021-01-17 09:07

    Something like that ?

        public decimal SpecialRound(decimal value) 
        {
            int posDot = value.ToString().IndexOf('.'); // Maybe use something about cultural (in Fr it's ",")
            if(posDot == -1)
                return value;
    
            int posFirstNumber = value.ToString().IndexOfAny(new char[9] {'1', '2', '3', '4', '5', '6', '7', '8', '9'}, posDot);
    
            return Math.Round(value, posFirstNumber);
        }
    
    0 讨论(0)
  • 2021-01-17 09:10
    var value = 0.000000564;
    
    int cnt = 0;
    bool hitNum = false;
    var tempVal = value;
    while (!hitNum)
    {
        if(tempVal > 1)
        {
            hitNum = true;
        }
        else
        {
            tempVal *= 10;
            cnt++;
        }
    }
    
    var newValue = (decimal)Math.Round(value, cnt);
    
    0 讨论(0)
提交回复
热议问题