Определите, может ли десятичное число храниться как int32 - PullRequest
4 голосов
/ 29 апреля 2010

Я делаю несколько пользовательских сериализаций, и чтобы сэкономить место, я хочу сериализовать десятичные дроби как int, если это возможно, с точки зрения значения. Производительность является проблемой, так как я имею дело с большим объемом данных. Текущий метод, который я использую:

if ((value > Int32.MinValue) && (value < Int32.MaxValue) && ((valueAsInt = Decimal.ToInt32(value)) == value))
{
    return true;
}

Можно ли это улучшить?

Ответы [ 6 ]

1 голос
/ 29 апреля 2010

Есть ли у вас отрицательные значения? Я предполагаю, что да, так как у вас есть проверка MinValue, в противном случае вы можете пропустить ее. Вы даже можете использовать unsigned int, что позволит вам конвертировать больше ваших двойных значений в целые.

Редактировать: Также, если у вас больше положительных чисел, вы можете поменять местами первые два условия. Таким образом, первый вариант, скорее всего, потерпит неудачу, уменьшив общее количество сравнений.

1 голос
/ 29 апреля 2010

Это зависит от того, сколько десятичных разрядов у вас есть или о чем вы действительно заботитесь. Если вы могли бы сказать, что я забочусь только о 3 десятичных разрядах, то наибольшее число, которое вы можете сохранить в int32, - это int.MaxValue / 1000. Если вы работаете только с положительными числами, вы можете получить большее число, используя uint. В любом случае, способ сделать это состоит в том, чтобы последовательно зарезервировать место для десятичной дроби и использовать * 1000 для их кодирования и / 1000 для декодирования их в / из десятичной дроби.

1 голос
/ 29 апреля 2010

Как насчет этого. Я думаю, что это должно занять меньше операций (по крайней мере, меньше сравнений):

    return (value == (Int32)value);

Также помните, что если оператор if просто возвращает логическое значение, вы можете просто вернуть сравнение. Одно это может сделать это быстрее (если компилятор уже не оптимизирует для этого). Если вам нужно использовать оператор if, вы можете сделать это следующим образом:

    if (value == (Int32)value)
    {
        //Do stuff...
    return true;
    }
    else
    {
        //Do stuff...
        return false;
    }

РЕДАКТИРОВАТЬ: Я понимаю, что это на самом деле не работает. Я думал, что приведение Int32 просто скопирует первые 32 бита из десятичного числа, оставляя после себя оставшиеся биты (и не выбрасывая исключение), но, увы, это не сработало (не говоря уже о том, что это будет неправильно все отрицательные значения).

1 голос
/ 29 апреля 2010

Ваши критерии признания недействительными:

1) Это больше, чем MaxValue?

2) Это меньше, чем MinValue?

3) Содержит ли дробный компонент?

Звучит так, будто ты их прикрыл. Моя реализация будет:

public bool IsConvertibleToInt(decimal value)
{
    if(value > int.MaxValue)
       return false;

    if(value < int.MinValue)
       return false;

    if(Math.Floor(value) < value && Math.Ceiling(value) > value)
       return false;

    return true;
}
0 голосов
/ 29 апреля 2010

Нет необходимости в "valueAsInt =". Я считаю, что (Decimal.ToInt32 (value) == value)) дает вам тот же результат с одним меньшим назначением. Вы используете valueAsInt как своего рода выходной параметр?

0 голосов
/ 29 апреля 2010

Не могли бы вы сделать что-то вроде:

if(Decimal.ToInt32(value) == value)
{
     return true;
}

Не эксперт по .net, но я думаю, что это должно быть все, что для этого потребуется. Кроме того, ваши два оператора сравнения должны быть «или равны», поскольку значения min / max также действительны.

Редактировать: Как указано в комментарии, это приведет к исключению. Вы могли бы попытаться перехватить исключение и вернуть false, но в этот момент, скорее всего, было бы намного быстрее выполнить тестирование мин / макс самостоятельно.

...