浮動小数点数と16進数の相互変換方法【JavaScript/Python完全解説】

フリーランスボード

20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード

ITプロパートナーズ

週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ

Midworks 10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks

浮動小数点数のバイナリ表現を16進数文字列として扱う処理は、システムプログラミングやデータ解析において重要です。この記事では、float値と16進数表現の文字列を相互変換する方法を詳しく解説します。

JavaScript での浮動小数点数と16進数変換

Float32(単精度)の変換

function floatToHex32(num) {
  const buffer = new ArrayBuffer(4);
  const view = new DataView(buffer);
  view.setFloat32(0, num, false); // ビッグエンディアン
  
  let hex = '';
  for (let i = 0; i < 4; i++) {
    hex += view.getUint8(i).toString(16).padStart(2, '0');
  }
  return hex;
}

function hexToFloat32(hex) {
  const buffer = new ArrayBuffer(4);
  const view = new DataView(buffer);
  
  for (let i = 0; i < 4; i++) {
    const byte = parseInt(hex.substr(i * 2, 2), 16);
    view.setUint8(i, byte);
  }
  return view.getFloat32(0, false);
}

// 使用例
console.log(floatToHex32(3.14159));  // "40490fdb"
console.log(hexToFloat32("40490fdb")); // 3.1415901184082031

Float64(倍精度)の変換

function floatToHex64(num) {
  const buffer = new ArrayBuffer(8);
  const view = new DataView(buffer);
  view.setFloat64(0, num, false);
  
  let hex = '';
  for (let i = 0; i < 8; i++) {
    hex += view.getUint8(i).toString(16).padStart(2, '0');
  }
  return hex;
}

function hexToFloat64(hex) {
  const buffer = new ArrayBuffer(8);
  const view = new DataView(buffer);
  
  for (let i = 0; i < 8; i++) {
    const byte = parseInt(hex.substr(i * 2, 2), 16);
    view.setUint8(i, byte);
  }
  return view.getFloat64(0, false);
}

// 使用例
console.log(floatToHex64(3.14159));  // "400921fb54442d18"
console.log(hexToFloat64("400921fb54442d18")); // 3.14159

Python での浮動小数点数と16進数変換

structモジュールを使用

import struct

def float_to_hex32(num):
    """32ビット浮動小数点数を16進数文字列に変換"""
    packed = struct.pack('>f', num)  # ビッグエンディアン
    return packed.hex()

def hex_to_float32(hex_str):
    """16進数文字列を32ビット浮動小数点数に変換"""
    bytes_data = bytes.fromhex(hex_str)
    return struct.unpack('>f', bytes_data)[0]

def float_to_hex64(num):
    """64ビット浮動小数点数を16進数文字列に変換"""
    packed = struct.pack('>d', num)
    return packed.hex()

def hex_to_float64(hex_str):
    """16進数文字列を64ビット浮動小数点数に変換"""
    bytes_data = bytes.fromhex(hex_str)
    return struct.unpack('>d', bytes_data)[0]

# 使用例
print(float_to_hex32(3.14159))      # "40490fdb"
print(hex_to_float32("40490fdb"))   # 3.1415901184082031
print(float_to_hex64(3.14159))      # "400921fb54442d18"
print(hex_to_float64("400921fb54442d18"))  # 3.14159

包括的な変換クラス

JavaScript版

class FloatHexConverter {
  static float32ToHex(num) {
    const buffer = new ArrayBuffer(4);
    const view = new DataView(buffer);
    view.setFloat32(0, num, false);
    
    return Array.from(new Uint8Array(buffer))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
  
  static hexToFloat32(hex) {
    if (hex.length !== 8) {
      throw new Error('32ビットfloatには8文字の16進数が必要です');
    }
    
    const buffer = new ArrayBuffer(4);
    const view = new DataView(buffer);
    
    for (let i = 0; i < 4; i++) {
      view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
    }
    return view.getFloat32(0, false);
  }
  
  static float64ToHex(num) {
    const buffer = new ArrayBuffer(8);
    const view = new DataView(buffer);
    view.setFloat64(0, num, false);
    
    return Array.from(new Uint8Array(buffer))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');
  }
  
  static hexToFloat64(hex) {
    if (hex.length !== 16) {
      throw new Error('64ビットfloatには16文字の16進数が必要です');
    }
    
    const buffer = new ArrayBuffer(8);
    const view = new DataView(buffer);
    
    for (let i = 0; i < 8; i++) {
      view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
    }
    return view.getFloat64(0, false);
  }
}

Python版

import struct

class FloatHexConverter:
    @staticmethod
    def float32_to_hex(num):
        """32ビット浮動小数点数を16進数文字列に変換"""
        try:
            packed = struct.pack('>f', num)
            return packed.hex()
        except (struct.error, OverflowError) as e:
            raise ValueError(f"変換エラー: {e}")
    
