补码的本质:十进制补码Java实现

十进制补码的本质是借9当10,关键操作是别忘记加上1。而如此做的原因是避免直接算减法而频繁处理借位的情况,所以干脆一下子把所有的位都借了

比如一个数有四位,-1234,那么先借9,就是8765,然后再加上1,就是8766 。

在这里,借了4个9,又借了1,刚好是欠了1 0000 。这里欠的,再计算玩结果后,还是要还的,这样得到的值才正确。

而怎么还呢,如果刚好有进位,那么这个位就是在万位上,此时把进位舍去,就刚好换掉了刚开始借的1 0000

比如

1234 + (-1234) = 1234 + (9999 - 1234 + 1) - 10000 = 1234 + 8766 - 10000 = 10000 - 10000 = 0;

那么如果,两个数相加没有进位呢?比如

-66 + (-66) = (99 - 66 + 1) + (99 - 66 + 1) - 100 - 100 = 34 + 34 - 100 - 100 = 68 - 100 - 100 = - (99 - 68 + 1) - 100 = -132;

这样看起来还是可以的,但是因为没有进位抵消掉一个,所以最后多减去100,这 显得有点不好看,为了保证都进位,所以干脆多借一位,于是

-66 + (-66) = (999 - 66 + 1) + (999 - 66 + 1) - 1000 - 1000 = 934 + 934 - 1000 - 1000 =1868 - 1000 - 1000  =868 - 1000 =-(999 - 868 + 1)= - 132;

这就舒服多了吧。所以进位一律舍去即可。这里多借的一位,就是传说中的符号位。

那正数为啥补码是他本身呢?这个嘛,因为正数不缺,所以不用补齐。补码是方便把减法转换成加法计算,所以负数由源码得到补码,再由补码换回源码,这里负数所借的位,在最后换算回来的时候,都已经还掉了。所以这个过程只和负数本身有关系,和正数没有任何关系。


呵呵,可能大家都发现了,只要最后加了一个1,前面加多少个9都可以,之后最后结果舍去进位即可(因为我已经强制他进位了,符号位)。这也是为什么在对齐数位的时候

负数补9正数补0了。

-66 + 34 = 934 + 034 = 968 = - 32;

看起来,已经差不多可以解释通了,但是0的问题呢?如何证明-0的补码就是0呢?因为本身0就是一个稳定点,既不是负,也不是正,也可以说既是正又是负。不是很好表达

-0 = 9 - 0 + 1 - 10 = 10 - 10 = 0 ;

注意到这里的进位已经偿还了0的借位。不用等到和其他数字加后,就已经偿还了。哦,叫他自偿还吧。不生不灭,不垢不净,不增不减。:P


/**

----------------------------------------------------------------------------------------------------------------------------------------

终于有时间把这件事情开个头。呵呵

处理说明:

如何求补码:

非负数的补码是自己

负数的补码是用9去减自己每位上的数,如此肯定够减,不用借位。得到的结果再加上1


如何补齐:

做加法的时候需要低位对齐,对于非负数,高位补0,对于负数,高位补9


如何处理最后的进位:

对齐后的数字按正常的运算逻辑进行加法即可,不用考虑符号位,但是高位的进位处理需要考虑,因为这里是要求准确值,不允许截断。

所以需要考虑两个数的符号。

若是两个数都是负数,那么结果一定是负数,不需要进位直接舍弃,然后再由补码得到真实值即可

若是两个数一个非负一个负,如果有进位,那么结果为正,此时直接返回即可,如果没有进位那么结果为负,由补码求真实值即可

若是两个数都是非负数,如果有进位则进位,然后返回,否则直接返回。



----------------------------------------------------------------------------------------------------------------------------------------

*/


package complement;

public class Complement {
	private static final int OFFSET = '0';
	private int[][] table = new int[10][10];

	public Complement() {
		this.initTable();
	}

	public void initTable() {
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j <= i; j++) {
				table[i][j] = i + j;
				table[j][i] = i + j;
			}
		}
	}

	public String lpadnum(String num, int len, boolean sign) {
		for (; len > 0; len--) {
			if (sign) {
				num = "9".concat(num);
			} else {
				num = "0".concat(num);
			}
		}
		return num;
	}

	// 处理补码运算,999xx-num + 1
	public String processComplement(String num) {
		StringBuilder sb = new StringBuilder(num);
		int len = sb.length();
		for (len--; len > -1; len--) {
			sb.setCharAt(len, (char) ('9' - sb.charAt(len) + '0'));
		}
		// +1
		len = sb.length() - 1;
		while (true) {
			char ch = sb.charAt(len);
			if (ch == '9') {
				ch = '0';
				sb.setCharAt(len, ch);
				if (len == 0) {
					break;
				}
				len--;
			} else {
				ch += 1;
				sb.setCharAt(len, ch);
				break;
			}
		}
		return sb.toString();
	}

	// 由补码表示的数,求出真实值
	public String deComplement(String num) {
		return "-" + processComplement(num);
	}

	// 求一个数的补码
	public String getComplement(String num) {
		if (num.startsWith("-")) {
			return "9" + processComplement(num.substring(1));
		} else {
			return num;
		}
	}

	// 只是处理了整数
	public String add(String num1, String num2) {
		/**
		 * 在处理-0问题上,代码没有能够和一般负数公用,先特例出来吧。
		 */
		if (num1.equals("-0")) {
			num1 = "0";
		}
		if (num2.equals("-0")) {
			num2 = "0";
		}
		String info = num1 + " + " + num2;
		// 符号系统
		boolean flag1 = num1.startsWith("-");
		boolean flag2 = num2.startsWith("-");
		// 求补数
		num1 = getComplement(num1);
		num2 = getComplement(num2);
		// 对齐
		int pad = num1.length() - num2.length();
		if (pad > 0) {
			num2 = lpadnum(num2, pad, flag2);
		} else {
			num1 = lpadnum(num1, -pad, flag1);
		}
		info += " = " + num1 + " + " + num2;
		int len = num1.length();
		boolean carry = false;
		StringBuilder sb = new StringBuilder(num1);
		for (len--; (len > -1); len--) {
			int ret = table[num1.charAt(len) - OFFSET][num2.charAt(len) - OFFSET];
			// 处理进位
			if (carry) {
				ret++;
			}
			// 设置结果
			sb.setCharAt(len, (char) (ret % 10 + '0'));
			if (ret > 9) {// 标志进位
				carry = true;
			} else {
				carry = false;
			}
		}

		String ret;
		// 这里要计算加减要得到正确的值,就必须得处理符号
		if (flag1 && flag2) {// 都是负的那么结果是负的
			ret = deComplement(sb.toString());
		} else if (!flag1 && !flag2) {// 有进位,且都是正的,那么进位
			if (carry) {
				ret = "1" + sb;
			} else {
				ret = sb.toString();
			}
		} else {// 两个数异号
			if (carry) {
				ret = sb.toString();
			} else {
				ret = deComplement(sb.toString());
			}
		}

		System.out.println(info + " = " + ret);

		return ret;
	}

	public static void main(String[] args) {
		Complement comp = new Complement();
		comp.add("988", "-12");
		comp.add("988", "988");
		comp.add("999", "-1");
		comp.add("-999", "1");
		comp.add("1", "-1");
		comp.add("-11", "-12");
		comp.add("12", "-12");
		comp.add("1", "1");
		comp.add("10", "10");
		comp.add("100", "100");
		comp.add("10000", "-100");
		comp.add("10000", "-99999");
		comp.add("10000", "-0");
	}
}



转载于:https://my.oschina.net/honchy/blog/349986

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值