编辑代码

// 递归写法
function add(num1, num2){
    if(num2 == 0)
        return num1;
    let sum = num1 ^ num2;
    let carry = (num1 & num2) << 1;
    return add(sum, carry);
}

console.log(add(123,123))

function substract(num1, num2){
    var subtractor = add(~num2, 1);// 先求减数的补码(取反加一)
    var result = add(num1, subtractor); // add()即上述加法运算  
    return result ;
}

console.log(substract(123,123))

function multiply(a, b) {  
    //将乘数和被乘数都取绝对值 
    var multiplicand = a < 0 ? add(~a, 1) : a;   
    var multiplier = b < 0 ? add(~b , 1) : b;  
     
    //计算绝对值的乘积  
    var product = 0;  
    while(multiplier > 0) {    
        if((multiplier & 0x1) > 0) {// 每次考察乘数的最后一位    
            product = add(product, multiplicand);    
        }     
        multiplicand = multiplicand << 1;// 每运算一次,被乘数要左移一位    
        multiplier = multiplier >> 1;// 每运算一次,乘数要右移一位(可对照上图理解)  
    }   
    //计算乘积的符号  
    if((a ^ b) < 0) {    
        product = add(~product, 1);  
    }   
    return product;
}

console.log(multiply(4,4))


function divide_v2(a,b) {   
    // 先取被除数和除数的绝对值    
    var dividend = a > 0 ? a : add(~a, 1);    
    var divisor = b > 0 ? a : add(~b, 1);    
    var quotient = 0;// 商    
    var remainder = 0;// 余数    
    for(var i = 31; i >= 0; i--) {
        // 比较dividend是否大于divisor的(1<<i)次方,不要将dividend与(divisor<<i)比较,而是用(dividend>>i)与divisor比较,
        // 效果一样,但是可以避免因(divisor<<i)操作可能导致的溢出,
        // 如果溢出则会可能dividend本身小于divisor,但是溢出导致dividend大于divisor
        if((dividend >> i) >= divisor) {            
            quotient = add(quotient, 1 << i);            
            dividend = substract(dividend, divisor << i);        
        }    
    }    
    // 确定商的符号    
    if((a ^ b) < 0){
        // 如果除数和被除数异号,则商为负数        
        quotient = add(~quotient, 1);    
    }    
    // 确定余数符号    
    remainder = b > 0 ? dividend : add(~dividend, 1);    
    return quotient;// 返回商
}