spitewaste 0.1.001 → 0.1.006

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,72 +1,74 @@
1
- import math
2
-
3
- ; TODO: don't use strings for bitwise operations
4
-
5
- ; bitwise bitwise_and
6
- ; ! clobbers heap address -1
7
- bitwise_and: ; [a b] => [a & b]
8
- push -1 push 0 store ; empty string tally
9
-
10
- _bitwise_and_loop:
11
- copy 1 copy 1 add jz _bitwise_done
12
- copy 1 push 2 mod
13
- copy 1 push 2 mod
14
- add push 2 sub jz _bitwise_and_yes
15
- push '0' jump _bitwise_and_update
16
-
17
- _bitwise_and_yes: push '1'
18
- _bitwise_and_update: :_bitwise_update jump _bitwise_and_loop
19
-
20
- _bitwise_update:
21
- push -1 load swap :strcat
22
- push -1 swap store
23
- push 2 div swap push 2 div ret
24
-
25
- _bitwise_done: push -1 load :strrev :bin slide 2 ret
26
-
27
- ; bitwise bitwise_or
28
- ; ! clobbers heap address -1
29
- bitwise_or: ; [a b] => [a | b]
30
- push -1 push 0 store ; empty string tally
31
-
32
- _bitwise_or_loop:
33
- copy 1 copy 1 add jz _bitwise_done
34
- copy 1 push 2 mod
35
- copy 1 push 2 mod
36
- add jz _bitwise_or_no
37
- push '1' jump _bitwise_or_update
38
-
39
- _bitwise_or_no: push '0'
40
- _bitwise_or_update: :_bitwise_update jump _bitwise_or_loop
41
-
42
- ; bitwise bitwise_xor
43
- ; ! clobbers heap address -1
44
- bitwise_xor: ; [a b] => [a ^ b]
45
- push -1 push 0 store ; empty string tally
46
-
47
- _bitwise_xor_loop:
48
- copy 1 copy 1 add jz _bitwise_done
49
- copy 1 push 2 mod
50
- copy 1 push 2 mod
51
- add push 1 sub jz _bitwise_xor_yes
52
- push '0' jump _bitwise_xor_update
53
-
54
- _bitwise_xor_yes: push '1'
55
- _bitwise_xor_update: :_bitwise_update jump _bitwise_xor_loop
56
-
57
- ; flip all bits in n ; [n]
58
- bitwise_not:
1
+ import math ; ilog, pow
2
+ import util ; digits
3
+
4
+ ; The bitwise operators all work very similarly, differing only in how they
5
+ ; map pairs of bits to 0 or 1. For AND, we simply multiply them. For OR, we
6
+ ; sum them, add 1, then divide by 2. For XOR, we only want 1 if they're neq.
7
+ ; We repeatedly halve the inputs while consuming bits and stop when at least
8
+ ; one of them becomes zero. For AND, the answer is in the accumulator and we
9
+ ; are done. For OR and XOR, it's likely the nonzero input still has bits to
10
+ ; contribute, so we also accumulate its product with the current power of 2.
11
+ $bitfun(op, bit, done) {
12
+ push -2,1,-1,0 store store
13
+ _`op`_loop: push -1
14
+ copy 2 push 2 mod copy 2 push 2 mod `bit`
15
+ push -1 load swap push -2 load dup push 2 mul
16
+ push -2 swap store mul add store
17
+ push 2 div swap push 2 div
18
+ dup copy 2 mul jz _`op`_done swap jump _`op`_loop
19
+ _`op`_done: `done` ret
20
+ }
21
+
22
+ ; returns the bitwise AND of A and B
23
+ ; [A B] => [A & B]
24
+ ;
25
+ ; [65 47] => [1] [83 25] => [17]
26
+ ; [40 64] => [0] [74 59] => [10]
27
+ ; [31 18] => [18] [86 32] => [0]
28
+ ; [93 79] => [77] [11 79] => [11]
29
+ band: $bitfun(band, mul, mul $-- load)
30
+
31
+ ; returns the bitwise OR of A and B
32
+ ; [A B] => [A | B]
33
+ ;
34
+ ; [66 51] => [115] [64 4] => [68]
35
+ ; [61 77] => [125] [93 65] => [93]
36
+ ; [14 87] => [95] [71 37] => [103]
37
+ ; [7 19] => [23] [38 92] => [126]
38
+ bor: $bitfun(bor, add $++ push 2 div, add push -2 load mul push -1 load add)
39
+
40
+ ; returns the bitwise XOR of A and B
41
+ ; [A B] => [A ^ B]
42
+ ;
43
+ ; [4 14] => [10] [0 80] => [80]
44
+ ; [51 5] => [54] [97 77] => [44]
45
+ ; [39 65] => [102] [12 26] => [22]
46
+ ; [44 36] => [8] [6 21] => [19]
47
+ bxor: $bitfun(bxor, :neq, add push -2 load mul push -1 load add)
48
+
49
+ ; returns the infinite-precision bitwise NOT of N by inverting all of its bits
50
+ ; [N] => [~N]
51
+ ;
52
+ ; [58] => [5] [46] => [17]
53
+ ; [48] => [15] [87] => [40]
54
+ ; [98] => [29] [51] => [12]
55
+ ; [3] => [0] [42] => [21]
56
+ bnot:
59
57
  dup push 0 swap push 1 add sub
60
58
  swap push 2 :ilog push 2 swap :pow mod ret
61
59
 
