or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

buffer-conversion.mdbuffer-management.mdfloating-point-operations.mdindex.mdinteger-operations.mdstring-operations.mdvarint-operations.md
tile.json

floating-point-operations.mddocs/

Floating Point Operations

Read and write operations for 32-bit and 64-bit floating point numbers with endianness support. These operations provide IEEE 754 compliant floating point I/O capabilities.

Capabilities

32-bit Float Operations

Read and write 32-bit floating point numbers (IEEE 754 single precision).

/**
 * Write 32-bit floating point number (IEEE 754 single precision)
 * @param {number} value - Float value to write
 * @param {number} offset - Offset to write at (default: current offset)
 * @returns {ByteBuffer} This ByteBuffer for chaining
 */
writeFloat32(value, offset);

/**
 * Alias for writeFloat32
 */
writeFloat(value, offset);

/**
 * Read 32-bit floating point number (IEEE 754 single precision)
 * @param {number} offset - Offset to read from (default: current offset)
 * @returns {number|{value: number, offset: number}} Float value or result object
 */
readFloat32(offset);

/**
 * Alias for readFloat32
 */
readFloat(offset);

Usage Examples:

const ByteBuffer = require("bytebuffer");
const bb = ByteBuffer.allocate(16);

// Write 32-bit floats
bb.writeFloat32(3.14159);      // Pi
bb.writeFloat(-42.5);          // Using alias
bb.writeFloat32(1.23e-4);      // Scientific notation
bb.writeFloat32(Infinity);     // Special values supported

// Endianness affects byte order
bb.LE(); // Switch to little endian
bb.writeFloat32(1.5);

bb.BE(); // Switch to big endian
bb.writeFloat32(2.5);

// Read back
bb.flip();
const pi = bb.readFloat32();        // 3.14159 (approximately)
const negative = bb.readFloat();    // -42.5
const scientific = bb.readFloat32(); // 0.000123 (approximately)
const infinite = bb.readFloat32();   // Infinity

// Handle precision limitations
console.log(pi === 3.14159); // May be false due to float precision
console.log(Math.abs(pi - 3.14159) < 0.00001); // Better comparison

64-bit Double Operations

Read and write 64-bit floating point numbers (IEEE 754 double precision).

/**
 * Write 64-bit floating point number (IEEE 754 double precision)
 * @param {number} value - Double value to write
 * @param {number} offset - Offset to write at (default: current offset)
 * @returns {ByteBuffer} This ByteBuffer for chaining
 */
writeFloat64(value, offset);

/**
 * Alias for writeFloat64
 */
writeDouble(value, offset);

/**
 * Read 64-bit floating point number (IEEE 754 double precision)
 * @param {number} offset - Offset to read from (default: current offset)
 * @returns {number|{value: number, offset: number}} Double value or result object
 */
readFloat64(offset);

/**
 * Alias for readFloat64
 */
readDouble(offset);

Usage Examples:

const bb = ByteBuffer.allocate(32);

// Write 64-bit doubles (higher precision than 32-bit floats)
bb.writeFloat64(Math.PI);          // Full precision pi
bb.writeDouble(-123.456789012345); // Using alias
bb.writeFloat64(1.7976931348623157e+308); // Near max double value
bb.writeFloat64(Number.MIN_VALUE); // Smallest positive value

// Special floating point values
bb.writeFloat64(NaN);              // Not a Number
bb.writeFloat64(Infinity);         // Positive infinity
bb.writeFloat64(-Infinity);        // Negative infinity
bb.writeFloat64(-0);               // Negative zero

// Read back
bb.flip();
const precisePi = bb.readFloat64();    // 3.141592653589793
const precise = bb.readDouble();       // -123.456789012345
const largeValue = bb.readFloat64();   // 1.7976931348623157e+308
const minValue = bb.readFloat64();     // 5e-324

// Handle special values
const notANumber = bb.readFloat64();   // NaN
const posInf = bb.readFloat64();       // Infinity
const negInf = bb.readFloat64();       // -Infinity
const negZero = bb.readFloat64();      // -0

// Test for special values
console.log(Number.isNaN(notANumber));    // true
console.log(Number.isFinite(posInf));     // false
console.log(Object.is(negZero, -0));      // true

Precision and Range Considerations

Understanding the differences between 32-bit and 64-bit floating point representations.

