Swift 4 - Double到big-endian的高效转换

时间:2022-01-13 15:41:02

I need to convert a Double to big-endian in order to write it to a file, using an oil-industry binary file standard, that was originally defined for IBM half-inch 9 track tapes in the 1970s!

我需要将Double转换为big-endian,以便将其写入文件,使用石油行业二进制文件标准,该标准最初是在20世纪70年代为IBM半英寸9磁道磁带定义的!

I need really efficient Swift 4 code, because this conversion is inside two nested-loops and will be executed upwards of 100,000 times.

我需要非常有效的Swift 4代码,因为这个转换在两个嵌套循环中,并且将执行超过100,000次。

2 个解决方案

#1


1  

You can create an UInt64 containing the big-endian representation of the Double with

您可以创建包含Double with的big-endian表示的UInt64

let value = 1.0
var n = value.bitPattern.bigEndian

In order to write that to a file you might need to convert it to Data:

为了将其写入文件,您可能需要将其转换为数据:

let data = Data(buffer: UnsafeBufferPointer(start: &n, count: 1))
print(data as NSData) // <3ff00000 00000000>

If many contiguous floating point values are written to the file then it would be more effective to create an [UInt64] array with the big-endian representations and convert that to Data, for example

如果将大量连续的浮点值写入文件,那么使用big-endian表示创建[UInt64]数组并将其转换为Data会更有效,例如

let values = [1.0, 2.0, 3.0, 4.0]
let array = values.map { $0.bitPattern.bigEndian }
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }

(All the above compiles with Swift 3 and 4.)

(以上所有内容均使用Swift 3和4进行编译。)

#2


0  

I successfully implemented Martin's array suggestion. I decided I should use some "interesting" test values and one thing led to another! Here's my test playground. I hope it is of interest:

我成功实现了Martin的阵列建议。我决定使用一些“有趣”的测试值,一件事导致另一件事!这是我的测试操场。我希望有兴趣:

//: Playground - noun: a place where people can play

import UIKit

func convert(doubleArray: [Double]) {
    let littleEndianArray = doubleArray.map { $0.bitPattern}
    var data = littleEndianArray.withUnsafeBufferPointer { Data(buffer: $0) }
    print("Little-endian : ", data as NSData)

    // Convert and display the big-endian bytes
    let bigEndianArray = doubleArray.map { $0.bitPattern.bigEndian }
    data = bigEndianArray.withUnsafeBufferPointer { Data(buffer: $0) }
    print("Big-endian    : ", data as NSData)
}
// Values below are from:
//      https://en.wikipedia.org/wiki/Double-precision_floating-point_format

let nan = Double.nan
let plusInfinity                  =  +1.0 / 0.0
let maxDouble                     =  +1.7976931348623157E308
let smallestNumberGreaterThanOne  =  +1.0000000000000002
let plusOne                       =  +1.0
let maxSubnormalPositiveDouble    =  +2.2250738585072009E-308
let minSubnormalPositiveDouble    =  +4.9E-324
let plusZero                      =  +0.0

let minusZero                     =  -0.0
let maxSubnormalNegativeDouble    =  -4.9E-324
let minSubnormalNegativeDouble    =  -2.2250738585072009E-308
let minusOne                      =  -1.0
let largestNumberLessThanOne      =  -1.0000000000000002
let minDouble                     =  -1.7976931348623157E308
let minusInfinity                 =  -1.0 / 0.0


let smallestNumber = "+1.0000000000000002"
let largestNumber  = "-1.0000000000000002"



print("\n\nPrint little-endian and big-endian Doubles")
print("\n\nDisplay: NaN and +0.0 to +1.0")
print("                                                      Min. Subnormal    Max. Subnormal")
print("                  Not a Number      Plus Zero         Positive Double   Positive Double   Plus One")
print(String(format: "Decimal       :   NaN               %+8.6e     %+8.6e    %+8.6e    %+8.6e", plusZero, minSubnormalPositiveDouble, maxSubnormalPositiveDouble, plusOne))
var doubleArray = [nan, plusZero, minSubnormalPositiveDouble, maxSubnormalPositiveDouble, plusOne]
convert(doubleArray: doubleArray)

print("\n\nDisplay: +1.0 to +Infinity")
print("                                    Smallest Number                  ")
print("                  Plus One          Greater Than 1.0  Max. Double       +Infinity")
print(String(format: "Decimal       :   %+8.6e   \(smallestNumber) %+8.6e%+8.6e", plusOne, maxDouble, plusInfinity))
doubleArray = [plusOne, smallestNumberGreaterThanOne, maxDouble, plusInfinity]
convert(doubleArray: doubleArray)

print("\n\nDisplay: NaN and -0.0 to -1.0")
print("                                                      Min. Subnormal    Max. Subnormal")
print("                  Not a Number      Minus Zero        Negative Double   Negative Double   Minus One")
print(String(format: "Decimal       :   NaN               %+8.6e     %+8.6e    %+8.6e    %+8.6e", minusZero, maxSubnormalNegativeDouble, minSubnormalNegativeDouble, minusOne))
doubleArray = [nan, minusZero, maxSubnormalNegativeDouble, minSubnormalNegativeDouble, minusOne]
convert(doubleArray: doubleArray)

