Path: blob/trunk/third_party/closure/goog/math/integer.js
2868 views
// Copyright 2009 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Defines an Integer class for representing (potentially)16* infinite length two's-complement integer values.17*18* For the specific case of 64-bit integers, use goog.math.Long, which is more19* efficient.20*21*/2223goog.provide('goog.math.Integer');24252627/**28* Constructs a two's-complement integer an array containing bits of the29* integer in 32-bit (signed) pieces, given in little-endian order (i.e.,30* lowest-order bits in the first piece), and the sign of -1 or 0.31*32* See the from* functions below for other convenient ways of constructing33* Integers.34*35* The internal representation of an integer is an array of 32-bit signed36* pieces, along with a sign (0 or -1) that indicates the contents of all the37* other 32-bit pieces out to infinity. We use 32-bit pieces because these are38* the size of integers on which Javascript performs bit-operations. For39* operations like addition and multiplication, we split each number into 16-bit40* pieces, which can easily be multiplied within Javascript's floating-point41* representation without overflow or change in sign.42*43* @struct44* @constructor45* @param {Array<number>} bits Array containing the bits of the number.46* @param {number} sign The sign of the number: -1 for negative and 0 positive.47* @final48*/49goog.math.Integer = function(bits, sign) {50/**51* @type {!Array<number>}52* @private53*/54this.bits_ = [];5556/**57* @type {number}58* @private59*/60this.sign_ = sign;6162// Copy the 32-bit signed integer values passed in. We prune out those at the63// top that equal the sign since they are redundant.64var top = true;65for (var i = bits.length - 1; i >= 0; i--) {66var val = bits[i] | 0;67if (!top || val != sign) {68this.bits_[i] = val;69top = false;70}71}72};737475// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the76// from* methods on which they depend.777879/**80* A cache of the Integer representations of small integer values.81* @type {!Object}82* @private83*/84goog.math.Integer.IntCache_ = {};858687/**88* Returns an Integer representing the given (32-bit) integer value.89* @param {number} value A 32-bit integer value.90* @return {!goog.math.Integer} The corresponding Integer value.91*/92goog.math.Integer.fromInt = function(value) {93if (-128 <= value && value < 128) {94var cachedObj = goog.math.Integer.IntCache_[value];95if (cachedObj) {96return cachedObj;97}98}99100var obj = new goog.math.Integer([value | 0], value < 0 ? -1 : 0);101if (-128 <= value && value < 128) {102goog.math.Integer.IntCache_[value] = obj;103}104return obj;105};106107108/**109* Returns an Integer representing the given value, provided that it is a finite110* number. Otherwise, zero is returned.111* @param {number} value The value in question.112* @return {!goog.math.Integer} The corresponding Integer value.113*/114goog.math.Integer.fromNumber = function(value) {115if (isNaN(value) || !isFinite(value)) {116return goog.math.Integer.ZERO;117} else if (value < 0) {118return goog.math.Integer.fromNumber(-value).negate();119} else {120var bits = [];121var pow = 1;122for (var i = 0; value >= pow; i++) {123bits[i] = (value / pow) | 0;124pow *= goog.math.Integer.TWO_PWR_32_DBL_;125}126return new goog.math.Integer(bits, 0);127}128};129130131/**132* Returns a Integer representing the value that comes by concatenating the133* given entries, each is assumed to be 32 signed bits, given in little-endian134* order (lowest order bits in the lowest index), and sign-extending the highest135* order 32-bit value.136* @param {Array<number>} bits The bits of the number, in 32-bit signed pieces,137* in little-endian order.138* @return {!goog.math.Integer} The corresponding Integer value.139*/140goog.math.Integer.fromBits = function(bits) {141var high = bits[bits.length - 1];142return new goog.math.Integer(bits, high & (1 << 31) ? -1 : 0);143};144145146/**147* Returns an Integer representation of the given string, written using the148* given radix.149* @param {string} str The textual representation of the Integer.150* @param {number=} opt_radix The radix in which the text is written.151* @return {!goog.math.Integer} The corresponding Integer value.152*/153goog.math.Integer.fromString = function(str, opt_radix) {154if (str.length == 0) {155throw Error('number format error: empty string');156}157158var radix = opt_radix || 10;159if (radix < 2 || 36 < radix) {160throw Error('radix out of range: ' + radix);161}162163if (str.charAt(0) == '-') {164return goog.math.Integer.fromString(str.substring(1), radix).negate();165} else if (str.indexOf('-') >= 0) {166throw Error('number format error: interior "-" character');167}168169// Do several (8) digits each time through the loop, so as to170// minimize the calls to the very expensive emulated div.171var radixToPower = goog.math.Integer.fromNumber(Math.pow(radix, 8));172173var result = goog.math.Integer.ZERO;174for (var i = 0; i < str.length; i += 8) {175var size = Math.min(8, str.length - i);176var value = parseInt(str.substring(i, i + size), radix);177if (size < 8) {178var power = goog.math.Integer.fromNumber(Math.pow(radix, size));179result = result.multiply(power).add(goog.math.Integer.fromNumber(value));180} else {181result = result.multiply(radixToPower);182result = result.add(goog.math.Integer.fromNumber(value));183}184}185return result;186};187188189/**190* A number used repeatedly in calculations. This must appear before the first191* call to the from* functions below.192* @type {number}193* @private194*/195goog.math.Integer.TWO_PWR_32_DBL_ = (1 << 16) * (1 << 16);196197198/** @type {!goog.math.Integer} */199goog.math.Integer.ZERO = goog.math.Integer.fromInt(0);200201202/** @type {!goog.math.Integer} */203goog.math.Integer.ONE = goog.math.Integer.fromInt(1);204205206/**207* @type {!goog.math.Integer}208* @private209*/210goog.math.Integer.TWO_PWR_24_ = goog.math.Integer.fromInt(1 << 24);211212213/**214* Returns the value, assuming it is a 32-bit integer.215* @return {number} The corresponding int value.216*/217goog.math.Integer.prototype.toInt = function() {218return this.bits_.length > 0 ? this.bits_[0] : this.sign_;219};220221222/** @return {number} The closest floating-point representation to this value. */223goog.math.Integer.prototype.toNumber = function() {224if (this.isNegative()) {225return -this.negate().toNumber();226} else {227var val = 0;228var pow = 1;229for (var i = 0; i < this.bits_.length; i++) {230val += this.getBitsUnsigned(i) * pow;231pow *= goog.math.Integer.TWO_PWR_32_DBL_;232}233return val;234}235};236237238/**239* @param {number=} opt_radix The radix in which the text should be written.240* @return {string} The textual representation of this value.241* @override242*/243goog.math.Integer.prototype.toString = function(opt_radix) {244var radix = opt_radix || 10;245if (radix < 2 || 36 < radix) {246throw Error('radix out of range: ' + radix);247}248249if (this.isZero()) {250return '0';251} else if (this.isNegative()) {252return '-' + this.negate().toString(radix);253}254255// Do several (6) digits each time through the loop, so as to256// minimize the calls to the very expensive emulated div.257var radixToPower = goog.math.Integer.fromNumber(Math.pow(radix, 6));258259var rem = this;260var result = '';261while (true) {262var remDiv = rem.divide(radixToPower);263// The right shifting fixes negative values in the case when264// intval >= 2^31; for more details see265// https://github.com/google/closure-library/pull/498266var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() >>> 0;267var digits = intval.toString(radix);268269rem = remDiv;270if (rem.isZero()) {271return digits + result;272} else {273while (digits.length < 6) {274digits = '0' + digits;275}276result = '' + digits + result;277}278}279};280281282/**283* Returns the index-th 32-bit (signed) piece of the Integer according to284* little-endian order (i.e., index 0 contains the smallest bits).285* @param {number} index The index in question.286* @return {number} The requested 32-bits as a signed number.287*/288goog.math.Integer.prototype.getBits = function(index) {289if (index < 0) {290return 0; // Allowing this simplifies bit shifting operations below...291} else if (index < this.bits_.length) {292return this.bits_[index];293} else {294return this.sign_;295}296};297298299/**300* Returns the index-th 32-bit piece as an unsigned number.301* @param {number} index The index in question.302* @return {number} The requested 32-bits as an unsigned number.303*/304goog.math.Integer.prototype.getBitsUnsigned = function(index) {305var val = this.getBits(index);306return val >= 0 ? val : goog.math.Integer.TWO_PWR_32_DBL_ + val;307};308309310/** @return {number} The sign bit of this number, -1 or 0. */311goog.math.Integer.prototype.getSign = function() {312return this.sign_;313};314315316/** @return {boolean} Whether this value is zero. */317goog.math.Integer.prototype.isZero = function() {318if (this.sign_ != 0) {319return false;320}321for (var i = 0; i < this.bits_.length; i++) {322if (this.bits_[i] != 0) {323return false;324}325}326return true;327};328329330/** @return {boolean} Whether this value is negative. */331goog.math.Integer.prototype.isNegative = function() {332return this.sign_ == -1;333};334335336/** @return {boolean} Whether this value is odd. */337goog.math.Integer.prototype.isOdd = function() {338return (this.bits_.length == 0) && (this.sign_ == -1) ||339(this.bits_.length > 0) && ((this.bits_[0] & 1) != 0);340};341342343/**344* @param {goog.math.Integer} other Integer to compare against.345* @return {boolean} Whether this Integer equals the other.346*/347goog.math.Integer.prototype.equals = function(other) {348if (this.sign_ != other.sign_) {349return false;350}351var len = Math.max(this.bits_.length, other.bits_.length);352for (var i = 0; i < len; i++) {353if (this.getBits(i) != other.getBits(i)) {354return false;355}356}357return true;358};359360361/**362* @param {goog.math.Integer} other Integer to compare against.363* @return {boolean} Whether this Integer does not equal the other.364*/365goog.math.Integer.prototype.notEquals = function(other) {366return !this.equals(other);367};368369370/**371* @param {goog.math.Integer} other Integer to compare against.372* @return {boolean} Whether this Integer is greater than the other.373*/374goog.math.Integer.prototype.greaterThan = function(other) {375return this.compare(other) > 0;376};377378379/**380* @param {goog.math.Integer} other Integer to compare against.381* @return {boolean} Whether this Integer is greater than or equal to the other.382*/383goog.math.Integer.prototype.greaterThanOrEqual = function(other) {384return this.compare(other) >= 0;385};386387388/**389* @param {goog.math.Integer} other Integer to compare against.390* @return {boolean} Whether this Integer is less than the other.391*/392goog.math.Integer.prototype.lessThan = function(other) {393return this.compare(other) < 0;394};395396397/**398* @param {goog.math.Integer} other Integer to compare against.399* @return {boolean} Whether this Integer is less than or equal to the other.400*/401goog.math.Integer.prototype.lessThanOrEqual = function(other) {402return this.compare(other) <= 0;403};404405406/**407* Compares this Integer with the given one.408* @param {goog.math.Integer} other Integer to compare against.409* @return {number} 0 if they are the same, 1 if the this is greater, and -1410* if the given one is greater.411*/412goog.math.Integer.prototype.compare = function(other) {413var diff = this.subtract(other);414if (diff.isNegative()) {415return -1;416} else if (diff.isZero()) {417return 0;418} else {419return +1;420}421};422423424/**425* Returns an integer with only the first numBits bits of this value, sign426* extended from the final bit.427* @param {number} numBits The number of bits by which to shift.428* @return {!goog.math.Integer} The shorted integer value.429*/430goog.math.Integer.prototype.shorten = function(numBits) {431var arr_index = (numBits - 1) >> 5;432var bit_index = (numBits - 1) % 32;433var bits = [];434for (var i = 0; i < arr_index; i++) {435bits[i] = this.getBits(i);436}437var sigBits = bit_index == 31 ? 0xFFFFFFFF : (1 << (bit_index + 1)) - 1;438var val = this.getBits(arr_index) & sigBits;439if (val & (1 << bit_index)) {440val |= 0xFFFFFFFF - sigBits;441bits[arr_index] = val;442return new goog.math.Integer(bits, -1);443} else {444bits[arr_index] = val;445return new goog.math.Integer(bits, 0);446}447};448449450/** @return {!goog.math.Integer} The negation of this value. */451goog.math.Integer.prototype.negate = function() {452return this.not().add(goog.math.Integer.ONE);453};454455456/**457* Returns the sum of this and the given Integer.458* @param {goog.math.Integer} other The Integer to add to this.459* @return {!goog.math.Integer} The Integer result.460*/461goog.math.Integer.prototype.add = function(other) {462var len = Math.max(this.bits_.length, other.bits_.length);463var arr = [];464var carry = 0;465466for (var i = 0; i <= len; i++) {467var a1 = this.getBits(i) >>> 16;468var a0 = this.getBits(i) & 0xFFFF;469470var b1 = other.getBits(i) >>> 16;471var b0 = other.getBits(i) & 0xFFFF;472473var c0 = carry + a0 + b0;474var c1 = (c0 >>> 16) + a1 + b1;475carry = c1 >>> 16;476c0 &= 0xFFFF;477c1 &= 0xFFFF;478arr[i] = (c1 << 16) | c0;479}480return goog.math.Integer.fromBits(arr);481};482483484/**485* Returns the difference of this and the given Integer.486* @param {goog.math.Integer} other The Integer to subtract from this.487* @return {!goog.math.Integer} The Integer result.488*/489goog.math.Integer.prototype.subtract = function(other) {490return this.add(other.negate());491};492493494/**495* Returns the product of this and the given Integer.496* @param {goog.math.Integer} other The Integer to multiply against this.497* @return {!goog.math.Integer} The product of this and the other.498*/499goog.math.Integer.prototype.multiply = function(other) {500if (this.isZero()) {501return goog.math.Integer.ZERO;502} else if (other.isZero()) {503return goog.math.Integer.ZERO;504}505506if (this.isNegative()) {507if (other.isNegative()) {508return this.negate().multiply(other.negate());509} else {510return this.negate().multiply(other).negate();511}512} else if (other.isNegative()) {513return this.multiply(other.negate()).negate();514}515516// If both numbers are small, use float multiplication517if (this.lessThan(goog.math.Integer.TWO_PWR_24_) &&518other.lessThan(goog.math.Integer.TWO_PWR_24_)) {519return goog.math.Integer.fromNumber(this.toNumber() * other.toNumber());520}521522// Fill in an array of 16-bit products.523var len = this.bits_.length + other.bits_.length;524var arr = [];525for (var i = 0; i < 2 * len; i++) {526arr[i] = 0;527}528for (var i = 0; i < this.bits_.length; i++) {529for (var j = 0; j < other.bits_.length; j++) {530var a1 = this.getBits(i) >>> 16;531var a0 = this.getBits(i) & 0xFFFF;532533var b1 = other.getBits(j) >>> 16;534var b0 = other.getBits(j) & 0xFFFF;535536arr[2 * i + 2 * j] += a0 * b0;537goog.math.Integer.carry16_(arr, 2 * i + 2 * j);538arr[2 * i + 2 * j + 1] += a1 * b0;539goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 1);540arr[2 * i + 2 * j + 1] += a0 * b1;541goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 1);542arr[2 * i + 2 * j + 2] += a1 * b1;543goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 2);544}545}546547// Combine the 16-bit values into 32-bit values.548for (var i = 0; i < len; i++) {549arr[i] = (arr[2 * i + 1] << 16) | arr[2 * i];550}551for (var i = len; i < 2 * len; i++) {552arr[i] = 0;553}554return new goog.math.Integer(arr, 0);555};556557558/**559* Carries any overflow from the given index into later entries.560* @param {Array<number>} bits Array of 16-bit values in little-endian order.561* @param {number} index The index in question.562* @private563*/564goog.math.Integer.carry16_ = function(bits, index) {565while ((bits[index] & 0xFFFF) != bits[index]) {566bits[index + 1] += bits[index] >>> 16;567bits[index] &= 0xFFFF;568index++;569}570};571572573/**574* Returns "this" Integer divided by the given one. Both "this" and the given575* Integer MUST be positive.576*577* This method is only needed for very large numbers (>10^308),578* for which the original division algorithm gets into an infinite579* loop (see https://github.com/google/closure-library/issues/500).580*581* The algorithm has some possible performance enhancements (or582* could be rewritten entirely), it's just an initial solution for583* the issue linked above.584*585* @param {!goog.math.Integer} other The Integer to divide "this" by.586* @return {!goog.math.Integer} "this" value divided by the given one.587* @private588*/589goog.math.Integer.prototype.slowDivide_ = function(other) {590if (this.isNegative() || other.isNegative()) {591throw Error('slowDivide_ only works with positive integers.');592}593594var twoPower = goog.math.Integer.ONE;595var multiple = other;596597// First we have to figure out what the highest bit of the result598// is, so we increase "twoPower" and "multiple" until "multiple"599// exceeds "this".600while (multiple.lessThanOrEqual(this)) {601twoPower = twoPower.shiftLeft(1);602multiple = multiple.shiftLeft(1);603}604605// Rewind by one power of two, giving us the highest bit of the606// result.607var res = twoPower.shiftRight(1);608var total = multiple.shiftRight(1);609610// Now we starting decreasing "multiple" and "twoPower" to find the611// rest of the bits of the result.612var total2;613multiple = multiple.shiftRight(2);614twoPower = twoPower.shiftRight(2);615while (!multiple.isZero()) {616// whenever we can add "multiple" to the total and not exceed617// "this", that means we've found a 1 bit. Else we've found a 0618// and don't need to add to the result.619total2 = total.add(multiple);620if (total2.lessThanOrEqual(this)) {621res = res.add(twoPower);622total = total2;623}624multiple = multiple.shiftRight(1);625twoPower = twoPower.shiftRight(1);626}627return res;628};629630631/**632* Returns this Integer divided by the given one.633* @param {!goog.math.Integer} other The Integer to divide this by.634* @return {!goog.math.Integer} This value divided by the given one.635*/636goog.math.Integer.prototype.divide = function(other) {637if (other.isZero()) {638throw Error('division by zero');639} else if (this.isZero()) {640return goog.math.Integer.ZERO;641}642643if (this.isNegative()) {644if (other.isNegative()) {645return this.negate().divide(other.negate());646} else {647return this.negate().divide(other).negate();648}649} else if (other.isNegative()) {650return this.divide(other.negate()).negate();651}652653// Have to degrade to slowDivide for Very Large Numbers, because654// they're out of range for the floating-point approximation655// technique used below.656if (this.bits_.length > 30) {657return this.slowDivide_(other);658}659660// Repeat the following until the remainder is less than other: find a661// floating-point that approximates remainder / other *from below*, add this662// into the result, and subtract it from the remainder. It is critical that663// the approximate value is less than or equal to the real value so that the664// remainder never becomes negative.665var res = goog.math.Integer.ZERO;666var rem = this;667while (rem.greaterThanOrEqual(other)) {668// Approximate the result of division. This may be a little greater or669// smaller than the actual value.670var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));671672// We will tweak the approximate result by changing it in the 48-th digit or673// the smallest non-fractional digit, whichever is larger.674var log2 = Math.ceil(Math.log(approx) / Math.LN2);675var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);676677// Decrease the approximation until it is smaller than the remainder. Note678// that if it is too large, the product overflows and is negative.679var approxRes = goog.math.Integer.fromNumber(approx);680var approxRem = approxRes.multiply(other);681while (approxRem.isNegative() || approxRem.greaterThan(rem)) {682approx -= delta;683approxRes = goog.math.Integer.fromNumber(approx);684approxRem = approxRes.multiply(other);685}686687// We know the answer can't be zero... and actually, zero would cause688// infinite recursion since we would make no progress.689if (approxRes.isZero()) {690approxRes = goog.math.Integer.ONE;691}692693res = res.add(approxRes);694rem = rem.subtract(approxRem);695}696return res;697};698699700/**701* Returns this Integer modulo the given one.702* @param {!goog.math.Integer} other The Integer by which to mod.703* @return {!goog.math.Integer} This value modulo the given one.704*/705goog.math.Integer.prototype.modulo = function(other) {706return this.subtract(this.divide(other).multiply(other));707};708709710/** @return {!goog.math.Integer} The bitwise-NOT of this value. */711goog.math.Integer.prototype.not = function() {712var len = this.bits_.length;713var arr = [];714for (var i = 0; i < len; i++) {715arr[i] = ~this.bits_[i];716}717return new goog.math.Integer(arr, ~this.sign_);718};719720721/**722* Returns the bitwise-AND of this Integer and the given one.723* @param {goog.math.Integer} other The Integer to AND with this.724* @return {!goog.math.Integer} The bitwise-AND of this and the other.725*/726goog.math.Integer.prototype.and = function(other) {727var len = Math.max(this.bits_.length, other.bits_.length);728var arr = [];729for (var i = 0; i < len; i++) {730arr[i] = this.getBits(i) & other.getBits(i);731}732return new goog.math.Integer(arr, this.sign_ & other.sign_);733};734735736/**737* Returns the bitwise-OR of this Integer and the given one.738* @param {goog.math.Integer} other The Integer to OR with this.739* @return {!goog.math.Integer} The bitwise-OR of this and the other.740*/741goog.math.Integer.prototype.or = function(other) {742var len = Math.max(this.bits_.length, other.bits_.length);743var arr = [];744for (var i = 0; i < len; i++) {745arr[i] = this.getBits(i) | other.getBits(i);746}747return new goog.math.Integer(arr, this.sign_ | other.sign_);748};749750751/**752* Returns the bitwise-XOR of this Integer and the given one.753* @param {goog.math.Integer} other The Integer to XOR with this.754* @return {!goog.math.Integer} The bitwise-XOR of this and the other.755*/756goog.math.Integer.prototype.xor = function(other) {757var len = Math.max(this.bits_.length, other.bits_.length);758var arr = [];759for (var i = 0; i < len; i++) {760arr[i] = this.getBits(i) ^ other.getBits(i);761}762return new goog.math.Integer(arr, this.sign_ ^ other.sign_);763};764765766/**767* Returns this value with bits shifted to the left by the given amount.768* @param {number} numBits The number of bits by which to shift.769* @return {!goog.math.Integer} This shifted to the left by the given amount.770*/771goog.math.Integer.prototype.shiftLeft = function(numBits) {772var arr_delta = numBits >> 5;773var bit_delta = numBits % 32;774var len = this.bits_.length + arr_delta + (bit_delta > 0 ? 1 : 0);775var arr = [];776for (var i = 0; i < len; i++) {777if (bit_delta > 0) {778arr[i] = (this.getBits(i - arr_delta) << bit_delta) |779(this.getBits(i - arr_delta - 1) >>> (32 - bit_delta));780} else {781arr[i] = this.getBits(i - arr_delta);782}783}784return new goog.math.Integer(arr, this.sign_);785};786787788/**789* Returns this value with bits shifted to the right by the given amount.790* @param {number} numBits The number of bits by which to shift.791* @return {!goog.math.Integer} This shifted to the right by the given amount.792*/793goog.math.Integer.prototype.shiftRight = function(numBits) {794var arr_delta = numBits >> 5;795var bit_delta = numBits % 32;796var len = this.bits_.length - arr_delta;797var arr = [];798for (var i = 0; i < len; i++) {799if (bit_delta > 0) {800arr[i] = (this.getBits(i + arr_delta) >>> bit_delta) |801(this.getBits(i + arr_delta + 1) << (32 - bit_delta));802} else {803arr[i] = this.getBits(i + arr_delta);804}805}806return new goog.math.Integer(arr, this.sign_);807};808809810