Определите десятичную точность входного числа

У нас возникла интересная проблема, когда нам нужно было определить десятичную точность пользовательского ввода (текстового поля). По сути, нам нужно знать количество введенных десятичных знаков, а затем возвращать число точности, это лучше всего проиллюстрировано на примерах:

Введено 4500 даст результат 1
4500.1 введено даст результат 0,1
4500.00 введено даст результат 0,01
4500.450 введено даст результат 0,001

Мы думаем поработать со строкой, найти десятичный разделитель, а затем вычислить результат. Просто интересно, есть ли более простое решение.


person Quinten    schedule 19.07.2010    source источник
comment
Вы уверены, что 4500 будет 1, а не 100?   -  person corsiKa    schedule 19.07.2010
comment
Каков ожидаемый результат в случае 0,0 и 0,1?   -  person user1785960    schedule 06.06.2016
comment
Для меня это непонятный вопрос. Вам не нужна десятичная точность. Вы спросите: как получить количество цифр в дробной части. Определение «десятичной точности» здесь для Меня: docs .oracle.com / cd / B28359_01 / server.111 / b28318 /   -  person user1785960    schedule 06.06.2016


Ответы (7)


Я думаю, вам следует просто сделать то, что вы предложили, - использовать позицию десятичной точки. Очевидным недостатком может быть то, что вам придется самому думать об интернационализации.

var decimalSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;

var position = input.IndexOf(decimalSeparator);

var precision = (position == -1) ? 0 : input.Length - position - 1;

// This may be quite unprecise.
var result = Math.Pow(0.1, precision);

Есть еще одна вещь, которую вы можете попробовать - тип Decimal хранит значение внутренней точности. Поэтому вы можете использовать Decimal.TryParse() и проверить возвращаемое значение. Возможно, алгоритм синтаксического анализа поддерживает точность ввода.

Наконец, я бы посоветовал не пробовать использовать числа с плавающей запятой. Простой анализ ввода удалит любую информацию о конечных нулях. Поэтому вам нужно добавить искусственную ненулевую цифру, чтобы сохранить их, или проделать аналогичные трюки. Вы можете столкнуться с проблемами точности. Наконец, найти точность на основе числа с плавающей запятой тоже непросто. Я вижу какую-то уродливую математику или цикл, умножающийся на десять на каждой итерации, пока не исчезнет дробная часть. И цикл имеет новые проблемы с точностью ...

ОБНОВЛЕНИЕ

Разбор на десятичную дробь работает. Дополнительную информацию см. В Decimal.GetBits().

var input = "123.4560";

var number = Decimal.Parse(input);

// Will be 4.
var precision = (Decimal.GetBits(number)[3] >> 16) & 0x000000FF;

Отсюда использование Math.Pow(0.1, precision) просто.

ОБНОВЛЕНИЕ 2

Использование decimal.GetBits () выделит массив int[]. Если вы хотите избежать распределения, вы можете использовать следующий вспомогательный метод, который использует явную структуру макета, чтобы получить масштаб непосредственно из десятичного значения:

static int GetScale(decimal d)
{
    return new DecimalScale(d).Scale;
}

[StructLayout(LayoutKind.Explicit)]
struct DecimalScale
{
    public DecimalScale(decimal value)
    {
        this = default;
        this.d = value;
    }

    [FieldOffset(0)]
    decimal d;

    [FieldOffset(0)]
    int flags;

    public int Scale => (flags >> 16) & 0xff;
}
person Daniel Brückner    schedule 19.07.2010
comment
+1 Что касается десятичной. "> stackoverflow.com/questions/1132765/ - person Binary Worrier; 19.07.2010
comment
Поскольку OP запросил более простое решение и, возможно, предполагал лучшую производительность, как это сравнить с точки зрения производительности с простым анализом строки? - person Doug S; 17.10.2012
comment
У вас в комментарии будет 4, но точность 123,4560 должна быть 7. Масштаб должен быть 4. - person Jeremy Holovacs; 23.10.2015
comment
Есть ли способ для 123,4560 получить точность = 3? так как 0 в конце не должен считаться? - person Philipp Munin; 05.06.2019

Просто интересно, есть ли более простое решение.

No.

Использовать строку:

string[] res = inputstring.Split('.');
int precision = res[1].Length;
person codymanix    schedule 19.07.2010
comment
Символ для разделения должен быть правильным десятичным разделителем - NumberFormatInfo.NumberDecimalSeparator - person ChrisF; 19.07.2010

Поскольку ваши последние примеры показывают, что конечные нули важны, я бы исключил любое численное решение и перешел к строковым операциям.

person Henk Holterman    schedule 19.07.2010

Нет, более простого решения нет, надо проверить строку. Если вы конвертируете "4500" и "4500.00" в числа, они оба становятся значением 4500, поэтому вы не можете определить, сколько цифр, не являющихся значениями, было за десятичным разделителем.

person Guffa    schedule 19.07.2010

Интересно отметить, что Decimal пытается сохранить точность, введенную пользователем. Например,

Console.WriteLine(5.0m);
Console.WriteLine(5.00m);
Console.WriteLine(Decimal.Parse("5.0"));
Console.WriteLine(Decimal.Parse("5.00"));

Имеет выход:

5.0
5.00
5.0
5.00

Если ваша мотивация в отслеживании точности ввода обусловлена ​​исключительно соображениями ввода и вывода, этого может быть достаточно для решения вашей проблемы.

person Brian    schedule 19.07.2010
comment
См. Ответ Даниэля Брукнера, чтобы узнать, как получить прямой доступ к этой информации. - person Brian; 19.07.2010

Работать со строкой достаточно просто.

Если нет "." в строке верните 1.

В противном случае верните «0.», за которым следует n-1 «0», за которым следует одна «1», где n - длина строки после десятичной точки.

person Amnon    schedule 19.07.2010
comment
Предупреждение: сначала убедитесь, что строка является допустимым числом / последний символ не является. - person luiscubal; 19.07.2010

Вот возможное решение с использованием строк;

static double GetPrecision(string s)
{ 
    string[] splitNumber = s.Split('.');
    if (splitNumber.Length > 1)
    {
        return 1 / Math.Pow(10, splitNumber[1].Length);
    }
    else
    {
        return 1;
    }
}

Здесь есть вопрос; Рассчитайте System.Decimal Precision and Scale, который, похоже, может быть интересен, если вы хотите вникнуть в это еще раз.

person Christopher McAtackney    schedule 19.07.2010
comment
Для получить правильный десятичный разделитель для локали. - person ChrisF; 19.07.2010