我正在开发一个在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
。
答案 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_15
,QEncoded2_14
,... QEncoded15_1
, QEncoded16_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