Есть ли функциональный или правильный способ для анализа десятичного числа в качестве экспоненциального - PullRequest
0 голосов
/ 16 мая 2019

Я пытаюсь разобрать C # decimal type to мой собственный тип Decimal, который имеет только significant и exponent.Я попробовал это:

    public static MyType.Decimal FromDecimal(decimal decimalValue)
    {
        decimal tempValue = decimalValue;
        int exponent = 0;

        while ((long) (tempValue) < decimalValue)
        {
            tempValue *= 10;
            decimalValue *= 10;
            exponent--;
        }

        return new MyType.Decimal()
        {
            Significand = (long)tempValue,
            Exponent = exponent
        };
    }

    public class Decimal
    {
        public long Significand;
        public int Exponent;
    }

но, по моему мнению, это будет медленным .

1 Ответ

0 голосов
/ 16 мая 2019

Вы можете попробовать decimal.GetBits () , например,

  public static MyType.Decimal FromDecimal(decimal decimalValue) {
    int[] parts = decimal.GetBits(decimalValue);

    int sign = 1 - 2 * (parts[3] >> 31 & 1);
    long mantissa = ((((long)parts[1]) << 32) | (((long)parts[0]))) * sign;
    int exponent = -((parts[3] >> 16) & 0xFF);

    return MyType.Decimal() {
      Significand = mantissa, 
      Exponent    = exponent
    };
  }

Но будьте осторожны: decimal использует 96-битный мантисса (пожалуйста, обратите внимание, абсент из parts[2], который мы игнорировали ), поэтому long Significand является слишком коротким (long является 64-разрядным * только 1019 *)

Демо-версия:

  decimal[] tests = new decimal[] {
    0m,
    10m,
    100m,
    0.01m,
    123e-1m,
   -3m,
    123456789e4m,
    123456789e-4m,
    1234567890123456m,
    1234567890123456e4m // 12345678901234560000 > long.MaxValue (9223372036854775807)
  };

  string report = string.Join(Environment.NewLine, tests
    .Select(test => {
      int[] parts = decimal.GetBits(test);

      int sign = 1 - 2 * (parts[3] >> 31 & 1);
      long mantissa = ((((long)parts[1]) << 32) | (((long)parts[0]))) * sign;
      int exponent = -((parts[3] >> 16) & 0xFF);

      return $"{test,20} == {mantissa}e{exponent}";
    })); 

Результат:

                   0 == 0e0
                  10 == 10e0
                 100 == 100e0
                0.01 == 1e-2
                12.3 == 123e-1
                  -3 == -3e0
       1234567890000 == 1234567890000e0
          12345.6789 == 123456789e-4
    1234567890123456 == 1234567890123456e0
12345678901234560000 == -350295040e0        -- mantissa is 96 bit, doesn't fit 64-bit long
...