print("\n\nDisplay: -1.0 to -Infinity")
print("                                    Smallest Number                  ")
print("                  Minus One         Less Than -1.0    Min. Double       -Infinity")
print(String(format: "Decimal       :   %+8.6e   \(largestNumber) %+8.6e%+8.6e", minusOne, minDouble, minusInfinity))
doubleArray = [minusOne, largestNumberLessThanOne, minDouble, minusInfinity]
convert(doubleArray: doubleArray)

#1


1  

You can create an UInt64 containing the big-endian representation of the Double with

您可以创建包含Double with的big-endian表示的UInt64

let value = 1.0
var n = value.bitPattern.bigEndian

In order to write that to a file you might need to convert it to Data:

为了将其写入文件,您可能需要将其转换为数据:

let data = Data(buffer: UnsafeBufferPointer(start: &n, count: 1))
print(data as NSData) // <3ff00000 00000000>

If many contiguous floating point values are written to the file then it would be more effective to create an [UInt64] array with the big-endian representations and convert that to Data, for example

如果将大量连续的浮点值写入文件,那么使用big-endian表示创建[UInt64]数组并将其转换为Data会更有效,例如

let values = [1.0, 2.0, 3.0, 4.0]
let array = values.map { $0.bitPattern.bigEndian }
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }

(All the above compiles with Swift 3 and 4.)

(以上所有内容均使用Swift 3和4进行编译。)

#2


0  

I successfully implemented Martin's array suggestion. I decided I should use some "interesting" test values and one thing led to another! Here's my test playground. I hope it is of interest:

我成功实现了Martin的阵列建议。我决定使用一些“有趣”的测试值,一件事导致另一件事!这是我的测试操场。我希望有兴趣:

//: Playground - noun: a place where people can play

import UIKit

func convert(doubleArray: [Double]) {
    let littleEndianArray = doubleArray.map { $0.bitPattern}
    var data = littleEndianArray.withUnsafeBufferPointer { Data(buffer: $0) }
    print("Little-endian : ", data as NSData)

    // Convert and display the big-endian bytes
    let bigEndianArray = doubleArray.map { $0.bitPattern.bigEndian }
    data = bigEndianArray.withUnsafeBufferPointer { Data(buffer: $0) }
    print("Big-endian    : ", data as NSData)
}
// Values below are from:
//      https://en.wikipedia.org/wiki/Double-precision_floating-point_format

let nan = Double.nan
let plusInfinity                  =  +1.0 / 0.0
let maxDouble                     =  +1.7976931348623157E308
let smallestNumberGreaterThanOne  =  +1.0000000000000002
let plusOne                       =  +1.0
let maxSubnormalPositiveDouble    =  +2.2250738585072009E-308
let minSubnormalPositiveDouble    =  +4.9E-324
let plusZero                      =  +0.0

let minusZero                     =  -0.0
let maxSubnormalNegativeDouble    =  -4.9E-324
let minSubnormalNegativeDouble    =  -2.2250738585072009E-308
let minusOne                      =  -1.0
let largestNumberLessThanOne      =  -1.0000000000000002
let minDouble                     =  -1.7976931348623157E308
let minusInfinity                 =  -1.0 / 0.0


let smallestNumber = "+1.0000000000000002"
let largestNumber  = "-1.0000000000000002"



print("\n\nPrint little-endian and big-endian Doubles")
print("\n\nDisplay: NaN and +0.0 to +1.0")
print("                                                      Min. Subnormal    Max. Subnormal")
print("                  Not a Number      Plus Zero         Positive Double   Positive Double   Plus One")
print(String(format: "Decimal       :   NaN               %+8.6e     %+8.6e    %+8.6e    %+8.6e", plusZero, minSubnormalPositiveDouble, maxSubnormalPositiveDouble, plusOne))
var doubleArray = [nan, plusZero, minSubnormalPositiveDouble, maxSubnormalPositiveDouble, plusOne]
convert(doubleArray: doubleArray)

print("\n\nDisplay: +1.0 to +Infinity")
print("                                    Smallest Number                  ")
print("                  Plus One          Greater Than 1.0  Max. Double       +Infinity")
print(String(format: "Decimal       :   %+8.6e   \(smallestNumber) %+8.6e%+8.6e", plusOne, maxDouble, plusInfinity))
doubleArray = [plusOne, smallestNumberGreaterThanOne, maxDouble, plusInfinity]
convert(doubleArray: doubleArray)

print("\n\nDisplay: NaN and -0.0 to -1.0")
print("                                                      Min. Subnormal    Max. Subnormal")
print("                  Not a Number      Minus Zero        Negative Double   Negative Double   Minus One")
print(String(format: "Decimal       :   NaN               %+8.6e     %+8.6e    %+8.6e    %+8.6e", minusZero, maxSubnormalNegativeDouble, minSubnormalNegativeDouble, minusOne))
doubleArray = [nan, minusZero, maxSubnormalNegativeDouble, minSubnormalNegativeDouble, minusOne]
convert(doubleArray: doubleArray)

print("\n\nDisplay: -1.0 to -Infinity")
print("                                    Smallest Number                  ")
print("                  Minus One         Less Than -1.0    Min. Double       -Infinity")
print(String(format: "Decimal       :   %+8.6e   \(largestNumber) %+8.6e%+8.6e", minusOne, minDouble, minusInfinity))
doubleArray = [minusOne, largestNumberLessThanOne, minDouble, minusInfinity]
convert(doubleArray: doubleArray)