Округлить десятичное число до первой десятичной позиции, которая не равна нулю
Я хочу сократить число до первой значащей цифры, которая не равна 0. Цифры позади должны быть округлены.
Примеры:
0.001 -> 0.001
0.00367 -> 0.004
0.00337 -> 0.003
0.000000564 -> 0.0000006
0.00000432907543029 -> 0.000004
В настоящее время у меня есть следующая процедура:
if (value < (decimal) 0.01)
{
value = Math.Round(value, 4);
}
Замечания:
- числа всегда будут положительными
- количество значащих цифр всегда будет 1
- значения больше 0,01 всегда будут округлены до двух знаков после запятой, следовательно, if <0.01
Как видно из приведенных выше примеров, округление до 4 десятичных разрядов может оказаться недостаточным, и значение может сильно различаться.
Ответы
Ответ 1
Я бы объявлял переменную precision
и использовал итерацию, умножая эту переменную на 10
с исходным значением, которое она не ударила, что precision
добавит 1
.
то используйте precision
переменную be 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);
}
Я бы написал метод расширения для этой функции.
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);
}
}
затем используйте
decimal input = 0.00001;
input.RoundFirstSignificantDigit();
С# онлайн
Результат
(-0.001m).RoundFirstSignificantDigit() -0.001
(-0.00367m).RoundFirstSignificantDigit() -0.004
(0.000000564m).RoundFirstSignificantDigit() 0.0000006
(0.00000432907543029m).RoundFirstSignificantDigit() 0.000004
Ответ 2
Что-то вроде того?
public decimal SpecialRound(decimal value)
{
int posDot = value.ToString().IndexOf('.'); // Maybe use something about cultural (in Fr it ",")
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);
}
Ответ 3
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);
Ответ 4
код из R
но алгоритм должен быть очевиден
> x = 0.0004932
> y = log10(x)
> z = ceiling(y)
> a = round(10^(y-z),1)
> finally = a*10^(z)
> finally
[1] 5e-04
в основном, уже было предусмотрено Бенджамином К
В случае опасности быть помеченным как полный wacko, я бы с радостью сообщал, что regexp
- ваш друг. Преобразуйте свой номер в строку символов, найдите местоположение первого символа, который не является ".". ни "0", хватайте символ в этом месте и следующий символ за ним, конвертируйте их в число, округлить и (потому что вы были осторожны), умножьте результат на $ 10 ^ {- (количество нулей, найденных между ". "и первое число)} $
Ответ 5
Другой подход
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);
}
Результат
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