Swift中Java的Integer.reverseBytes()等价于什么?

时间:2019-05-20 13:48:44

标签: ios swift

我正在开发一个在Q Number format中读取一些字符串的应用程序。

java实现将这样的字符串转换:

int i = Integer.parseInt("00801600", 16);
System.out.println("Number from Integer.parseInt = " + i); // i=8394240
float j = Integer.reverseBytes(i);
System.out.println("After Integer.reverseBytes = " + j); // j=1474560.0
float k = j / 65536; //TWO_POWER_OF_16 = 65536
System.out.println("After Q division = " + k); // k=22.5

我玩过很多快速功能的组合,(希望)这很接近:

let i: Int = Int("00801600", radix: 16) ?? 0
let istr = "Number from Int = \(i)"
let j: Double = Double(i.byteSwapped)
let jstr = "After byte swapping = \(j)"
let k: Double = Double(j) / 65536.0
let kstr = "After Q division = \(k)"

很显然,Int.byteSwapped不是我想要的。在上面的示例中,j是所有问题的解决之道。 Java代码产生1474560.0,而我的迅捷是6333186975989760.0

3 个答案:

答案 0 :(得分:6)

Java int始终为32位,因此Integer.reverseBytes将0x00801600转换为0x00168000。

Swift Int在32位平台上为32位,而在64位平台(这是当前最新的平台)上为64位。因此,在32位平台上,i.byteSwapped将0x00801600转换为0x00168000,而在64位平台上,i.byteSwapped将0x0000000000801600转换为0x0016800000000000。

如果需要32位,请明确:

  1> let i = Int32("00801600", radix: 16)!
i: Int32 = 8394240
  2> let j = Double(i.byteSwapped)
j: Double = 1474560
  3> let k = j / 65536
k: Double = 22.5
  4>  

答案 1 :(得分:-1)

您说您正在尝试实现Q编码的数字,但是您显示的Java代码并没有真正做到这一点。它对Q16的情况进行了硬编码(通过除以65536(即2 ^ 16)),但是坦率地说,我什至不确定它的工作原理,但事实并非如此。

0x00801600当Q用大小为16的分子编码时,表示0x0080 / 0x1600,即128 / 5632,等于〜0.0227。即使您认为交换了输入,5632 / 128还是44,而不是22.5。因此,我看不到任何数学解释。

要在Swift(和Java)中实现这一点,我将创建一个新的QEncoded数据类型,该数据类型存储一个整数和一些计入分子的位数(位数)分母的计数可以推导为形成的形式减去后者)。

这种方法是最灵活的,但并不是特别有效(因为每个实例的Int浪费一个numeratorBitWidth)。如果您有太多这样的问题以至于内存使用成为问题,则可以使用一种面向协议的方法,我在second answer中对此进行了详细介绍。

// A QEncoded binary number of the form Qm.n https://en.wikipedia.org/wiki/Q_%28number_format%29
struct QEncoded<I: BinaryInteger> {
    var i: I
    var numeratorBitWidth: Int // "m"   
    var denominatorBitWidth: Int { return i.bitWidth - numeratorBitWidth } // "n"

    var numerator: I {
        return i >> denominatorBitWidth
    }

    var denominator: I {
        if denominatorBitWidth == 0 { return 1 }
        let denominatorMask: I = (1 << I(numeratorBitWidth)) - 1
        return i & denominatorMask
    }

    var ratio: Double { return Double(numerator) / Double(denominator) }

    var qFormatDescription: String {
        let (m, n) = (self.numeratorBitWidth, self.denominatorBitWidth)
        return (n == 0) ?  "Q\(m)" : "Q\(m).\(n)"
    }

    init(bitPattern: I, numeratorBitWidth: Int, denominatorBitWidth: Int) {
        assert(numeratorBitWidth + denominatorBitWidth == bitPattern.bitWidth, """
        The number of bits in the numerator (\(numeratorBitWidth)) and denominator (\(denominatorBitWidth)) \
        must sum to the total number of bits in the integer \(bitPattern.bitWidth)
        """)

        self.i = bitPattern
        self.numeratorBitWidth = numeratorBitWidth
    }

//  Might be useful to implement something like this:
//  init(numerator: I, numeratorBits: Int, denominator: I, denominatorBits: Int) {
//      
//  }
}

这是一个小演示:

extension BinaryInteger {
    var binaryDescription: String {
        var binaryString = ""
        var internalNumber = self
        var counter = 0

        for _ in (1...self.bitWidth) {
            binaryString.insert(contentsOf: "\(internalNumber & 1)", at: binaryString.startIndex)
            internalNumber >>= 1
            counter += 1
            if counter % 4 == 0 {
                binaryString.insert(contentsOf: " ", at: binaryString.startIndex)
            }
        }

        return binaryString
    }
}

extension QEncoded {
    func test() {
        print("\(self.i.binaryDescription) with \(qFormatDescription) encoding is: \(numerator.binaryDescription) (numerator: \(numerator)) / \(denominator.binaryDescription) (denominator: \(denominator)) = \(ratio)")
    }
}

