c# - redondeo - Redondea un número decimal a la primera posición decimal que no sea cero
redondear decimales online (5)
Algo como eso ?
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);
}
Quiero acortar un número al primer dígito significativo que no es 0. Los dígitos detrás deben redondearse.
Ejemplos:
0.001 -> 0.001
0.00367 -> 0.004
0.00337 -> 0.003
0.000000564 -> 0.0000006
0.00000432907543029 -> 0.000004
Actualmente tengo el siguiente procedimiento:
if (value < (decimal) 0.01)
{
value = Math.Round(value, 4);
}
Nota:
- los números siempre serán positivos
- El número de dígitos significativos siempre será 1.
- los valores mayores 0.01 siempre se redondearán a dos lugares decimales, por lo tanto, si <0.01
Como puede ver en los ejemplos anteriores, un redondeo a 4 posiciones decimales puede no ser suficiente y el valor puede variar mucho.
El código es de R
pero el algo debería ser obvio.
> x = 0.0004932
> y = log10(x)
> z = ceiling(y)
> a = round(10^(y-z),1)
> finally = a*10^(z)
> finally
[1] 5e-04
lo siguiente fue básicamente ya proporcionado por Benjamin K
A riesgo de ser etiquetado como un completo loco, me alegraría anunciar que regexp
es tu amigo. Convierta su número en una cadena de caracteres, busque la ubicación del primer carácter que no sea "." ni "0", tome el carácter en esa ubicación y el siguiente carácter detrás de él, conviértalos a un número, redondee y (porque fue cuidadoso), multiplique el resultado por $ 10 ^ {- (número de ceros que encontró entre " . "y el primer número)} $
Otro enfoque
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);
}
Resultado
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
Yo declararía la variable de precision
y utilizaría una iteración que multiplica esa variable por 10
con el valor original que no alcanzó, esa precision
agregará 1
.
luego use la variable de precision
ser Math.Round
segundo parámetro.
static decimal RoundFirstSignificantDigit(decimal input) {
int precision = 0;
var val = input;
while (Math.Abs(val) < 1)
{
val *= 10;
precision++;
}
return Math.Round(input, precision);
}
Escribiría un método de extensión para esta función.
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);
}
}
entonces usa como
decimal input = 0.00001;
input.RoundFirstSignificantDigit();
Resultado
(-0.001m).RoundFirstSignificantDigit() -0.001
(-0.00367m).RoundFirstSignificantDigit() -0.004
(0.000000564m).RoundFirstSignificantDigit() 0.0000006
(0.00000432907543029m).RoundFirstSignificantDigit() 0.000004
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);