Show More
Commit Description:
merge with algo and add brython files that were missing
Commit Description:
merge with algo and add brython files that were missing
References:
File last commit:
Show/Diff file:
Action:
lib/assets/libs/long_int.js | 639 lines | 20.9 KiB | application/javascript | JavascriptLexer |
/*
Module to manipulate long integers
*/
var $module=(function($B){
eval($B.InjectBuiltins())
var $LongIntDict = {__class__:$B.$type,__name__:'LongInt'}
function add_pos(v1, v2){
// Add two positive numbers
// v1, v2 : strings
// Return an instance of LongInt
var res = '', carry = 0, iself=v1.length, sv=0
for(var i=v2.length-1;i>=0;i--){
iself--
if(iself<0){sv=0}else{sv=parseInt(v1.charAt(iself))}
x = (carry+sv+parseInt(v2.charAt(i))).toString()
if(x.length==2){res=x.charAt(1)+res;carry=parseInt(x.charAt(0))}
else{res=x+res;carry=0}
}
while(iself>0){
iself--
x = (carry+parseInt(v1.charAt(iself))).toString()
if(x.length==2){res=x.charAt(1)+res;carry=parseInt(x.charAt(0))}
else{res=x+res;carry=0}
}
if(carry){res=carry+res}
return {__class__:$LongIntDict, value:res, pos:true}
}
function check_shift(shift){
// Check the argument of >> and <<
if(!isinstance(shift, LongInt)){
throw TypeError("shift must be LongInt, not '"+
$B.get_class(shift).__name__+"'")
}
if(!shift.pos){throw ValueError("negative shift count")}
}
function clone(obj){
// Used for traces
var obj1 = {}
for(var attr in obj){obj1[attr]=obj[attr]}
return obj1
}
function comp_pos(v1, v2){
// Compare two positive numbers
if(v1.length>v2.length){return 1}
else if(v1.length<v2.length){return -1}
else{
if(v1>v2){return 1}
else if(v1<v2){return -1}
}
return 0
}
function divmod_pos(v1, v2){
// v1, v2 : strings, represent 2 positive integers A and B
// Return [a, b] where a and b are instances of LongInt
// a = A // B, b = A % B
var v1_init = v1, quotient, mod
if(comp_pos(v1, v2)==-1){ // a < b
quotient='0'
mod = LongInt(v1)
}else if(v2==v1){ // a = b
quotient = '1';
mod = LongInt('0')
}else{
var quotient = '', v1_init = v1
var left = v1.substr(0, v2.length)
if(v1<v2){left = v1.substr(0, v2.length+1)}
var right = v1.substr(left.length)
// mv2 maps integers i from 2 to 9 to i*v2, used as a cache to avoid
// having to compute i*v2 each time
var mv2 = {}
// Javascript "safe integer" with the 15 first digits in v2,
// used in the algorithm to test candidate values
var jsv2 = parseInt(v2.substr(0,15))
// Division algorithm
// At each step in the division, v1 is split into substrings
// "left" is the left part, with the same length as v2
// "rest" is the rest of v1 after "left"
// The algorithm finds the one-digit integer "candidate" such
// that 0 <= left - candidate*v2 < v2
// It stops when right is empty
while(true){
// Uses JS division to test an approximate result
var jsleft = parseInt(left.substr(0,15))
var candidate = Math.floor(jsleft/jsv2).toString()
// Check that candidate is the correct result
// Start by computing candidate*v2 : for this, use the table
// mv2, which stores the multiples of v2 already calculated
if(mv2[candidate]===undefined){
mv2[candidate] = mul_pos(v2, candidate).value
}
if(comp_pos(left, mv2[candidate])==-1){
// If left < candidate * v2, use candidate-1
candidate--
if(mv2[candidate]===undefined){
mv2[candidate] = mul_pos(v2, candidate).value
}
}
// Add candidate to the quotient
quotient += candidate
// New value for left : left - v2*candidate
left = sub_pos(left, mv2[candidate]).value
// Stop if all digits in v1 have been used
if(right.length==0){break}
// Else, add next digit to left and remove it from right
left += right.charAt(0)
right = right.substr(1)
}
// Modulo is A - (A//B)*B
mod = sub_pos(v1, mul_pos(quotient, v2).value)
}
return [LongInt(quotient), mod]
}
function mul_pos(v1, v2){
// Multiply positive numbers v1 by v2
// Make v2 smaller than v1
if(v1.length<v2.length){var a=v1; v1=v2 ; v2=a}
if(v2=='0'){return LongInt('0')}
var cols = {}, i=v2.length, j
// Built the object "cols", indexed by integers from 1 to nb1+nb2-2
// where nb1 and nb2 are the number of digits in v1 and v2.
// cols[n] is the sum of v1[i]*v2[j] for i+j = n
while(i--){
var car = v2.charAt(i)
if(car=="0"){
j = v1.length
while(j--){
if(cols[i+j]===undefined){cols[i+j]=0}
}
}else if(car=="1"){
j = v1.length
while(j--){
var z = parseInt(v1.charAt(j))
if(cols[i+j]===undefined){cols[i+j]=z}
else{cols[i+j] += z}
}
}else{
var x = parseInt(car), j = v1.length, y, z
while(j--){
y = x * parseInt(v1.charAt(j))
if(cols[i+j]===undefined){cols[i+j]=y}
else{cols[i+j] += y}
}
}
}
// Transform cols so that cols[x] is a one-digit integers
i = v1.length+v2.length-1
while(i--){
var col = cols[i].toString()
if(col.length>1){
// If the value in cols[i] has more than one digit, only keep the
// last one and report the others at the right index
// For instance if cols[i] = 123, keep 3 in cols[i], add 2 to
// cols[i-1] and 1 to cols[i-2]
cols[i] = parseInt(col.charAt(col.length-1))
j = col.length
while(j-->1){
var report = parseInt(col.charAt(j-1))
var pos = i-col.length+j
if(cols[pos]===undefined){cols[pos]=report}
else{cols[pos] += report}
}
}
}
// Find minimum index in cols
// The previous loop may have introduced negative indices
var imin
for(var attr in cols){
i = parseInt(attr)
if(imin===undefined){imin=i}
else if(i<imin){imin=i}
}
// Result is the concatenation of digits in cols
var res = ''
for(var i=imin;i<=v1.length+v2.length-2;i++){res+=cols[i].toString()}
return LongInt(res)
}
function sub_pos(v1, v2){
// Substraction of positive numbers with v1>=v2
var res = '', carry = 0, i1=v1.length, sv=0
// For all digits in v2, starting by the rightmost, substract it from
// the matching digit in v1
// This is the equivalent of the manual operation :
// 12345678
// - 98765
//
// We begin by the rightmost operation : 8-5 (3, no carry),
// then 7-6 (1, no carry)
// then 6-7 (9, carry 1) and so on
for(var i=v2.length-1;i>=0;i--){
i1--
sv = parseInt(v1.charAt(i1))
x = (sv-carry-parseInt(v2.charAt(i)))
if(x<0){res=(10+x)+res;carry=1}
else{res=x+res;carry=0}
}
// If there are remaining digits in v1, substract the carry, if any
while(i1>0){
i1--
x = (parseInt(v1.charAt(i1))-carry)
if(x<0){res=(10+x)+res;carry=1}
else{res=x+res;carry=0}
}
// Remove leading zeros and return the result
while(res.charAt(0)=='0' && res.length>1){res=res.substr(1)}
return {__class__:$LongIntDict, value:res, pos:true}
}
// Special methods to implement operations on instances of LongInt
$LongIntDict.__abs__ = function(self){
return {__class__:$LongIntDict, value: self.value, pos:true}
}
$LongIntDict.__add__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
// Addition of "self" and "other"
// If both have the same sign (+ or -) we add their absolute values
// If they have different sign we use the substraction of their
// absolute values
var res
if(self.pos&&other.pos){ // self > 0, other > 0
return add_pos(self.value, other.value)
}else if(!self.pos&&!other.pos){ // self < 0, other < 0
res = add_pos(self.value, other.value)
res.pos = false
return res
}else if(self.pos && !other.pos){ // self > 0, other < 0
switch (comp_pos(self.value, other.value)){
case 1:
res = sub_pos(self.value, other.value)
break
case 0:
res = {__class__:$LongIntDict, value:0, pos:true}
break
case -1:
res = sub_pos(other.value, self.value)
res.pos = false
break
}
return res
}else{ // self < 0, other > 0
switch(comp_pos(self.value, other.value)){
case 1:
res = sub_pos(self.value, other.value)
res.pos = false
break
case 0:
res = {__class__:$LongIntDict, value:0, pos:true}
break
case -1:
res = sub_pos(other.value, self.value)
break
}
return res
}
}
$LongIntDict.__and__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
// Bitwise "and" : build the binary representation of self and other
var v1 = $LongIntDict.__index__(self)
var v2 = $LongIntDict.__index__(other)
// apply "and" on zeros and ones
if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
var start = v1.length-v2.length
var res = ''
for(var i=0;i<v2.length;i++){
if(v1.charAt(start+i)=='1' && v2.charAt(i)=='1'){res += '1'}
else{res += '0'}
}
// Return the LongInt instance represented by res in base 2
return LongInt(res, 2)
}
$LongIntDict.__divmod__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
var dm = divmod_pos(self.value, other.value)
if(self.pos!==other.pos){
if(dm[0].value!='0'){dm[0].pos = false}
if(dm[1].value!='0'){
// If self and other have different signs and self is not a multiple
// of other, round to the previous integer
dm[0] = $LongIntDict.__sub__(dm[0], LongInt('1'))
dm[1] = $LongIntDict.__add__(dm[1], LongInt('1'))
}
}
return dm
}
$LongIntDict.__eq__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
return self.value==other.value && self.pos==other.pos
}
$LongIntDict.__floordiv__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
return $LongIntDict.__divmod__(self, other)[0]
}
$LongIntDict.__ge__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
if(self.value.length>other.value.length){return true}
else if(self.value.length<other.value.length){return false}
else{return self.value >= other.value}
}
$LongIntDict.__gt__ = function(self, other){
return !$LongIntDict.__le__(self, other)
}
$LongIntDict.__index__ = function(self){
// Used by bin()
// returns a string with the binary value of self
// The algorithm computes the result of the floor division of self by 2
// XXX to do : negative integers
var res = '', pos=self.value.length,
temp = self.value, d
while(true){
d = divmod_pos(temp, '2')
res = d[1].value + res
temp = d[0].value
if(temp=='0'){break}
}
return res
}
$LongIntDict.__invert__ = function(self){
var bin = $LongIntDict.__index__(self)
var res = ''
for(var i=0;i<bin.length;i++){
res += bin.charAt(i)=='0' ? '1' : '0'
}
return LongInt(res, 2)
}
$LongIntDict.__le__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
if(self.value.length>other.value.length){return false}
else if(self.value.length<other.value.length){return true}
else{return self.value <= other.value}
}
$LongIntDict.__lt__ = function(self, other){
return !$LongIntDict.__ge__(self, other)
}
$LongIntDict.__lshift__ = function(self, shift){
check_shift(shift)
var res = self.value
while(true){
var x, carry=0, res1=''
for(var i=res.length-1;i>=0;i--){
x = (carry+parseInt(res.charAt(i))*2).toString()
if(x.length==2){res1=x.charAt(1)+res1;carry=parseInt(x.charAt(0))}
else{res1=x+res1;carry=0}
}
if(carry){res1=carry+res1}
res=res1
shift = sub_pos(shift.value, '1')
if(shift.value=='0'){break}
}
return {__class__:$LongIntDict, value:res, pos:self.pos}
}
$LongIntDict.__mod__ = function(self, other){
return $LongIntDict.__divmod__(self, other)[1]
}
$LongIntDict.__mro__ = [$LongIntDict, _b_.object.$dict]
$LongIntDict.__mul__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
var res = mul_pos(self.value, other.value)
if(self.pos==other.pos){return res}
res.pos = false
return res
}
$LongIntDict.__neg__ = function(obj){
return {__class__:$LongIntDict, value:obj.value, pos:!obj.pos}
}
$LongIntDict.__or__ = function(self, other){
var v1 = $LongIntDict.__index__(self)
var v2 = $LongIntDict.__index__(other)
if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
var start = v1.length-v2.length
var res = v1.substr(0, start)
for(var i=0;i<v2.length;i++){
if(v1.charAt(start+i)=='1' || v2.charAt(i)=='1'){res += '1'}
else{res += '0'}
}
return LongInt(res, 2)
}
$LongIntDict.__pow__ = function(self, power){
if (typeof power == "number") {
power=LongInt(_b_.str(power))
}else if(!isinstance(power, LongInt)){
var msg = "power must be a LongDict, not '"
throw TypeError(msg+$B.get_class(power).__name__+"'")
}
if(!power.pos){
if(self.value=='1'){return self}
// For all other integers, x**-n is 0
return LongInt('0')
}else if(power.value=='0'){
return LongInt('1')
}
var res = {__class__:$LongIntDict, value:self.value, pos:self.pos}
var pow = power.value
while(true){
pow = sub_pos(pow, '1').value
if(pow == '0'){break}
res = $LongIntDict.__mul__(res, self)
}
return res
}
$LongIntDict.__rshift__ = function(self, shift){
check_shift(shift)
var res = self.value
while(true){
res = divmod_pos(res, '2')[0].value
if(res.value=='0'){break}
shift = sub_pos(shift.value, '1')
if(shift.value=='0'){break}
}
return {__class__:$LongIntDict, value:res, pos:self.pos}
}
$LongIntDict.__str__ = $LongIntDict.__repr__ = function(self){
var res = "LongInt('"
if(!self.pos){res += '-'}
return res+self.value+"')"
}
$LongIntDict.__sub__ = function(self, other){
if (typeof other == 'number') other=LongInt(_b_.str(other))
var res
if(self.pos && other.pos){
switch(comp_pos(self.value, other.value)){
case 1:
res = sub_pos(self.value, other.value)
break
case 0:
res = {__class__:$LongIntDict, value:'0', pos:true}
break
case -1:
res = sub_pos(other.value, self.value)
res.pos = false
break
}
return res
}else if(!self.pos && !other.pos){
switch(comp_pos(self.value, other.value)){
case 1:
res = sub_pos(self.value, other.value)
res.pos = false
break
case 0:
res = {__class__:$LongIntDict, value:'0', pos:true}
break
case -1:
res = sub_pos(other.value, self.value)
break
}
return res
}else if(self.pos && !other.pos){
return add_pos(self.value, other.value)
}else{
res = add_pos(self.value, other.value)
res.pos = false
return res
}
}
$LongIntDict.__xor__ = function(self, other){
var v1 = $LongIntDict.__index__(self)
var v2 = $LongIntDict.__index__(other)
if(v1.length<v2.length){var temp=v2;v2=v1;v1=temp}
var start = v1.length-v2.length
var res = v1.substr(0, start)
for(var i=0;i<v2.length;i++){
if(v1.charAt(start+i)=='1' && v2.charAt(i)=='0'){res += '1'}
else if(v1.charAt(start+i)=='0' && v2.charAt(i)=='1'){res += '1'}
else{res += '0'}
}
return LongInt(res, 2)
}
$LongIntDict.to_base = function(self, base){
// Returns the string representation of self in specified base
var res='', v=self.value
while(v>0){
var dm = divmod_pos(v, base.toString())
res = parseInt(dm[1].value).toString(base)+res
v = dm[0].value
if(v==0){break}
}
return res
}
function digits(base){
// Return an object where keys are all the digits valid in specified base
// and value is "true"
// Used to test if the string passed as first argument to LongInt is valid
var is_digits = {}
// Number from 0 to base, or from 0 to 9 if base > 10
for(var i=0;i<base;i++){
if(i==10){break}
is_digits[i]=true
}
if(base>10){
// Additional letters
// For instance in base 16, add "abcdefABCDEF" as keys
for(var i=0;i<base-10;i++){
is_digits[String.fromCharCode(65+i)]=true
is_digits[String.fromCharCode(97+i)]=true
}
}
return is_digits
}
var MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
var MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;
function isSafeInteger(n) {
return (typeof n === 'number' &&
Math.round(n) === n &&
Number.MIN_SAFE_INTEGER <= n &&
n <= Number.MAX_SAFE_INTEGER);
}
function LongInt(value, base){
if(arguments.length>2){
throw _b_.TypeError("LongInt takes at most 2 arguments ("+
arguments.length+" given)")
}
// base defaults to 10
if(base===undefined){base = 10}
else if(!isinstance(base, int)){
throw TypeError("'"+$B.get_class(base).__name__+"' object cannot be interpreted as an integer")
}
if(base<0 || base==1 || base>36){
throw ValueError("LongInt() base must be >= 2 and <= 36")
}
if(isinstance(value, float)){
if(value>=0){value=Math.round(value.value)}
else{value=Math.ceil(value.value)}
}
if(typeof value=='number'){
if(isSafeInteger(value)){value = value.toString()}
else{throw ValueError("argument of long_int is not a safe integer")}
}else if(typeof value!='string'){
throw ValueError("argument of long_int must be a string, not "+
$B.get_class(value).__name__)
}
var has_prefix = false, pos = true, start = 0
// Strip leading and trailing whitespaces
while(value.charAt(0)==' ' && value.length){value = value.substr(1)}
while(value.charAt(value.length-1)==' ' && value.length){
value = value.substr(0, value.length-1)
}
// Check if string starts with + or -
if(value.charAt(0)=='+'){has_prefix=true}
else if(value.charAt(0)=='-'){has_prefix=true;pos=false}
if(has_prefix){
// Remove prefix
if(value.length==1){
// "+" or "-" alone are not valid arguments
throw ValueError('LongInt argument is not a valid number: "'+value+'"')
}else{value=value.substr(1)}
}
// Ignore leading zeros
while(start<value.length-1 && value.charAt(start)=='0'){start++}
value = value.substr(start)
// Check if all characters in value are valid in the base
var is_digits = digits(base), point = -1
for(var i=0;i<value.length;i++){
if(value.charAt(i)=='.' && point==-1){point=i}
else if(!is_digits[value.charAt(i)]){
throw ValueError('LongInt argument is not a valid number: "'+value+'"')
}
}
if(point!=-1){value=value.substr(0,point)}
if(base!=10){
// Conversion to base 10
var coef = '1', v10 = LongInt(0),
pos = value.length, digit_base10
while(pos--){
digit_base10 = parseInt(value.charAt(pos), base).toString()
digit_by_coef = mul_pos(coef, digit_base10).value
v10 = add_pos(v10.value, digit_by_coef)
coef = mul_pos(coef, base.toString()).value
}
return v10
}
return {__class__:$LongIntDict, value:value, pos:pos}
}
LongInt.__class__ = $B.$factory
LongInt.$dict = $LongIntDict
$LongIntDict.$factory = LongInt
return {LongInt:LongInt}
})(__BRYTHON__)