web-dev-qa-db-fra.com

Arrondir un nombre décimal à la première position décimale qui n'est pas zéro

Je veux raccourcir un nombre au premier chiffre significatif qui n'est pas 0. Les chiffres derrière doivent être arrondis.

Exemples:

0.001 -> 0.001
0.00367 -> 0.004
0.00337 -> 0.003
0.000000564 -> 0.0000006
0.00000432907543029 ->  0.000004

Actuellement, j'ai la procédure suivante:

if (value < (decimal) 0.01)
{
    value = Math.Round(value, 4);
}

Remarque:

  • les chiffres seront toujours positifs
  • le nombre de chiffres significatifs sera toujours 1
  • les valeurs supérieures à 0.01 seront toujours arrondies à deux décimales, d’où le si <0.01

Comme vous pouvez le constater dans les exemples ci-dessus, un arrondi à 4 décimales peut ne pas être suffisant et la valeur peut varier considérablement.

19
julian bechtold

Je déclarerais la variable precision et utiliserais une itération, multipliant cette variable par 10 avec la valeur d'origine non frappée, cette precision ajoutera 1.

utilisez ensuite la variable precision comme étant le second paramètre Math.Round.

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

Je voudrais écrire une méthode d'extension pour cette fonction.

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

puis utiliser comme

decimal input = 0.00001;
input.RoundFirstSignificantDigit();

c # en ligne

Résultat

(-0.001m).RoundFirstSignificantDigit()                  -0.001
(-0.00367m).RoundFirstSignificantDigit()                -0.004
(0.000000564m).RoundFirstSignificantDigit()             0.0000006
(0.00000432907543029m).RoundFirstSignificantDigit()     0.000004
17
D-Shih

Quelque chose comme ca ?

    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);
    }
2
Benjamin K

le code est de R mais l'algo devrait être évident

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

ce qui suit a été essentiellement déjà fourni par Benjamin K

Au risque d'être étiqueté comme un wacko complet, j'annoncerais avec joie que regexp est votre ami. Convertissez votre numéro en chaîne de caractères, recherchez l'emplacement du premier caractère qui n'est ni "." ni "0", prenez le caractère à cet endroit et le caractère suivant derrière, convertissez-les en nombre, tour, et (parce que vous avez fait attention), multipliez le résultat par 10 $ ^ {- (nombre de zéros que vous avez trouvés entre " . "et le premier numéro)} $ 

1
Carl Witthoft
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);
1
ManishM

Une autre approche

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

Résultat

        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
crazy_p