Category talk:Wren-big: Difference between revisions
Content added Content deleted
(→Source code: Added BigInt.prevPrime method.) |
(→Source code: Added BigDec and BigDecs classes.) |
||
Line 2,017: | Line 2,017: | ||
static mean(a) { sum(a)/a.count } |
static mean(a) { sum(a)/a.count } |
||
static prod(a) { a.reduce(BigRat.one) { |acc, x| acc * x } } |
static prod(a) { a.reduce(BigRat.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 } } |
|||
} |
|||
/* BigDec represents an arbitrary length decimal number. Internally, it is simply a BigRat object |
|||
but with the number of decimal places in its expansion limited to a given 'precision'. |
|||
The minimum and default precision is 16 decimal places. BigDec objects are immutable. |
|||
*/ |
|||
class BigDec is Comparable { |
|||
// Private helper function to check that 'o' is a suitable type and throw an error otherwise. |
|||
// Numbers, rational numbers and numeric strings are returned as BigDecs. |
|||
static check_(o) { |
|||
if (o is BigDec) return o |
|||
if (o is Num || o is String) return new(o) |
|||
if (o.type.toString == "Rat") return new_(BigRat.fromRat(o)) |
|||
if (o is BigRat) return fromBigRat(o) |
|||
if (o is BigInt) return fromBigInt(o) |
|||
Fiber.abort("Argument must either be a number, a rational number or a numeric string.") |
|||
} |
|||
// Numeric constants (all have default precision) |
|||
static minusOne { fromInt(-1) } |
|||
static zero { fromInt(0) } |
|||
static one { fromInt(1) } |
|||
static two { fromInt(2) } |
|||
static three { fromInt(3) } |
|||
static four { fromInt(4) } |
|||
static five { fromInt(5) } |
|||
static six { fromInt(6) } |
|||
static seven { fromInt(7) } |
|||
static eight { fromInt(8) } |
|||
static nine { fromInt(9) } |
|||
static ten { fromInt(10) } |
|||
static half { new(0.5) } |
|||
static quarter { new(0.25) } |
|||
static fifth { new(0.2) } |
|||
static eighth { new(0.125) } |
|||
static tenth { new(0.1) } |
|||
// Transcendental constants (all have precision 64) |
|||
static e { new("2.7182818284590452353602874713526624977572470936999595749669676277", 64) } |
|||
static ln2 { new("0.6931471805599453094172321214581765680755001343602552541206800095", 64) } |
|||
static ln10 { new("2.3025850929940456840179914546843642076011014886287729760333279010", 64) } |
|||
static pi { new("3.1415926535897932384626433832795028841971693993751058209749445923", 64) } |
|||
static tau { new("6.2831853071795864769252867665590057683943387987502116419498891846", 64) } |
|||
static phi { new("1.6180339887498948482045868343656381177203091798057628621354486227", 64) } |
|||
static sqrt2 { new("1.4142135623730950488016887242096980785696718753769480731766797380", 64) } |
|||
// Returns the greater of two BigDec objects. |
|||
static max(d1, d2) { (d1 < d2) ? d2 : d1 } |
|||
// Returns the smaller of two BigDec objects. |
|||
static min(d1, d2) { (d1 < d2) ? d1 : d2 } |
|||
// Constructs a BigDec object from a number or decimal numeric string. |
|||
construct new(s, prec) { |
|||
_prec = prec.max(16) |
|||
_br = BigRat.fromDecimal(s) |
|||
if (s is String) _br = _br.round(_prec) |
|||
} |
|||
// Constructs a BigDec object from an integer. |
|||
construct fromInt(i, prec) { |
|||
if (!(i is Num && i.isInteger)) Fiber.abort ("Argument must be an integer.") |
|||
_br = BigRat.new(i, 1) |
|||
_prec = prec.max(16) |
|||
} |
|||
// Constructs a BigDec object from a big integer. |
|||
construct fromBigInt(bi, prec) { |
|||
if (!(bi is BigInt)) Fiber.abort ("Argument must be a big integer.") |
|||
_br = BigRat.new(bi, BigInt.one) |
|||
_prec = prec.max(16) |
|||
} |
|||
// Constructs a BigDec object from a rational number. |
|||
construct fromRat(r, prec) { |
|||
_br = BigRat.fromRat(r) |
|||
_prec = prec.max(16) |
|||
} |
|||
// Constructs a BigDec object from a big rational number. |
|||
construct fromBigRat(br, prec) { |
|||
if (!(br is BigRat)) Fiber.abort ("Argument must be a big rational number.") |
|||
_br = br.copy() |
|||
_prec = prec.max(16) |
|||
} |
|||
// Convenience versions of the above constructors which always use a precision of 16. |
|||
static new(s) { new(s, 16) } |
|||
static fromInt(i) { fromInt(i, 16) } |
|||
static fromBigInt(bi) { fromBigInt(bi, 16) } |
|||
static fromRat(r) { fromRat(r, 16) } |
|||
static fromBigRat(br) { fromBigRat(br, 16) } |
|||
// Private constructor. |
|||
construct new_(br, prec) { |
|||
_br = br.round(prec) |
|||
_prec = prec |
|||
} |
|||
// Private method to return the internal BigRat without copying. |
|||
br_ { _br } |
|||
// Get or sets the precision for this object. |
|||
prec { _prec } |
|||
prec=(p) { _prec = p.floor.max(16) } |
|||
// Other properties. |
|||
isInteger { _br.isInteger } // checks if integral or not |
|||
isPositive { _br.isPositive } // checks if positive |
|||
isNegative { _br.isNegative } // checks if negative |
|||
isUnit { _br.isUnit } // checks if plus or minus one |
|||
isZero { _br.isZero } // checks if zero |
|||
/* Note that the result of unary operations has the same precision as the operand |
|||
and the result of binary operations has the greater precision of the operands */ |
|||
// Rounding methods (similar to those in Num class). |
|||
ceil { BigDec.new_(_br.ceil, _prec) } // higher integer, towards zero |
|||
floor { BigDec.new_(_br.floor, _prec) } // lower integer |
|||
truncate { BigDec.new_(_br.truncate, _prec) } // lower integer, towards zero |
|||
round { BigDec.new_(_br.round, _prec) } // nearer integer |
|||
roundUp { BigDec.new_(_br.roundUp, _prec) } // higher integer, away from zero |
|||
round(digits) { BigDec.new(_br.round(digits), _prec) } // rounds to 'digits' decimal places |
|||
fraction { this - truncate } // fractional part (same sign as this) |
|||
// Negation. |
|||
- { BigDec.new (-_br, _prec) } |
|||
// Arithmetic operators (work with numbers, rational numbers and numeric strings |
|||
// as well as other decimal numbers). |
|||
+(o) { (o = BigDec.check_(o)) && BigDec.new_(_br + o.br_, _prec.max(o.prec)) } |
|||
-(o) { (o = BigDec.check_(o)) && BigDec.new_(_br - o.br_, _prec.max(o.prec)) } |
|||
*(o) { (o = BigDec.check_(o)) && BigDec.new_(_br * o.br_, _prec.max(o.prec)) } |
|||
/(o) { (o = BigDec.check_(o)) && BigDec.new_(_br / o.br_, _prec.max(o.prec)) } |
|||
%(o) { (o = BigDec.check_(o)) && BigDec.new_(_br % o.br_, _prec.max(o.prec)) } |
|||
// Integral power methods. |
|||
pow(i) { BigDec.new_(_br.pow(i), _prec) } |
|||
square { BigDec.new_(_br.square, _prec) } |
|||
cube { BigDec.new_(_br.cube, _prec) } |
|||
// Roots to 'digits' places or 16 places by default. |
|||
sqrt(digits) { BigDec.new_(_br.sqrt(digits), _prec) } |
|||
cbrt(digits) { BigDec.new_(_br.cbrt(digits), _prec) } |
|||
sqrt { sqrt(16) } |
|||
cbrt { cbrt(16) } |
|||
// Other methods. |
|||
inverse { BigDec.new_(_br.inverse, _prec) } // inverse |
|||
idiv(o) { (this/o).truncate } // integer division |
|||
inc { this + BigDec.one } // increment |
|||
dec { this - BigDec.one } // decrement |
|||
abs { BigDec.new_(_br.abs, _prec)} // absolute value |
|||
sign { _br.num.sign } // sign |
|||
// The inherited 'clone' method just returns 'this' as BigDec objects are immutable. |
|||
// If you need an actual copy use this method instead. |
|||
copy() { BigDec.new_(_br.copy(), _prec) } |
|||
// Compares this BigDec with another one to enable comparison operators via Comparable trait. |
|||
compare(other) { _br.compare(other.br_) } |
|||
// As above but compares the absolute values of the BigDecs. |
|||
compareAbs(other) { _br.compareAbs(other.br_) } |
|||
// Returns this BigDec expressed as a BigInt with any fractional part truncated. |
|||
toBigInt { _br.num/_br.den } |
|||
// Returns this BigDec expressed as a BigRat. |
|||
toBigRat { _br.copy() } |
|||
// Converts the current instance to a Num where possible. |
|||
// Will probably lose accuracy for larger numbers. |
|||
toFloat { Num.fromString(this.toString(14)) } |
|||
// Converts the current instance to an integer where possible with any fractional part truncated. |
|||
// Will probably lose accuracy for integers >= 2^53. |
|||
toInt { this.toFloat.truncate } |
|||
// Returns the string representation of this BigDec object to 'digits' decimal places. |
|||
// If 'rounded' is true, the value is rounded to that number of places with halves |
|||
// being rounded away from zero. Otherwise the value is truncated to that number of places. |
|||
// If 'zfill' is true, any unfilled decimal places are filled with zeros. |
|||
toString(digits, rounded, zfill) { _br.toDecimal(digits, rounded, zfill) } |
|||
// Convenience versions of the above which use default values for some or all parameters |
|||
// and never add trailing zeros. |
|||
toString(digits, rounded) { toString(digits, rounded, false) } |
|||
toString(digits) { toString(digits, true, false) } // always rounded |
|||
toString { toString(_prec, true, false) } // precision digits, always rounded |
|||
toDefaultString { toString(16, true, false) } // 16 digits, always rounded |
|||
} |
|||
/* BigDecs contains various routines applicable to lists of big decimal numbers */ |
|||
class BigDecs { |
|||
static sum(a) { a.reduce(BigDec.zero) { |acc, x| acc + x } } |
|||
static mean(a) { sum(a)/a.count } |
|||
static prod(a) { a.reduce(BigDec.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 } } |