You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
451 lines
9.7 KiB
451 lines
9.7 KiB
/** |
|
C-like unsigned 32 bits integers in Javascript |
|
Copyright (C) 2013, Pierre Curto |
|
MIT license |
|
*/ |
|
;(function (root) { |
|
|
|
// Local cache for typical radices |
|
var radixPowerCache = { |
|
36: UINT32( Math.pow(36, 5) ) |
|
, 16: UINT32( Math.pow(16, 7) ) |
|
, 10: UINT32( Math.pow(10, 9) ) |
|
, 2: UINT32( Math.pow(2, 30) ) |
|
} |
|
var radixCache = { |
|
36: UINT32(36) |
|
, 16: UINT32(16) |
|
, 10: UINT32(10) |
|
, 2: UINT32(2) |
|
} |
|
|
|
/** |
|
* Represents an unsigned 32 bits integer |
|
* @constructor |
|
* @param {Number|String|Number} low bits | integer as a string | integer as a number |
|
* @param {Number|Number|Undefined} high bits | radix (optional, default=10) |
|
* @return |
|
*/ |
|
function UINT32 (l, h) { |
|
if ( !(this instanceof UINT32) ) |
|
return new UINT32(l, h) |
|
|
|
this._low = 0 |
|
this._high = 0 |
|
this.remainder = null |
|
if (typeof h == 'undefined') |
|
return fromNumber.call(this, l) |
|
|
|
if (typeof l == 'string') |
|
return fromString.call(this, l, h) |
|
|
|
fromBits.call(this, l, h) |
|
} |
|
|
|
/** |
|
* Set the current _UINT32_ object with its low and high bits |
|
* @method fromBits |
|
* @param {Number} low bits |
|
* @param {Number} high bits |
|
* @return ThisExpression |
|
*/ |
|
function fromBits (l, h) { |
|
this._low = l | 0 |
|
this._high = h | 0 |
|
|
|
return this |
|
} |
|
UINT32.prototype.fromBits = fromBits |
|
|
|
/** |
|
* Set the current _UINT32_ object from a number |
|
* @method fromNumber |
|
* @param {Number} number |
|
* @return ThisExpression |
|
*/ |
|
function fromNumber (value) { |
|
this._low = value & 0xFFFF |
|
this._high = value >>> 16 |
|
|
|
return this |
|
} |
|
UINT32.prototype.fromNumber = fromNumber |
|
|
|
/** |
|
* Set the current _UINT32_ object from a string |
|
* @method fromString |
|
* @param {String} integer as a string |
|
* @param {Number} radix (optional, default=10) |
|
* @return ThisExpression |
|
*/ |
|
function fromString (s, radix) { |
|
var value = parseInt(s, radix || 10) |
|
|
|
this._low = value & 0xFFFF |
|
this._high = value >>> 16 |
|
|
|
return this |
|
} |
|
UINT32.prototype.fromString = fromString |
|
|
|
/** |
|
* Convert this _UINT32_ to a number |
|
* @method toNumber |
|
* @return {Number} the converted UINT32 |
|
*/ |
|
UINT32.prototype.toNumber = function () { |
|
return (this._high * 65536) + this._low |
|
} |
|
|
|
/** |
|
* Convert this _UINT32_ to a string |
|
* @method toString |
|
* @param {Number} radix (optional, default=10) |
|
* @return {String} the converted UINT32 |
|
*/ |
|
UINT32.prototype.toString = function (radix) { |
|
return this.toNumber().toString(radix || 10) |
|
} |
|
|
|
/** |
|
* Add two _UINT32_. The current _UINT32_ stores the result |
|
* @method add |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.add = function (other) { |
|
var a00 = this._low + other._low |
|
var a16 = a00 >>> 16 |
|
|
|
a16 += this._high + other._high |
|
|
|
this._low = a00 & 0xFFFF |
|
this._high = a16 & 0xFFFF |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Subtract two _UINT32_. The current _UINT32_ stores the result |
|
* @method subtract |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.subtract = function (other) { |
|
//TODO inline |
|
return this.add( other.clone().negate() ) |
|
} |
|
|
|
/** |
|
* Multiply two _UINT32_. The current _UINT32_ stores the result |
|
* @method multiply |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.multiply = function (other) { |
|
/* |
|
a = a00 + a16 |
|
b = b00 + b16 |
|
a*b = (a00 + a16)(b00 + b16) |
|
= a00b00 + a00b16 + a16b00 + a16b16 |
|
|
|
a16b16 overflows the 32bits |
|
*/ |
|
var a16 = this._high |
|
var a00 = this._low |
|
var b16 = other._high |
|
var b00 = other._low |
|
|
|
/* Removed to increase speed under normal circumstances (i.e. not multiplying by 0 or 1) |
|
// this == 0 or other == 1: nothing to do |
|
if ((a00 == 0 && a16 == 0) || (b00 == 1 && b16 == 0)) return this |
|
|
|
// other == 0 or this == 1: this = other |
|
if ((b00 == 0 && b16 == 0) || (a00 == 1 && a16 == 0)) { |
|
this._low = other._low |
|
this._high = other._high |
|
return this |
|
} |
|
*/ |
|
|
|
var c16, c00 |
|
c00 = a00 * b00 |
|
c16 = c00 >>> 16 |
|
|
|
c16 += a16 * b00 |
|
c16 &= 0xFFFF // Not required but improves performance |
|
c16 += a00 * b16 |
|
|
|
this._low = c00 & 0xFFFF |
|
this._high = c16 & 0xFFFF |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Divide two _UINT32_. The current _UINT32_ stores the result. |
|
* The remainder is made available as the _remainder_ property on |
|
* the _UINT32_ object. It can be null, meaning there are no remainder. |
|
* @method div |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.div = function (other) { |
|
if ( (other._low == 0) && (other._high == 0) ) throw Error('division by zero') |
|
|
|
// other == 1 |
|
if (other._high == 0 && other._low == 1) { |
|
this.remainder = new UINT32(0) |
|
return this |
|
} |
|
|
|
// other > this: 0 |
|
if ( other.gt(this) ) { |
|
this.remainder = this.clone() |
|
this._low = 0 |
|
this._high = 0 |
|
return this |
|
} |
|
// other == this: 1 |
|
if ( this.eq(other) ) { |
|
this.remainder = new UINT32(0) |
|
this._low = 1 |
|
this._high = 0 |
|
return this |
|
} |
|
|
|
// Shift the divisor left until it is higher than the dividend |
|
var _other = other.clone() |
|
var i = -1 |
|
while ( !this.lt(_other) ) { |
|
// High bit can overflow the default 16bits |
|
// Its ok since we right shift after this loop |
|
// The overflown bit must be kept though |
|
_other.shiftLeft(1, true) |
|
i++ |
|
} |
|
|
|
// Set the remainder |
|
this.remainder = this.clone() |
|
// Initialize the current result to 0 |
|
this._low = 0 |
|
this._high = 0 |
|
for (; i >= 0; i--) { |
|
_other.shiftRight(1) |
|
// If shifted divisor is smaller than the dividend |
|
// then subtract it from the dividend |
|
if ( !this.remainder.lt(_other) ) { |
|
this.remainder.subtract(_other) |
|
// Update the current result |
|
if (i >= 16) { |
|
this._high |= 1 << (i - 16) |
|
} else { |
|
this._low |= 1 << i |
|
} |
|
} |
|
} |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Negate the current _UINT32_ |
|
* @method negate |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.negate = function () { |
|
var v = ( ~this._low & 0xFFFF ) + 1 |
|
this._low = v & 0xFFFF |
|
this._high = (~this._high + (v >>> 16)) & 0xFFFF |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Equals |
|
* @method eq |
|
* @param {Object} other UINT32 |
|
* @return {Boolean} |
|
*/ |
|
UINT32.prototype.equals = UINT32.prototype.eq = function (other) { |
|
return (this._low == other._low) && (this._high == other._high) |
|
} |
|
|
|
/** |
|
* Greater than (strict) |
|
* @method gt |
|
* @param {Object} other UINT32 |
|
* @return {Boolean} |
|
*/ |
|
UINT32.prototype.greaterThan = UINT32.prototype.gt = function (other) { |
|
if (this._high > other._high) return true |
|
if (this._high < other._high) return false |
|
return this._low > other._low |
|
} |
|
|
|
/** |
|
* Less than (strict) |
|
* @method lt |
|
* @param {Object} other UINT32 |
|
* @return {Boolean} |
|
*/ |
|
UINT32.prototype.lessThan = UINT32.prototype.lt = function (other) { |
|
if (this._high < other._high) return true |
|
if (this._high > other._high) return false |
|
return this._low < other._low |
|
} |
|
|
|
/** |
|
* Bitwise OR |
|
* @method or |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.or = function (other) { |
|
this._low |= other._low |
|
this._high |= other._high |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise AND |
|
* @method and |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.and = function (other) { |
|
this._low &= other._low |
|
this._high &= other._high |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise NOT |
|
* @method not |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.not = function() { |
|
this._low = ~this._low & 0xFFFF |
|
this._high = ~this._high & 0xFFFF |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise XOR |
|
* @method xor |
|
* @param {Object} other UINT32 |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.xor = function (other) { |
|
this._low ^= other._low |
|
this._high ^= other._high |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise shift right |
|
* @method shiftRight |
|
* @param {Number} number of bits to shift |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.shiftRight = UINT32.prototype.shiftr = function (n) { |
|
if (n > 16) { |
|
this._low = this._high >> (n - 16) |
|
this._high = 0 |
|
} else if (n == 16) { |
|
this._low = this._high |
|
this._high = 0 |
|
} else { |
|
this._low = (this._low >> n) | ( (this._high << (16-n)) & 0xFFFF ) |
|
this._high >>= n |
|
} |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise shift left |
|
* @method shiftLeft |
|
* @param {Number} number of bits to shift |
|
* @param {Boolean} allow overflow |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.shiftLeft = UINT32.prototype.shiftl = function (n, allowOverflow) { |
|
if (n > 16) { |
|
this._high = this._low << (n - 16) |
|
this._low = 0 |
|
if (!allowOverflow) { |
|
this._high &= 0xFFFF |
|
} |
|
} else if (n == 16) { |
|
this._high = this._low |
|
this._low = 0 |
|
} else { |
|
this._high = (this._high << n) | (this._low >> (16-n)) |
|
this._low = (this._low << n) & 0xFFFF |
|
if (!allowOverflow) { |
|
// Overflow only allowed on the high bits... |
|
this._high &= 0xFFFF |
|
} |
|
} |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise rotate left |
|
* @method rotl |
|
* @param {Number} number of bits to rotate |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.rotateLeft = UINT32.prototype.rotl = function (n) { |
|
var v = (this._high << 16) | this._low |
|
v = (v << n) | (v >>> (32 - n)) |
|
this._low = v & 0xFFFF |
|
this._high = v >>> 16 |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Bitwise rotate right |
|
* @method rotr |
|
* @param {Number} number of bits to rotate |
|
* @return ThisExpression |
|
*/ |
|
UINT32.prototype.rotateRight = UINT32.prototype.rotr = function (n) { |
|
var v = (this._high << 16) | this._low |
|
v = (v >>> n) | (v << (32 - n)) |
|
this._low = v & 0xFFFF |
|
this._high = v >>> 16 |
|
|
|
return this |
|
} |
|
|
|
/** |
|
* Clone the current _UINT32_ |
|
* @method clone |
|
* @return {Object} cloned UINT32 |
|
*/ |
|
UINT32.prototype.clone = function () { |
|
return new UINT32(this._low, this._high) |
|
} |
|
|
|
if (typeof define != 'undefined' && define.amd) { |
|
// AMD / RequireJS |
|
define([], function () { |
|
return UINT32 |
|
}) |
|
} else if (typeof module != 'undefined' && module.exports) { |
|
// Node.js |
|
module.exports = UINT32 |
|
} else { |
|
// Browser |
|
root['UINT32'] = UINT32 |
|
} |
|
|
|
})(this)
|
|
|