多倍長演算、その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>