NSDecimalNumber, как определить, есть ли дробная составляющая

У меня есть вариант использования, когда я хочу определить, имеет ли NSDecimalNumber в swift дробный компонент (отличный от 0). Я могу обрезать десятичную часть, но это связано с созданием нового NSDecimalNumber, и я хотел бы избежать этого, если это возможно.

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

extension NSDecimalNumber {
    func decimalNumberRoundedToDigits(withDecimals: UInt8, roundingMode: NSRoundingMode = NSRoundingMode.RoundPlain) -> NSDecimalNumber
    {
        // round to required decimals
        let disp = decimalNumberByRoundingAccordingToBehavior(NSDecimalNumberHandler(roundingMode: roundingMode, scale: Int16(withDecimals), raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false));

        return disp;
    }

    //  Convert the least significant byte into a signed 8-bit integer
    // Currently just truncates the fractional portion - I would like
    // to test it instead and only round if there are decimals.
    var safeByteValue: Int8 {
        get {
            let bits = UInt8(decimalNumberRoundedToDigits(0).longLongValue & 0xFF);

            return Int8(bitPattern: bits);
        }
    };
}

// just a test loop for demonstration
for i in 0...256
{
    print(NSDecimalNumber(unsignedInt: UInt32(bitPattern: Int32(i))).safeByteValue);
}

person absmiths    schedule 14.01.2016    source источник
comment
Можете ли вы объяснить вариант использования? Какая разница, есть дробные числа или нет?   -  person matt    schedule 14.01.2016
comment
Я пишу вычислительное приложение, которое в значительной степени зависит от битовых шаблонов, таких как работа с 32-битными целыми числами без знака или 64-битными длинными числами со знаком и т. д. Я обнаружил, что в NSDecimalNumber иногда свойства для EG, longValue работают неправильно, когда есть являются десятичными. Проблема всегда исчезает, когда вы ее округляете, поэтому я просто хотел избежать создания нового числа каждый раз, когда пользователь хочет увидеть подписанную 8-битную версию числа, и округлять только тогда, когда это именно то, что хочет пользователь (следовательно вопрос, я не могу сказать, округлено ли число еще).   -  person absmiths    schedule 14.01.2016
comment
Вы не можете сделать это без округления. Чтобы проверить цифры дроби, вам нужно проверить как значение мантиссы, так и показатель степени. Представьте, что мантисса равна 1000000, а показатель степени равен -20 или 0. Вы всегда должны округлить, а затем сравнить с исходным числом. Другого безопасного пути нет.   -  person Sulthan    schedule 14.01.2016
comment
Это печально, но я могу жить с этим. Мне нужна правильность больше, чем производительность. Я просто надеялся, что еще не нашел то, что мне нужно.   -  person absmiths    schedule 14.01.2016
comment
Кстати, все методы longLongValue сначала преобразуют NSDecimalNumber в double, обрезая всю дополнительную точность. Обратите внимание, что NSDecimalNumber использует десятичную арифметику, а не двоичную. Это означает, что все вычисления выполняются медленнее, чем с double. Я не уверен, что это хорошая идея для приложения, основанного на битовых шаблонах, то есть на двоичной арифметике.   -  person Sulthan    schedule 14.01.2016
comment
Когда вы говорите «обрезка дополнительной точности», вы имеете в виду числа, которые может представлять двойное число, которые больше, чем то, что может содержать UInt64, или есть что-то еще? Если это так, я согласен с этим - это часть API, так что предостережение, я полагаю. Я действительно просто хочу получить младшие 64 бита числа как можно лучше. Что я ДЕЙСТВИТЕЛЬНО хочу, так это использовать лучший числовой класс, но я не смог найти его в Swift.   -  person absmiths    schedule 14.01.2016


Ответы (1)


Я не знаю, насколько это будет эффективно, но это дает вам ответ:

extension NSDecimalNumber {
    var hasFractionalComponent: Bool {
        return ("\(num)").unicodeScalars.contains(UnicodeScalar("."))
    }
}
person Aaron Rasmussen    schedule 14.01.2016