Лучший способ получить целую часть десятичного числа

89

Как лучше всего вернуть целую часть десятичной дроби (в С #)? (Это должно работать для очень больших чисел, которые могут не поместиться в int).

GetIntPart(343564564.4342) >> 343564564
GetIntPart(-323489.32) >> -323489
GetIntPart(324) >> 324

Цель этого: я вставляю десятичное (30,4) поле в базе данных и хочу убедиться, что я не пытаюсь вставить число, превышающее длину поля. Частью этой операции является определение длины целой части десятичной дроби.

Яаков Эллис
источник
Вы не можете получить часть int; вы можете получить целую числовую часть и отказаться от дробной части. Целая числовая часть Decimal может легко переполнить int и либо бросить, либо обернуть вокруг, тихо убивая ваш код.
1
Что ж, поэтому этот вопрос не так прост, как кажется. Мне нужно, чтобы это работало для очень больших чисел так же надежно, как и для маленьких. Однако «целое число» точнее, чем «int» - я перефразирую выше.
Яаков Эллис

Ответы:

212

Кстати, ребята, (int) Decimal.MaxValue переполнится. Вы не можете получить "int" часть десятичной дроби, потому что десятичная дробь слишком велика, чтобы помещать ее в поле int. Только что проверил ... он даже великоват надолго (Int64).

Если вы хотите, чтобы бит десятичного значения был слева от точки, вам нужно сделать следующее:

Math.Truncate(number)

и верните значение как ... ДЕСЯТИЧНОЕ или ДВОЙНОЕ.

edit: Truncate - определенно правильная функция!


источник
Таким образом, результат является десятичным или двойным, который никогда не будет иметь ничего после точки, но нет встроенного объекта для хранения результата как "int" (без десятичных знаков), который кажется немного неубедительным?
Coops
@CodeBlend: нет особой необходимости разрабатывать фреймворки на основе желания потерять точность.
@CodeBlend: вы все равно потеряете точность, потому что вы отрубаете десятичные значения числа. Не уверен, к чему вы клоните.
Не уверен, что это сработает или нет. Поскольку Math.Truncate (-5.99999999999999999) возвращает -6.0 для меня ... !!
Бхарат Мори
@Bharat Mori: Кажется, что -5.99999999999999999 округляется до -6.0 перед усечением. Попробуйте использовать суффикс «m», и это сработает. Math.Truncate (-5.99999999999999999m) дает -5.
Генри
4

Зависит от того, что вы делаете.

Например:

//bankers' rounding - midpoint goes to nearest even
GetIntPart(2.5) >> 2
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -6

или

//arithmetic rounding - midpoint goes away from zero
GetIntPart(2.5) >> 3
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -7

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

Ваше явное приведение подойдет:

int intPart = (int)343564564.5
// intPart will be 343564564

int intPart = (int)343564565.5
// intPart will be 343564566

Судя по тому, как вы сформулировали вопрос, похоже, что это не то, что вам нужно - вы хотите каждый раз отказываться от этого.

Я бы сделал:

Math.Floor(Math.Abs(number));

Также проверьте размер вашего decimal- они могут быть довольно большими, поэтому вам, возможно, потребуется использовать файл long.

Кит
источник
(длинный) Decimal.MaxValue переполняется.
Справедливый вопрос - я думаю, поэтому Math.Truncate (decimal) возвращает десятичное число.
Кейт
В C # приведение к int не округляется, поэтому (int) 0.6f будет 0, а (int) 343564565.5 закончится на 5, а не на 6. Попробуйте здесь: repl.it/repls/LuxuriousCheratingDistributeddatabase
sschmidTU
0

Вам просто нужно отлить его как таковое:

int intPart = (int)343564564.4342

Если вы по-прежнему хотите использовать его в качестве десятичной дроби в более поздних вычислениях, то Math.Truncate (или, возможно, Math.Floor, если вы хотите определенного поведения для отрицательных чисел) - это функция, которая вам нужна.

Нолдорин
источник
5
Это неправильно неправильно неправильно. Если результат больше, чем может содержать Int32, он либо вызовет исключение, либо (что еще хуже !!!) молча переполнится и вернется обратно, дав вам совершенно неверный результат, даже если вы об этом не узнаете.
2
Нет, это не так . Во многих случаях это недопустимо для очень больших десятичных чисел / значений с плавающей запятой, но для большинства ситуаций это прекрасно. При кодировании числа очень часто ограничиваются достаточно маленькими значениями, поэтому это не должно быть проблемой. Кроме того, я предоставил решение Math.Truncate, которое работает для всех значений.
Noldorin
2
Я понимаю, почему ты злишься на меня. Дело в том, что ваш ответ неверен. Вы говорите ему рискнуть и не сломаться, потому что, эй, многие числа маленькие. Это глупый риск. Вы должны отредактировать свой ответ и удалить все, кроме Math.Truncate, как единственно правильную часть.
1
Вы знаете, что они говорят о ПРИНЯТИИ. Кроме того, ваше предположение особенно ужасно. Это подстрекательское? Думаю, вы могли бы так сказать. Вы также можете сказать, что приказание кому-то сделать что-то глупое, что вызовет проблемы в будущем, тоже подстрекательское, если не прямо неэтичное.
1
На самом деле это было бы неправильно, если бы я намеревался дать вводящий в заблуждение ответ. Как бы то ни было, я просто пытался помочь. Если я виноват в небольшом недоразумении или не полностью понимаю вопрос, это справедливо - это не преступление. Так почему мы сейчас спорим? Мы все согласны с тем, что Truncate - правильный ответ.
Noldorin
0

Очень простой способ разделить значение и его дробную часть.

double  d = 3.5;
int i = (int)d;
string s = d.ToString();
s = s.Replace(i + ".", "");

s - дробная часть = 5, а
i - целое число = 3

Амит Гохель
источник
1
См. Верхний ответ выше. Это не работает, потому что (int)Decimal.MaxValueпроизойдет переполнение.
Яаков Эллис
0

Надеюсь помочь вам.

/// <summary>
/// Get the integer part of any decimal number passed trough a string 
/// </summary>
/// <param name="decimalNumber">String passed</param>
/// <returns>teh integer part , 0 in case of error</returns>
private int GetIntPart(String decimalNumber)
{
    if(!Decimal.TryParse(decimalNumber, NumberStyles.Any , new CultureInfo("en-US"), out decimal dn))
    {
        MessageBox.Show("String " + decimalNumber + " is not in corret format", "GetIntPart", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return default(int);
    } 

    return Convert.ToInt32(Decimal.Truncate(dn));
}
Лука
источник
-2
   Public Function getWholeNumber(number As Decimal) As Integer
    Dim round = Math.Round(number, 0)
    If round > number Then
        Return round - 1
    Else
        Return round
    End If
End Function
Мэттью Норвуд
источник
1
Принятый ответ, опубликованный более восьми лет назад, объясняет, почему этот ответ неверен. Диапазон decimalнамного больше, чем у int. Кроме того, это не вопрос VB.
Джо Фаррелл
@JoeFarrell - если вы считаете, что ответ неверен, вы можете рассмотреть возможность его отрицательного голосования в дополнение к тому, чтобы просто оставить комментарий к эффекту. Однако не отмечайте это (я не говорю, что вы это сделали). Это попытка ответить на вопрос. Он может быть на неправильном языке, может быть неправильным даже в VB, но это попытка. См., Например, « Разве ответ не является ответом на неправильный вопрос? ».
Вай Ха Ли