古いデータの変換

MS Binary形式浮動小数点数の取得

ニャンコロさんのVB用ルーチンをJavaに移植したものです(単精度のみ)。
詳細はhttp://homepage3.nifty.com/buckybecky/sw/ms2ieee.htmをどうぞ。

import org.junit.*;

/**
 * 古いマイクロソフト浮動小数点形式との変換。現在floatのみ、doubleは未サポート。
 * 
 * 参考資料:http://homepage3.nifty.com/buckybecky/sw/ms2ieee.htm
 * 上記サイトより:
 * MS Binary 形式とは、N88NASIC 等、初期の Microsoft Basic の浮動小数点数の
 * フォーマット。Quick Basic や Visual Basic の浮動小数点数は IEEE 形式とのこと。 
 * 
 */
public class MSBinFloat {
  
  /**
   * 4バイトのMS Binary形式単精度浮動小数点バイト列を(javaの)floatに変換する。
   * 入力バイトの順序はlittle Endian
   */
  public static float msbinToFloat(byte[]_msbin) {
    int[]msbin = new int[4];
    for (int i = 0; i < 4; i++) {
      msbin[i] = (int)_msbin[i] & 0xff;
    }    
    int expo = msbin[3] - 2;
    if (expo < 0) {
      return 0;
    }
    int sign = msbin[2] & 0x80;
    int ieee0 = msbin[0];
    int ieee1 = msbin[1];
    int ieee2 = ((expo & 1) * 128) | (msbin[2] & 0x7f);
    int ieee3 = sign | (expo / 2);    
    return Float.intBitsToFloat(
        (ieee3 << 24) + (ieee2 << 16) + (ieee1 << 8) + ieee0
    );
  }

  /** 
   * (javaの)floatをMS Binary形式単精度浮動小数点数バイト列(4バイト)に変換する。
   * 出力バイトの順序はLittle Endian
   */
  public static byte[]floatToMsbin(float value) {    
    int intBits = Float.floatToIntBits(value);
    int ieee0 = (intBits >>  0) & 0xff;
    int ieee1 = (intBits >>  8) & 0xff;
    int ieee2 = (intBits >> 16) & 0xff;
    int ieee3 = (intBits >> 24) & 0xff;
    int sign = ieee3 & 0x80;
    int expo = ((ieee3 & 0x7f) * 2) | (ieee2 / 128);
    if (expo > 0) {
      expo += 2;
    }
    if (expo <= 0xff) {
      return new byte[] {
          (byte)ieee0,
          (byte)ieee1,
          (byte)((ieee2 & 0x7f) | sign),
          (byte)expo,
      };
    }
    return new byte[] {
        (byte)0xff,
        (byte)0xff,
        (byte)(0x7f | sign),
        (byte)0xff,
    };    
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // 以下はJUnitを使用したテスト
  /////////////////////////////////////////////////////////////////////////////
  
  private static class TestFloat {
    
    /** float値 */
    float value;
    
    /** MS Binary形式バイト列 */
    byte[]bytes;
    
    private TestFloat(float value, byte[]bytes) {
      this.value = value;
      this.bytes = bytes;
    }
  }
  
  /** 値とバイト配列のサンプル */
  private static TestFloat[]testFloats = new TestFloat[] {
    new TestFloat(350F,   new byte[] { 0x00, 0x00, 0x2f, (byte)0x89 }),
    new TestFloat(94500F, new byte[] { 0x00, (byte)0x92, 0x38, (byte)0x91 }),
    new TestFloat(2100F,  new byte[] { 0x00, 0x40, 0x03, (byte)0x8c }),
    new TestFloat(2200F,  new byte[] { 0x00, (byte)0x80, 0x09, (byte)0x8c }),
  };
  
  @Test
  public void test() {
    for (TestFloat testFloat: testFloats) {
      float value = msbinToFloat(testFloat.bytes);
      Assert.assertEquals(testFloat.value, value);
    }
    for (TestFloat testFloat: testFloats) {
      byte[]bytes = floatToMsbin(testFloat.value);
      Assert.assertArrayEquals(testFloat.bytes, bytes);
    }
  }
}