Получить целое и дробную часть десятичного числа - PullRequest
0 голосов
/ 26 декабря 2018

Учитывая X.Y, я хочу получить X и Y.

Например, учитывая 123.456 Я хочу получить 123 и 456 ( НЕ 0.456).

Я могу сделать следующее:

decimal num = 123.456M;
decimal integer = Math.Truncate(num);
decimal fractional = num - Math.Truncate(num);    

// integer = 123
// fractional = 0.456   but I want 456

REF

Однако, как указано выше, используя этотметод я получу 0.456, а мне нужно 456.Конечно, я могу сделать следующее:

int fractionalNums = (int)((num - Math.Truncate(num)) * 1000); 

// fracionalNums = 456

Однако этот метод требует знания, сколько дробных чисел имеет данное десятичное число, чтобы вы могли умножить на это число (например, 123.456 имеет три, 123.4567 имеет четыре, 123.456789 имеет шесть, 123.1234567890123456789 имеет девятнадцать).

Несколько моментов для рассмотрения:

  • Эта операция будет выполнена миллионы раз;следовательно, производительность имеет решающее значение (возможно, решение на основе битов будет лучше);
  • Точность имеет решающее значение, а округление не допустимо.

ПРИМЕЧАНИЕ 1:

По соображениям производительности я НЕ заинтересован в ЛЮБЫХ подходах, основанных на манипулировании строками;пожалуйста, не рекомендуйте такой метод.


ПРИМЕЧАНИЕ 2

Числа в моем вопросе относятся к типу decimal, и методы, которые работают только для *Допустимы типы 1053 * и сбой float или double (из-за точности с плавающей запятой).


ПРИМЕЧАНИЕ 3

Две десятичные части (т. Е. Целые и дробные части) можно считать двумя целыми числами.Следовательно, 123.000456 никогда не дается на вызов, и даже если он задан, допустимо разделить его на 123 и 456 (потому что обе стороны должны рассматриваться как целые числа).

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Десятичное число имеет 96-битную мантиссу, поэтому long недостаточно для получения каждого возможного значения.

Определение всех (положительных) степеней 10, определенных для Десятичное число :

decimal mults[] = {1M, 1e1M, 1e2M, 1e3M, <insert rest here>, 1e27M, 1e28M};

Затем внутри цикла необходимо получить шкалу (степень 10, на которую "мантисса" делится , чтобы получить номинальное значение десятичной дроби):

int[] bits = Decimal.GetBits(n);
int scale = (bits[3] >> 16) & 31;               // 567.1234 represented as 5671234 x 10^-4

decimal intPart = (int)n;                       // 567.1234 --> 567
decimal decPart = (n - intPart) * mults[scale]; // 567.1234 --> 0.1234 --> 1234
0 голосов
/ 26 декабря 2018

BitConverter.GetBytes(decimal.GetBits(num)[3])[2]; - количество цифр после запятой

long[] tens = new long[] {1, 10, 100, 1000, ...};

decimal num = 123.456M;
int iPart = (int)num;
decimal dPart = num - iPart;
int count = BitConverter.GetBytes(decimal.GetBits(num)[3])[2];

long pow = tens[count];

Console.WriteLine(iPart);
Console.WriteLine((long)(dPart * pow));
...