1

How can one convert an array of bytes into a double value in Swift?

(It's an NSInputStream extension)

My snippet attached below, but it's not returning correct double value:

func readDouble() -> Double
{
var readBuffer = Array<UInt8>(count:sizeof(Double), repeatedValue: 0)

        let numberOfBytesRead = self.read(&readBuffer, maxLength: readBuffer.count)
        let help1 = Int(readBuffer[0] & 0xff) << 56 | Int(readBuffer[1] & 0xff) << 48
        let help2 = Int(readBuffer[2] & 0xff) << 40 | Int(readBuffer[3] & 0xff) << 32
        let help3 = Int(readBuffer[4] & 0xff) << 24 | Int(readBuffer[5] & 0xff) << 16
        let help4 = (Int(readBuffer[6] & 0xff) << 8) | Int(readBuffer[7] & 0xff)
        return Double(help1 | help2 | help3 | help4)
}
AVEbrahimi
  • 17,993
  • 23
  • 107
  • 210
  • How is the data represented in the input stream? As an integer or IEEE binary double? Which byte order? What result do you get and what do you expect? – Martin R Aug 02 '15 at 15:25
  • It's an array of doubles written in java. – AVEbrahimi Aug 02 '15 at 15:26
  • You are asking the Swift people, so it might be helpful to add the information *how* Java writes an array of doubles. – Martin R Aug 02 '15 at 15:27
  • What does `println(readBuffer)` show (after the read operation), and what should be the result? – Martin R Aug 02 '15 at 15:32
  • Possible duplicate of [Convert an Objective-C method into Swift for NSInputStream (convert bytes into double)](http://stackoverflow.com/questions/25845574/convert-an-objective-c-method-into-swift-for-nsinputstream-convert-bytes-into-d) ? – Martin R Aug 02 '15 at 15:37
  • Byte array to Double also in this answer: http://stackoverflow.com/a/26954091/1630618 – vacawama Aug 02 '15 at 15:52
  • @vacawama: My point is that you (probably) don't need to read into a byte array first, you can read into the Double directly. But we still have no concrete information about the representation in the input stream. – Martin R Aug 02 '15 at 15:57

2 Answers2

3

It's very simple:

extension FloatingPoint {

    init?(_ bytes: [UInt8]) {

        guard bytes.count == MemoryLayout<Self>.size else { return nil }

        self = bytes.withUnsafeBytes {

            return $0.load(fromByteOffset: 0, as: Self.self)
        }
    }
}

let array: [UInt8] =  [0, 0, 0, 0, 0, 0, 240, 63]
let num = Double(array) // 1.0

This code does work for any floating point type in Swift.

Swift 3.0 on macOS (little-endian representation of Double)

You can look up my cheat sheet for byte conversion here. (little/big endian number conversion)

DevAndArtist
  • 4,971
  • 1
  • 23
  • 48
  • I don't understand how is that byte array is converted into a Double. Currently running into issues when converting data – Kehlin Swain Feb 09 '19 at 02:53
  • 1
    What is it that you don't understand? This is just a convenient initializer that re-interprets an array of `UInt8` as the floating point type of your choice. It's your responsibility to provide the correct stream of bytes Swift would expect. – DevAndArtist Feb 10 '19 at 09:28
0

My understanding is that your byte array is a serialization of the binary representation. However, the Double constructor you're using takes an integer value and returns a corresponding Double. Double(3) returns 3.0.

The right constructor would probably be Double(_bits:), but it accepts a Builtin.FPIEEE64 and it looks like its availability is an implementation detail. You should probably consider making a C function and bridge it to Swift.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • You can read from an input stream directly into a Swift `Double` variable, see for example http://stackoverflow.com/a/25846086/1187415. But it depends on the data representation (that's what I am still trying to figure out). – Martin R Aug 02 '15 at 15:33