多倍長演算、その2(足し算でつまずく)

書いては消し、試しては消し、声を掛けられては妄想が消え、
小数なんて含まなければ良かったと・・・。


足し算のところで速度を気にしてどうすんだ?!
割り算までは遠い(涙)


小数点を取り去り、計算に不要な小数の端数を保存し
15桁づつ計算する。桁あふれは crf として繰り越す。

<!DOCTYPE html>
<title>多倍長演算</title>
  
<style>

</style>


<body>
<script>



(function () {
  var DIGIT = 15;
  var DIGIT_MASK = (new Array (DIGIT + 1)).join ('0');
  
  
  // 先頭の0を取り去る
  function zeroFTrim (str) {
    var cnt = 0;
    for (;48 === str.charCodeAt (cnt); cnt += 1);
    return str.substring (cnt);
  }
  
  // 後尾の0を取り去る
  function zeroBTrim (str) {
    var cnt = str.length -1;
    for (;48 === str.charCodeAt (cnt); cnt--);
    return str.substring (0, cnt +1);
  }

  //_________________________________________________________
  
  function BigNumber (sign, integer, decimal) {
    this.sign    = sign; // 符号
    this.integer = integer; // 整数
    this.decimal = decimal; // 小数
  }




//######################################
//絶対値の差を評価する
function absoluteComparison (a, b) { // (a > b):1, (a == b): 0, (a < b): -1
  var sa, i;
  var a_ = a.integer;
  var b_ = b.integer;
  var cha, cha2;
  
  sa = a_.length - b_.length; //長さで判断
  if (sa) {
    return 1 - (sa < 0) * 2;
  }
  
  sa = Number (a_.substring (0, DICIMAL)) - Number (b_.substring (0, DIGIT));//整数の一部で判断
  if (sa) {
    return 1 - (sa < 0) * 2;
  }
  
  a_ += a.decimal;
  b_ += b.decimal;

  for (i = 0; cha = a_.charAt (i); i++) {
    cha2 = b_.charAt (i);
    if (! cha2) return 1;
    if (cha < cha2) return -1;
  }
  if (b_.charAt (i)) return -1;
  return 0;
}


//######################################
  function subtraction (a, b) {
    ;
  }



  function addition (b) {
    var a = this;
    var wd = DIGIT;
    var a_, b_, aLen, bLen, wa, wa_, waLen, sa;
    var as, bs;
    var aIdx, bIdx;
    var r = [];
    var dm = 0;
    var crf = false;
    
    // 計算不要な小数部分の端数を求める
    a_ = a.decimal; aLen = a_.length;
    b_ = b.decimal; bLen = b_.length;
    sa = aLen - bLen;
    
    if (sa) { //小数の桁に差があるとき
      if (sa < 0) { // b_が大きい
        r[0] = b_.slice (sa); // -sa
        b_ = b_.substring (0, aLen);
        dm = bLen;
      }
      else {
        r[0] = a_.slice (-sa);
        a_ = a_.substring (0, bLen);
        dm = aLen;
      }
    }
    else {
      dm = 0;
    }

    // 整数と小数を繋げて後ろから DIGIT 桁ごと計算
    a_ = a.integer + a_; aLen = a_.length;
    b_ = b.integer + b_; bLen = b_.length;
    sa = aLen - bLen;
    
    do {
      aIdx = aLen - wd;
      as = a_.substring (aIdx, aLen);
      
      bIdx = bLen - wd;
      bs = b_.substring (bIdx, bLen);
      if (! as && !bs && ! crf)
        break; 
      
      wa = Number (as) + Number (bs) + Boolean (crf) * 1;
      wa_ = String (wa);
      if (wa_.length > wd) {
        crf = true;
        r[r.length] = wa_.slice (1);
      }
      else {
        crf = false;
        r[r.length] = (DIGIT_MASK + wa_).slice (-Math.max (as.length, bs.length));
      }

      aLen = aIdx;
      bLen = bIdx;
      
    } while (as || bs ||crf);
    a_ = r.reverse ().join ("");

    this.integer = a_.substring (0, a_.length - dm);
    this.decimal = zeroBTrim (a_.slice (-dm)) || '0';

    return this;
  }


  function add (b) {
    var sign, integer, decimal;
    var result;
    
    if (this.sign) { // -a
      if (b.sign) {
        addition.call (this, b);
      }
      else {
        switch (absoluteComparison (a, b)) {

        case 0 : // a == b
          this.sign = false;
          this.integer = 0;
          this.decimal = 0;
          break;
        
        case 1 : // a > b
          subtraction.call (this, b);
          this.sign = true;
          break; 

        case -1 : // a < b
          subtraction.call (b, this);//これはbを書き換えるので問題あり!!
          this.sign = false;
          break; 
        }
      }
    }
    else { // +a
      if (b.sign) {
        switch (absoluteComparison (a, b)) {
        case 0 : // a == b
          this.sign = false;
          this.integer = 0;
          this.decimal = 0;
          break;
        
        case 1 : // a > b
          subtraction.call (this, b);
          this.sign = false;
          break; 

        case -1 : // a < b
          subtraction.call (b, this);//これはbを書き換えるので問題あり!!
          this.sign = true;
          break; 
        }
      }
      else { // +b
        addition.call (this, b);
      }
    }

    return this;
  }


  function sub (b) {
    if (this.sign == b.sign) { // 引き算
      addition.call (this, b);
    }
    else {
      subtraction.call (this, b); //足し算
    }
    return this;
  }
  
  

//######################################
  
  
  function toString () {
    return ((this.sign) ? '-': '') +
           (this.integer ? String (this.integer) : '0') +
           ((this.decimal === '0' || ! this.decimal) ? '': '.' + String (this.decimal));
  }
  
  
  function create (num) {
    if ('string' !== typeof num)
      throw new Error;
    
    var cha = num.charAt (0);
    var sign = ('-' === cha); // 負なら true
    var integer, point, decimal;

    if (sign || ('+' === cha)) { // 符合があるのなら
      num = num.substring (1);
    }
    point = num.indexOf ('.');
    
    if (point) {
      if (point < 0) {
        integer = num || '0';
        decimal = '0';
      }
      else { // 0 < point
        integer = num.substring (0, point) || '0';
        decimal = zeroBTrim (num.slice (point + 1)) || '0';
      }
    }
    else { // point == 0
      integer = '0';
      decimal = zeroBTrim (num.slice (1)) || '0';
    }
    return new BigNumber (sign, integer, decimal);
  }
  
  //_________________________
  
  BigNumber.prototype.add = add;
  BigNumber.prototype.sub = sub;
  BigNumber.prototype.toString = toString;
  
  BigNumber.create = create;
  
  this.BigNumber = BigNumber;
}) ();


  //_________________________

var time = + (new Date);
var m, n = m = 100000;

var a = BigNumber.create ('91000000009000000009000000000.9000000000900000000090000000009');
var b = BigNumber.create (         '20000000030000000004.000000000100000000010000000001');

//alert (a.isBigger (b)== 1 ? 'a > b': a.isBigger (b)==-1 ? 'a < b': ' a == b')

while (m--)
  a.add (b)

var sa = (new Date) - time;

document.write ('Time:' + sa + 'ms/ ['+ (sa / n) + 'ms]<br>');
document.write (a.toString());
</script>