it-swarm.com.de

Runden Sie eine Dezimalzahl auf die erste Dezimalstelle, die nicht Null ist

Ich möchte eine Zahl auf die erste signifikante Ziffer kürzen, die nicht 0 ist. Die Ziffern dahinter sollten gerundet werden.

Beispiele:

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

Derzeit habe ich folgendes Verfahren:

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

Hinweis:

  • zahlen werden immer positiv sein
  • die Anzahl der signifikanten Stellen ist immer 1
  • werte größer 0,01 werden immer auf zwei Dezimalstellen gerundet, daher das If <0,01

Wie Sie in den obigen Beispielen sehen können, reicht eine Rundung auf 4 Dezimalstellen möglicherweise nicht aus und der Wert kann stark variieren.

19
julian bechtold

Ich würde precision Variable deklarieren und eine Iteration verwenden, multipliziert diese Variable mit 10 mit dem ursprünglichen Wert, den es nicht getroffen hat, dass precision1 hinzufügt.

verwenden Sie dann die Variable precision und den zweiten Parameter 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);
}

Ich würde eine Erweiterungsmethode für diese Funktion schreiben.

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

dann verwenden Sie gerne

decimal input = 0.00001;
input.RoundFirstSignificantDigit();

c # online

Ergebnis

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

Sowas in der Art ?

    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

der Code stammt von R, aber der Algo sollte offensichtlich sein

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

folgendes wurde im Wesentlichen bereits von Benjamin K zur Verfügung gestellt

Auf die Gefahr hin, als kompletter Wacko bezeichnet zu werden, würde ich freudig verkünden, dass regexp Ihr Freund ist. Wandeln Sie Ihre Nummer in eine Zeichenfolge um, suchen Sie nach dem Ort des ersten Zeichens, das weder "." noch "0", schnappen Sie sich das Zeichen an dieser Stelle und das nächste Zeichen dahinter, konvertieren Sie es in eine Zahl, eine Runde, und (weil Sie vorsichtig waren), multiplizieren Sie das Ergebnis mit $ 10 ^ (- Anzahl der gefundenen Nullen zwischen . "und die erste Zahl)} $ 

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

Ein anderer Ansatz

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

Ergebnis

        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