UNPKG

algebrite

Version:

Computer Algebra System in Coffeescript

709 lines (540 loc) 10.2 kB
#double convert_rational_to_double(U *) #double convert_bignum_to_double(unsigned int *) #int ge(unsigned int *, unsigned int *, int) mint = (a) -> return bigInt a # b is +1 or -1, a is a bigint setSignTo = (a,b) -> if a.isPositive() if b < 0 return a.multiply bigInt -1 else # a is negative if b > 0 return a.multiply bigInt -1 return a makeSignSameAs = (a,b) -> if a.isPositive() if b.isNegative() return a.multiply bigInt -1 else # a is negative if b.isPositive() return a.multiply bigInt -1 return a makePositive = (a) -> if a.isNegative() return a.multiply bigInt -1 return a # n is an int ### mtotal = 0 MP_MIN_SIZE = 2 MP_MAX_FREE = 1000 mnew = (n) -> if (n < MP_MIN_SIZE) n = MP_MIN_SIZE if (n == MP_MIN_SIZE && mfreecount) p = free_stack[--mfreecount] else p = [] #(unsigned int *) malloc((n + 3) * sizeof (int)) #if (p == 0) # stop("malloc failure") p[0] = n mtotal += n return p[3] ### # p is the index of array of ints # !!! array wasn't passed here ### free_stack = [] mfree = (array, p) -> p -= 3 mtotal -= array[p] if (array[p] == MP_MIN_SIZE && mfreecount < MP_MAX_FREE) free_stack[mfreecount++] = p else free(p) ### # convert int to bignum # n is an int ### mint = (n) -> p = mnew(1) if (n < 0) # !!! this is FU # MSIGN(p) = -1 fu = true else # !!! this is FU #MSIGN(p) = 1 fu = true # !!! this is FU #MLENGTH(p) = 1 p[0] = Math.abs(n) return p ### # copy bignum # a is an array of ints ### mcopy = (a) -> #unsigned int *b b = mnew(MLENGTH(a)) # !!! fu #MSIGN(b) = MSIGN(a) #MLENGTH(b) = MLENGTH(a) for i in [0...MLENGTH(a)] b[i] = a[i] return b ### ### # # ge not invoked from anywhere - is you need ge # just use the bigNum's ge implementation # leaving it here just in case I decide to backport to C # # a >= b ? # and and b arrays of ints, len is an int ge = (a, b, len) -> i = 0 for i in [0...len] if (a[i] == b[i]) continue else break if (a[i] >= b[i]) return 1 else return 0 ### add_numbers = -> a = 1.0 b = 1.0 #if DEBUG then console.log("add_numbers adding numbers: " + print_list(stack[tos - 1]) + " and " + print_list(stack[tos - 2])) if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) qadd() return save() p2 = pop() p1 = pop() if (isdouble(p1)) a = p1.d else a = convert_rational_to_double(p1) if (isdouble(p2)) b = p2.d else b = convert_rational_to_double(p2) theResult = a+b push_double(theResult) restore() subtract_numbers = -> a = 0.0 b = 0.0 if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) qsub() return save() p2 = pop() p1 = pop() if (isdouble(p1)) a = p1.d else a = convert_rational_to_double(p1) if (isdouble(p2)) b = p2.d else b = convert_rational_to_double(p2) push_double(a - b) restore() multiply_numbers = -> a = 0.0 b = 0.0 if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) qmul() return save() p2 = pop() p1 = pop() if (isdouble(p1)) a = p1.d else a = convert_rational_to_double(p1) if (isdouble(p2)) b = p2.d else b = convert_rational_to_double(p2) push_double(a * b) restore() divide_numbers = -> a = 0.0 b = 0.0 if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) qdiv() return save() p2 = pop() p1 = pop() if (iszero(p2)) stop("divide by zero") if (isdouble(p1)) a = p1.d else a = convert_rational_to_double(p1) if (isdouble(p2)) b = p2.d else b = convert_rational_to_double(p2) push_double(a / b) restore() invert_number = -> #unsigned int *a, *b save() p1 = pop() if (iszero(p1)) stop("divide by zero") if (isdouble(p1)) push_double(1 / p1.d) restore() return a = bigInt(p1.q.a) b = bigInt(p1.q.b) b = makeSignSameAs(b,a) a = setSignTo(a,1) p1 = new U() p1.k = NUM p1.q.a = b p1.q.b = a push(p1) restore() # a and b are Us compare_rationals = (a, b) -> t = 0 #unsigned int *ab, *ba ab = mmul(a.q.a, b.q.b) ba = mmul(a.q.b, b.q.a) t = mcmp(ab, ba) return t # a and b are Us compare_numbers = (a,b) -> x = 0.0 y = 0.0 if (isrational(a) && isrational(b)) return compare_rationals(a, b) if (isdouble(a)) x = a.d else x = convert_rational_to_double(a) if (isdouble(b)) y = b.d else y = convert_rational_to_double(b) if (x < y) return -1 if (x > y) return 1 return 0 negate_number = -> save() p1 = pop() if (iszero(p1)) push(p1) restore() return switch (p1.k) when NUM p2 = new U() p2.k = NUM p2.q.a = bigInt(p1.q.a.multiply(bigInt.minusOne)) p2.q.b = bigInt(p1.q.b) push(p2) when DOUBLE push_double(-p1.d) else stop("bug caught in mp_negate_number") restore() bignum_truncate = -> #unsigned int *a save() p1 = pop() a = mdiv(p1.q.a, p1.q.b) p1 = new U() p1.k = NUM p1.q.a = a p1.q.b = bigInt(1) push(p1) restore() mp_numerator = -> save() p1 = pop() if (p1.k != NUM) push(one) restore() return p2 = new U() p2.k = NUM p2.q.a = bigInt(p1.q.a) p2.q.b = bigInt(1) push(p2) restore() mp_denominator = -> save() p1 = pop() if (p1.k != NUM) push(one) restore() return p2 = new U() p2.k = NUM p2.q.a = bigInt(p1.q.b) p2.q.b = bigInt(1) push(p2) restore() # expo is an integer bignum_power_number = (expo) -> #unsigned int *a, *b, *t save() p1 = pop() a = mpow(p1.q.a, Math.abs(expo)) b = mpow(p1.q.b, Math.abs(expo)) if (expo < 0) # swap a and b t = a a = b b = t a = makeSignSameAs(a,b) b = setSignTo(b,1) p1 = new U() p1.k = NUM p1.q.a = a p1.q.b = b push(p1) restore() # p an array of ints convert_bignum_to_double = (p) -> return p.toJSNumber() # p is a U convert_rational_to_double = (p) -> if !p.q? debugger quotientAndRemainder = p.q.a.divmod(p.q.b) result = quotientAndRemainder.quotient + quotientAndRemainder.remainder / p.q.b.toJSNumber() return result # n an integer push_integer = (n) -> if DEBUG then console.log "pushing integer " + n save() p1 = new U() p1.k = NUM p1.q.a = bigInt(n) p1.q.b = bigInt(1) push(p1) restore() # d a double push_double = (d) -> save() p1 = new U() p1.k = DOUBLE p1.d = d push(p1) restore() # a,b parts of a rational push_rational = (a,b) -> ### save() p1 = new U() p1.k = NUM p1.q.a = bigInt(a) p1.q.b = bigInt(b) ## FIXME -- normalize ## push(p1) restore() ### p = new U() p.k = NUM p.q.a = bigInt(a) p.q.b = bigInt(b) push(p) pop_integer = -> n = NaN save() p1 = pop() switch (p1.k) when NUM if (isinteger(p1) && p1.q.a.isSmall) n = p1.q.a.toJSNumber() when DOUBLE if DEBUG console.log "popping integer but double is found" if Math.floor(p1.d) == p1.d if DEBUG console.log "...altough it's an integer" n = p1.d restore() return n # p is a U, flag is an int print_double = (p,flag) -> accumulator = "" buf = doubleToReasonableString(p.d) if (flag == 1 && buf == '-') accumulator += print_str(buf + 1) else accumulator += print_str(buf) return accumulator # s is a string bignum_scan_integer = (s) -> #unsigned int *a #char sign save() scounter = 0 sign_ = s[scounter] if (sign_ == '+' || sign_ == '-') scounter++ # !!!! some mess in here, added an argument a = bigInt(s.substring(scounter)) p1 = new U() p1.k = NUM p1.q.a = a p1.q.b = bigInt(1) push(p1) if (sign_ == '-') negate() restore() # s a string bignum_scan_float = (s) -> push_double(parseFloat(s)) # gives the capability of printing the unsigned # value. This is handy because printing of the sign # might be taken care of "upstream" # e.g. when printing a base elevated to a negative exponent # prints the inverse of the base powered to the unsigned # exponent. # p is a U print_number = (p, signed) -> accumulator = "" denominatorString = "" buf = "" switch (p.k) when NUM aAsString = p.q.a.toString() if !signed if aAsString[0] == "-" aAsString = aAsString.substring(1) if (printMode == PRINTMODE_LATEX and isfraction(p)) aAsString = "\\frac{"+aAsString+"}{" accumulator += aAsString if (isfraction(p)) if printMode != PRINTMODE_LATEX accumulator += ("/") denominatorString = p.q.b.toString() if printMode == PRINTMODE_LATEX then denominatorString += "}" accumulator += denominatorString when DOUBLE aAsString = doubleToReasonableString(p.d) if !signed if aAsString[0] == "-" aAsString = aAsString.substring(1) accumulator += aAsString return accumulator gcd_numbers = -> save() p2 = pop() p1 = pop() # if (!isinteger(p1) || !isinteger(p2)) # stop("integer args expected for gcd") p3 = new U() p3.k = NUM p3.q.a = mgcd(p1.q.a, p2.q.a) p3.q.b = mgcd(p1.q.b, p2.q.b) p3.q.a = setSignTo(p3.q.a,1) push(p3) restore() pop_double = -> d = 0.0 save() p1 = pop() switch (p1.k) when NUM d = convert_rational_to_double(p1) when DOUBLE d = p1.d else d = 0.0 restore() return d bignum_float = -> d = 0.0 d = convert_rational_to_double(pop()) push_double(d) #static unsigned int *__factorial(int) # n is an int bignum_factorial = (n) -> save() p1 = new U() p1.k = NUM p1.q.a = __factorial(n) p1.q.b = bigInt(1) push(p1) restore() # n is an int __factorial = (n) -> i = 0 #unsigned int *a, *b, *t if (n == 0 || n == 1) a = bigInt(1) return a a = bigInt(2) b = bigInt(0) if 3 <= n for i in [3..n] b = bigInt(i) t = mmul(a, b) a = t return a mask = [ 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, ] # unsigned int *x, unsigned int k mp_set_bit = (x, k) -> console.log "not implemented yet" debugger x[k / 32] |= mask[k % 32] # unsigned int *x, unsigned int k mp_clr_bit = (x,k) -> console.log "not implemented yet" debugger x[k / 32] &= ~mask[k % 32] # unsigned int *a mshiftright = (a) -> a = a.shiftRight()