    @staticmethod
    def hex_to_float32(hex_str):
        """16進数文字列を32ビット浮動小数点数に変換"""
        if len(hex_str) != 8:
            raise ValueError("32ビットfloatには8文字の16進数が必要です")
        
        try:
            bytes_data = bytes.fromhex(hex_str)
            return struct.unpack('>f', bytes_data)[0]
        except (ValueError, struct.error) as e:
            raise ValueError(f"変換エラー: {e}")
    
    @staticmethod
    def float64_to_hex(num):
        """64ビット浮動小数点数を16進数文字列に変換"""
        try:
            packed = struct.pack('>d', num)
            return packed.hex()
        except (struct.error, OverflowError) as e:
            raise ValueError(f"変換エラー: {e}")
    
    @staticmethod
    def hex_to_float64(hex_str):
        """16進数文字列を64ビット浮動小数点数に変換"""
        if len(hex_str) != 16:
            raise ValueError("64ビットfloatには16文字の16進数が必要です")
        
        try:
            bytes_data = bytes.fromhex(hex_str)
            return struct.unpack('>d', bytes_data)[0]
        except (ValueError, struct.error) as e:
            raise ValueError(f"変換エラー: {e}")

特殊値の処理

JavaScript

function handleSpecialValues() {
  console.log("正の無限大:", FloatHexConverter.float32ToHex(Infinity));
  console.log("負の無限大:", FloatHexConverter.float32ToHex(-Infinity));
  console.log("NaN:", FloatHexConverter.float32ToHex(NaN));
  console.log("ゼロ:", FloatHexConverter.float32ToHex(0.0));
  console.log("負のゼロ:", FloatHexConverter.float32ToHex(-0.0));
}

Python

import math

def handle_special_values():
    print("正の無限大:", FloatHexConverter.float32_to_hex(float('inf')))
    print("負の無限大:", FloatHexConverter.float32_to_hex(float('-inf')))
    print("NaN:", FloatHexConverter.float32_to_hex(float('nan')))
    print("ゼロ:", FloatHexConverter.float32_to_hex(0.0))
    print("負のゼロ:", FloatHexConverter.float32_to_hex(-0.0))

エンディアンの考慮

リトルエンディアン対応

// JavaScript
function floatToHexLE(num) {
  const buffer = new ArrayBuffer(4);
  const view = new DataView(buffer);
  view.setFloat32(0, num, true); // リトルエンディアン
  
  return Array.from(new Uint8Array(buffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

function hexToFloatLE(hex) {
  const buffer = new ArrayBuffer(4);
  const view = new DataView(buffer);
  
  for (let i = 0; i < 4; i++) {
    view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
  }
  return view.getFloat32(0, true); // リトルエンディアン
}
# Python
def float_to_hex_le(num):
    """リトルエンディアンで変換"""
    packed = struct.pack('<f', num)  # リトルエンディアン
    return packed.hex()

def hex_to_float_le(hex_str):
    """リトルエンディアンで変換"""
    bytes_data = bytes.fromhex(hex_str)
    return struct.unpack('<f', bytes_data)[0]

IEEE 754形式の詳細解析

ビット構造の表示

function analyzeFloat32Bits(num) {
  const buffer = new ArrayBuffer(4);
  const view = new DataView(buffer);
  view.setFloat32(0, num, false);
  
  const bits = view.getUint32(0, false);
  const sign = (bits >>> 31) & 1;
  const exponent = (bits >>> 23) & 0xFF;
  const mantissa = bits & 0x7FFFFF;
  
  return {
    hex: bits.toString(16).padStart(8, '0'),
    sign: sign,
    exponent: exponent,
    mantissa: mantissa,
    binary: bits.toString(2).padStart(32, '0')
  };
}

// 使用例
console.log(analyzeFloat32Bits(3.14159));
def analyze_float32_bits(num):
    """32ビットfloatのビット構造を解析"""
    packed = struct.pack('>f', num)
    bits = struct.unpack('>I', packed)[0]
    
    sign = (bits >> 31) & 1
    exponent = (bits >> 23) & 0xFF
    mantissa = bits & 0x7FFFFF
    
    return {
        'hex': f"{bits:08x}",
        'sign': sign,
        'exponent': exponent,
        'mantissa': mantissa,
        'binary': f"{bits:032b}"
    }

# 使用例
print(analyze_float32_bits(3.14159))

バリデーション付き変換関数

JavaScript版

class SafeFloatHexConverter {
  static validateHex(hex, expectedLength) {
    if (typeof hex !== 'string') {
      throw new Error('16進数文字列である必要があります');
    }
    
    if (hex.length !== expectedLength) {
      throw new Error(`${expectedLength}文字の16進数が必要です`);
    }
    
    if (!/^[0-9a-fA-F]+$/.test(hex)) {
      throw new Error('無効な16進数文字列です');
    }
  }
  
  static safeFloat32ToHex(num) {
    if (!Number.isFinite(num) && !Number.isNaN(num)) {
      console.warn('特殊値を変換しています:', num);
    }
    return FloatHexConverter.float32ToHex(num);
  }
  
  static safeHexToFloat32(hex) {
    this.validateHex(hex, 8);
    return FloatHexConverter.hexToFloat32(hex);
  }
}

Python版

import re

class SafeFloatHexConverter:
    @staticmethod
    def validate_hex(hex_str, expected_length):
        """16進数文字列の妥当性をチェック"""
        if not isinstance(hex_str, str):
            raise ValueError("16進数文字列である必要があります")
        
        if len(hex_str) != expected_length:
            raise ValueError(f"{expected_length}文字の16進数が必要です")
        
        if not re.match(r'^[0-9a-fA-F]+, hex_str):
            raise ValueError("無効な16進数文字列です")
    
    @staticmethod
    def safe_float32_to_hex(num):
        """安全な32ビット浮動小数点数変換"""
        import math
        if math.isinf(num) or math.isnan(num):
            print(f"警告: 特殊値を変換しています: {num}")
        return FloatHexConverter.float32_to_hex(num)
    
    @staticmethod
    def safe_hex_to_float32(hex_str):
        """安全な16進数から32ビット浮動小数点数変換"""
        SafeFloatHexConverter.validate_hex(hex_str, 8)
        return FloatHexConverter.hex_to_float32(hex_str)

実用的な使用例

データシリアライゼーション

class FloatSerializer {
  static serialize(floats) {
    return floats.map(f => FloatHexConverter.float32ToHex(f)).join('');
  }
  
  static deserialize(hexString) {
    const floats = [];
    for (let i = 0; i < hexString.length; i += 8) {
      const hex = hexString.substr(i, 8);
      if (hex.length === 8) {
        floats.push(FloatHexConverter.hexToFloat32(hex));
      }
    }
    return floats;
  }
}

// 使用例
const data = [3.14, 2.71, 1.41];
const serialized = FloatSerializer.serialize(data);
console.log("シリアライズ:", serialized);
console.log("デシリアライズ:", FloatSerializer.deserialize(serialized));
class FloatSerializer:
    @staticmethod
    def serialize(floats):
        """浮動小数点数配列を16進数文字列にシリアライズ"""
        return ''.join(FloatHexConverter.float32_to_hex(f) for f in floats)
    
    @staticmethod
    def deserialize(hex_string):
        """16進数文字列から浮動小数点数配列にデシリアライズ"""
        floats = []
        for i in range(0, len(hex_string), 8):
            hex_chunk = hex_string[i:i+8]
            if len(hex_chunk) == 8:
                floats.append(FloatHexConverter.hex_to_float32(hex_chunk))
        return floats

# 使用例
data = [3.14, 2.71, 1.41]
serialized = FloatSerializer.serialize(data)
print("シリアライズ:", serialized)
print("デシリアライズ:", FloatSerializer.deserialize(serialized))

パフォーマンステスト

JavaScript版

function performanceTest() {
  const testData = Array.from({length: 10000}, () => Math.random() * 1000);
  
  console.time('Float to Hex conversion');
  const hexData = testData.map(FloatHexConverter.float32ToHex);
  console.timeEnd('Float to Hex conversion');
  
  console.time('Hex to Float conversion');
  const backToFloat = hexData.map(FloatHexConverter.hexToFloat32);
  console.timeEnd('Hex to Float conversion');
}
import time

def performance_test():
    import random
    test_data = [random.random() * 1000 for _ in range(10000)]
    
    start_time = time.time()
    hex_data = [FloatHexConverter.float32_to_hex(f) for f in test_data]
    print(f"Float to Hex変換: {time.time() - start_time:.4f}秒")
    
    start_time = time.time()
    back_to_float = [FloatHexConverter.hex_to_float32(h) for h in hex_data]
    print(f"Hex to Float変換: {time.time() - start_time:.4f}秒")

まとめ

浮動小数点数と16進数の相互変換は、システム間でのデータ交換やバイナリ形式での保存において重要な技術です。JavaScriptではArrayBufferとDataView、Pythonではstructモジュールを使用することで、効率的で正確な変換が可能です。エラーハンドリングやバリデーションを含めた実装により、堅牢なシステムを構築できます。

「らくらくPython塾」が切り開く「呪文コーディング」とは?

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座

フリーランスボード

20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード

ITプロパートナーズ

週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ

Midworks 10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks