【问题标题】:2's complement hex number to decimal in javajava中2的补码十六进制数到十进制数
【发布时间】:2011-10-05 16:05:10
【问题描述】:

我有一个表示 2 的补码的十六进制字符串。有没有一种简单的方法(库/函数)可以将十六进制转换为十进制而不直接使用它的位??

例如这是给定左侧十六进制的预期输出:

"0000" => 0
"7FFF" => 32767 (max positive number)
"8000" => -32768 (max negative number)
"FFFF" => -1

谢谢!

【问题讨论】:

  • 如果你知道如何获得一个无符号数,那么如果值大于 32767,则只需减去 65536
  • 起初我说的是 Integer.parseInt 但后来意识到它的 2 的恭维。所以我删除了我的答案。

标签: java hex twos-complement negative-number


【解决方案1】:

这似乎会诱使 java 在不强制结果的情况下转换数字:

Integer.valueOf("FFFF",16).shortValue(); // evaluates to -1 (short)

当然,这种事情只适用于 8、16、32 和 64 位 2 的补码:

Short.valueOf("FF",16).byteValue(); // -1 (byte)
Integer.valueOf("FFFF",16).shortValue(); // -1 (short)
Long.valueOf("FFFFFFFF",16).intValue(); // -1 (int)
new BigInteger("FFFFFFFFFFFFFFFF",16).longValue(); // -1 (long)

Example here.

【讨论】:

  • 非常有趣!你知道这里到底发生了什么吗? :|
  • 我很确定转换为低精度类型只会保留最低位,所以 0000FFFF int 变成了 FFFF short。同样Integer.valueOf("A7FFFF",16).shortValue(); 也会导致-1 - 高位被切断。
  • 你可能是对的。尽管如此,我仍然不完全理解为什么在转换为较低精度时符号会变为负数......这可能取决于数字在内部的存储方式,我可能需要对此进行一些研究..
  • 特别是“有符号整数到整数类型 T 的窄化转换只会丢弃除 n 个最低位之外的所有位,其中 n 是用于表示类型 T 的位数。除了可能的丢失有关数值大小的信息,这可能会导致结果值的符号与输入值的符号不同。”
【解决方案2】:

只需要写一个实用方法:

 public static Integer twosComp(String str) throws java.lang.Exception {
       Integer num = Integer.valueOf(str, 16);
       return (num > 32767) ? num - 65536 : num;
 }

测试:

 twosComp("7FFF") -> 32767
 twosComp("8000") -> -32768
 twosComp("FFFF") -> -1

【讨论】:

  • +1 用于编写你自己的,但它不起作用长或更大的值吗?
  • +1 看起来很容易融入 BigInteger 实现以获得最终的可扩展性。
【解决方案3】:

这似乎运作良好。它可以通过传递非标准长度的字符串来愚弄:“FFF”映射到-1。零填充将纠正错误。

你不清楚你想要什么类型的返回,所以我返回了Number,大小合适。

public Number hexToDec(String hex)  {
   if (hex == null) {
      throw new NullPointerException("hexToDec: hex String is null.");
   }

   // You may want to do something different with the empty string.
   if (hex.equals("")) { return Byte.valueOf("0"); }

   // If you want to pad "FFF" to "0FFF" do it here.

   hex = hex.toUpperCase();

   // Check if high bit is set.
   boolean isNegative =
      hex.startsWith("8") || hex.startsWith("9") ||
      hex.startsWith("A") || hex.startsWith("B") ||
      hex.startsWith("C") || hex.startsWith("D") ||
      hex.startsWith("E") || hex.startsWith("F");

   BigInteger temp;

   if (isNegative) {
      // Negative number
      temp = new BigInteger(hex, 16);
      BigInteger subtrahend = BigInteger.ONE.shiftLeft(hex.length() * 4);
      temp = temp.subtract(subtrahend);
   } else {
      // Positive number
      temp = new BigInteger(hex, 16);
   }

   // Cut BigInteger down to size.
   if (hex.length() <= 2) { return (Byte)temp.byteValue(); }
   if (hex.length() <= 4) { return (Short)temp.shortValue(); }
   if (hex.length() <= 8) { return (Integer)temp.intValue(); }
   if (hex.length() <= 16) { return (Long)temp.longValue(); }
   return temp;
}

样本输出:

"33" -> 51
"FB" -> -5
"3333" -> 13107
"FFFC" -> -4
"33333333" -> 53687091
"FFFFFFFD" -> -3
"3333333333333333" -> 3689348814741910323
"FFFFFFFFFFFFFFFE" -> -2
"33333333333333333333" -> 241785163922925834941235
"FFFFFFFFFFFFFFFFFFFF" -> -1

【讨论】:

  • 使用 BigInteger 转换效果很好,没有你拥有的 'isNegative' 逻辑。我所要做的就是像你一样创建 BigInteger,然后根据我想要的宽度调用 byteValue/shortValue/intValue/longValue,我得到了与你相同的结果。除了...我认为“33333333”的值应该是 858993459。这就是我通过 Java 和 Windows 计算器得到的。试试System.out.println(new BigInteger("33333333", 16).intValue()+" -&gt; "+53687091);
猜你喜欢
  • 2014-11-03
  • 1970-01-01
  • 2020-02-09
  • 2014-04-16
  • 2012-11-02
  • 2014-12-25
  • 2016-05-24
  • 1970-01-01
  • 2011-12-09
相关资源
最近更新 更多