Hex2num.java

/*
 * $Id: Hex2num.java,v 1.12 2008/02/25 08:35:52 koga Exp $
 * 
 * Copyright (C) 2004 Koga Laboratory. All rights reserved.
 */
package org.mklab.tool.matrix;

import org.mklab.nfc.matrix.IntMatrix;


/**
 * IEEE十六進表現から倍精度実数に変換するクラスです。
 * 
 * <p>IEEE hexidecimal to double precision number conversion
 * 
 * @author koga
 * @version $Revision: 1.12 $
 * @see org.mklab.tool.matrix.Hex2dec
 */
public class Hex2num {

  /**
   * メインメソッド
   * 
   * @param args コマンドライン引数
   */
  @SuppressWarnings("nls")
  public static void main(String[] args) {
    System.out.println("400921fb54442d18 = " + hex2num("400921fb54442d18"));

  }

  /**
   * IEEE16進数表現(IEEE倍精度浮動小数点数)の文字列を実数に変換します。 16文字より少ない場合、ゼロで埋められます。
   * 
   * @param s IEEE十六進表現
   * @return number 倍精度実数
   */
  public static double hex2num(String s) {
    IntMatrix d = new IntMatrix(1, 16);
    int n = s.length();
    int z = '0';
    int a = 'a';

    d.setSubVector(IntMatrix.series(1, n), new IntMatrix(s.getBytes()).subtractElementWise(z));
    IntMatrix idx = d.compareElementWise(".>", 10).find(); //$NON-NLS-1$
    d.setSubVector(idx, d.getSubVector(idx).addElementWise(z + 10 - a));

    boolean nf = d.getIntElement(1) > 7;

    if (nf) {
      d.setElement(1, d.getIntElement(1) - 8);
    }

    int e = 16 * (16 * (d.getIntElement(1) - 4) + d.getIntElement(2)) + d.getIntElement(3) + 1;
    double f = 0;
    for (int i = 16; i >= 4; i--) {
      f = (f + d.getIntElement(i)) / 16;
    }

    double x;
    if (e > 1023) {
      if (f == 0.0) {
        x = Double.POSITIVE_INFINITY;
      } else {
        x = Double.NaN;
      }
    } else if (e < -1022) {
      x = f * Math.pow(2, -1022);
    } else {
      x = (1 + f) * Math.pow(2, e);
    }

    if (nf) {
      x = -x;
    }
    return x;
  }

}