多精度算術學習(二)

==
減法:
  按照數學定義 x-y 等價於 x+(-y), 所以實現上先將 y 求其對應負數, 而後
用已經實現的加法就可完成減法的運算. 算法

  所以只須要研究如何求負數便可. rem

  求一個數的負數 neg(), 等於將該數字二進制求補碼, 也即先反轉全部二進制位
而後加上 1. 代碼示例以下: 數學

  int carry = 1; // 整個數反轉後要+1, 因此初始爲 1.
  for (int i = 0; i < len; ++i) {
    carry += (~src.arr[i]) // 二進制反轉, ~ 爲求反運算.
        & 0xff; // 取 byte 部分.
    dest[i] = (byte)carry; // 取低位.
    carry >>>= 8;  // 進位部分
  }
  boolean overflow = src[len-1] < 0 && dest[len-1] < 0;
  if (overflow) dest[len++] = 0;
  return new mp_int (len, dest); // 結果 原理

  關於 overflow 標誌, 舉例如數字 = -128=0x80 時, 取反獲得 0x7F, 加上1
又回到 0x80, 此時稱爲 overflow. 這種狀況只發生在最高位爲 1, 其他全部位
都是 0 的狀況. 此時求負以後的數字要當作無符號數看待, 在最高位補上一個 0
(dest[len++] = 0 即爲最高位補0). 二進制

==
乘法
  爲簡化問題, 只考慮正數的乘法, 若是x,y 有負數, 先對齊求負轉換爲正數,
而後再進行乘法. 方法

  相似於咱們手寫數字乘法豎式, 咱們將各個位逐個相乘, 並累加到結果上,
有進位的繼續向高一位累加. 這樣一個 m位的數字乘上一個 n位的數字, 獲得的
結果爲 m*n 位的. 僞代碼以下: word

  mul(byte[] dest, byte[] x, int xlen, byte[] y, int ylen)
  // 計算乘積, 使得 dest = x*y
    for (int i = 0; i < ylen; ++i) {
      int yword = (int)y[i] & 0xff; // 取y 的第 i位.
      int carry = 0; // 進位.
      for (int j = 0; j < xlen; ++j) {
        carry += ((int)x[i] & 0xff) // 取 x 的第 j 位.
    * yword ; // 乘上 y 的第 i 位
    + ((int)dest[i+j] & 0xff); // 加上現有第 i+j 位.
 dest[i+j] = (byte) carry;  // 更新到結果的第 i+j 位
 carry >>>= 8; // 獲得第 i+j+1 位的進位. 這個進位可能大於 1
      }
      dest[i+xlen] = (byte)carry;
    } 註釋

  這裏細節可能有些忽略的地方, 但基本原理是每位分別乘積, 最後累加到一塊兒. 移動

==
除法
  除法的實現代碼看起來是比較複雜. 不如直接看書理解原理容易. 實際上我看
的 Kawa 源代碼中也註釋寫着使用的是基本的 Knuth 經典算法的公式. 因此爲
學原理, 這裏仍是看書更直接些.
 
  爲實現除法 u/v, 咱們先排除掉一些簡單的狀況:
1. 若是 u < v, 則除法 u/v 的商(quotient)=0, 餘數(remainder)=u
2. 排除掉 u = v 的狀況. 源代碼

  如今 u > v, 先考慮 u 只比 v 多一位的狀況, 此時 u 表示爲
(u_n, u_(n-1), ... , u_1, u_0) 這裏用下劃線這裏表示後面跟着下標的意思.
v 表示爲 (v_(n-1), v_(n-2), ..., v_1, v_0) 的形式. 若是找到了求
這種形式的商, 也就能爲更多位的 u 進行計算了, 由於能夠先計算前 n+1 位,
而後再進一步加上後面的位.

  設 u = q*v + r;  則這裏 q 表示商, 知足 q < b; 而 r 表示餘數, 知足 r < v.
  要推測 q 的值的合理方法是, 使用 u,v 的最高位的有效數字進行推測.
這裏最高位的有效數字, 指高位的 m 個二進制位, 其中最高位是1. (這裏都按照
無符號整數看待, 最高位爲1 仍然是正數). m 越多, 推測的就越準確.

  Knuth 的書上還有這方面的定理, 以及...證實. 這裏說明, 要有好的數學功底,
才能真正理解這背後的原理, 而我數學已經不少年不學從而忘得差很少了.
所以這裏, 咱們努力理解這些原理, 實在理解不了, 就只能照用了.

  要獲得最高位的有效數字, 在代碼中我看到是使用了向左移位的方法, 將有效
位都移動到了高位. 這樣計算試驗商 q 比較準確些. 而且這裏使用 int 型而非
byte 型, 可使二進制位數 m 較多, 從而 q 準確性更高. 實際書上證實了
q'-2 <= q <= q', 這裏 q' 表示試驗商. 也即試驗的商 q' 的偏差毫不大於 2.

  到這裏, 咱們基本能夠理解算法D(整數除法)的核心部分: 試商的求取了. 算法D 系統的給出了求取試商以及修正方法, 而後其它一些步驟, 這裏略, 請 參考原書.

相關文章
相關標籤/搜索