Skip to content

Commit

Permalink
Add reading/writing of floats and doubles from/to buffers
Browse files Browse the repository at this point in the history
Code for readIEEE754/writeIEEE754 is from jspack: http://code.google.com/p/jspack/
  • Loading branch information
mscdex authored and ry committed May 16, 2011
1 parent 91bd144 commit e505a12
Show file tree
Hide file tree
Showing 8 changed files with 640 additions and 0 deletions.
3 changes: 3 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ The externally maintained libraries used by Node are:

- tools/cpplint.py is copyright Google Inc. and released under a
BSD license.

- lib/buffer_ieee754.js is copyright 2008 Fair Oaks Labs, Inc. and released
under the New BSD license.
80 changes: 80 additions & 0 deletions doc/api/buffers.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,48 @@ bytes from the buffer in.
Works as `buffer.readUInt32`, except buffer contents are treated as twos
complement signed values.

### buffer.readFloat(offset, endian)

Reads a 32 bit float from the buffer at the specified offset. Endian must be
either 'big' or 'little' and specifies what endian ordering to read the bytes
from the buffer in.

Example:

var buf = new Buffer(4);

buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x80;
buf[3] = 0x3f;

console.log(buf.readFloat(0, 'little');

// 0x01

### buffer.readDouble(offset, endian)

Reads a 64 bit double from the buffer at the specified offset. Endian must be
either 'big' or 'little' and specifies what endian ordering to read the bytes
from the buffer in.

Example:

var buf = new Buffer(8);

buf[0] = 0x55;
buf[1] = 0x55;
buf[2] = 0x55;
buf[3] = 0x55;
buf[4] = 0x55;
buf[5] = 0x55;
buf[6] = 0xd5;
buf[7] = 0x3f;

console.log(buf.readDouble(0, 'little');

// 0.3333333333333333

### buffer.writeUInt8(value, offset, endian)

Writes `value` to the buffer at the specified offset with specified endian
Expand Down Expand Up @@ -364,6 +406,44 @@ format. Note, `value` must be a valid 16 bit signed integer.
Works as `buffer.writeUInt832, except value is written out as a two's complement
signed integer into `buffer`.

### buffer.writeFloat(value, offset, endian)

Writes `value` to the buffer at the specified offset with specified endian
format. Note, `value` must be a valid 32 bit float.

Example:

var buf = new Buffer(4);
buf.writeFloat(0xcafebabe, 0, 'big');

console.log(buf);

buf.writeFloat(0xcafebabe, 0, 'little');

console.log(buf);

// <Buffer 4f 4a fe bb>
// <Buffer bb fe 4a 4f>

### buffer.writeDouble(value, offset, endian)

Writes `value` to the buffer at the specified offset with specified endian
format. Note, `value` must be a valid 64 bit double.

Example:

var buf = new Buffer(8);
buf.writeFloat(0xdeadbeefcafebabe, 0, 'big');

console.log(buf);

buf.writeFloat(0xdeadbeefcafebabe, 0, 'little');

console.log(buf);

// <Buffer 43 eb d5 b7 dd f9 5f d7>
// <Buffer d7 5f f9 dd b7 d5 eb 43>


### buffer.fill(value, offset=0, length=-1)

Expand Down
95 changes: 95 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var SlowBuffer = process.binding('buffer').SlowBuffer;
var IEEE754 = require('buffer_ieee754');
var assert = require('assert');


Expand Down Expand Up @@ -684,6 +685,43 @@ Buffer.prototype.readInt32 = function(offset, endian) {
};


Buffer.prototype.readFloat = function(offset, endian) {
var buffer = this;

assert.ok(endian !== undefined && endian !== null,
'missing endian');

assert.ok(endian == 'big' || endian == 'little',
'bad endian value');

assert.ok(offset !== undefined && offset !== null,
'missing offset');

assert.ok(offset + 3 < buffer.length,
'Trying to read beyond buffer length');

return IEEE754.readIEEE754(buffer, offset, endian, 23, 4);
};

Buffer.prototype.readDouble = function(offset, endian) {
var buffer = this;

assert.ok(endian !== undefined && endian !== null,
'missing endian');

assert.ok(endian == 'big' || endian == 'little',
'bad endian value');

assert.ok(offset !== undefined && offset !== null,
'missing offset');

assert.ok(offset + 7 < buffer.length,
'Trying to read beyond buffer length');

return IEEE754.readIEEE754(buffer, offset, endian, 52, 8);
};


/*
* We have to make sure that the value is a valid integer. This means that it is
* non-negative. It has no fractional component and that it does not exceed the
Expand Down Expand Up @@ -843,6 +881,17 @@ function verifsint(value, max, min) {
assert.ok(Math.floor(value) === value, 'value has a fractional component');
}


function verifIEEE754(value, max, min) {
assert.ok(typeof (value) == 'number',
'cannot write a non-number as a number');

assert.ok(value <= max, 'value larger than maximum allowed value');

assert.ok(value >= min, 'value smaller than minimum allowed value');
}


Buffer.prototype.writeInt8 = function(value, offset, endian) {
var buffer = this;

Expand Down Expand Up @@ -924,3 +973,49 @@ Buffer.prototype.writeInt32 = function(value, offset, endian) {
buffer.writeUInt32(0xffffffff + value + 1, offset, endian);
}
};


Buffer.prototype.writeFloat = function(value, offset, endian) {
var buffer = this;

assert.ok(value !== undefined && value !== null,
'missing value');

assert.ok(endian !== undefined && endian !== null,
'missing endian');

assert.ok(endian == 'big' || endian == 'little',
'bad endian value');

assert.ok(offset !== undefined && offset !== null,
'missing offset');

assert.ok(offset + 3 < buffer.length,
'Trying to read beyond buffer length');

verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
IEEE754.writeIEEE754(buffer, value, offset, endian, 23, 4);
};


Buffer.prototype.writeDouble = function(value, offset, endian) {
var buffer = this;

assert.ok(value !== undefined && value !== null,
'missing value');

assert.ok(endian !== undefined && endian !== null,
'missing endian');

assert.ok(endian == 'big' || endian == 'little',
'bad endian value');

assert.ok(offset !== undefined && offset !== null,
'missing offset');

assert.ok(offset + 7 < buffer.length,
'Trying to read beyond buffer length');

verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
IEEE754.writeIEEE754(buffer, value, offset, endian, 52, 8);
};
118 changes: 118 additions & 0 deletions lib/buffer_ieee754.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2008, Fair Oaks Labs, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
// Modifications to writeIEEE754 to support negative zeroes made by Brian White

exports.readIEEE754 = function(buffer, offset, endian, mLen, nBytes) {
var e, m,
bBE = (endian === 'big'),
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
nBits = -7,
i = bBE ? 0 : (nBytes - 1),
d = bBE ? 1 : -1,
s = buffer[offset + i];

i += d;

e = s & ((1 << (-nBits)) - 1);
s >>= (-nBits);
nBits += eLen;
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);

m = e & ((1 << (-nBits)) - 1);
e >>= (-nBits);
nBits += mLen;
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);

if (e === 0) {
e = 1 - eBias;
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity);
} else {
m = m + Math.pow(2, mLen);
e = e - eBias;
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
};

exports.writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) {
var e, m, c,
bBE = (endian === 'big'),
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
i = bBE ? (nBytes-1) : 0,
d = bBE ? -1 : 1,
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;

value = Math.abs(value);

if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0;
e = eMax;
} else {
e = Math.floor(Math.log(value) / Math.LN2);
if (value * (c = Math.pow(2, -e)) < 1) {
e--;
c *= 2;
}
if (e+eBias >= 1) {
value += rt / c;
} else {
value += rt * Math.pow(2, 1 - eBias);
}
if (value * c >= 2) {
e++;
c /= 2;
}

if (e + eBias >= eMax) {
m = 0;
e = eMax;
} else if (e + eBias >= 1) {
m = (value * c - 1) * Math.pow(2, mLen);
e = e + eBias;
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
e = 0;
}
}

for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);

e = (e << mLen) | m;
eLen += mLen;
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);

buffer[offset + i - d] |= s * 128;
};
Loading

0 comments on commit e505a12

Please sign in to comment.