32-bit Float (Single Precision):

  • Range: ±1.175494351e-38 to ±3.402823466e+38
  • Precision: ~7 decimal digits
  • Uses 4 bytes of storage

64-bit Double (Double Precision):

  • Range: ±2.2250738585072014e-308 to ±1.7976931348623157e+308
  • Precision: ~15-17 decimal digits
  • Uses 8 bytes of storage

Usage Examples:

const bb = ByteBuffer.allocate(16);

// Demonstrate precision differences
const preciseValue = 1.23456789012345;

// 32-bit float loses precision
bb.writeFloat32(preciseValue);
bb.flip();
const float32Result = bb.readFloat32();
console.log(float32Result); // ~1.2345679 (lost precision)

// 64-bit double maintains precision
bb.clear();
bb.writeFloat64(preciseValue);
bb.flip();
const float64Result = bb.readFloat64();
console.log(float64Result); // 1.23456789012345 (full precision)

// Range demonstration
const veryLarge = 1e200;
bb.clear();

try {
    bb.writeFloat32(veryLarge); // May become Infinity
    bb.flip();
    console.log(bb.readFloat32()); // Infinity
} catch (error) {
    console.log("Value too large for float32");
}

bb.clear();
bb.writeFloat64(veryLarge); // Fits in double
bb.flip();
console.log(bb.readFloat64()); // 1e+200

Endianness and Floating Point

Floating point numbers are affected by endianness settings just like integers.

Usage Examples:

const bb = ByteBuffer.allocate(16);
const testValue = 1.25; // Simple value for testing

// Big endian (default)
bb.BE();
bb.writeFloat32(testValue);
const bigEndianBytes = bb.toHex(0, 4);
console.log("Big endian:", bigEndianBytes);

// Little endian
bb.clear();
bb.LE();
bb.writeFloat32(testValue);
const littleEndianBytes = bb.toHex(0, 4);
console.log("Little endian:", littleEndianBytes);

// The byte order is reversed but the value is the same
bb.flip();
const readValue = bb.readFloat32();
console.log("Read value:", readValue); // Still 1.25

Absolute Positioning

Read and write floats at specific buffer positions without moving the offset.

Usage Examples:

const bb = ByteBuffer.allocate(32);

// Write floats at specific positions
bb.writeFloat32(1.1, 0);    // Position 0
bb.writeFloat32(2.2, 8);    // Position 8
bb.writeFloat64(3.3, 16);   // Position 16

// Read from specific positions
const first = bb.readFloat32(0);   // 1.1
const second = bb.readFloat32(8);  // 2.2
const third = bb.readFloat64(16);  // 3.3

// Offset remains at 0 since we used absolute positioning
console.log(bb.offset); // 0

// Sequential read/write moves the offset
bb.writeFloat32(4.4);  // Writes at current offset (0)
console.log(bb.offset); // 4

Error Handling

Floating point operations may encounter the following error conditions:

  • TypeError: When non-numeric values are provided for float operations
  • Error: When attempting to read beyond buffer limits (if assertions enabled)
  • RangeError: When buffer capacity is insufficient for the operation

Example Error Handling:

const bb = ByteBuffer.allocate(4);

try {
    // This will throw TypeError
    bb.writeFloat32("not a number");
} catch (error) {
    console.error("Invalid value:", error.message);
}

try {
    // This will throw Error if reading beyond buffer
    bb.readFloat64(); // Trying to read 8 bytes from 4-byte buffer
} catch (error) {
    console.error("Read error:", error.message);
}

// Handle special float values
const testValues = [NaN, Infinity, -Infinity, 0, -0];
testValues.forEach(value => {
    bb.clear();
    bb.writeFloat32(value);
    bb.flip();
    const result = bb.readFloat32();
    
    if (Number.isNaN(value)) {
        console.log("NaN preserved:", Number.isNaN(result));
    } else if (!Number.isFinite(value)) {
        console.log("Infinity preserved:", result === value);
    } else if (Object.is(value, -0)) {
        console.log("Negative zero preserved:", Object.is(result, -0));
    }
});

Performance Considerations

  • 32-bit floats use less memory and may have faster I/O on some platforms
  • 64-bit doubles provide higher precision but use twice the storage
  • Endianness conversion may have performance implications on some platforms
  • Absolute positioning avoids offset calculations but requires manual position management