以下代码用于理解计算原理,并不具有通用性!
//================== utils =======================
let MQ, ACC, X;
function strSplice(str, index, num, insert = '') {
return str.slice(0, index) + insert + str.slice(index + num);
}
function accLeftShift() {
let moveOut = ACC[0];
ACC = strSplice(ACC, 0, 1);
ACC = strSplice(ACC, ACC.length, 0, "0");
return moveOut;
}
function accRightShift() {
let moveOut = ACC[ACC.length-1];
ACC = strSplice(ACC, ACC.length-1, 1);
ACC = strSplice(ACC, 0, 0, "0");
return moveOut;
}
function accRightShiftWithComplementCode(isDoubleFlags) {
let flag = ACC[0];// double flag first bit is positive or negtive
let firstNumBit = isDoubleFlags?2:1;
let moveOut = ACC[ACC.length-1];
ACC = strSplice(ACC, ACC.length-1, 1);
ACC = strSplice(ACC, firstNumBit, 0, flag);
return moveOut;
}
// test spec
// ACC = '00100000';
// console.log(accRightShiftWithComplementCode(true));
// console.log(accRightShiftWithComplementCode(true));
// console.log(accRightShiftWithComplementCode(true));
// console.log(accRightShiftWithComplementCode(true));
// console.log(accRightShiftWithComplementCode(true));
function bitAdd(ACC, num) {
let carry = 0;// 1 or 0
for (let i = num.length-1; i >= 0; i--) {
let sum = parseInt(ACC[i]) + parseInt(num[i]) + carry;
carry = sum > 1 ? 1 : 0;
ACC = strSplice(ACC, i, 1, sum % 2);
};
return ACC;
}
function mQRightShift(moveOut) {
MQ = strSplice(MQ, 0, 0, moveOut);
MQ = strSplice(MQ, MQ.length-1, 1);// remove last bit
}
/*
decime convert to binary
*/
function dec2Bin(num, bits = 8) {
let b = new Array(bits).fill(0);
if(num<0) b[0] = 1;
num = Math.abs(num);
let i = bits - 1;
while(parseInt(num / 2)) {
b[i--] = (num % 2);
num = parseInt(num / 2);
}
b[i--] = num % 2;
return b.join('');
}
function originCode2ComplementCode(bStr, isUnsigned = false) {
// default first bit is flag bit
let b = bStr.split('');
if(b[0] == '0' && !isUnsigned) return bStr; // positive num originCode equ with complementCode
for(let i = isUnsigned?0:1; i < b.length; i++) {// unisigned code uppest bit is not flag bit can be reversed
b[i] = (!parseInt(b[i])?1:0);
}
//
bStr = b.join('');
return bitAdd(bStr, '0'.repeat(bStr.length-1) + '1');// +1
}
// add double flag bit
function addDoubleFlags(a) {
return (a[0] === '1'? '1' : '0' ) + a;
}
// ============ calc ================
// ++++++++++++ originCodeMultiple +++++++++++++++
function originCodeMultiple(a, b) {
let aAbs = Math.abs(a).toString().replace(".", "");
let bAbs = Math.abs(b).toString().replace(".", "");// remove minus point default 0.xxx
let aFlag = a < 0 ? 0 : 1;
let bFlag = b < 0 ? 0 : 1;
let cFlag = (aFlag ^ bFlag).toString();
ACC = "0".repeat( aAbs.length);// 0(.)0000 without minus point
MQ = bAbs.slice(1);// 01111 => 1111
X = aAbs;// add flag bit "0"
for (let i = MQ.length-1; i >= 0; i--) {
if(MQ[MQ.length-1] === "1") {
ACC = bitAdd(ACC, X);
}
mQRightShift(accRightShift());
}
return cFlag + strSplice(ACC,1,0,'.') + MQ;
}
// ++++++++++++ complementCodeMultiple +++++++++++++++
function complementCodeMultiple(a, b) {
ACC = '0'.repeat(a.length-1).toString();// -1 remove minus point bit
ACC = '0' + ACC;// double flags
let aAbs = a.toString().replace(".", "");
let bAbs = b.toString().replace(".", "");// remove minus point default 00.xxx
MQ = originCode2ComplementCode(bAbs) + '0';// add aux bit
let aComplementCode = originCode2ComplementCode(aAbs);
let subAComplementCode = originCode2ComplementCode((aAbs[0]==='1'?'0':'1') + aAbs.slice(1));
aComplementCode = aComplementCode[0] + aComplementCode;
subAComplementCode = subAComplementCode[0] + subAComplementCode;
for(let i=MQ.length-1; i>=1 ; i--) {
// do n + 1 loop add, n loop rightShift
let prev = MQ[MQ.length-1];
let next = MQ[MQ.length-2];
if(prev === '0' && next === '1') {
ACC = bitAdd(ACC, subAComplementCode);
}else if(prev === '1' && next === '0') {
ACC = bitAdd(ACC, aComplementCode);
}else{
// ACC + 0
}
// n+1 add n rightShift
i>1 && mQRightShift(accRightShiftWithComplementCode(true));
}
ACC = [...ACC]
ACC.splice(2, 0, '.');// double flag add minus point
return ACC.join('') + MQ.slice(0, -2);
}
// console.log(complementCodeMultiple('1.1101000', '0.1011000'));
// console.log(complementCode('1.1101', '0.1011'));
// ++++++++++++ originCodeDivide +++++++++++++++
function originCodeDivideWithRecover(a, b) {
// use one flag bit
a = a.toString().replace('.', '');
b = b.toString().replace('.', '');
let aFlag = a[0];
let bFlag = b[0];
let cFlag = parseInt(aFlag) ^ parseInt(bFlag);
ACC = a;
let bComplementCode = originCode2ComplementCode(b);
let bSubComplementCode = originCode2ComplementCode(b[0]==='1'?'0':'1' + b.slice(1));
MQ = [];
for(let i=a.length-1; i>=0; i--) {
let curQuotient = '1';
ACC = bitAdd(ACC, bSubComplementCode);
if(ACC[0] === '1') {
// recover curQuotient
ACC = bitAdd(ACC, bComplementCode);
MQ.push('0');
}else{
MQ.push(curQuotient);
}
i>0 && accLeftShift();
}
ACC[0] = cFlag;
ACC = [...ACC]
ACC.splice(1, 0, '.');// double flag add minus point
let Remainder = ACC.join('');
MQ[0] = cFlag;
MQ = [...MQ]
MQ.splice(1, 0, '.');// double flag add minus point
let Quotient = MQ.join('');
let nBitNum = a.length-1;
console.log(`Remainder => ${Remainder}X${2}^${-nBitNum}`, `Quotient => ${Quotient}`)
}
function originCodeDivideWithoutRecover(a, b) {
// use one flag bit
a = a.toString().replace('.', '');
b = b.toString().replace('.', '');
let aFlag = a[0];
let bFlag = b[0];
let cFlag = parseInt(aFlag) ^ parseInt(bFlag);
ACC = a;
let bComplementCode = originCode2ComplementCode(b);
let bSubComplementCode = originCode2ComplementCode(b[0]==='1'?'0':'1' + b.slice(1));
MQ = [];
let nextQuotient = '1';
for(let i=a.length-1; i>=0; i--) {
let curQuotient = nextQuotient;
if(curQuotient === '1') {
ACC = bitAdd(ACC, bSubComplementCode);
}else{
ACC = bitAdd(ACC, bComplementCode);
}
if(ACC[0] === '1') {
MQ.push('0');
nextQuotient = '0';
}else{
MQ.push('1');
nextQuotient = '1';
}
i>0 && accLeftShift();
}
if(ACC[0] === '1') {
// remainder is negtive add positive complement code
ACC = bitAdd(ACC, bComplementCode);
}
ACC[0] = cFlag;
ACC = [...ACC]
ACC.splice(1, 0, '.');// double flag add minus point
let Remainder = ACC.join('');
MQ[0] = cFlag;
MQ = [...MQ]
MQ.splice(1, 0, '.');// double flag add minus point
let Quotient = MQ.join('');
let nBitNum = a.length-1;
console.log(`Remainder => ${Remainder}X${2}^${-nBitNum}`, `Quotient => ${Quotient}`)
}
// ====== test spec ========
// console.log(originCodeDivideWithRecover('0.1011', '0.1101'));
// console.log(originCodeDivideWithoutRecover('0.1011', '0.1101'));
// ++++++++ complementCodeDivideWithoutRecover ++++++++
function complementCodeDivideWithoutRecover(a, b) {
// use one flag bit
a = a.toString().replace('.', '');
b = b.toString().replace('.', '');
a = originCode2ComplementCode(a)
ACC = a[0] + a;// double flags
MQ = [];
let n = a.length;
let bComplementCode = originCode2ComplementCode(b);
let subBComplementCode = originCode2ComplementCode((b[0]==='1'?'0':'1') + b.slice(1));
bComplementCode = bComplementCode[0] + bComplementCode;
subBComplementCode = subBComplementCode[0] + subBComplementCode;
for(let i=n-1; i>=0; i--) {
if(ACC[0] === bComplementCode[0]) {
ACC = bitAdd(ACC, subBComplementCode);
MQ.unshift('1');
}else{
ACC = bitAdd(ACC, bComplementCode);
MQ.unshift('0');
}
i>0 && accLeftShift();
}
ACC = [...ACC].slice(1);
ACC.splice(1, 0, '.');// double flag add minus point
let Remainder = ACC.join('');
MQ = [...MQ]
MQ.splice(1, 0, '.');// double flag add minus point
let Quotient = MQ.join('');
let nBitNum = n-1;
console.log(`Remainder => ${Remainder}X${2}^${-nBitNum}`, `Quotient => ${Quotient}`)
}
// ====== test spec ========
// console.log(complementCodeDivideWithoutRecover('0.1011', '0.1101'));
// console.log(originCodeDivideWithoutRecover('0.1011', '0.1101'));
// ++++++++++++ complementCodeAddMinus +++++++++++++++
/*
bits max bits with a flag bit
*/
function complementCodeAddMinus(a = 15, b = 124, bits = 8) {
a = originCode2ComplementCode(dec2Bin(a, bits));
b = originCode2ComplementCode(dec2Bin(b, bits));
// use double flags judge overflow
a = addDoubleFlags(a);
b = addDoubleFlags(b);
let acc = bitAdd(a, b);
console.log(overflowjudgeByDouFlags(acc));
return acc
}
function overflowjudgeByDouFlags(num) {
let isOverFlow = num[0] ^ num[1]// if double flags equ with each other is not overflow
if(isOverFlow) {
if(num[0] === '1') return 'lower overflow'
else return 'upper overflow'
}else{
return 'in the range';
}
}
// ++++++++++++ unsignedCodeAddMinus +++++++++++++++
/*
action 0 => add, 1 => minus
*/
function unsignedCodeAddMinus(a, b, action = 0,bits = 8) {
a = dec2Bin(a);
b = dec2Bin(b);
// unsigned code without any flag bit
if(action === 1) {
b = originCode2ComplementCode(b, true);
}
let acc = bitAdd('0'+a, '0'+b);// add zero bit is to judge overflow without modify bitAdd func
console.log(judgeUnsignedCodeAddMinusOverFlow(acc, action));
return acc.slice(1);// remove temp judge overflow bit
}
function judgeUnsignedCodeAddMinusOverFlow(a, action = 0) {
if(action === 1 && a[0] === '0') {
return 'lower overflow';
}else if(action === 0 && a[0] === '1') {
return 'upper overflow';
}
return 'in the range';
}
// ++++++++++++ originCodeAddMinus +++++++++++++++
function bitMinus(MCC, num) {
MCC = MCC.split('');
num = num.split('');
for(let i=num.length-1; i>=0; i--) {
let a = MCC[i];
let b = num[i];
if((a=='1' && b=='1') || (a=='0' && b=='0')) {
MCC[i]= '0';
} else if(a=='1' && b=='0') {
MCC[i]= '1';
}else{
// need borrow bit
let borrowSuc = false;
for(let j = i-1; j>=0; j--) {
if(MCC[j] === '1') {
MCC[j] = '0';
borrowSuc = true;
for(let z=j+1; z<=i; z++) {
MCC[z] = '1';
}
break;
}
}
if(!borrowSuc) {
console.log(`can't borrow bit!`);
return NaN;
}
}
}
return MCC.join('');
}
function originCodeAddMinus(a, b, action = 0) {
a = dec2Bin(a);
b = dec2Bin(b);
// warning: when minus num , use ACC calc can be mistake, so use MCC calc
if(action === 1) {
let mcc = bitMinus(a, b);
return mcc;
}else{
let acc = bitAdd(a, b);
return acc
}
}
//================== test spec ====================
console.log(bitMinus('10000000', '00000001'));// 01111111
console.log(originCodeAddMinus(10, 6));// 00010000
console.log(originCodeAddMinus(10, 6, 1));// 00000100
console.log(complementCodeAddMinus(15, 124));// 01,0001011
console.log(complementCodeAddMinus(-24, -124));// 10,1101100
console.log(unsignedCodeAddMinus(99, 100));// 11000111
console.log(unsignedCodeAddMinus(99, 100, 1));// 11111111
console.log(originCodeMultiple(-0.1101111111111, -0.1100110110111));// 0.65625
console.log(complementCodeMultiple('1.1101000', '0.1011000'));
(originCodeDivideWithRecover('0.1011', '0.1101'));
(originCodeDivideWithoutRecover('0.1011', '0.1101'));
(complementCodeDivideWithoutRecover('0.1011', '0.1101'));