Есть ли способ получить «значительные фигуры» десятичной?

StackOverflow https://stackoverflow.com/questions/3683718

Вопрос

Обновлять

ОК, после некоторого расследования, и благодаря большой части полезных ответов, предоставляемых Джоном и Гансом, это то, что я смог собрать вместе. Пока я думаю, что это, кажется, хорошо работает. Конечно, я бы не поставил на свою жизнь в своей полной корректности.

public static int GetSignificantDigitCount(this decimal value)
{
    /* So, the decimal type is basically represented as a fraction of two
     * integers: a numerator that can be anything, and a denominator that is 
     * some power of 10.
     * 
     * For example, the following numbers are represented by
     * the corresponding fractions:
     * 
     * VALUE    NUMERATOR   DENOMINATOR
     * 1        1           1
     * 1.0      10          10
     * 1.012    1012        1000
     * 0.04     4           100
     * 12.01    1201        100
     * 
     * So basically, if the magnitude is greater than or equal to one,
     * the number of digits is the number of digits in the numerator.
     * If it's less than one, the number of digits is the number of digits
     * in the denominator.
     */

    int[] bits = decimal.GetBits(value);

    if (value >= 1M || value <= -1M)
    {
        int highPart = bits[2];
        int middlePart = bits[1];
        int lowPart = bits[0];

        decimal num = new decimal(lowPart, middlePart, highPart, false, 0);

        int exponent = (int)Math.Ceiling(Math.Log10((double)num));

        return exponent;
    }
    else
    {
        int scalePart = bits[3];

        // Accoring to MSDN, the exponent is represented by
        // bits 16-23 (the 2nd word):
        // http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx
        int exponent = (scalePart & 0x00FF0000) >> 16;

        return exponent + 1;
    }
}

Я не тестировал все это полностью. Вот несколько образцов входов / выходов, хотя:

Точность значения 0 1 цифры (ы). 0,000 4 цифры (ы). 1,23 3 цифры (ы). 12,324 5 цифры (ы). 1,2300 5 цифр (ы). -5 1 цифры (ы). -5,01 3 цифры (ы). -0,012 4 цифры (ы). -0,100 4 цифры (ы). 0,0 2 цифры (ы). 10443,31 7 цифр (ы). -130,340 6 цифр (ы). -80,8000 6 цифр (ы).

Используя этот код, я представляю, я бы достигли мою цель, делая что-то подобное:

public static decimal DivideUsingLesserPrecision(decimal x, decimal y)
{
    int xDigitCount = x.GetSignificantDigitCount();
    int yDigitCount = y.GetSignificantDigitCount();

    int lesserPrecision = System.Math.Min(xDigitCount, yDigitCount);

    return System.Math.Round(x / y, lesserPrecision);
}

Я действительно не закончил работать через это, хотя. Любой, кто хочет поделиться мыслями: это было бы очень ценится!


Оригинальный вопрос

Предположим, я написал этот код:

decimal a = 1.23M;
decimal b = 1.23000M;

Console.WriteLine(a);
Console.WriteLine(b);

Вышепередается вывод:

1.23
1.23000

Я считаю, что это также работает, если я использую decimal.Parse("1.23") для a а также decimal.Parse("1.23000") для b (что означает, что этот вопрос относится к случаям, когда программа получает ввод пользователя).

Так явно а decimal Значение как-то «осознает» то, что я позвоню точность. Отказ Тем не менее, я не вижу членов на decimal Тип, который предоставляет любой способ доступа к этому, кроме ToString сам.

Предположим, я хотел умножить два decimal Значения и обрезать результат к точности менее точного аргумента. Другими словами:

decimal a = 123.4M;
decimal b = 5.6789M;

decimal x = a / b;

Console.WriteLine(x);

Вышеуказанные выходы:

21.729560302171195125816619416

Что я спрашиваю: как я могу написать метод, который вернется 21.73 вместо этого (с 123.4M имеет четыре важных цифры)?

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

также осознать, что в большинстве сценариев, где вы имеете дело со значительными цифрами, вам, вероятно, не нужно использовать decimal тип. Но я спрашиваю, потому что, как я уже говорил в начале, decimal тип появляется включить информацию о точности, тогда как double не так далеко, насколько я знаю.)

Это было полезно?

Решение

Вы можете использовать Decimal.GetBits Чтобы получить необработанные данные и разговаривать от этого.

К сожалению, у меня нет времени писать образец кода на данный момент - и вы, вероятно, захотите использовать BigInteger Для некоторых манипуляций, если вы используете .NET 4 - Но, надеюсь, это сделает вас. Просто разрабатывать точность, а затем звонить Math.Round На исходный результат вполне может быть хорошим началом.

Другие советы

Да, в отличие от типов плавающих точек, System.decimal отслеживает количество цифр в литерате. Это особенность PECIMAL. SARSE (), выполняется, выполняется вашим кодом или компилятором, когда он анализирует литерал в вашей программе. Вы можете восстановить эту информацию, проверить код в моем ответе в эта нить.

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

Раствор выше выпадает из кровати быстро с ценностями, такими как 1200, где количество значительных цифр составляет 2, но функция возвращается 4. Возможно, существует последовательная манера для решения такой ситуации, то есть проверка, чтобы убедиться, что возвращаемое значение не включает в себя. во всей номерной части без дробной части.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top