Подтвердить что ты не робот

Int to UInt (и наоборот) бит в Swift

Я ищу прямой способ, чтобы бит передавал битовые значения Int в UInt и наоборот. Например (с использованием 8-битных целых чисел для простоты), я хочу добиться следующего:

let unsigned: UInt8 = toUInt8(-1)  // unsigned is 255 or 0xff
let signed:   Int8  = toInt8(0xff) // signed is -1 

Сначала я вышел со следующим решением:

let unsigned = unsafeBitCast(Int8(-1), UInt8.self)
let signed   = unsafeBitCast(UInt8(0xff), Int8.self)

Но Apple в документации "unsafeBitCast()" заявляет следующее:

.. Предостережение:: Прерывает гарантии системы типа Swift; использовать с чрезвычайная осторожность. Практически всегда есть лучший способ сделать что-либо.

Есть ли у кого лучший способ?

4b9b3361

Ответ 1

Вы можете сделать:

let unsigned = UInt8(bitPattern: Int8(-1)) // -> 255
let signed   = Int8(bitPattern: UInt8(0xff)) // -> -1

Существует много подобных инициализаторов:

extension Int8 {
    init(_ v: UInt8)
    init(_ v: UInt16)
    init(truncatingBitPattern: UInt16)
    init(_ v: Int16)
    init(truncatingBitPattern: Int16)
    init(_ v: UInt32)
    init(truncatingBitPattern: UInt32)
    init(_ v: Int32)
    init(truncatingBitPattern: Int32)
    init(_ v: UInt64)
    init(truncatingBitPattern: UInt64)
    init(_ v: Int64)
    init(truncatingBitPattern: Int64)
    init(_ v: UInt)
    init(truncatingBitPattern: UInt)
    init(_ v: Int)
    init(truncatingBitPattern: Int)
    init(bitPattern: UInt8)
}

Ответ 2

Я взял маршрут алгебры. Тестирование было больно, потому что легко получить переполнение с сильной типизацией, нарушающей выполнение, PlayGround возвратил отрицательное значение из функции toUInt, он продолжал сбой или приводил смешные ошибки, делающие двойное кастинг (я открыл отчет об ошибке). Во всяком случае, это то, с чем я закончил:

func toUint(signed: Int) -> UInt {

    let unsigned = signed >= 0 ?
        UInt(signed) :
        UInt(signed  - Int.min) + UInt(Int.max) + 1

    return unsigned
}

func toInt(unsigned: UInt) -> Int {

    let signed = (unsigned <= UInt(Int.max)) ?
        Int(unsigned) :
        Int(unsigned - UInt(Int.max) - 1) + Int.min

    return signed
}

Я тестировал их со всеми крайними значениями (UInt.min, UInt.max, Int.min, Int.max), и когда XCode не сходит с ума, похоже, он работает, но он выглядит слишком сложным. Достаточно странно, что приведение бит UInt в Int может быть просто достигнуто с помощью свойства hashvalue, как в:

signed = UInt.max.hashValue // signed is -1

Но, очевидно, не всегда гарантируется работа (она должна, но я бы предпочел не рискнуть).

Будет оценена любая другая идея.

Ответ 3

numericCast(...) - это то, что вы ищете. Это набор общих функций, которые преобразуются из и в разные типы номеров. Он выбирает правильную реализацию на основе типов своего аргумента и типа возврата.