Category talk:Wren-i64: Difference between revisions
Content added Content deleted
m (→Source code (Wren): Minor bug fix.) |
(→Source code (Wren): Fixed some minor issues and improved U64.isPrime method.) |
||
Line 63: | Line 63: | ||
// If 'n' is less than 0, returns zero. O.pow(0) returns one. |
// If 'n' is less than 0, returns zero. O.pow(0) returns one. |
||
static pow(x, n) { |
static pow(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (n is Num) n = from(n) |
||
if (n < 0) return zero |
if (n < 0) return zero |
||
if (n.isZero) return one |
if (n.isZero) return one |
||
Line 95: | Line 95: | ||
// Throws an error if 'x' is negative and 'n' is even. |
// Throws an error if 'x' is negative and 'n' is even. |
||
static root(x, n) { |
static root(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if (!((n is Num) && n.isInteger && n > 0)) { |
if (!((n is Num) && n.isInteger && n > 0)) { |
||
Fiber.abort("'n' must be a positive integer.") |
Fiber.abort("'n' must be a positive integer.") |
||
Line 134: | Line 134: | ||
// The arguments can either be I64 objects or Nums but 'mod' must be non-zero. |
// The arguments can either be I64 objects or Nums but 'mod' must be non-zero. |
||
static modPow(x, exp, mod) { |
static modPow(x, exp, mod) { |
||
if |
if (x is Num) x = from(x) |
||
exp = from(exp) |
exp = from(exp) |
||
if |
if (mod is Num) mod = from(mod) |
||
if (mod.isZero) Fiber.abort("Cannot take modPow with modulus 0.") |
if (mod.isZero) Fiber.abort("Cannot take modPow with modulus 0.") |
||
var r = one |
var r = one |
||
Line 156: | Line 156: | ||
// The arguments can either be I64 objects or Nums but must be co-prime. |
// The arguments can either be I64 objects or Nums but must be co-prime. |
||
static modInv(x, n) { |
static modInv(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (n is Num) n = from(n) |
||
var r = from(n) |
var r = from(n) |
||
var newR = from(x).abs |
var newR = from(x).abs |
||
Line 179: | Line 179: | ||
// Returns the smaller of two I64 objects. |
// Returns the smaller of two I64 objects. |
||
static min(x, y) { |
static min(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x < y) return x |
if (x < y) return x |
||
return y |
return y |
||
Line 187: | Line 187: | ||
// Returns the greater of two I64 objects. |
// Returns the greater of two I64 objects. |
||
static max(x, y) { |
static max(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x > y) return x |
if (x > y) return x |
||
return y |
return y |
||
Line 195: | Line 195: | ||
// Returns the positive difference of two I64 objects. |
// Returns the positive difference of two I64 objects. |
||
static dim(x, y) { |
static dim(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x >= y) return x - y |
if (x >= y) return x - y |
||
return zero |
return zero |
||
Line 412: | Line 412: | ||
// If 'n' is less than 0, returns zero. O.pow(0) returns one. |
// If 'n' is less than 0, returns zero. O.pow(0) returns one. |
||
static pow(x, n) { |
static pow(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (n is Num) n = from(n) |
||
if (n.isZero) return one |
if (n.isZero) return one |
||
if (n.isOne) return x.copy() |
if (n.isOne) return x.copy() |
||
Line 439: | Line 439: | ||
// 'x' can either be a U64 object or a Num but 'n' must be a positive integer. |
// 'x' can either be a U64 object or a Num but 'n' must be a positive integer. |
||
static root(x, n) { |
static root(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if (!((n is Num) && n.isInteger && n > 0)) { |
if (!((n is Num) && n.isInteger && n > 0)) { |
||
Fiber.abort("'n' must be a positive integer.") |
Fiber.abort("'n' must be a positive integer.") |
||
Line 453: | Line 453: | ||
} |
} |
||
return s |
return s |
||
⚫ | |||
// Private helper method for modMul method to avoid overflow. |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
} |
|||
} |
} |
||
Line 458: | Line 468: | ||
// The arguments can either be U64 objects or Nums. |
// The arguments can either be U64 objects or Nums. |
||
static modMul(x, n, mod) { |
static modMul(x, n, mod) { |
||
if |
if (x is Num) x = from(x) |
||
n = from(n) |
n = from(n) |
||
mod = from(mod) |
|||
if (mod.isZero) Fiber.abort("Cannot take modMul with modulus 0.") |
|||
var z = zero |
var z = zero |
||
var y = x |
var y = x % mod |
||
n.rem(mod) |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
} |
|||
while (n > zero) { |
while (n > zero) { |
||
if (n.isOdd) z |
if (n.isOdd) checkedAdd_(z, y, mod) |
||
checkedAdd_(y, y, mod) |
|||
n.rsh(1) |
n.rsh(1) |
||
} |
} |
||
Line 474: | Line 491: | ||
// The arguments can either be U64 objects or Nums but 'mod' must be non-zero. |
// The arguments can either be U64 objects or Nums but 'mod' must be non-zero. |
||
static modPow(x, exp, mod) { |
static modPow(x, exp, mod) { |
||
if |
if (x is Num) x = from(x) |
||
exp = from(exp) |
exp = from(exp) |
||
if |
if (mod is Num) mod = from(mod) |
||
if (mod.isZero) Fiber.abort("Cannot take modPow with modulus 0.") |
if (mod.isZero) Fiber.abort("Cannot take modPow with modulus 0.") |
||
var r = one |
var r = one |
||
Line 492: | Line 509: | ||
// The arguments can either be U64 objects or Nums but must be co-prime. |
// The arguments can either be U64 objects or Nums but must be co-prime. |
||
static modInv(x, n) { |
static modInv(x, n) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (n is Num) n = from(n) |
||
return I64.modInv(x.toI64, n.toI64).toU64 |
return I64.modInv(x.toI64, n.toI64).toU64 |
||
} |
} |
||
Line 499: | Line 516: | ||
// Returns the smaller of two U64 objects. |
// Returns the smaller of two U64 objects. |
||
static min(x, y) { |
static min(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x < y) return x |
if (x < y) return x |
||
return y |
return y |
||
Line 507: | Line 524: | ||
// Returns the greater of two U64 objects. |
// Returns the greater of two U64 objects. |
||
static max(x, y) { |
static max(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x > y) return x |
if (x > y) return x |
||
return y |
return y |
||
Line 515: | Line 532: | ||
// Returns the positive difference of two U64 objects. |
// Returns the positive difference of two U64 objects. |
||
static dim(x, y) { |
static dim(x, y) { |
||
if |
if (x is Num) x = from(x) |
||
if |
if (y is Num) y = from(y) |
||
if (x >= y) return x - y |
if (x >= y) return x - y |
||
return zero |
return zero |
||
Line 580: | Line 597: | ||
// Returns whether or not 'x' is an instance of U64. |
// Returns whether or not 'x' is an instance of U64. |
||
static isInstance(x) { x is U64 } |
static isInstance(x) { x is U64 } |
||
// Private method to determine if a U64 is a basic prime or not. |
|||
⚫ | |||
⚫ | |||
if (n == two || n == three || n == five) return true |
|||
⚫ | |||
⚫ | |||
return null // unknown if prime or not |
|||
⚫ | |||
// Private method to apply the Miller-Rabin test. |
// Private method to apply the Miller-Rabin test. |
||
Line 618: | Line 626: | ||
} |
} |
||
} |
} |
||
} |
|||
⚫ | |||
} |
|||
// Private helper method for 'isPrime' method. |
|||
// Determines whether 'x' is prime using a wheel with basis [2, 3, 5]. |
|||
// Should be faster than Miller-Rabin if 'x' is below 2^37. |
|||
static isPrimeWheel_(x) { |
|||
⚫ | |||
var n = x.copy() |
|||
if (n.isEven) return n == 2 |
|||
if ((n%3).isZero) return n == 3 |
|||
if ((n%5).isZero) return n == 5 |
|||
var d = U64.seven |
|||
⚫ | |||
if ((n%d).isZero) return false |
|||
⚫ | |||
if ((n%d).isZero) return false |
|||
d.add(2) |
|||
if ((n%d).isZero) return false |
|||
d.add(4) |
|||
if ((n%d).isZero) return false |
|||
d.add(2) |
|||
if ((n%d).isZero) return false |
|||
d.add(4) |
|||
if ((n%d).isZero) return false |
|||
d.add(6) |
|||
if ((n%d).isZero) return false |
|||
d.add(2) |
|||
if ((n%d).isZero) return false |
|||
d.add(6) |
|||
if ((n%d).isZero) return false |
|||
} |
} |
||
return true |
return true |
||
Line 624: | Line 664: | ||
// Returns true if 'x' is prime, false otherwise. |
// Returns true if 'x' is prime, false otherwise. |
||
static isPrime(x) { |
static isPrime(x) { |
||
if |
if (x is Num) x = from(x) |
||
if (x < 137438953472) return isPrimeWheel_(x) // use wheel if below 2^37 |
|||
⚫ | |||
if ( |
if (x.isEven || x.isDivisible(three) || x.isDivisible(five) || |
||
⚫ | |||
var a |
var a |
||
if (x < |
if (x < 1122004669633) { |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
} else if (x < 3215031751) { |
|||
⚫ | |||
} else if (x < 4759123141) { |
|||
⚫ | |||
} else if (x < 1122004669633) { |
|||
a = [2, 13, 23, 1662803] |
a = [2, 13, 23, 1662803] |
||
} else if (x < 2152302898747) { |
} else if (x < 2152302898747) { |
||
Line 648: | Line 677: | ||
} else if (x < 341550071728321) { |
} else if (x < 341550071728321) { |
||
a = [2, 3, 5, 7, 11, 13, 17] |
a = [2, 3, 5, 7, 11, 13, 17] |
||
} else if (x < |
} else if (x < fromStr("3825123056546413051")) { |
||
a = [2, 3, 5, 7, 11, 13, 17, 19, 23] |
a = [2, 3, 5, 7, 11, 13, 17, 19, 23] |
||
} else { |
} else { |
||
Line 658: | Line 687: | ||
// Returns the next prime number greater than 'x'. |
// Returns the next prime number greater than 'x'. |
||
static nextPrime(x) { |
static nextPrime(x) { |
||
if |
if (x is Num) x = from(x) |
||
⚫ | |||
var n = x.isEven ? x + one : x + two |
var n = x.isEven ? x + one : x + two |
||
while (true) { |
while (true) { |
||
Line 1,048: | Line 1,076: | ||
copy() { U64.from(this) } // copies 'this' to a new U64 object |
copy() { U64.from(this) } // copies 'this' to a new U64 object |
||
isOdd { this % U64.two == 1 } // true if 'this' is odd |
isOdd { this % U64.two == 1 } // true if 'this' is odd |
||
isEven { this % U64.two == 0 } // true if 'this' is even |
isEven { this % U64.two == 0 } // true if 'this' is even |
||
isZero { this == 0 } // true if 'this' is zero |
isZero { this == 0 } // true if 'this' is zero |
||
isOne { this == 1 } // true if 'this' is one |
isOne { this == 1 } // true if 'this' is one |
||
isSafe { this <= U64.maxSafe |
isSafe { this <= U64.maxSafe } // true if 'this' is safe |
||
isDivisible(d) { this % d == U64.zero } // true if 'this' is divisible by d |
isDivisible(d) { this % d == U64.zero } // true if 'this' is divisible by d |