62
- ;;;
63
-
64
- ; number of set bits in n ; [n]
60
+ ; returns the number of bits in the binary representation of N
61
+ ; [N] => [# of bits]
62
+ ;
63
+ ; [0] => [0] [1] => [1]
64
+ ; [7] => [3] [8] => [4]
65
+ ; [255] => [8]
66
+ blength: dup jz _blength_zero push 2 :ilog $++ ret
67
+ _blength_zero: ret
68
+
69
+ ; returns the number of set bits in N
70
+ ; [N] => [popcount]
71
+ ;
72
+ ; [0] => [0] [1] => [1]
73
+ ; [7] => [3] [8] => [1]
65
74
  popcount: push 2 :digits reduce (add) ret
66
-
67
- ;;;
68
-
69
- ; most significant set bit in n, as a power of 2 ; [n]
70
- msb: dup jz _msb_zero
71
- push 2 :itos :strlen $-- push 2 swap :pow ret
72
- _msb_zero: ret
@@ -1,32 +1,40 @@
1
- import bits
2
1
  ;;; Case conversion
3
2
 
4
- upcase: :strunpack push 0 ; tally
5
- _upcase_loop:
6
- swap dup jz _upcase_done
7
- dup :isalpha jz _upcase_cat
8
- push 95 :bitwise_and
9
- _upcase_cat:
10
- :strcat jump _upcase_loop
3
+ import bits ; band, bor, bxor
4
+ import string ; isalpha, strcat, strunpack
11
5
 
12
- _upcase_done: pop ret
6
+ ; The case conversion functions all behave very similarly, differing only in
7
+ ; how they modify the ordinal value V of a character to be kept.
8
+ ; upcase is V & 95, downcase is V | 32, and swapcase is V ^ 32.
9
+ $casefun(case, op) {
10
+ :strunpack push 0 ; get characters on stack and initialize accumulator
11
+ _`case`_loop: swap dup jz _`case`_done dup :isalpha jz _`case`_cat `op`
12
+ _`case`_cat: :strcat jump _`case`_loop
13
+ _`case`_done: pop ret
14
+ }
13
15
 
14
- downcase: :strunpack push 0 ; tally
15
- _downcase_loop:
16
- swap dup jz _downcase_done
17
- dup :isalpha jz _downcase_cat
18
- push 32 :bitwise_or
19
- _downcase_cat:
20
- :strcat jump _downcase_loop
16
+ ; returns string S with all alphabetical characters capitalized
17
+ ; [S] => [S']
18
+ ;
19
+ ; [""] => [""]
20
+ ; ["abc"] => ["ABC"]
21
+ ; ["123"] => ["123"]
22
+ ; ["Abc123Def"] => ["ABC123DEF"]
23
+ upcase: $casefun(upcase, push 0x5F :band)
21
24
 
22
- _downcase_done: pop ret
25
+ ; returns string S with all alphabetical characters lower-cased
26
+ ; [S] => [S']
27
+ ;
28
+ ; [""] => [""]
29
+ ; ["ABC"] => ["abc"]
30
+ ; ["123"] => ["123"]
31
+ ; ["aBC123dEF"] => ["abc123def"]
32
+ downcase: $casefun(downcase, push 0x20 :bor)
23
33
 
24
- swapcase: :strunpack push 0 ; tally
25
- _swapcase_loop:
26
- swap dup jz _swapcase_done
27
- dup :isalpha jz _swapcase_cat
28
- push 32 :bitwise_xor
29
- _swapcase_cat:
30
- :strcat jump _swapcase_loop
31
-
32
- _swapcase_done: pop ret
34
+ ; returns string S with the case of all alphabetical characters swapped
35
+ ; [S] => [S']
36
+ ;
37
+ ; [""] => [""]
38
+ ; ["FooBar"] => ["fOObAR"]
39
+ ; ["Abc123deF"] => ["aBC123DEf"]
40
+ swapcase: $casefun(swapcase, push 0x20 :bxor)
@@ -0,0 +1 @@
1
+ {"fun":{"palindrome?":{"full":"returns whether the string S is the same forwards and backwards\n[S] => [0 | 1]\n\n[\"racecar\"] => [1]\n[\"divider\"] => [0]\n[\"redivider\"] => [1]\n","desc":"returns whether the string S is the same forwards and backwards","effect":"[S] => [0 | 1]","cases":[[[504736985444594],[1]],[[504874701534436],[0]],[[8271867109940212466],[1]]]},"anagrams?":{"full":"returns whether the strings S and T are composed of the same characters\n[S T] => [0 | 1]\n\n[\"allergy\" \"gallery\"] => [1]\n[\"largely\" \"regally\"] => [1]\n[\"foo\" \"bar\"] => [0]\n","desc":"returns whether the strings S and T are composed of the same characters","effect":"[S T] => [0 | 1]","cases":[[[535733496133217,536107978272999],[1]],[[535901809455340,535903675740914],[1]],[[1832934,1880290],[0]]]},"isop":{"full":"returns the sum of the alphabetical characters in string S where A=1, B=2...\n[S] => [sum]\n\n[\"Math\"] => [42]\n[\"wizards\"] => [100]\n[\"AbCd\"] => [10]\n","desc":"returns the sum of the alphabetical characters in string S where A=1, B=2...","effect":"[S] => [sum]","cases":[[[220016845],[42]],[[509242129691895],[100]],[[210825537],[10]]]},"collatz":{"full":"returns the elements of the Collatz sequence for integer N as a pseudo-array\n[N] => [A]\n\n[1] => [1 1]\n[2] => [2 1 2]\n[3] => [3 10 5 16 8 4 2 1 8]\n[4] => [4 2 1 3]\n[5] => [5 16 8 4 2 1 6]\n","desc":"returns the elements of the Collatz sequence for integer N as a pseudo-array","effect":"[N] => [A]","cases":[[[1],[1,1]],[[2],[2,1,2]],[[3],[3,10,5,16,8,4,2,1,8]],[[4],[4,2,1,3]],[[5],[5,16,8,4,2,1,6]]]}},"math":{"pow":{"full":"returns B raised to the power E\n[B E] => [B**E]\n\n[0 0] => [1], [0 9] => [0], [9 0] => [1]\n[3 2] => [9], [2 3] => [8], [7 4] => [2401]\n","desc":"returns B raised to the power E","effect":"[B E] => [B**E]","cases":[[[0,0],[1]],[[0,9],[0]],[[9,0],[1]],[[3,2],[9]],[[2,3],[8]],[[7,4],[2401]]]},"factorial":{"full":"returns the product of the integers from 1 to N, with 0! defined to be 1\n[N] => [N!]\n\n[0] => [1], [1] => [1], [2] => [2]\n[3] => [6], [5] => [120], [10] => [3628800]\n","desc":"returns the product of the integers from 1 to N, with 0! defined to be 1","effect":"[N] => [N!]","cases":[[[0],[1]],[[1],[1]],[[2],[2]],[[3],[6]],[[5],[120]],[[10],[3628800]]]},"isqrt":{"full":"returns the integer square root of N\n[N] => [floor(sqrt(N))]\n\n[0] => [0], [1] => [1], [2] => [1], [3] => [1]\n[4] => [2], [8] => [2], [9] => [3], [99] => [9], [100] => [10]\n","desc":"returns the integer square root of N","effect":"[N] => [floor(sqrt(N))]","cases":[[[0],[0]],[[1],[1]],[[2],[1]],[[3],[1]],[[4],[2]],[[8],[2]],[[9],[3]],[[99],[9]],[[100],[10]]]},"ilog":{"full":"returns the intger logarithm of N in base B\n[N B] => [logB(N)]\n\n[15 4] => [1]\n[16 4] => [2]\n[100 10] => [2]\n[42 2] => [5]\n","desc":"returns the intger logarithm of N in base B","effect":"[N B] => [logB(N)]","cases":[[[15,4],[1]],[[16,4],[2]],[[100,10],[2]],[[42,2],[5]]]},"gcd":{"full":"returns the greatest common divisor of A and B\n[A B] => [gcd(A, B)]\n\n[6 9] => [3]\n[13 17] => [1]\n[24 36] => [12]\n","desc":"returns the greatest common divisor of A and B","effect":"[A B] => [gcd(A, B)]","cases":[[[6,9],[3]],[[13,17],[1]],[[24,36],[12]]]},"lcm":{"full":"returns the least common multiple of A and B\n[A B] => [lcm(A, B)]\n\n[6 9] => [18]\n[13 17] => [221]\n[24 36] => [72]\n","desc":"returns the least common multiple of A and B","effect":"[A B] => [lcm(A, B)]","cases":[[[6,9],[18]],[[13,17],[221]],[[24,36],[72]]]},"min":{"full":"keeps the minimum of the top two stack values\n[A B] => [A < B ? A : B]\n\n[3 1] => [1]\n[2 4] => [2]\n","desc":"keeps the minimum of the top two stack values","effect":"[A B] => [A < B ? A : B]","cases":[[[3,1],[1]],[[2,4],[2]]]},"max":{"full":"keeps the maximum of the top two stack values\n[A B] => [A > B ? A : B]\n\n[3 1] => [3]\n[2 4] => [4]\n","desc":"keeps the maximum of the top two stack values","effect":"[A B] => [A > B ? A : B]","cases":[[[3,1],[3]],[[2,4],[4]]]},"sign":{"full":"returns -1, 0, or 1 to indicate the sign of N\n[N] => [-1 | 0 | 1]\n\n[17] => [1]\n[-25] => [-1]\n[0] => [0]\n","desc":"returns -1, 0, or 1 to indicate the sign of N","effect":"[N] => [-1 | 0 | 1]","cases":[[[17],[1]],[[-25],[-1]],[[0],[0]]]},"abs":{"full":"returns the absolute value of N\n[N] => [N < 0 ? -N : N]\n\n[-5] => [5]\n[10] => [10]\n[0] => [0]\n","desc":"returns the absolute value of N","effect":"[N] => [N < 0 ? -N : N]","cases":[[[-5],[5]],[[10],[10]],[[0],[0]]]},"divmod":{"full":"pops A and B and pushes both their quotient and modulus\n[A B] => [A/B A%B]\n\n[17 5] => [3 2]\n[42 6] => [7 0]\n[ 1 5] => [0 1]\n","desc":"pops A and B and pushes both their quotient and modulus","effect":"[A B] => [A/B A%B]","cases":[[[17,5],[3,2]],[[42,6],[7,0]],[[1,5],[0,1]]]},"pos?":{"full":"returns whether N is greater than 0\n[N] => [N > 0]\n\n[5] => [1] [-3] => [0] [0] => [0]\n","desc":"returns whether N is greater than 0","effect":"[N] => [N > 0]","cases":[[[5],[1]],[[-3],[0]],[[0],[0]]]},"neg?":{"full":"returns whether N is less than 0\n[N] => [N < 0]\n\n[5] => [0] [-3] => [1] [0] => [0]\n","desc":"returns whether N is less than 0","effect":"[N] => [N < 0]","cases":[[[5],[0]],[[-3],[1]],[[0],[0]]]},"divisors":{"full":"returns a pseudo-array of the positive divisors of N; as an optimization,\nthey're not returned in ascending order, but rather in two \"halves\".\nThe alternative is unnecessarily invoking to_a and clobbering heap.\n[N] => [D1 ... Dn n]\n\n[10] => [1 2 10 5 4]\n[12] => [1 2 3 12 6 4 6]\n[25] => [1 5 25 3] ; no duplicate for perfect squares\n[60] => [1 2 3 4 5 6 60 30 20 15 12 10 12]\n","desc":"returns a pseudo-array of the positive divisors of N; as an optimization,\nthey're not returned in ascending order, but rather in two \"halves\".\nThe alternative is unnecessarily invoking to_a and clobbering heap.","effect":"[N] => [D1 ... Dn n]","cases":[[[10],[1,2,10,5,4]],[[12],[1,2,3,12,6,4,6]],[[25],[1,5,25,3]],[[60],[1,2,3,4,5,6,60,30,20,15,12,10,12]]]},"nCk":{"full":"returns the number of ways to choose K elements from a set of N\n[N K]\n\n[ 4 5] => [0]\n[ 7 7] => [1]\n[13 3] => [286]\n[16 4] => [1820]\n[50 3] => [19600]\n","desc":"returns the number of ways to choose K elements from a set of N","effect":"[N K]","cases":[[[4,5],[0]],[[7,7],[1]],[[13,3],[286]],[[16,4],[1820]],[[50,3],[19600]]]}},"stack":{"roll":{"full":"rolls the Ith element (counting from 0) to the top of the stack,\nshifting the elements above it down by 1.\n[I]\n\n[1 2 3 2] => [2 3 1]\n[1 2 3 4 1] => [1 2 4 3]\n[1 2 3 4 5 3] => [1 3 4 5 2]\n","desc":"rolls the Ith element (counting from 0) to the top of the stack,\nshifting the elements above it down by 1.","effect":"[I]","cases":[[[1,2,3,2],[2,3,1]],[[1,2,3,4,1],[1,2,4,3]],[[1,2,3,4,5,3],[1,3,4,5,2]]]},"bury":{"full":"\"buries\" X in the stack at index I, counting from 0\n[X I]\n\n[1 2 3 4 2] => [1 4 2 3] ; 2nd element of stack now 4\n[1 2 3 4 5 8 5] => [8 1 2 3 4 5]\n","desc":"\"buries\" X in the stack at index I, counting from 0","effect":"[X I]","cases":[[[1,2,3,4,2],[1,4,2,3]],[[1,2,3,4,5,8,5],[8,1,2,3,4,5]]]},"dig":{"full":"\"digs\" out the Ith element of the stack and discards it\n[I]\n\n[1 2 3 4 5 2] => [1 2 4 5]\n[1 2 3 4 5 4] => [2 3 4 5]\n","desc":"\"digs\" out the Ith element of the stack and discards it","effect":"[I]","cases":[[[1,2,3,4,5,2],[1,2,4,5]],[[1,2,3,4,5,4],[2,3,4,5]]]},"to_a":{"full":"pops elements off the stack until it hits the specified sentinel value S,\npushing them to the resulting pseudo-array. It's often more convenient to\nbuild up a collection in reverse order, and we often don't know in advance\nhow many elements we'll meet, but we do know to stop at the sentinel.\n[S En ... E1 S] => [E1 ... En n]\n\n[-1 9 8 7 -1] => [7 8 9 3]\n[0 'c' 'b' 'a' 0] => ['a' 'b' 'c' 3]\n","desc":"pops elements off the stack until it hits the specified sentinel value S,\npushing them to the resulting pseudo-array. It's often more convenient to\nbuild up a collection in reverse order, and we often don't know in advance\nhow many elements we'll meet, but we do know to stop at the sentinel.","effect":"[S En ... E1 S] => [E1 ... En n]","cases":[[[-1,9,8,7,-1],[7,8,9,3]],[[0,99,98,97,0],[97,98,99,3]]]},"npop":{"full":"pops N elements off the top of the stack\n[N]\n\n[1 2 3 4 5 3] => [1 2]\n[1 2 3 4 0] => [1 2 3 4]\n","desc":"pops N elements off the top of the stack","effect":"[N]","cases":[[[1,2,3,4,5,3],[1,2]],[[1,2,3,4,0],[1,2,3,4]]]},"nslide":{"full":"slides N elements off the stack, as if the `slide` operator took an argument\n[N]\n\n[1 2 3 4 5 2] => [1 2 5]\n[1 2 3 4 1] => [1 2 4]\n","desc":"slides N elements off the stack, as if the `slide` operator took an argument","effect":"[N]","cases":[[[1,2,3,4,5,2],[1,2,5]],[[1,2,3,4,1],[1,2,4]]]},"ncopy":{"full":"copies the Nth element to the top of the stack; this does exactly what\na `copy N` instruction would do, but we don't always know N in advance\n[N]\n\n[1 2 3 4 0] => [1 2 3 4 4] ; `copy 0` is just dup\n[1 2 3 4 3] => [1 2 3 4 1]\n","desc":"copies the Nth element to the top of the stack; this does exactly what\na `copy N` instruction would do, but we don't always know N in advance","effect":"[N]","cases":[[[1,2,3,4,0],[1,2,3,4,4]],[[1,2,3,4,3],[1,2,3,4,1]]]}},"rational":{"to_r":{"full":"encodes a numerator N and a denominator D as a rational number R with the\nfollowing structure: ((N × $RAT + D) << 1) + sign (0 for negative, else 1).\nThis representation is nice because, with care, it makes it so that we never\nhave to involve the heap (besides divmod) just to do fairly basic arithmetic.\n[N D] => [R]\n\n[22 7] => [R(22,7)]\n[4 8] => [R(4,8)] ; no implicit simplification TODO: make it configurable?\n[5 1] => [R(5,1)] ; no conversion to integer (duh)\n[-3 4] => [R(-3,4)]\n[3 -4] => [R(-3,4)] ; sign always held in the numerator\n[-1 -3] => [R(1,3)]\n","desc":"encodes a numerator N and a denominator D as a rational number R with the\nfollowing structure: ((N × $RAT + D) << 1) + sign (0 for negative, else 1).\nThis representation is nice because, with care, it makes it so that we never\nhave to involve the heap (besides divmod) just to do fairly basic arithmetic.","effect":"[N D] => [R]","cases":[[[22,7],[94489280527]],[[4,8],[17179869201]],[[5,1],[21474836483]],[[-3,4],[12884901896]],[[3,-4],[12884901896]],[[-1,-3],[4294967303]]]},"ratnum":{"full":"returns the numerator N of the rational number R, which may be negative\n[R] => [N]\n\n[R(22,7)] => [22]\n[R(-3,4)] => [-3]\n[R(3,-4)] => [-3]\n","desc":"returns the numerator N of the rational number R, which may be negative","effect":"[R] => [N]","cases":[[[94489280527],[22]],[[12884901896],[-3]],[[12884901896],[-3]]]},"ratden":{"full":"returns the denominator D of the rational number R; always positive\n[R] => [D]\n\n[R(22,7)] => [7]\n[R(-3,4)] => [4]\n[R(3,-4)] => [4]\n","desc":"returns the denominator D of the rational number R; always positive","effect":"[R] => [D]","cases":[[[94489280527],[7]],[[12884901896],[4]],[[12884901896],[4]]]},"from_r":{"full":"decomposes the rational number R into its numerator N and denominator D\n[R] => [N D]\n\n[R(22,7)] => [22 7]\n[R(-3,4)] => [-3 4]\n[R(3,-4)] => [-3 4]\n[R(4,8)] => [4 8] ; no implicit simplification\n","desc":"decomposes the rational number R into its numerator N and denominator D","effect":"[R] => [N D]","cases":[[[94489280527],[22,7]],[[12884901896],[-3,4]],[[12884901896],[-3,4]],[[17179869201],[4,8]]]},"ratsimp":{"full":"fully simplifies the rational number R by dividing both of its components\nby their greatest common divisor\n[R] => [R, simplified]\n\n[R(4,8)] => [R(1,2)]\n[R(-3,12)] => [R(-1,4)]\n[R(17,-51)] => [R(-1,3)]\n","desc":"fully simplifies the rational number R by dividing both of its components\nby their greatest common divisor","effect":"[R] => [R, simplified]","cases":[[[17179869201],[4294967301]],[[12884901912],[4294967304]],[[73014444134],[4294967302]]]},"ratadd":{"full":"returns the simplified sum of the rational numbers Ra and Rb\n[Ra Rb] => [Ra + Rb]\n\n[R(-9,-14) R(-3,19)] => [R(129,266)]\n[R(17,30) R(18,10)] => [R(71,30)]\n[R(-27,14) R(15,-23)] => [R(-831,322)]\n[R(3,-9) R(8,3)] => [R(7,3)]\n[R(-5,27) R(-2,-27)] => [R(-1,9)]\n[R(-27,-8) R(-15,22)] => [R(237,88)]\n[R(-9,-29) R(-27,3)] => [R(-252,29)]\n[R(2,-21) R(4,6)] => [R(4,7)]\n","desc":"returns the simplified sum of the rational numbers Ra and Rb","effect":"[Ra Rb] => [Ra + Rb]","cases":[[[38654705693,12884901926],[554050781717]],[[73014444093,77309411349],[304942678077]],[[115964117020,64424509486],[3569117823620]],[[12884901906,34359738375],[30064771079]],[[21474836534,8589934647],[4294967314]],[[115964117009,64424509484],[1017907249329]],[[38654705723,115964116998],[1082331758650]],[[8589934634,17179869197],[17179869199]]]},"ratsub":{"full":"returns the simplified difference of the rational numbers Ra and Rb\n[Ra Rb] => [Ra - Rb]\n\n[R(21,25) R(-28,27)] => [R(1267,675)]\n[R(14,7) R(13,6)] => [R(-1,6)]\n[R(-24,-9) R(-5,-21)] => [R(17,7)]\n[R(-27,-2) R(-2,26)] => [R(353,26)]\n[R(-27,3) R(2,-22)] => [R(-98,11)]\n[R(-4,23) R(-9,13)] => [R(155,299)]\n[R(-14,19) R(-18,-11)] => [R(-496,209)]\n[R(-29,21) R(-15,-16)] => [R(-779,336)]\n","desc":"returns the simplified difference of the rational numbers Ra and Rb","effect":"[Ra Rb] => [Ra - Rb]","cases":[[[90194313267,120259084342],[5441723565383]],[[60129542159,55834574861],[4294967308]],[[103079215123,21474836523],[73014444047]],[[115964116997,8589934644],[1516123455541]],[[115964116998,8589934636],[420906795030]],[[17179869230,38654705690],[665719931479]],[[60129542182,77309411351],[2130303779234]],[[124554051626,64424509473],[3345779524256]]]},"ratmul":{"full":"returns the simplified product of the rational numbers Ra and Rb\n[Ra Rb] => [Ra × Rb]\n\n[R(-24,26) R(-1,-30)] => [R(-2,65)]\n[R(19,4) R(27,2)] => [R(513,8)]\n[R(25,27) R(4,-11)] => [R(-100,297)]\n[R(1,18) R(4,8)] => [R(1,36)]\n[R(1,27) R(-8,29)] => [R(-8,783)]\n[R(25,-13) R(-6,24)] => [R(25,52)]\n[R(6,-13) R(9,23)] => [R(-54,299)]\n[R(11,8) R(-19,-19)] => [R(11,8)]\n","desc":"returns the simplified product of the rational numbers Ra and Rb","effect":"[Ra Rb] => [Ra × Rb]","cases":[[[103079215156,4294967357],[8589934722]],[[81604378633,115964116997],[2203318222865]],[[107374182455,17179869206],[429496730194]],[[4294967333,17179869201],[4294967369]],[[4294967351,34359738426],[34359739934]],[[107374182426,25769803824],[107374182505]],[[25769803802,38654705711],[231928234582]],[[47244640273,81604378663],[47244640273]]]},"ratdiv":{"full":"returns the simplified quotient of the rational numbers Ra and Rb\n[Ra Rb] => [Ra / Rb]\n\n[R(-30,-22) R(15,12)] => [R(12,11)]\n[R(13,28) R(-15,29)] => [R(-377,420)]\n[R(7,-30) R(-22,-12)] => [R(-7,55)]\n[R(15,4) R(8,-8)] => [R(-15,4)]\n[R(-23,28) R(-16,-15)] => [R(-345,448)]\n[R(-18,12) R(6,18)] => [R(-9,2)]\n[R(29,-2) R(11,-21)] => [R(609,22)]\n[R(-23,25) R(25,-3)] => [R(69,625)]\n","desc":"returns the simplified quotient of the rational numbers Ra and Rb","effect":"[Ra Rb] => [Ra / Rb]","cases":[[[128849018925,64424509465],[51539607575]],[[55834574905,64424509498],[1619202671432]],[[30064771132,94489280537],[30064771182]],[[64424509449,34359738384],[64424509448]],[[98784247864,68719476767],[1481763718016]],[[77309411352,25769803813],[38654705668]],[[124554051588,47244640298],[2615635083309]],[[98784247858,107374182406],[296352744675]]]},"ratmod":{"full":"returns the simplified modulus of the rational numbers Ra and Rb\n[Ra Rb] => [Ra % Rb]\n\n[R(-15,-3) R(-16,-10)] => [R(1,5)]\n[R(4,2) R(21,21)] => [R(0,1)]\n[R(24,10) R(-18,-3)] => [R(12,5)]\n[R(3,-7) R(-2,16)] => [R(-3,56)]\n[R(4,28) R(-29,7)] => [R(-4,1)]\n[R(7,-27) R(10,23)] => [R(109,621)]\n[R(28,-3) R(30,-12)] => [R(-11,6)]\n[R(-29,21) R(19,-23)] => [R(-268,483)]\n","desc":"returns the simplified modulus of the rational numbers Ra and Rb","effect":"[Ra Rb] => [Ra % Rb]","cases":[[[64424509447,68719476757],[4294967307]],[[17179869189,90194313259],[3]],[[103079215125,77309411335],[51539607563]],[[12884901902,8589934624],[12884902000]],[[17179869241,124554051598],[17179869186]],[[30064771126,42949673007],[468151436507]],[[120259084294,128849018904],[47244640268]],[[124554051626,81604378670],[1151051236294]]]},"ratsign":{"full":"returns the sign of the rational number R\n[R] => [-1 | 0 | 1]\n\n[R(4,3)] => [1]\n[R(4,-3)] => [-1]\n[R(0,10)] => [0]\n[R(-3,4)] => [-1]\n[R(-3,-4)] => [1]\n","desc":"returns the sign of the rational number R","effect":"[R] => [-1 | 0 | 1]","cases":[[[17179869191],[1]],[[17179869190],[-1]],[[21],[0]],[[12884901896],[-1]],[[12884901897],[1]]]}},"string":{"strpack":{"full":"convert a 0-terminated string on the stack to a single base-128 integer\n[0 ... c b a] => [\"abc...\"]\n\n[0 99 98 97] => [\"abc\"]\n[0 99 98 97] => [1634657]\n[0] => [0]\n","desc":"convert a 0-terminated string on the stack to a single base-128 integer","effect":"[0 ... c b a] => [\"abc...\"]","cases":[[[0,99,98,97],[1634657]],[[0,99,98,97],[1634657]],[[0],[0]]]},"strunpack":{"full":"convert a single base-128 integer to a 0-terminated string on the stack\n[\"abc...\"] => [0 ... c b a]\n\n[\"abc\"] => [0 99 98 97]\n[1634657] => [0 99 98 97]\n[0] => [0]\n","desc":"convert a single base-128 integer to a 0-terminated string on the stack","effect":"[\"abc...\"] => [0 ... c b a]","cases":[[[1634657],[0,99,98,97]],[[1634657],[0,99,98,97]],[[0],[0]]]},"strlen":{"full":"returns the length of a packed string, which is just the\nvalue itself log-128, +1 if the integer logarithm isn't exact.\n[S] => [len(S)]\n\n[\"\"] => [0]\n[\"abc\"] => [3]\n[\"foobar\"] => [6]\n","desc":"returns the length of a packed string, which is just the\nvalue itself log-128, +1 if the integer logarithm isn't exact.","effect":"[S] => [len(S)]","cases":[[[0],[0]],[[1634657],[3]],[[3943255767014],[6]]]},"strcat":{"full":"takes two packed strings and returns their concatenation (as a packed string)\n[S T] => [S+T]\n\n[\"foo\" \"\"] => [\"foo\"]\n[\"\" \"foo\"] => [\"foo\"]\n[\"foo\" \"bar\"] => [\"foobar\"]\n","desc":"takes two packed strings and returns their concatenation (as a packed string)","effect":"[S T] => [S+T]","cases":[[[1832934,0],[1832934]],[[0,1832934],[1832934]],[[1832934,1880290],[3943255767014]]]},"strrev":{"full":"reverses a packed string \"in-place\"\n[S] => [S']\n\n[\"foo\"] => [\"oof\"]\n[\"bark\"] => [\"krab\"]\n[\"ab\"] => [\"ba\"] ['a'] => ['a'] [\"\"] => [\"\"]\n","desc":"reverses a packed string \"in-place\"","effect":"[S] => [S']","cases":[[[1832934],[1685487]],[[226275554],[207124843]],[[12641],[12514]],[[97],[97]],[[0],[0]]]},"strslice":{"full":"takes a packed string S, a start index I, and a length L and returns the\ncorresponding substring (simply by doing division with powers of 128; neat)\n[S I L] => [S']\n\n[\"foobar\" 0 6] => [\"foobar\"]\n[\"foobar\" 1 4] => [\"ooba\"]\n[\"foobar\" 1 10] => [\"oobar\"]\n[\"foobar\" 5 1] => ['r']\n[\"foobar\" 6 0] => [\"\"]\n","desc":"takes a packed string S, a start index I, and a length L and returns the\ncorresponding substring (simply by doing division with powers of 128; neat)","effect":"[S I L] => [S']","cases":[[[3943255767014,0,6],[3943255767014]],[[3943255767014,1,4],[205043695]],[[3943255767014,1,10],[30806685679]],[[3943255767014,5,1],[114]],[[3943255767014,6,0],[0]]]},"strindex":{"full":"returns the index I of substring T in string S (or -1 if not found)\n[S T] => [I]\n\n[\"foobar\" 'o'] => [1]\n[\"foobar\" \"ob\"] => [2]\n[\"foobar\" \"\"] => [0]\n[\"foobar\" \"bar\"] => [3]\n[\"foobar\" \"bark\"] => [-1]\n","desc":"returns the index I of substring T in string S (or -1 if not found)","effect":"[S T] => [I]","cases":[[[3943255767014,111],[1]],[[3943255767014,12655],[2]],[[3943255767014,0],[0]],[[3943255767014,1880290],[3]],[[3943255767014,226275554],[-1]]]},"charat":{"full":"returns the character C at index I in string S\n[S I] => [C]\n\n[\"foobar\" 1] => ['o']\n[\"foobar\" 3] => ['b']\n[\"foobar\" 5] => ['r']\n[\"foobar\" 6] => [\"\"]\n","desc":"returns the character C at index I in string S","effect":"[S I] => [C]","cases":[[[3943255767014,1],[111]],[[3943255767014,3],[98]],[[3943255767014,5],[114]],[[3943255767014,6],[0]]]},"isalpha":{"full":"returns 1 if the character at the top of the stack is\nalphabetical (ASCII 65-90 or 97-122), 0 otherwise\n[C] => [0 | 1]\n\n['@'] => [0] ['a'] => [1]\n['z'] => [1] ['['] => [0]\n['`'] => [0] ['A'] => [1]\n['Z'] => [1] ['{'] => [0]\n","desc":"returns 1 if the character at the top of the stack is\nalphabetical (ASCII 65-90 or 97-122), 0 otherwise","effect":"[C] => [0 | 1]","cases":[[[64],[0]],[[97],[1]],[[122],[1]],[[91],[0]],[[96],[0]],[[65],[1]],[[90],[1]],[[123],[0]]]},"strrep":{"full":"returns string S replicated N times\n[S N] => [S']\n\n[\"abc\" 1] => [\"abc\"]\n[\"abc\" 2] => [\"abcabc\"]\n[\"abc\" 0] => [\"\"]\n","desc":"returns string S replicated N times","effect":"[S N] => [S']","cases":[[[1634657,1],[1634657]],[[1634657,2],[3428125831521]],[[1634657,0],[0]]]},"ljustc":{"full":"left-justifies string S to width W with character C\n[S W C] => [S']\n\n[\"foo\" 5 'x'] => [\"fooxx\"]\n[\"foobar\" 4 'x'] => [\"foobar\"]\n[\"\" 3 'x'] => [\"xxx\"]\n","desc":"left-justifies string S to width W with character C","effect":"[S W C] => [S']","cases":[[[1832934,5,120],[32465745894]],[[3943255767014,4,120],[3943255767014]],[[0,3,120],[1981560]]]},"ljust":{"full":"left-justifies string S to width W with spaces\n[S W] => [S']\n\n[\"foo\" 5] => [\"foo \"]\n[\"foobar\" 4] => [\"foobar\"]\n[\"\" 3] => [528416]\n","desc":"left-justifies string S to width W with spaces","effect":"[S W] => [S']","cases":[[[1832934,5],[8658876390]],[[3943255767014,4],[3943255767014]],[[0,3],[528416]]]},"rjustc":{"full":"right-justifies string S to width W with character C\n[S W C] => [S']\n\n[\"foo\" 5 'x'] => [\"xxfoo\"]\n[\"foobar\" 4 'x'] => [\"foobar\"]\n[\"\" 3 'x'] => [\"xxx\"]\n","desc":"right-justifies string S to width W with character C","effect":"[S W C] => [S']","cases":[[[1832934,5,120],[30030806136]],[[3943255767014,4,120],[3943255767014]],[[0,3,120],[1981560]]]},"rjust":{"full":"right-justifies string S to width W with spaces\n[S W C] => [S']\n\n[\"foo\" 5] => [\" foo\"]\n[\"foobar\" 4] => [\"foobar\"]\n[\"\" 3] => [528416]\n","desc":"right-justifies string S to width W with spaces","effect":"[S W C] => [S']","cases":[[[1832934,5],[30030794784]],[[3943255767014,4],[3943255767014]],[[0,3],[528416]]]},"centerc":{"full":"centers string S to width W with character C, favoring left alignment when\nthere's a parity mismatch (even-length string to odd width or vice versa)\n[S W C] => [S']\n\n[\"abc\" 7 'x'] => [\"xxabcxx\"]\n[\"abc\" 6 'x'] => [\"xabcxx\"]\n[\"abcd\" 6 'o'] => [\"oabcdo\"]\n[\"abcd\" 7 'o'] => [\"oabcdoo\"]\n[\"abcd\" 3 '!'] => [\"abcd\"]\n","desc":"centers string S to width W with character C, favoring left alignment when\nthere's a parity mismatch (even-length string to odd width or vice versa)","effect":"[S W C] => [S']","cases":[[[1634657,7,120],[531915532172408]],[[1634657,6,120],[4155590095096]],[[211349857,6,111],[3840983740655]],[[211349857,7,111],[492024146473199]],[[211349857,3,33],[211349857]]]},"center":{"full":"centers string S to width W with spaces\n[S W] => [S']\n\n[\"abc\" 7] => [\" abc \"]\n[\"abc\" 6] => [\" abc \"]\n[\"abcd\" 6] => [\" abcd \"]\n[\"abcd\" 7] => [\" abcd \"]\n[\"abcd\" 3] => [\"abcd\"]\n","desc":"centers string S to width W with spaces","effect":"[S W] => [S']","cases":[[[1634657,7],[141863782207520]],[[1634657,6],[1108310798496]],[[211349857,6],[1126564409504]],[[211349857,7],[141864052764832]],[[211349857,3],[211349857]]]},"strchop":{"full":"removes the last character of a string\n[S] => [S']\n\n[\"foobar\"] => [\"fooba\"]\n[\"abc\"] => [\"ab\"]\n[\"a\"] => [\"\"]\n","desc":"removes the last character of a string","effect":"[S] => [S']","cases":[[[3943255767014],[26245593062]],[[1634657],[12641]],[[97],[0]]]},"strsplit":{"full":"splits string S on delimiting character C, leaving the resultant substrings\non the stack as a pseudo-array (length at top of stack)\n[S C] => [A]\n\n[\"fooxbar\" 'x'] => [\"foo\" \"bar\" 2]\n[\"foobar\" 'x'] => [\"foobar\" 1]\n[\"foo|bar|baz\" '|'] => [\"foo\" \"bar\" \"baz\" 3]\n[\"foo,,bar\" ','] => [\"foo\" \"\" \"bar\" 3]\n[\"/foo/bar/\" '/'] => [\"\" \"foo\" \"bar\" \"\" 4]\n","desc":"splits string S on delimiting character C, leaving the resultant substrings\non the stack as a pseudo-array (length at top of stack)","effect":"[S C] => [A]","cases":[[[504736757053414,120],[1832934,1880290,2]],[[3943255767014,120],[3943255767014,1]],[[144933976769845798893542,124],[1832934,1880290,2011362,3]],[[64606284361234406,44],[1832934,0,1880290,3]],[[3451313205089661743,47],[0,1832934,1880290,0,4]]]},"lines":{"full":"splits the string S on newlines\n","desc":"","effect":"splits the string S on newlines","cases":[]},"strjoinc":{"full":"joins the pseudo-array of strings A into string S with delimiter string D\n[A D] => [S]\n\n[\"foo\" \"bar\" 2 'x'] => [\"fooxbar\"]\n[\"foo\" \"bar\" \"baz\" 3 '--'] => [\"foo--bar--baz\"]\n[\"foo\" 1 \"?!\"] => [\"foo\"]\n","desc":"joins the pseudo-array of strings A into string S with delimiter string D","effect":"[A D] => [S]","cases":[[[1832934,1880290,2,120],[504736757053414]],[[1832934,1880290,2011362,3,5805],[2374597541788353508880938982]],[[1832934,1,4287],[1832934]]]},"strjoin":{"full":"concatenates the pseudo-array of strings A into string S\n[A] => [S]\n\n[\"foo\" 1] => [\"foo\"]\n[\"foo\" \"bar\" 2] => [\"foobar\"]\n[\"foo\" 'x' \"bar\" 'x' \"baz\" 5] => [\"fooxbarxbaz\"]\n","desc":"concatenates the pseudo-array of strings A into string S","effect":"[A] => [S]","cases":[[[1832934,1],[1832934]],[[1832934,1880290,2],[3943255767014]],[[1832934,120,1880290,120,2011362,5],[144933974518045976819686]]]},"strcountc":{"full":"returns the number of ocurrences of character C in string S\n[S C] => [N]\n\n[\"foobar\" 'a'] => [1]\n[\"foobar\" 'o'] => [2]\n[\"foobar\" 'c'] => [0]\n","desc":"returns the number of ocurrences of character C in string S","effect":"[S C] => [N]","cases":[[[3943255767014,97],[1]],[[3943255767014,111],[2]],[[3943255767014,99],[0]]]},"strcount":{"full":"returns the total number of ocurrences of all characters in string T in string S\n[S T] => [N]\n\n[\"foobar\" 'o'] => [2]\n[\"foobar\" \"ob\"] => [3]\n[\"foxboar\" \"box\"] => [4]\n[\"eunoia\" \"aeiou\"] => [5]\n[\"why\" \"aeiou\"] => [0]\n","desc":"returns the total number of ocurrences of all characters in string T in string S","effect":"[S T] => [N]","cases":[[[3943255767014,111],[2]],[[3943255767014,12655],[3]],[[504740200724454,1980386],[4]],[[3361314945765,31641465569],[5]],[[1995895,31641465569],[0]]]},"strtrans":{"full":"translates all characters in A to the corresponding characters in B\nin stirng S, ; similar to the `tr` utility in Unix. A and B must be\nof the same length. TODO: make this smarter (ranges, length mismatch)\n[S A B] => [S']\n\n[\"abcd\" \"abc\" \"xyz\"] => [\"xyzd\"]\n[\"foobar\" \"oba\" \"ele\"] => [\"feeler\"]\n[\"abcdcba\" \"abcd\" \"xyz|\"] => [\"xyz|zyx\"]\n","desc":"translates all characters in A to the corresponding characters in B\nin stirng S, ; similar to the `tr` utility in Unix. A and B must be\nof the same length. TODO: make this smarter (ranges, length mismatch)","effect":"[S A B] => [S']","cases":[[[211349857,1634657,2014456],[211729656]],[[3943255767014,1601903,1668709],[3944350315238]],[[430004552397153,211349857,262061304],[531956120861944]]]},"strexpand":{"full":"expands the length-2 string S to contain the intervening ASCII characters\n[S] => [S']\n\n[\"CJ\"] => [\"CDEFGHIJ\"]\n[\"DA\"] => [\"DE\"] TODO: bug\n[\"af\"] => [\"abcdef\"]\n[\"09\"] => [\"0123456789\"]\n[\"(1\"] => [\"()*+,-./01\"]\n","desc":"expands the length-2 string S to contain the intervening ASCII characters","effect":"[S] => [S']","cases":[[[9539],[41981847056507459]],[[8388],[8900]],[[13153],[3532016644449]],[[7344],[529798632943928514736]],[[6312],[455430656835745125544]]]},"strsqueeze":{"full":"\"squeezes\" runs of the same character in string S to just one occurrence\n[S] => [S']\n\n[\"abc\"] => [\"abc\"]\n[\"foobar\"] => [\"fobar\"]\n[\"bookkeeper\"] => [\"bokeper\"]\n[\"xxxxxxx\"] => [\"x\"]\n","desc":"\"squeezes\" runs of the same character in string S to just one occurrence","effect":"[S] => [S']","cases":[[[1634657],[1634657]],[[3943255767014],[30806685670]],[[1058805727296038369250],[504877914191842]],[[531921215831160],[120]]]},"strsum":{"full":"returns the sum of the ordinal values of the characters in string S\n[S] => [N]\n\n[\"ABC\"] => [198]\n[\"012\"] => [147]\n[\"a\"] => [97]\n[\"\"] => [] TODO: bug, should be 0\n","desc":"returns the sum of the ordinal values of the characters in string S","effect":"[S] => [N]","cases":[[[1106241],[198]],[[825520],[147]],[[97],[97]],[[0],[]]]},"strrotl":{"full":"rotates the string S to the left N times, wrapping\n[S N]\n\n[\"abc\" 0] => [\"abc\"]\n[\"abcd\" 1] => [\"bcda\"]\n[\"abcd\" 5] => [\"bcda\"]\n[\"foodbar\" 4] => [\"barfood\"]\n","desc":"rotates the string S to the left N times, wrapping","effect":"[S N]","cases":[[[1634657,0],[1634657]],[[211349857,1],[205074914]],[[211349857,5],[205074914]],[[504736715110374,4],[443648594194658]]]},"strrotr":{"full":"rotates the string S to the right N times, wrapping\n[S N]\n\n[\"abcd\" 1] => [\"dabc\"]\n[\"abcd\" 5] => [\"dabc\"]\n[\"foodbar\" 3] => [\"barfood\"]\n","desc":"rotates the string S to the right N times, wrapping","effect":"[S N]","cases":[[[211349857,1],[209236196]],[[211349857,5],[209236196]],[[504736715110374,3],[443648594194658]]]}},"bits":{"band":{"full":"returns the bitwise AND of A and B\n[A B] => [A & B]\n\n[65 47] => [1] [83 25] => [17]\n[40 64] => [0] [74 59] => [10]\n[31 18] => [18] [86 32] => [0]\n[93 79] => [77] [11 79] => [11]\n","desc":"returns the bitwise AND of A and B","effect":"[A B] => [A & B]","cases":[[[65,47],[1]],[[83,25],[17]],[[40,64],[0]],[[74,59],[10]],[[31,18],[18]],[[86,32],[0]],[[93,79],[77]],[[11,79],[11]]]},"bor":{"full":"returns the bitwise OR of A and B\n[A B] => [A | B]\n\n[66 51] => [115] [64 4] => [68]\n[61 77] => [125] [93 65] => [93]\n[14 87] => [95] [71 37] => [103]\n[7 19] => [23] [38 92] => [126]\n","desc":"returns the bitwise OR of A and B","effect":"[A B] => [A | B]","cases":[[[66,51],[115]],[[64,4],[68]],[[61,77],[125]],[[93,65],[93]],[[14,87],[95]],[[71,37],[103]],[[7,19],[23]],[[38,92],[126]]]},"bxor":{"full":"returns the bitwise XOR of A and B\n[A B] => [A ^ B]\n\n[4 14] => [10] [0 80] => [80]\n[51 5] => [54] [97 77] => [44]\n[39 65] => [102] [12 26] => [22]\n[44 36] => [8] [6 21] => [19]\n","desc":"returns the bitwise XOR of A and B","effect":"[A B] => [A ^ B]","cases":[[[4,14],[10]],[[0,80],[80]],[[51,5],[54]],[[97,77],[44]],[[39,65],[102]],[[12,26],[22]],[[44,36],[8]],[[6,21],[19]]]},"bnot":{"full":"returns the infinite-precision bitwise NOT of N by inverting all of its bits\n[N] => [~N]\n\n[58] => [5] [46] => [17]\n[48] => [15] [87] => [40]\n[98] => [29] [51] => [12]\n[3] => [0] [42] => [21]\n","desc":"returns the infinite-precision bitwise NOT of N by inverting all of its bits","effect":"[N] => [~N]","cases":[[[58],[5]],[[46],[17]],[[48],[15]],[[87],[40]],[[98],[29]],[[51],[12]],[[3],[0]],[[42],[21]]]},"blength":{"full":"returns the number of bits in the binary representation of N\n[N] => [# of bits]\n\n[0] => [0] [1] => [1]\n[7] => [3] [8] => [4]\n[255] => [8]\n","desc":"returns the number of bits in the binary representation of N","effect":"[N] => [# of bits]","cases":[[[0],[0]],[[1],[1]],[[7],[3]],[[8],[4]],[[255],[8]]]},"popcount":{"full":"returns the number of set bits in N\n[N] => [popcount]\n\n[0] => [0] [1] => [1]\n[7] => [3] [8] => [1]\n","desc":"returns the number of set bits in N","effect":"[N] => [popcount]","cases":[[[0],[0]],[[1],[1]],[[7],[3]],[[8],[1]]]}},"io":{"print":{"full":"prints the character at the top of the stack until terminating zero\n","desc":"","effect":"prints the character at the top of the stack until terminating zero","cases":[]},"println":{"full":"print with newline\n","desc":"","effect":"print with newline","cases":[]},"getline":{"full":"reads a line of input onto the top of the stack as a packed string\n","desc":"","effect":"reads a line of input onto the top of the stack as a packed string","cases":[]},"readall":{"full":"consume stdin until EOF\n","desc":"","effect":"consume stdin until EOF","cases":[]}},"case":{"upcase":{"full":"returns string S with all alphabetical characters capitalized\n[S] => [S']\n\n[\"\"] => [\"\"]\n[\"abc\"] => [\"ABC\"]\n[\"123\"] => [\"123\"]\n[\"Abc123Def\"] => [\"ABC123DEF\"]\n","desc":"returns string S with all alphabetical characters capitalized","effect":"[S] => [S']","cases":[[[0],[0]],[[1634657],[1106241]],[[842033],[842033]],[[7407033370199781697],[5083175962476077377]]]},"downcase":{"full":"returns string S with all alphabetical characters lower-cased\n[S] => [S']\n\n[\"\"] => [\"\"]\n[\"ABC\"] => [\"abc\"]\n[\"123\"] => [\"123\"]\n[\"aBC123dEF\"] => [\"abc123def\"]\n","desc":"returns string S with all alphabetical characters lower-cased","effect":"[S] => [S']","cases":[[[0],[0]],[[1106241],[1634657]],[[842033],[842033]],[[5083316699964432737],[7407174107688137057]]]},"swapcase":{"full":"returns string S with the case of all alphabetical characters swapped\n[S] => [S']\n\n[\"\"] => [\"\"]\n[\"FooBar\"] => [\"fOObAR\"]\n[\"Abc123deF\"] => [\"aBC123DEf\"]\n","desc":"returns string S with the case of all alphabetical characters swapped","effect":"[S] => [S']","cases":[[[0],[0]],[[3943188658118],[2835153676262]],[[5101331098474443073],[7389018971689771361]]]}},"test":{},"array":{"arysum":{"full":"returns the sum of the array A\n[A] => [sum]\n\n[3 1] => [3]\n[4 3 2 1 4] => [10]\n[-10 -5 7 5 10 5] => [7]\n","desc":"returns the sum of the array A","effect":"[A] => [sum]","cases":[[[3,1],[3]],[[4,3,2,1,4],[10]],[[-10,-5,7,5,10,5],[7]]]},"arydup":{"full":"duplicates the array at the top of the stack\n[A] => [A A]\n\n[1 2 3 3] => [1 2 3 3 1 2 3 3]\n[7 50 10 2] => [7 50 10 2 50 10 2]\n","desc":"duplicates the array at the top of the stack","effect":"[A] => [A A]","cases":[[[1,2,3,3],[1,2,3,3,1,2,3,3]],[[7,50,10,2],[7,50,10,2,50,10,2]]]},"arypop":{"full":"removes the element at the end of the array A\n[A] => [A']\n\n[10 1] => [0]\n[1 2 3 4 4] => [1 2 3 3]\n[7 10 20 30 3] => [7 10 20 2]\n","desc":"removes the element at the end of the array A","effect":"[A] => [A']","cases":[[[10,1],[0]],[[1,2,3,4,4],[1,2,3,3]],[[7,10,20,30,3],[7,10,20,2]]]},"aryshift":{"full":"removes the element at the beginning of the array A\n[A] => [A']\n\n[10 1] => [0]\n[1 2 3 4 4] => [2 3 4 3]\n[7 10 20 30 3] => [7 20 30 2]\n","desc":"removes the element at the beginning of the array A","effect":"[A] => [A']","cases":[[[10,1],[0]],[[1,2,3,4,4],[2,3,4,3]],[[7,10,20,30,3],[7,20,30,2]]]},"arycat":{"full":"returns the concatenation of arrays A and B\n[A B] => [A+B]\n\n[1 2 3 3 4 5 6 3] => [1 2 3 4 5 6 6]\n[7 10 2 5 4 3 3] => [7 10 5 4 3 5]\n","desc":"returns the concatenation of arrays A and B","effect":"[A B] => [A+B]","cases":[[[1,2,3,3,4,5,6,3],[1,2,3,4,5,6,6]],[[7,10,2,5,4,3,3],[7,10,5,4,3,5]]]},"aryindex":{"full":"returns the index I of element E in array A (or -1 if not found)\n[A E] => [I]\n\n[1 2 3 4 4 2] => [1]\n[1 2 3 4 4 4] => [3]\n[1 2 3 4 4 5] => [-1]\n","desc":"returns the index I of element E in array A (or -1 if not found)","effect":"[A E] => [I]","cases":[[[1,2,3,4,4,2],[1]],[[1,2,3,4,4,4],[3]],[[1,2,3,4,4,5],[-1]]]},"aryat":{"full":"returns the element E at index I in array A (or dies on out of bounds)\n[A I] => [E]\n\n[1 2 3 4 4 0] => [1]\n[1 2 3 4 4 2] => [3]\n[1 2 3 4 4 -1] => [4] negative index counts from the end\n","desc":"returns the element E at index I in array A (or dies on out of bounds)","effect":"[A I] => [E]","cases":[[[1,2,3,4,4,0],[1]],[[1,2,3,4,4,2],[3]],[[1,2,3,4,4,-1],[4]]]},"minmax":{"full":"returns the minimum and maximum elements of array A\n[A] => [min max]\n\n[4 3 2 1 4] => [1 4]\n[6 8 -3 4 0 5] => [-3 8]\n[7 1] => [7 7]\n","desc":"returns the minimum and maximum elements of array A","effect":"[A] => [min max]","cases":[[[4,3,2,1,4],[1,4]],[[6,8,-3,4,0,5],[-3,8]],[[7,1],[7,7]]]},"aryrev":{"full":"reverses the array A\n[A] => [A']\n\n[1 2 3 3] => [3 2 1 3]\n[7 1] => [7 1]\n[5 4 3 2 1 5] => [1 2 3 4 5 5]\n","desc":"reverses the array A","effect":"[A] => [A']","cases":[[[1,2,3,3],[3,2,1,3]],[[7,1],[7,1]],[[5,4,3,2,1,5],[1,2,3,4,5,5]]]},"aryrep":{"full":"returns the array A replicated N times\n[A N] => [A']\n\n[3 2 1 3 4] => [3 2 1 3 2 1 3 2 1 3 2 1 12]\n","desc":"returns the array A replicated N times","effect":"[A N] => [A']","cases":[[[3,2,1,3,4],[3,2,1,3,2,1,3,2,1,3,2,1,12]]]}},"syntax":{},"util":{"range":{"full":"inserts between the top two stack values the intervening consecutive elements\n[I J] => [I I+1 ... J]\n\n[2 5] => [2 3 4 5]\n[0 4] => [0 1 2 3 4]\n[-2 0] => [-2 -1 0]\n[-3 3] => [-3 -2 -1 0 1 2 3]\n[4 4] => [4 5] TODO: bug\n","desc":"inserts between the top two stack values the intervening consecutive elements","effect":"[I J] => [I I+1 ... J]","cases":[[[2,5],[2,3,4,5]],[[0,4],[0,1,2,3,4]],[[-2,0],[-2,-1,0]],[[-3,3],[-3,-2,-1,0,1,2,3]],[[4,4],[4,5]]]},"die!":{"full":"prints the string at the top of the stack and halts execution\n","desc":"","effect":"prints the string at the top of the stack and halts execution","cases":[]},"alpha":{"full":"for stoi and itos\n","desc":"","effect":"for stoi and itos","cases":[]},"stoi":{"full":"converts the string S to an integer in base B (2-36)\n[S B]\n\n[\"101010\" 2] => [42]\n[\"0777\" 8] => [511]\n[\"12345\" 10] => [12345]\n[\"123_\" 10] => [123]\n[\"123____\" 10] => [123000] ; TODO: bug\n[\"dead\" 16] => [57005]\n[\"gabe\" 17] => [81699]\n","desc":"converts the string S to an integer in base B (2-36)","effect":"[S B]","cases":[[[1662522251313,2],[42]],[[116251568,8],[511]],[[14336973105,10],[12345]],[[200071473,10],[123]],[[421104295139633,10],[123000]],[[211317476,16],[57005]],[[213430503,17],[81699]]]},"bin":{"full":"creature comforts\n","desc":"","effect":"creature comforts","cases":[]},"itos":{"full":"converts the integer N to a string in base B\n[N B]\n\n[42 2] => [\"101010\"]\n[511 8] => [\"777\"]\n[12345 10] => [\"12345\"]\n[57005 16] => [\"dead\"]\n[81699 17] => [\"gabe\"]\n","desc":"converts the integer N to a string in base B","effect":"[N B]","cases":[[[42,2],[1662522251313]],[[511,8],[908215]],[[12345,10],[14336973105]],[[57005,16],[211317476]],[[81699,17],[213430503]]]},"to_bin":{"full":"creature comforts\n","desc":"","effect":"creature comforts","cases":[]},"digits":{"full":"puts the digits of N in base B on the stack as a pseudo-array\n[N B] => [Dn ...D0 n]\n\n[42 2] => [1 0 1 0 1 0 6]\n[12345 10] => [1 2 3 4 5 5]\n[255 16] => [15 15 2]\n[256 16] => [1 0 0 3]\n","desc":"puts the digits of N in base B on the stack as a pseudo-array","effect":"[N B] => [Dn ...D0 n]","cases":[[[42,2],[1,0,1,0,1,0,6]],[[12345,10],[1,2,3,4,5,5]],[[255,16],[15,15,2]],[[256,16],[1,0,0,3]]]},"inc":{"full":"increments the value at heap address N TODO: make heap effects test-able ?\n[N]\n","desc":"increments the value at heap address N TODO: make heap effects test-able ?","effect":"[N]","cases":[]},"dec":{"full":"decrements the value at heap address N\n[N]\n","desc":"decrements the value at heap address N","effect":"[N]","cases":[]},"eq":{"full":"pops A and B and pushes 1 if they're equal, 0 otherwise\n[A B] => [A == B]\n\n[1 2] => [0]\n[3 3] => [1]\n[-4 4] => [0]\n['A' 65] => [1]\n['B' 65] => [0]\n","desc":"pops A and B and pushes 1 if they're equal, 0 otherwise","effect":"[A B] => [A == B]","cases":[[[1,2],[0]],[[3,3],[1]],[[-4,4],[0]],[[65,65],[1]],[[66,65],[0]]]},"neq":{"full":"pops A and B and pushes 1 if they're not equal, 0 otherwise\n[A B] => [A != B]\n\n[1 2] => [1]\n[3 3] => [0]\n[-4 4] => [1]\n['A' 65] => [0]\n['B' 65] => [1]\n","desc":"pops A and B and pushes 1 if they're not equal, 0 otherwise","effect":"[A B] => [A != B]","cases":[[[1,2],[1]],[[3,3],[0]],[[-4,4],[1]],[[65,65],[0]],[[66,65],[1]]]},"gt":{"full":"pops A and B and pushes 1 if A is greater than B, 0 otherwise\n[A B] => [A > B]\n\n[4 3] => [1]\n[3 4] => [0]\n[2 2] => [0]\n[2 1] => [1]\n","desc":"pops A and B and pushes 1 if A is greater than B, 0 otherwise","effect":"[A B] => [A > B]","cases":[[[4,3],[1]],[[3,4],[0]],[[2,2],[0]],[[2,1],[1]]]},"lt":{"full":"pops A and B and pushes 1 if A is less than than B, 0 otherwise\n[A B] => [A < B]\n\n[3 4] => [1]\n[4 3] => [0]\n[2 2] => [0]\n[1 2] => [1]\n","desc":"pops A and B and pushes 1 if A is less than than B, 0 otherwise","effect":"[A B] => [A < B]","cases":[[[3,4],[1]],[[4,3],[0]],[[2,2],[0]],[[1,2],[1]]]},"heap_seeking_missile":{"full":"Though extremely rare, it's possible that we know a particular value is\nstored in the heap at some key, just not which one. This subroutine takes\na value V to search for and a starting index I, and either returns the first\nkey associated with that value or loops forever. Probably don't touch.\n[V I]\n","desc":"Though extremely rare, it's possible that we know a particular value is\nstored in the heap at some key, just not which one. This subroutine takes\na value V to search for and a starting index I, and either returns the first\nkey associated with that value or loops forever. Probably don't touch.","effect":"[V I]","cases":[]}},"prime":{"prime?":{"full":"[n] => [0|1]\n","desc":"","effect":"[n] => [0|1]","cases":[]},"factor":{"full":"prime factorization\n","desc":"","effect":"prime factorization","cases":[]}}}
@@ -1,42 +1,58 @@
1
- import string
2
-
1
+ import array ; sort
2
+ import case ; upcase
3
+ import stack ; to_a
4
+ import string ; isalpha, strcat, strjoin, strrev, strunpack
5
+ import util ; eq
6
+
7
+ ; returns whether the string S is the same forwards and backwards
8
+ ; [S] => [0 | 1]
9
+ ;
10
+ ; ["racecar"] => [1]
11
+ ; ["divider"] => [0]
12
+ ; ["redivider"] => [1]
3
13
  palindrome?: dup :strrev :eq ret
4
14
 
5
- ;;;
6
-
15
+ ; returns whether the strings S and T are composed of the same characters
16
+ ; [S T] => [0 | 1]
17
+ ;
18
+ ; ["allergy" "gallery"] => [1]
19
+ ; ["largely" "regally"] => [1]
20
+ ; ["foo" "bar"] => [0]
7
21
  anagrams?:
8
22
  :strunpack push 0 :to_a :sort :strjoin swap
9
23
  :strunpack push 0 :to_a :sort :strjoin :eq ret
10
24
 
11
- ;;;
12
-
13
- isop: :upcase push 0 swap ; tally
14
- _isop_loop: ; [t s]
15
- dup jz _isop_done
25
+ ; returns the sum of the alphabetical characters in string S where A=1, B=2...
26
+ ; [S] => [sum]
27
+ ;
28
+ ; ["Math"] => [42]
29
+ ; ["wizards"] => [100]
30
+ ; ["AbCd"] => [10]
31
+ isop: :upcase push 0 swap
32
+ _isop_loop: dup jz _isop_done
16
33
  swap copy 1 push 128 mod
17
- dup :isalpha jz _isop_no ; ignore non-alphabetical
18
- push 64
19
- _isop_resume:
20
- sub add
21
- swap push 128 div jump _isop_loop
22
-
34
+ dup :isalpha jz _isop_no push 64
35
+ _isop_resume: sub add swap push 128 div jump _isop_loop
23
36
  _isop_no: dup jump _isop_resume
24
-
25
37
  _isop_done: pop ret
26
38
 
27
- ;;;
28
-
39
+ ; returns the elements of the Collatz sequence for integer N as a pseudo-array
40
+ ; ! may run forever on some as-yet-unknown input
41
+ ; [N] => [A]
42
+ ;
43
+ ; [1] => [1 1]
44
+ ; [2] => [2 1 2]
45
+ ; [3] => [3 10 5 16 8 4 2 1 8]
46
+ ; [4] => [4 2 1 3]
47
+ ; [5] => [5 16 8 4 2 1 6]
29
48
  collatz: push 1 ; sequence length
30
49
  _collatz_loop:
31
50
  copy 1 dup push 1 sub jz _collatz_done
32
- dup push 2 mod ; m2 n m2
51
+ dup push 2 mod
33
52
  swap copy 1 push 2 mul $++ mul
34
53
  push 2 copy 2 sub div add
35
54
  swap $++ jump _collatz_loop
36
-
37
55
  _collatz_done: pop ret
38
56
 
39
- ;;;
40
-
41
- ruby:
42
- push "'" :strcat push "ruby -e 'p " swap :strcat shell ret
57
+ ; ruby:
58
+ ; push "'" :strcat push "ruby -e 'p " swap :strcat shell ret
@@ -1,3 +1,5 @@
1
+ import string ; strcat, strpack, strrev, strunpack
2
+
1
3
  ; prints the character at the top of the stack until terminating zero
2
4
  print: :strunpack
3
5
  _print_loop:
@@ -1,116 +1,157 @@
1
- import util (range) ; for factorial
2
-
3
- ; [b e] => [b^e]
4
- pow:
5
- push 1 swap
6
-
1
+ import array ; arycat, arydup
2
+ import util ; eq, inc, range
3
+
4
+ ; returns B raised to the power E
5
+ ; [B E] => [B**E]
6
+ ;
7
+ ; [0 0] => [1], [0 9] => [0], [9 0] => [1]
8
+ ; [3 2] => [9], [2 3] => [8], [7 4] => [2401]
9
+ pow: push 1 swap
7
10
  _pow_loop: ; [b n e]
8
11
  dup jz _pow_done
9
12
  swap copy 2 mul ; [b e n*b]
10
13
  swap push 1 sub jump _pow_loop
14
+ _pow_done: swap slide 2 ret
11
15
 
12
- _pow_done: ; b n e
13
- pop slide 1 ret
14
-
15
- ;;;
16
-
17
- ; [n] => [n!]
16
+ ; returns the product of the integers from 1 to N, with 0! defined to be 1
17
+ ; [N] => [N!]
18
+ ;
19
+ ; [0] => [1], [1] => [1], [2] => [2]
20
+ ; [3] => [6], [5] => [120], [10] => [3628800]
18
21
  factorial: push 0 swap :range
19
22
  _fac_loop: swap dup jz _fac_done mul jump _fac_loop
20
- _fac_done: pop ret
21
23
 
22
- ;;;
24
+ _fac_done: pop ret
23
25
 
24
- isqrt: ; [n] -> [isqrt(n)]
25
- dup push 2 sub jn _isqrt_done
26
- dup push 4 div :isqrt push 2 mul
27
- dup push 1 add
28
- copy 2 copy 1 dup mul sub jn _isqrt_cleanup
29
- swap
30
- _isqrt_cleanup: swap slide 2
26
+ ; returns the integer square root of N
27
+ ; [N] => [floor(sqrt(N))]
28
+ ;
29
+ ; [0] => [0], [1] => [1], [2] => [1], [3] => [1]
30
+ ; [4] => [2], [8] => [2], [9] => [3], [99] => [9], [100] => [10]
31
+ isqrt:
32
+ dup push 2 sub jn _isqrt_done ; nothing to do for 0 and 1
33
+ dup push 2 div
34
+ _isqrt_loop:
35
+ copy 1 copy 1 div copy 1 add push 2 div ; new guess is (n / g + g) / 2
36
+ dup copy 2 sub jn _isqrt_update
37
+ swap slide 2
31
38
  _isqrt_done: ret
32
-
33
- ;;;
34
-
35
- ; intger logarithm ; [a b] => [log(a, b)]
36
- ; ! clobbers heap address -1 TODO: maybe not necessary?
37
- ilog:
38
- push -1 push 0 store ; tally
39
-
40
- _ilog_loop: ; a b
41
- swap dup jz _ilog_done
42
- push -1 :inc
43
- copy 1 div swap
44
- jump _ilog_loop
45
-
46
- _ilog_done: ; a b t
47
- push -1 load slide 2 ret
48
-
49
- ;;;
50
-
51
- ; greatest common divisor
52
- gcd: ; [a b]
53
- dup jz _gcd_done
54
- swap copy 1 mod
55
- jump gcd
56
-
39
+ _isqrt_update: slide 1 jump _isqrt_loop
40
+
41
+ ; returns the intger logarithm of N in base B
42
+ ; ! clobbers heap address -1 TODO: maybe unnecessarily?
43
+ ; [N B] => [logB(N)]
44
+ ;
45
+ ; [15 4] => [1]
46
+ ; [16 4] => [2]
47
+ ; [100 10] => [2]
48
+ ; [42 2] => [5]
49
+ ilog: push -1,0 store ; accumulator at -1
50
+ _ilog_loop: ; [n b]
51
+ swap copy 1 div dup jz _ilog_done
52
+ push -1 :inc swap jump _ilog_loop
53
+ _ilog_done: push -1 load slide 2 ret
54
+
55
+ ; returns the greatest common divisor of A and B
56
+ ; [A B] => [gcd(A, B)]
57
+ ;
58
+ ; [6 9] => [3]
59
+ ; [13 17] => [1]
60
+ ; [24 36] => [12]
61
+ gcd: dup jz _gcd_done swap copy 1 mod jump gcd
57
62
  _gcd_done: pop ret
58
63
 
59
- ; least common multiple
60
- lcm: ; [a b]
61
- copy 1 mul
62
- swap dup copy 2 swap div
63
- :gcd div ret
64
-
65
- ;;;
66
-
67
- min: ; [a b]
68
- copy 1 copy 1 sub jn _min_done swap
64
+ ; returns the least common multiple of A and B
65
+ ; [A B] => [lcm(A, B)]
66
+ ;
67
+ ; [6 9] => [18]
68
+ ; [13 17] => [221]
69
+ ; [24 36] => [72]
70
+ lcm: copy 1 mul swap dup copy 2 swap div :gcd div ret
71
+
72
+ ; keeps the minimum of the top two stack values
73
+ ; [A B] => [A < B ? A : B]
74
+ ;
75
+ ; [3 1] => [1]
76
+ ; [2 4] => [2]
77
+ min: copy 1 copy 1 sub jn _min_done swap
69
78
  _min_done: pop ret
70
79
 
71
- max: ; [a b]
72
- copy 1 copy 1 sub jn _max_done swap
80
+ ; keeps the maximum of the top two stack values
81
+ ; [A B] => [A > B ? A : B]
82
+ ;
83
+ ; [3 1] => [3]
84
+ ; [2 4] => [4]
85
+ max: copy 1 copy 1 sub jn _max_done swap
73
86
  _max_done: slide 1 ret
74
87
 
75
- ;;;
76
-
77
- ; -1, 0, or 1 to indicate the sign of the argument
78
- sign: ; [n]
79
- dup jz _sign_zero
80
- jn _sign_neg
81
- push 1 ret
88
+ ; returns -1, 0, or 1 to indicate the sign of N
89
+ ; [N] => [-1 | 0 | 1]
90
+ ;
91
+ ; [17] => [1]
92
+ ; [-25] => [-1]
93
+ ; [0] => [0]
94
+ sign: dup jz _sign_zero jn _sign_neg push 1 ret
82
95
  _sign_zero: ret
83
96
  _sign_neg: push -1 ret
84
97
 
85
- ; absolute value ; [n] => [abs(n)]
98
+ ; returns the absolute value of N
99
+ ; [N] => [N < 0 ? -N : N]
100
+ ;
101
+ ; [-5] => [5]
102
+ ; [10] => [10]
103
+ ; [0] => [0]
86
104
  abs: dup :sign mul ret
87
105
 
88
- ;;;
89
-
106
+ ; pops A and B and pushes both their quotient and modulus
107
+ ; [A B] => [A/B A%B]
108
+ ;
109
+ ; [17 5] => [3 2]
110
+ ; [42 6] => [7 0]
111
+ ; [ 1 5] => [0 1]
112
+ ; ! [9 0] => [!!] TODO: find a way to expect exceptions
90
113
  divmod:
91
114
  push -1 swap store
92
115
  dup push -1 load div
93
116
  swap push -1 load mod ret
94
117
 
95
- ;;;
96
-
118
+ ; returns whether N is greater than 0
119
+ ; [N] => [N > 0]
120
+ ;
121
+ ; [5] => [1] [-3] => [0] [0] => [0]
97
122
  pos?: :sign push 1 :eq ret
98
- neg?: :sign push -1 :eq ret
99
123
 
100
- ;;;
124
+ ; returns whether N is less than 0
125
+ ; [N] => [N < 0]
126
+ ;
127
+ ; [5] => [0] [-3] => [1] [0] => [0]
128
+ neg?: :sign push -1 :eq ret
101
129
 
130
+ ; returns a pseudo-array of the positive divisors of N; as an optimization,
131
+ ; they're not returned in ascending order, but rather in two "halves".
132
+ ; The alternative is unnecessarily invoking to_a and clobbering heap.
133
+ ; [N] => [D1 ... Dn n]
134
+ ;
135
+ ; [10] => [1 2 10 5 4]
136
+ ; [12] => [1 2 3 12 6 4 6]
137
+ ; [25] => [1 5 25 3] ; no duplicate for perfect squares
138
+ ; [60] => [1 2 3 4 5 6 60 30 20 15 12 10 12]
102
139
  divisors: ; [n]
103
- dup push -1 swap store ; preserve n because array operations
104
- :isqrt push 1 swap :range dup ; 1..n**0.5
140
+ dup push -1 swap store ; preserve N because array operations
141
+ :isqrt push 1 swap :range dup ; 1..isqrt(N)
105
142
  reject (push -1 load swap mod) :arydup ; get first half of divisors
106
143
  map (push -1 load swap div) :arycat ; map first half to second half
107
- push -1 load copy 2 dup mul sub jz _divisors_square
108
- ret
109
-
144
+ push -1 load copy 2 dup mul sub jz _divisors_square ret
110
145
  _divisors_square: slide 1 $-- ret ; de-duplicate when N is a perfect square
111
146
 
112
- ;;;
113
-
147
+ ; returns the number of ways to choose K elements from a set of N
148
+ ; [N K]
149
+ ;
150
+ ; [ 4 5] => [0]
151
+ ; [ 7 7] => [1]
152
+ ; [13 3] => [286]
153
+ ; [16 4] => [1820]
154
+ ; [50 3] => [19600]
114
155
  nCk:
115
156
  copy 1 copy 1 sub :factorial
116
157
  swap :factorial mul