Category talk:Wren-long: Difference between revisions
Content added Content deleted
(→Source code: Added a second divisors method.) |
(→Source code: Added support for signed 64 bit arithmetic (Long class).) |
||
Line 60: | Line 60: | ||
static smallest { lohi_(0, 0) } |
static smallest { lohi_(0, 0) } |
||
// Private method to determine whether a number is a short unsigned integer or not. |
|||
static isShort_(n) { (n is Num) && n.isInteger && n >= 0 && n <= 4294967295 } |
static isShort_(n) { (n is Num) && n.isInteger && n >= 0 && n <= 4294967295 } |
||
// Private method to determine whether a number is a small unsigned integer or not. |
// Private method to determine whether a number is a small unsigned integer or not. |
||
static isSmall_(n) { (n is Num) && n.isInteger && n >= 0 && n <= 9007199254740991 } |
static isSmall_(n) { (n is Num) && n.isInteger && n >= 0 && n <= 9007199254740991 } |
||
// Private method to determine whether a number is a non-negative Long or not. |
|||
static isNonNegLong_(n) { (n is Long) && !n.isNegative } |
|||
// Private method to calculate the base 2 logarithm of a number. |
// Private method to calculate the base 2 logarithm of a number. |
||
Line 343: | Line 346: | ||
} |
} |
||
// Creates a ULong object from either a numeric base 10 string |
// Creates a ULong object from either a numeric base 10 string, an unsigned 'small' integer or a non-negative Long. |
||
static new(value) { |
static new(value) { |
||
if (!(value is String) && !isSmall_(value)) { |
if (!(value is String) && !isSmall_(value) && !isNonNegLong_(value)) { |
||
Fiber.abort("Value must be a base 10 numeric string |
Fiber.abort("Value must be a base 10 numeric string, an unsigned small integer or a non-negative Long.") |
||
} |
} |
||
return (value is String) ? fromString_(value) : fromSmall_(value) |
return (value is String) ? fromString_(value) : (value is Num) ? fromSmall_(value) : value.toULong |
||
} |
} |
||
Line 588: | Line 591: | ||
min(n) { ULong.min(this, n) } |
min(n) { ULong.min(this, n) } |
||
// Clamps this instance into the range [a, b]. |
// Clamps this instance into the range [a, b]. |
||
// If this instance is less than min, min is returned. |
// If this instance is less than min, min is returned. |
||
// If it's more than max, max is returned. Otherwise, this instance is returned. |
// If it's more than max, max is returned. Otherwise, this instance is returned. |
||
clamp(a, b) { |
clamp(a, b) { |
||
Line 618: | Line 621: | ||
} |
} |
||
// Returns the integer n'th root of the current instance |
// Returns the integer n'th root of the current instance |
||
// i.e. the precise n'th root truncated towards zero if not an integer. |
// i.e. the precise n'th root truncated towards zero if not an integer. |
||
iroot(n) { |
iroot(n) { |
||
Line 746: | Line 749: | ||
// Expresses the current instance as a list of 8 unsigned bytes in little-endian format. |
// Expresses the current instance as a list of 8 unsigned bytes in little-endian format. |
||
toBytes { |
toBytes { |
||
return [_lo & 0xff, _lo >> 8 & 0xff, _lo >> 16 & 0xff, _lo >> 24 |
return [_lo & 0xff, _lo >> 8 & 0xff, _lo >> 16 & 0xff, _lo >> 24 , |
||
_hi & 0xff, _hi >> 8 & 0xff, _hi >> 16 & 0xff, _hi >> 24] |
_hi & 0xff, _hi >> 8 & 0xff, _hi >> 16 & 0xff, _hi >> 24] |
||
} |
} |
||
// Converts the current instance to a Long. |
|||
toLong { Long.sigma_(sign, this) } |
|||
// Private worker method for toBaseString, toHexString and toString. |
// Private worker method for toBaseString, toHexString and toString. |
||
Line 924: | Line 930: | ||
divs.add(i) |
divs.add(i) |
||
var j = n / i |
var j = n / i |
||
if (j != i) divs2.add(j) |
if (j != i) divs2.add(j) |
||
} |
} |
||
i = i + k |
i = i + k |
||
Line 971: | Line 977: | ||
static mean(a) { sum(a)/a.count } |
static mean(a) { sum(a)/a.count } |
||
static prod(a) { a.reduce(ULong.one) { |acc, x| acc * x } } |
static prod(a) { a.reduce(ULong.one) { |acc, x| acc * x } } |
||
static max(a) { a.reduce { |acc, x| (x > acc) ? x : acc } } |
|||
static min(a) { a.reduce { |acc, x| (x < acc) ? x : acc } } |
|||
} |
|||
/* |
|||
Long represents a 64-bit signed integer together with arithmetic operations thereon. |
|||
Long objects, which are immutable, are stored as a magnitude (ULong) and a sign |
|||
+1 for positive numbers, 0 for zero and -1 for negative numbers. |
|||
*/ |
|||
class Long is Comparable { |
|||
// Constants |
|||
static minusOne { sigma_(-1, ULong.one) } |
|||
static zero { sigma_( 0, ULong.zero) } |
|||
static one { sigma_( 1, ULong.one) } |
|||
static two { sigma_( 1, ULong.two) } |
|||
static three { sigma_( 1, ULong.three) } |
|||
static four { sigma_( 1, ULong.four) } |
|||
static five { sigma_( 1, ULong.five) } |
|||
static ten { sigma_( 1, ULong.ten) } |
|||
// Returns the maximum 'short' Long = 2^32-1 = 4294967295 |
|||
static maxShort { sigma_(1, ULong.maxShort) } |
|||
// Returns the minimum 'short' Long = -(2^32-1) = -4294967295 |
|||
static minShort { sigma_(-1, ULong.maxShort) } |
|||
// Returns the maximum 'small' Long = 2^53-1 = 9007199254740991 |
|||
static maxSmall { sigma_(1, ULong.maxSmall) } |
|||
// Returns the minimum 'small' Long = -(2^53-1) = -9007199254740991 |
|||
static minSmall { sigma_(-1, ULong.maxSmall) } |
|||
// Returns the largest Long = 2^64-1 = 18446744073709551615 |
|||
static largest { sigma_(1, ULong.largest) } |
|||
// Returns the smallest Long = -(2^64-1) = -18446744073709551615 |
|||
static smallest { sigma_(-1, ULong.smallest) } |
|||
// Private method to determine whether a number is a short integer or not. |
|||
static isShort_(n) { (n is Num) && n.isInteger && n.abs <= 4294967295 } |
|||
// Private method to determine whether a number is a small integer or not. |
|||
static isSmall_(n) { (n is Num) && n.isInteger && n.abs <= 9007199254740991 } |
|||
// Returns the greater of two Longs. |
|||
static max(a, b) { |
|||
if (!(a is Long)) a = new(a) |
|||
if (!(b is Long)) b = new(b) |
|||
return (a > b) ? a : b |
|||
} |
|||
// Returns the lesser of two Longs. |
|||
static min(a, b) { |
|||
if (!(a is Long)) a = new(a) |
|||
if (!(b is Long)) b = new(b) |
|||
return (a < b) ? a : b |
|||
} |
|||
// Returns the greatest common divisor of a and b. The result is never negative. |
|||
static gcd(a, b) { |
|||
if (!(a is Long)) a = new(a) |
|||
if (!(b is Long)) b = new(b) |
|||
while (!b.isZero) { |
|||
var t = b |
|||
b = a % b |
|||
a = t |
|||
} |
|||
return a.abs |
|||
} |
|||
// Returns the least common multiple of a and b. The result is never negative. |
|||
static lcm(a, b) { |
|||
if (!(a is Long)) a = new(a) |
|||
if (!(b is Long)) b = new(b) |
|||
if (a.isZero && b.isZero) return Long.zero |
|||
return (a * b).abs / gcd(a, b) |
|||
} |
|||
// Returns whether or not 'n' is an instance of Long. |
|||
static isInstance(n) { n is Long } |
|||
// Private constructor which creates a Long object from a sign and a ULong. |
|||
construct sigma_(sig, mag) { |
|||
_sig = sig |
|||
_mag = mag |
|||
if (mag.isZero && sig != 0) _sig = 0 |
|||
} |
|||
// Private constructor which creates a Long object from a 'small' integer. |
|||
construct fromSmall_(v) { |
|||
_sig = v.sign |
|||
_mag = ULong.fromSmall_(v.abs) |
|||
} |
|||
// Private method which creates a Long object from a Num. |
|||
// If 'v' is not small, will probably lose accuracy. |
|||
static fromNum_(v) { sigma_(v.sign, ULong.fromNum_(v.abs)) } |
|||
// Private method which creates a Long object from a base 10 numeric string. |
|||
// A leading sign is permitted and so is scientific notation. |
|||
// Raises an error if the result is out of bounds. |
|||
static fromString_(v) { |
|||
v = v.trim() |
|||
if (v.count == 0) Fiber.abort("Invalid integer.") |
|||
var sig |
|||
var mag |
|||
if (v[0] == "-") { |
|||
sig = -1 |
|||
mag = ULong.fromString_(v[1..-1]) |
|||
} else { |
|||
sig = 1 |
|||
mag = ULong.fromString_(v) |
|||
} |
|||
if (mag == ULong.zero) sig = 0 |
|||
return sigma_(sig, mag) |
|||
} |
|||
// Creates a Long object from an (unprefixed) numeric string in a given base (2 to 36). |
|||
// A leading sign is permitted but scientific notation is not. |
|||
// Wraps out of range values. |
|||
static fromBaseString(v, base) { |
|||
v = v.trim() |
|||
if (v.count == 0) Fiber.abort("Invalid integer.") |
|||
var sig |
|||
var mag |
|||
if (v[0] == "-") { |
|||
sig = -1 |
|||
mag = ULong.fromBaseString(v[1..-1], base) |
|||
} else { |
|||
sig = 1 |
|||
mag = ULong.fromBaseString(v, base) |
|||
} |
|||
if (mag == ULong.zero) sig = 0 |
|||
return sigma_(sig, mag) |
|||
} |
|||
// Creates a Long object from either a numeric base 10 string, a 'small' integer or a ULong. |
|||
static new(value) { |
|||
if (!(value is String) && !isSmall_(value) && !(value is ULong)) { |
|||
Fiber.abort("Value must be a base 10 numeric string, a small integer or a ULong.") |
|||
} |
|||
return (value is String) ? fromString_(value) : (value is Num) ? fromSmall_(value) : value.toLong |
|||
} |
|||
// Creates a Long object from an (unprefixed) hexadecimal string. Wraps out of range values. |
|||
static fromHexString(v) { fromBaseString(v, 16) } |
|||
// Properties to return the sign and magnitude of this instance. |
|||
sign { _sig } |
|||
magnitude { _mag } |
|||
mag { _mag } // synonym for magnitude |
|||
// Public self-evident properties. |
|||
isShort { _mag.isShort } |
|||
isSmall { _mag.isSmall } |
|||
isEven { _mag.isEven } |
|||
isOdd { _mag.isOdd } |
|||
isOne { _mag.isOne && _sig == 1 } |
|||
isUnit { _mag.isOne } |
|||
isZero { _sig == 0 } |
|||
isPositive { _sig == 1 } |
|||
isNegative { _sig == -1 } |
|||
// Returns true if 'n' is a divisor of the current instance, false otherwise |
|||
isDivisibleBy(n) { (this % n).isZero } |
|||
// negates 'this' |
|||
- { Long.sigma_(-_sig, _mag) } |
|||
// Adds a Long to the current instance. Wraps on overflow. |
|||
+ (n) { |
|||
if (!(n is Long)) n = Long.new(n) |
|||
var res |
|||
if (_sig >= 0 && n.sign >= 0) { |
|||
res = Long.sigma_(1, _mag + n.mag) |
|||
} else if (_sig >= 0 && n.sign < 0) { |
|||
res = (_mag >= n.mag) ? Long.sigma_(1, _mag - n.mag) : Long.sigma_(-1, n.mag - _mag) |
|||
} else if (_sig < 0 && n.sign >= 0) { |
|||
res = (n.mag >= _mag) ? Long.sigma_(1, n.mag - _mag) : Long.sigma_(-1, _mag - n.mag) |
|||
} else { // _sig < 0 && n.sign < 0) |
|||
res = Long.sigma_(-1, _mag + n.mag) |
|||
} |
|||
return res |
|||
} |
|||
// Subtracts a Long from the current instance. Wraps on underflow. |
|||
- (n) { this + (-n) } |
|||
// Multiplies the current instance by a Long. Wraps on overflow. |
|||
* (n) { |
|||
if (!(n is Long)) n = Long.new(n) |
|||
return Long.sigma_(_sig * n.sign, _mag * n.mag) |
|||
} |
|||
// Returns a list containing the quotient and the remainder after dividing |
|||
// the current instance by a Long. The remainder always has the same sign as 'this'. |
|||
divMod(n) { |
|||
if (!(n is Long)) n = Long.new(n) |
|||
if (n.isZero) Fiber.abort("Cannot divide by zero.") |
|||
var dm = _mag.divMod(n.mag) |
|||
return [Long.sigma_(_sig / n.sign, dm[0]), Long.sigma_(_sig, dm[1])] |
|||
} |
|||
// Divides the current instance by a Long. |
|||
/ (n) { divMod(n)[0] } |
|||
// Returns the remainder after dividing the current instance by a Long. |
|||
% (n) { divMod(n)[1] } |
|||
// Returns the absolute value of 'this'. |
|||
abs { isNegative ? -this : this } |
|||
// The inherited 'clone' method just returns 'this' as Long objects are immutable. |
|||
// If you need an actual copy use this method instead. |
|||
copy() { Long.sigma_(_sig, _mag) } |
|||
// Compares the current instance with a Long. If they are equal returns 0. |
|||
// If 'this' is greater, returns 1. Otherwise returns -1. |
|||
// Also allows a comparison with positive or negative infinity. |
|||
compare(n) { |
|||
if ((n is Num) && n.isInfinity && n > 0) return -1 |
|||
if ((n is Num) && n.isInfinity && n < 0) return 1 |
|||
if (!(n is Long)) n = Long.new(n) |
|||
if (_sig == n.sign && _mag == n.mag) return 0 |
|||
if (_sig >= 0 && n.sign >= 0) return (_mag > n.mag) ? 1 : -1 |
|||
if (_sig >= 0 && n.sign < 0) return 1 |
|||
if (_sig < 0 && n.sign >= 0) return -1 |
|||
return (n.mag > _mag) ? 1 : -1 |
|||
} |
|||
// Returns the greater of this instance and another Long instance. |
|||
max(n) { Long.max(this, n) } |
|||
// Returns the smaller of this instance and another Long instance. |
|||
min(n) { Long.min(this, n) } |
|||
// Clamps this instance into the range [a, b]. |
|||
// If this instance is less than min, min is returned. |
|||
// If it's more than max, max is returned. Otherwise, this instance is returned. |
|||
clamp(a, b) { |
|||
if (!(a is Long)) a = Long.new(a) |
|||
if (!(b is Long)) b = Long.new(b) |
|||
if (a > b) Fiber.abort("Range cannot be decreasing.") |
|||
if (this < a) return a |
|||
if (this > b) return b |
|||
return this.copy() |
|||
} |
|||
// Squares the current instance. Wraps on overflow. |
|||
square { this * this } |
|||
// Cubes the current instance. Wraps on overflow. |
|||
cube { this * this * this } |
|||
// Returns true if the current instance is a perfect square, false otherwise. |
|||
isSquare { |
|||
if (isNegative) System.print("A negative real number cannot be a perfect square.") |
|||
return _mag.isSquare |
|||
} |
|||
// Returns true if the current instance is a perfect cube, false otherwise. |
|||
isCube { _mag.isCube } |
|||
// Returns the integer n'th root of the current instance |
|||
// i.e. the precise n'th root truncated towards zero if not an integer. |
|||
iroot(n) { |
|||
if (!((n is Num) && n.isInteger && n > 0)) { |
|||
Fiber.abort("Argument must be a positive integer.") |
|||
} |
|||
if (isNegative && n.isEven) Fiber.abort("A negative real number cannot have an even root.") |
|||
return Long.sigma_(_sig, _mag.iroot(n)) |
|||
} |
|||
// Returns the integer cube root of the current instance |
|||
// i.e. the precise cube root truncated towards zero if not an integer. |
|||
icbrt { Long.sigma_(_sig, _mag.icbrt) } |
|||
// Returns the integer square root of the current instance |
|||
// i.e. the precise sqaure root truncated towards zero if not an integer. |
|||
isqrt { |
|||
if (isNegative) System.print("A negative real number cannot have a square root.") |
|||
return Long.sigma_(_sig, _mag.isqrt) |
|||
} |
|||
// Returns the current instance raised to the power of a 'small' ULong. Wraps on overflow. |
|||
// If the exponent is less than 0, returns 0. O.pow(0) returns one. |
|||
pow(n) { |
|||
var mag = _mag.pow(n) |
|||
var sign |
|||
if (mag == ULong.zero) { |
|||
sign = 0 |
|||
} else if (isNegative && n % 2 == 1) { |
|||
sign = -1 |
|||
} else { |
|||
sign = 1 |
|||
} |
|||
return Long.sigma_(sign, mag) |
|||
} |
|||
// Returns the current instance multiplied by 'n' modulo 'mod'. |
|||
modMul(n, mod) { Long.sigma_(_sig, _mag.modMul(n, mod)) } |
|||
// Returns the current instance to the power 'exp' modulo 'mod'. |
|||
modPow(exp, mod) { |
|||
var mag = _mag.modPow(exp, mod) |
|||
var sign |
|||
if (mag == ULong.zero) { |
|||
sign = 0 |
|||
} else if (isNegative && (exp % mod).isOdd) { |
|||
sign = -1 |
|||
} else { |
|||
sign = 1 |
|||
} |
|||
return Long.sigma_(sign, mag) |
|||
} |
|||
// Increments the current instance by one. |
|||
inc { this + Long.one } |
|||
// Decrements the current instance by one. |
|||
dec { this - Long.one } |
|||
// Converts the current instance to a Num where possible. |
|||
// Will probably lose accuracy if the current instance is not 'small'. |
|||
toNum { _sig * _mag.toNum } |
|||
// Converts the current instance to a 'small' integer where possible. |
|||
// Otherwise returns null. |
|||
toSmall { isSmall ? toNum : null } |
|||
// Converts the current instance to a ULong where possible. |
|||
// Otherwise returns null. |
|||
toULong { !isNegative ? _mag : null } |
|||
// Returns the string representation of the current instance in a given base (2 to 36). |
|||
toBaseString(base) { |
|||
var bs = _mag.toBaseString(base) |
|||
return isNegative ? "-" + bs : bs |
|||
} |
|||
// Returns the string representation of the current instance in base 16. |
|||
toHexString { toBaseString(16) } |
|||
// Returns the string representation of the current instance in base 10. |
|||
toString { toBaseString(10) } |
|||
} |
|||
/* Longs contains various routines applicable to lists of signed 64-bit integers. */ |
|||
class Longs { |
|||
static sum(a) { a.reduce(Long.zero) { |acc, x| acc + x } } |
|||
static mean(a) { sum(a)/a.count } |
|||
static prod(a) { a.reduce(Long.one) { |acc, x| acc * x } } |
|||
static max(a) { a.reduce { |acc, x| (x > acc) ? x : acc } } |
static max(a) { a.reduce { |acc, x| (x > acc) ? x : acc } } |
||
static min(a) { a.reduce { |acc, x| (x < acc) ? x : acc } } |
static min(a) { a.reduce { |acc, x| (x < acc) ? x : acc } } |