有時候肴颊,我們?yōu)榱俗非笮拭フ唬蛘吣承﹫鼍跋拢赡茚槍\算方式進(jìn)行調(diào)整
比如說苫昌,不同語言進(jìn)行數(shù)據(jù)傳輸?shù)臅r候颤绕,數(shù)據(jù)類型精度不匹配幸海,如何盡量減少這種情況的發(fā)生
就需要使用到一些位運算的技巧了祟身。
拋開語言層面,僅從邏輯出發(fā)即可物独,以下代碼袜硫,都可以使用其他語言方式替換
/**
* 兩數(shù)加法運算
* **/
const add = function (num1, num2) {
//進(jìn)位運算為0則結(jié)束
if (num2 === 0) {
return num1;
}
//沒有進(jìn)位的運算 亦或操作,(兩不相等則1)
let sum = num1 ^ num2;
//與操作挡篓,同1 則1婉陷,這時候使用左移一位的操作表示進(jìn)位
let carry = (num1 & num2) << 1;
return this.add(sum, carry);
}
/**
* 兩數(shù)減法運算
* 減法帚称,簡單的做法就是把減法看做是加法,(加一個負(fù)數(shù))
* **/
const plus = function (num1, num2) {
//取反相加
let num3 = this.add(~num2, 1);
let result = this.add(num1, num3);
return result;
}
/**
* 兩數(shù)乘法運算m * n
* 實際上就是將m進(jìn)行n次相加運算秽澳,但是要考慮到負(fù)數(shù)的情況等
* 所以需要對負(fù)數(shù)進(jìn)行取反處理
* **/
const multi = function (num1, num2) {
let a = num1 < 0 ? this.add(~num1, 1) : num1;
let b = num2 < 0 ? this.add(~num2, 1) : num2;
let result = 0;
while (b > 0) {
//取尾數(shù)闯睹,因為要累加
if ((b & 0x1) > 0) {
result = this.add(result, a);
}
//每次運算結(jié)束,被乘數(shù)進(jìn)行一次左移運算担神,進(jìn)位的操作
a = a << 1;
//乘數(shù)進(jìn)行一次右移操作楼吃,表示要執(zhí)行次數(shù)
b = b >> 1;
}
//亦或操作,兩不相等則1妄讯,判斷正負(fù)號孩锡,取最高位比較,如果為負(fù)數(shù)亥贸,則取反加一
if ((num1 ^ num2) < 0) {
result = this.add(~result, 1);
}
return result;
}
/**
* 兩數(shù)除法運算
* 后續(xù)實現(xiàn)躬窜,目前僅用的到加法與乘法
* **/
const division = function (num1, num2) {
//可以想一想如何使用位運算實現(xiàn)除法的方式
}
/**
* java實現(xiàn)
* 兩數(shù)除法運算
* @param decimals 保留幾位小數(shù),默認(rèn)保留10位
* **/
public static Long divide(Long d1, Long d2, int decimals){
long a = d1 >> 63 == 1 ? add(~d1, 1L) : d1;
long b = d2 >> 63 == 1 ? add(~d2, 1L) : d2;
long result = 0;
// 余數(shù)
long remainder = 0;
//累加:整體表示炕置,以雙倍的加法計算荣挨,提升效率。(b & 0x1) > 0時候才累加一次朴摊;
while(a >= b){
result = add(result, 1L);
a = subtraction(a, b);
}
//判斷符號位垦沉,異或操作,同位同值則0仍劈,否則1,厕倍;與負(fù)負(fù)得正,一負(fù)為負(fù)相同贩疙,故可根據(jù)亦或操作判斷符號
if((d1 ^ d2) < 0){
result = add(~result, 1L);
}
//獲取余數(shù)符號
remainder = d2 > 0 ? a : add(~a, 1L);
return result;
}