//                     ↙︎ This common "0_" prefix does nothing, it's just necessary because "0b_..." isn't a valid form
//                        The rest of the `_` denote the seperation between the numerator and denominator, strictly for human understanding only (it has no impact on the code's behaviour)
QEncoded(bitPattern: 0b0__00111111 as UInt8, numeratorBitWidth: 0, denominatorBitWidth: 8).test()
QEncoded(bitPattern: 0b0_0_0111111 as UInt8, numeratorBitWidth: 1, denominatorBitWidth: 7).test()
QEncoded(bitPattern: 0b0_00_111111 as UInt8, numeratorBitWidth: 2, denominatorBitWidth: 6).test()
QEncoded(bitPattern: 0b0_001_11111 as UInt8, numeratorBitWidth: 3, denominatorBitWidth: 5).test()
QEncoded(bitPattern: 0b0_0011_1111 as UInt8, numeratorBitWidth: 4, denominatorBitWidth: 4).test()
QEncoded(bitPattern: 0b0_00111_111 as UInt8, numeratorBitWidth: 5, denominatorBitWidth: 3).test()
QEncoded(bitPattern: 0b0_001111_11 as UInt8, numeratorBitWidth: 6, denominatorBitWidth: 2).test()
QEncoded(bitPattern: 0b0_0011111_1 as UInt8, numeratorBitWidth: 7, denominatorBitWidth: 1).test()
QEncoded(bitPattern: 0b0_00111111_ as UInt8, numeratorBitWidth: 8, denominatorBitWidth: 0).test()

哪些印刷品:

0011 1111 with Q0.8 encoding is:  0000 0000 (numerator: 0) /  0000 0000 (denominator: 0) = -nan
 0011 1111 with Q1.7 encoding is:  0000 0000 (numerator: 0) /  0000 0001 (denominator: 1) = 0.0
 0011 1111 with Q2.6 encoding is:  0000 0000 (numerator: 0) /  0000 0011 (denominator: 3) = 0.0
 0011 1111 with Q3.5 encoding is:  0000 0001 (numerator: 1) /  0000 0111 (denominator: 7) = 0.14285714285714285
 0011 1111 with Q4.4 encoding is:  0000 0011 (numerator: 3) /  0000 1111 (denominator: 15) = 0.2
 0011 1111 with Q5.3 encoding is:  0000 0111 (numerator: 7) /  0001 1111 (denominator: 31) = 0.22580645161290322
 0011 1111 with Q6.2 encoding is:  0000 1111 (numerator: 15) /  0011 1111 (denominator: 63) = 0.23809523809523808
 0011 1111 with Q7.1 encoding is:  0001 1111 (numerator: 31) /  0011 1111 (denominator: 63) = 0.49206349206349204
 0011 1111 with Q8 encoding is:  0011 1111 (numerator: 63) /  0000 0001 (denominator: 1) = 63.0

答案 2 :(得分:-1)

这是my main answer的替代方法。先读一个。

这是一种更加面向协议的方法。它在类型级别对numeratorBitWidth进行编码,因此每个实例仅需要有足够的内存来存储I。不幸的是,这需要为您可能需要的每种Q编码整数类型提供新的结构定义(仅针对16位整数提供16种变体:QEncoded1_15QEncoded2_14,... QEncoded15_1QEncoded16_0

protocol QEncoded {
    associatedtype I: BinaryInteger

    var i: I { get set }
    static var numeratorBitWidth: Int { get } // "m"    
    static var denominatorBitWidth: Int { get }  // "n"

}

extension QEncoded {
    static var denominatorBitWidth: Int { return I().bitWidth - Self.numeratorBitWidth }

    static var qFormatDescription: String {
        let (m, n) = (self.numeratorBitWidth, self.denominatorBitWidth)
        return (n == 0) ?  "Q\(m)" : "Q\(m).\(n)"
    }

    var numerator: I {
        return i >> Self.denominatorBitWidth
    }

    var denominator: I {
        if Self.denominatorBitWidth == 0 { return 1 }
        let denominatorMask: I = (1 << I(Self.numeratorBitWidth)) - 1
        return i & denominatorMask
    }

    var ratio: Double { return Double(numerator) / Double(denominator) }
}

用法示例:


extension BinaryInteger {
    var binaryDescription: String {
        var binaryString = ""
        var internalNumber = self
        var counter = 0

        for _ in (1...self.bitWidth) {
            binaryString.insert(contentsOf: "\(internalNumber & 1)", at: binaryString.startIndex)
            internalNumber >>= 1
            counter += 1
            if counter % 4 == 0 {
                binaryString.insert(contentsOf: " ", at: binaryString.startIndex)
            }
        }

        return binaryString
    }
}

extension QEncoded {
    func test() {
        print("\(self.i.binaryDescription) with \(Self.qFormatDescription) encoding is: \(numerator.binaryDescription) (numerator: \(numerator)) / \(denominator.binaryDescription) (denominator: \(denominator)) = \(ratio)")
    }
}

struct QEncoded16_0: QEncoded {
    static let numeratorBitWidth = 16

    var i: UInt16
    init(bitPattern: I) { self.i = bitPattern }
}

struct QEncoded8_8: QEncoded {
    static let numeratorBitWidth = 8

    var i: UInt16
    init(bitPattern: I) { self.i = bitPattern }
}

struct QEncoded4_12: QEncoded {
    static let numeratorBitWidth = 4

    var i: UInt16
    init(bitPattern: I) { self.i = bitPattern }
}

输出:

 0011 1110 0000 1111 with Q16 encoding is:  0011 1110 0000 1111 (numerator: 15887) /  0000 0000 0000 0001 (denominator: 1) = 15887.0
 0011 1110 0000 1111 with Q8.8 encoding is:  0000 0000 0011 1110 (numerator: 62) /  0000 0000 0000 1111 (denominator: 15) = 4.133333333333334
 0011 1110 0000 1111 with Q4.12 encoding is:  0000 0000 0000 0011 (numerator: 3) /  0000 0000 0000 1111 (denominator: 15) = 0.2