【问题标题】:Double to Hex String and Back加倍到十六进制字符串并返回
【发布时间】:2011-07-22 23:20:24
【问题描述】:

在 Java 中将 double 转换为十六进制字符串相当简单。但是我该如何做相反的事情呢?我的代码在下面,我已经注意到 NumberFormatException 被抛出的位置(大约下降了 2/3)。

public class HexToDoubleTest {
    public static void main( String args[] ) {

        // This is the starting double value
        double doubleInput = -9.156013e-002;

        // Convert the starting value to the equivalent value in a long
        long doubleAsLong = Double.doubleToRawLongBits( doubleInput );

        // Convert the long to a String
        String doubleAsString = Long.toHexString( doubleAsLong );

        // Print the String
        System.out.println( doubleAsString );

        // Attempt to parse the string back as a long
        // !!! This fails with a NumberFormatException !!!
        long doubleAsLongReverse = Long.parseLong( doubleAsString, 16 );

        // Convert the long back into the original double
        double doubleOutput = Double.longBitsToDouble( doubleAsLongReverse );

        // Confirm that the values match
        assert( doubleInput == doubleOutput );

    }
}

使用Double.valueOf 以同样的方式失败。

编辑:我已经在网络上进行了一些搜索,发现了一些非常不雅的解决方案。例如:使用BigInteger 似乎有点矫枉过正。一定有更好的方法!

【问题讨论】:

    标签: java string data-structures hex


    【解决方案1】:

    你可以将String分成两半并解析每一半,但我认为这是最简单的。

    long doubleAsLongReverse = new BigInteger(doubleAsString, 16).longValue();
    

    在 Java 8 中,现在有一个

    long l = Long.parseUnsignedLong(doubleAsString, 16);
    

    并扭转这一点

    String s = Long.toUnsignedString(l, 16);
    

    这些可以与将原始double 转换为long 等的方法结合使用。

    【讨论】:

    • 最终这样做了(尽管我说我想避免使用 BigInteger)。
    • 我也倾向于避免使用 BigDecimal/BigInteger,但有时它是最好的选择。
    • @PeterLawrey - 是否可以将此长值转换回原始字符串?
    【解决方案2】:

    为什么不使用标准库中提供的方法: Double.valueOfDouble.toHexString

    所以一个完整的往返示例是

    public static void main(String[] args){
    
        double doubleValue = -0.03454568;
        System.out.println("Initial double value is " + doubleValue);
    
        String hexStringRepresentation = Double.toHexString(doubleValue);
        System.out.println("Hex value is " + hexStringRepresentation);
    
        double roundtrippedDoubleValue = Double.valueOf(hexStringRepresentation);
        System.out.println("Round tripped double value is " + roundtrippedDoubleValue);
    }
    

    Nb Double.valueOf 将给出一个盒装的DoubleDouble.parseDouble 将给出一个原始的double choose as appropriate

    还是我误解了什么?

    【讨论】:

    • 失败的方式完全相同:NumberFormatException
    • @Andy:只是为了确保,您能否指定:a)String str = Double.toHexString(-9.156013e-002) 和 b)Double d = Double.valueOf(str) 的输出
    • 这似乎对我有用,适用于非常小的数字、非常大的数字、负数和正数。我认为@Andy 可能没有完全理解您的意思,所以我进行了编辑以添加使用示例
    【解决方案3】:

    反转双精度值的示例函数:

    public Double ReverseDouble( Double d) {
    
       byte[] bytes = new byte[8]; 
       ByteBuffer.wrap( bytes).putDouble( d); 
    
       for (int i=0;i<bytes.length/2;i++) {
           byte b = bytes[ i];
           bytes[ i] = bytes[ bytes.length -i -1];
           bytes[ bytes.length -i -1] = b;
       }
    
       return ByteBuffer.wrap( bytes).getDouble();
    }
    

    【讨论】:

    • 这个答案与问题无关。但它提出了一个有趣的观点:也许 NIO 缓冲区可以提供帮助?
    【解决方案4】:

    问题在于输入值为负数,Long.toHexString() 的 javadoc 声明“将 long 参数的字符串表示形式返回为以 16 为底的无符号整数。无符号 long 值是参数加上 2^64,如果论点是否定的;否则,它等于论点。”然而 parseLong 声明“将字符串参数解析为基数中的有符号长......”

    所以当你有一个负输入时,那个 2^64 会导致 NumberFormatException。

    如果输入改为

    double doubleInput = 9.156013e-002;
    

    转换正常工作,无一例外。要处理负输入,需要进行一些额外的处理。

    这是一个类,它展示了一种不使用 BigInteger 或字节缓冲区进行转换的方法:

    public class Temp {
      public String getDoubleAsHexString(double input) {
        // Convert the starting value to the equivalent value in a long
        long doubleAsLong = Double.doubleToRawLongBits(input);
        // and then convert the long to a hex string
        return Long.toHexString(doubleAsLong);
      }
    
      public double convertHexStrToDouble(String input) {
        // convert the input to positive, as needed
        String s2 = preprocess(input);
        boolean negative = true;
        // if the original equals the new string, then it is not negative
        if (input.equalsIgnoreCase(s2))
          negative = false;
    
        // convert the hex string to long
        long doubleAsLongReverse = Long.parseLong(s2, 16);
    
        // Convert the long back into the original double
        double doubleOutput = Double.longBitsToDouble(doubleAsLongReverse);
    
        // return as a negative value, as needed
        if (negative)
          return -doubleOutput;
    
        return doubleOutput;
      }
    
      private String preprocess(String doubleAsHexString) {
        // get the first char and convert it to an int
        String s0 = doubleAsHexString.substring(0, 1);
        int int1 = Integer.parseInt(s0, 16);
    
        // if the int is < 8, then the string is not negative
        // and is returned without further processing
        if (int1 < 8)
          return doubleAsHexString;
    
        // otherwise subtract 8
        int1 = int1 - 8;
        s0 = Integer.toString(int1);
    
        // don't prepend a "0"
        if (int1 == 0)
          s0 = "";
    
        // return the string with a new inital char
        return s0 + doubleAsHexString.substring(1);
      }
    }
    

    这是一个junit测试类:

    public class TempTest {
      private Temp t;
    
      @Before
      public void setUp() throws Exception {
        t = new Temp();
      }
    
      @Test
      public void testConvertHexStrToNegativeDouble() {
          double doubleInput = -9.156013e-002;
          String hexStr = t.getDoubleAsHexString(doubleInput);
          double doubleOutput = t.convertHexStrToDouble(hexStr);
          assertEquals(doubleInput, doubleOutput, 0.0);
        }
    
      @Test
      public void testConvertHexStrToPositiveDouble() {
        double doubleInput = 9.156013e-002;
        String hexStr = t.getDoubleAsHexString(doubleInput);
        double doubleOutput = t.convertHexStrToDouble(hexStr);
        assertEquals(doubleInput, doubleOutput, 0.0);
      }
    }
    

    【讨论】:

      【解决方案5】:

      HexString 到 Long 的转换。

      public long ConvertHexToLong(String hexValue){
              return  new BigInteger(hexValue, 16).longValue();
           }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-07
        • 2011-03-02
        • 1970-01-01
        • 1970-01-01
        • 2010-10-04
        • 2014-03-07
        • 1970-01-01
        相关资源
        最近更新 更多