【问题标题】:Calculating Carry Flag计算进位标志
【发布时间】:2015-07-01 19:38:23
【问题描述】:

我正在用 Java 编写一个 x86 解释器,并有一个 Python 脚本来测试我的 x86 指令实现与使用 NASM 的真实对应物。 根据这个测试,除了进位标志之外,所有标志都被正确设置。 有趣的部分是:

long result;
    switch (op) {
    case ADD:
        result = Math.abs(x) + Math.abs(y);
        if (result > U_MAX)
            registers.carry_flag = true;
        else
            registers.carry_flag = false;
        break;

其中 U_MAX 是 4294967295L(全部 32 位设置)。
我发现的所有答案都没有意识到进位和溢出是两个不同的东西。那么,如何在 Java 中正确实现进位标志呢?

【问题讨论】:

  • x 和 y 是如何声明的?
  • x 和 y 是整数。

标签: java x86 intel carryflag


【解决方案1】:

所有这些绝对值业务都是不必要的,坦率地说是令人困惑的,并且它有一个极端情况,即Math.abs(Integer.MIN_VALUE) 是负数(当你开始处理它时并不奇怪,但它看起来不像这段代码所期望的那样),您可以用更简单的方法计算进位。

例如使用旧的“结果是无符号小于一个操作数”。结果当然只是x + y(如int),签名与加法无关。然后用Java 8,你可以使用Integer.compareUnsigned,否则你可以使用这个身份:

x <u y = (x ^ Integer.MIN_VALUE) <s (y ^ Integer.MIN_VALUE)

其中&lt;u&lt;s 分别是无符号小于和有符号小于。

您还可以计算 (x &amp; 0xffffffffL) + (y &amp; 0xffffffffL) 并将其用于结果(转换为 int)和进位标志(第 33 位)。

【讨论】:

  • (x & 0xffffffffL) + (y & 0xffffffffL) 确实通过了所有测试!我也不知道 compareUnsigned,谢谢!
  • @Benjoyo 是的,借用同样的方法,但不是只出现在第 33 位,而是出现在所有 32 个高位中
  • 对不起,我不明白你的意思。
  • @Benjoyo r = (x &amp; 0xffffffffL) - (y &amp; 0xffffffffL),转换为int得到结果,高位都是借位标志的副本(如果它借到高半部分,那么它都是零,所以它然后它一直借用它)。所以你可以像r &lt; 0一样检查借用。或者完全按照您现在添加的方式进行操作。
  • 啊,现在我明白了,非常感谢。但是,至少对于(当前)x86 减法进位标志似乎设置在r &gt; 0 而不是r &lt; 0
【解决方案2】:

如果 x 和 y 是整数,则 Math.abs(x) 和 Math.abs(y) 是整数。比如说x = y = Integer.MAX_VALUE,Math.abs(x)+Math.abs(y)相加的结果是负数,如下程序所示:

public class t {
    public static void main(String args[]) {
        int x = Integer.MAX_VALUE;
        int y = Integer.MAX_VALUE;
        System.out.println(x+y);
    }
}

$ javac t.java
$ java t
 -2

因此,您应该将 x 和 y 设为 long,或者在添加之前转换为 longresult = ((long)Math.abs(x)) + ((long)Math.abs(y));

【讨论】:

    猜你喜欢
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    相关资源
    最近更新 更多