コンテンツにスキップ

利用者:Ef3/Bfloat16Array

出典: フリー教科書『ウィキブックス(Wikibooks)』
/**
 * Bfloat16Array - A polyfill for Brain Floating Point 16-bit arrays
 * 
 * Bfloat16 format:
 * - 1 bit: sign
 * - 8 bits: exponent
 * - 7 bits: mantissa
 * 
 * This is different from IEEE 754 half-precision (Float16) which uses:
 * - 1 bit: sign
 * - 5 bits: exponent
 * - 10 bits: mantissa
 */
class Bfloat16Array extends Uint16Array {
  static get [Symbol.species]() {
    return Bfloat16Array;
  }

  // float32からbfloat16に変換
  static _float32ToBFloat16(value) {
    const float32 = new Float32Array(1);
    const uint32 = new Uint32Array(float32.buffer);
    float32[0] = value;
    return uint32[0] >>> 16;
  }

  // bfloat16からfloat32に変換
  static _bfloat16ToFloat32(value) {
    const uint32 = new Uint32Array(1);
    uint32[0] = value << 16;
    const float32 = new Float32Array(uint32.buffer);
    return float32[0];
  }

  // インデックスアクセス (getter)
  get(index) {
    return Bfloat16Array._bfloat16ToFloat32(this[index]);
  }

  // インデックスアクセス (setter)
  set(index, value) {
    super[index] = Bfloat16Array._float32ToBFloat16(value);
  }

  // イテレータをオーバーライドしてfloat32値を返す
  *[Symbol.iterator]() {
    for (let i = 0; i < this.length; i++) {
      yield this.get(i);
    }
  }

  // mapメソッドをオーバーライド
  map(fn) {
    const result = new (this.constructor[Symbol.species])(this.length);
    for (let i = 0; i < this.length; i++) {
      result.set(i, fn(this.get(i), i, this));
    }
    return result;
  }

  // sliceメソッドをオーバーライド
  slice(start, end) {
    const sliced = super.slice(start, end);
    return new this.constructor(sliced.buffer);
  }

}

// Usage example:
function testBfloat16Array() {
  console.log("Testing Bfloat16Array...");
  
  // Create a new array with 5 elements
  const bf16 = new Bfloat16Array(5);
  
  // Set some values
  bf16[0] = 1.0;
  bf16[1] = 1234.5678;
  bf16[2] = 3.14159265359;
  bf16[3] = 2.71828;
  bf16[4] = 1.0e20;
  
  console.log("Array values:");
  for (let i = 0; i < bf16.length; i++) {
    console.log(`bf16[${i}] = ${bf16[i]}`);
  }
  
  // Compare with Float32Array to show precision differences
  const f32 = new Float32Array([1.0, 1234.5678, 3.14159265359, 2.71828, 1.0e20]);
  
  console.log("\nComparison with Float32Array (precision differences):");
  for (let i = 0; i < bf16.length; i++) {
    console.log(`bfloat16: ${bf16[i]} vs float32: ${f32[i]}`);
  }
  
  // Test array methods
  console.log("\nTesting array methods:");
  console.log("forEach:");
  bf16.forEach((value, index) => console.log(`${index}: ${value}`));
  
  console.log("\nmap (multiply by 2):");
  const doubled = bf16.map(x => x * 2);
  for (let i = 0; i < doubled.length; i++) {
    console.log(`doubled[${i}] = ${doubled[i]}`);
  }
  
  // Test subarray
  console.log("\nTesting subarray:");
  const subarray = bf16.subarray(1, 4);
  for (let i = 0; i < subarray.length; i++) {
    console.log(`subarray[${i}] = ${subarray[i]}`);
  }
  
  return "Bfloat16Array test completed";
}

// Run tests if script is executed directly
if (typeof require !== 'undefined' && require.main === module) {
  testBfloat16Array();
}