This document uses the following conventions:
M, N
: IntegersX, Y
: Real numbersZ
: Complex numbersL1
: A real or complex list
There are 243 one-byte tokens in TI-BASIC with the remainder being two bytes. Know the sizes of the most common tokens so you can golf in your head while cooking, taking a shower, etc.
The following are the ways to reuse subexpressions in TI-BASIC:
-
Ans
- Holds the value of the last expression
- Overwritten by storing to a non-equation variable
-
Letter variables
A
- 2 bytes to store, 1 byte to use
-
List variables
|LA
- 2 bytes to store, 2 bytes to use
- The
|L
can be omitted when storing to a named list, so named lists are always shorter thanL1
-L6
1. - Lists can be associated with formulas; store an expression that evaluates to a list to a named list instead of
u
to save 1 byte. - See the Lists section for more information.
-
Matrices
[A]
-
String variables:
Str1
- See the Strings section.
-
Equation variables
Y1
/u
:- Relatively expensive: 4 bytes to store, 2 bytes to use.
- Stores expressions, not values.
Y1(W
evaluatesY1
temporarily settingW->X
, which is sometimes golfy.u
,v
,w
have two rarely used forms:u(N)
and the sequence formu(M,N,S)
. Both setN+1->[recursiven]
after evaluation, one of the only TI-BASIC commands with side effects. I have yet to find a case where one of these forms is optimal.
DelVar
sets numeric variables to zero. Uniquely, the following linebreak can be omitted, making it one byte shorter than 0->
.
ZStandard
and other zoom tokens set Y
to 0
, saving one further byte over DelVar Y
and making them the shortest way to store a value to a variable.
By CGCC rules, real variables can be assumed to have their default value of 0
at the start of a program, so this is only useful in the middle of a program.
The omitted linebreak after DelVar
means a second command can fit in a single-line If
statement: see If
for an example.
*
can be omitted, except in an expression like L1*(L1>X
; in this case use L1not(L1<=X
.
iPart(
rounds to zero, whereas int(
rounds towards minus infinity: {iPart(~.5),int(~.5)} = {0,~1}
. This difference can be useful. Ceiling is ~int(~X
.
A linear combination of int(X
and fPart(X
can be shorter expressed in terms of X
and int(X)
, or X
and fPart(X)
.
1>=abs(X
can benot(iPart(X
.
round(
rounds to 9 significant figures. round(X,N)
rounds to X
digits after the decimal point.
- To get the first digit of a positive number, one might use
int(10^(X/int(log(X
.int(10^(fPart(log(X
suffers from rounding errors, butint(10^(round(fPart(log(X
is correct and saves one byte.
When these commands are called on complex numbers, the real and imaginary part are processed separately. int(3.14-2.71[i])
is 3-3[i]
.
3=int(real(Z)) and ~3=int(imag(Z
can be3-3[i]=int(Z
rand
gets a random float in randInt(M,N)
gets a random integer in rand
is 1 byte; the others are 2-byte tokens.
rand(N
is the shortest way to create a new list of lengthN
.int(Xrand
is shorter thanrandInt(0,X
.
randIntNoRep(M,N
gets the list of integers between M
and N
.
randIntNoRep(M,N
is the shortest way to get the list of integers betweenM
andN
when order doesn't matter.2=sum(not(fPart(N/randIntNoRep(1,N
checks whetherN
is prime.
nCr
and nPr
have a precedence higher than (implied) multiplication.
Useful in computing advanced mathematical functions; otherwise usually too expensive.
-
cos(piN
maps evenN
to 1 and oddN
to -1; it is shorter than[i]^^2^n
or(~1)^N
. -
cos^-1(cos(X
takesX
modulo$\pi$ . -
tan^-1(tan(X
mapsX
into the interval$[-\pi/2, \pi/2]$ .-
5/pitan^-1(tan(L1pi/5
mapsX
into the interval$(-5,5)$ , throwing an error when$X \equiv 5 \mod 10$ .
-
-
sin^-1(sin(X
is also useful, left as an exercise to the reader.
Radian mode can be assumed as the default, so ^^o
is the more useful token.
-
tanh(|E9X
is the sign function;tanh(|E9{0,~3.14,42
is{0,~1,1}
. -
cosh(sinh^-1(X
is$\sqrt{1+X^2}$ . -
The golden ratio is
e^(sinh^-1(.5
.
Trigonometric and hyperbolic functions do not support complex numbers.
Powers, Inverses, Exponents and Logarithms: ^^-1
, ^^2
, ^^3
, sqrt(
, cuberoot(
, xroot
, 10^(
, e^(
, log(
, ln(
, |E
E9
is the standard large number.
conj(
, real(
, imag(
, and angle(
are two bytes. Nevertheless, complex numbers are the go-to method of representing 2D coordinates.
angle(
can be called on real arguments, returning pi
on negative numbers and 0
on nonnegatives. (On monochrome calcs, angle(
is unaffected by Degree
mode, returning pi
for negative numbers whose datatype is real.)
- In particular,
cos(angle(X
maps negatives to$-1$ and nonnegatives to$1$ (on color calcs, this works inDegree
orRadian
mode.) -
Degree:pi!=angle(~1
returns1
on color calcs and0
on monochrome calcs.
A linear combination of real(Z
and imag(Z
can be shorter expressed in terms of Z
and one of conj(Z)
, real(Z)
, imag(Z
.
- Example from Flip a number:
real(.1Ans)+10[i]imag(Ans)
->10Ans-9.9real(Ans)
.
conj
is useful for reflecting a point over a line.
- Map
X+Yi
to-Yi
(flip over the X-axis):conj(Z
- Map
X+Yi
toX-X+Yi
(flip over the Y-axis):~[i]conj([i]Z
- Exchange real and imaginary parts (flip over the line X=Y):
~conj(iZ
When it is not possible to use a complex numbers for a 2D vector, the angle commands are occasionally useful.
The or
and xor
operators have equal precedence; and
has higher precedence. Remember to use DeMorgan's laws to eliminate not(
and parentheses.
Comparison operators have a tolerance because their arguments are round(
ed first: 1>=1+4.99|E~10
is 1
, but 1>=1+5|E~10
is 0
.
Comparison operators do not chain together: X=Y=C
is equivalent to (X=Y)=C
. This is only useful when C
is not always 0 or 1, since otherwise X!=Y xor C
would be the same length.
Comparison operators do not support complex numbers.
variance(L1
andstdDev(L1
return zero if all elements ofL1
are equal.- Remember the two-argument (weighted) forms of
mean(
andmedian(
. - When a challenge asks for multiple statistical properties of the same list, consider using
1-Var Stats
or2-Var Stats
.
min(
and max(
compare complex numbers by their absolute values.
remainder(
is two bytes. lcm(
, gcd(
, and remainder(
require their arguments to be positive integers in the range lcm(L1)
and gcd(L1)
are not valid, so you must do 1:For(N,1,dim(L1:lcm(Ans,L1(N:End
, preferably reusing an existing loop.
sub(
and %
(a postfix token not available in the program editor) are 2 bytes. They both multiply their argument by .01
, which can occasionally save bytes. For example:
not(fPart(N/4/4^not(fPart(sub(N
gets whether yearN
is a leap year.
Most math commands automatically vectorize over lists.
augment(
is 2 bytes. Can be useful for constructing lists of a fixed length.
- Append an element to the end of a list:
augment(L1,{X->L1
DeltaList(
and cumSum(
are extremely useful, despite being 2 bytes.
{4,8,15,16,23,42}
can becumSum({4,4,7,1,7,19
.DeltaList(cumSum(L1
removes the first element ofL1
.cumSum(DeltaList(L1
is equivalent toDeltaList(cumSum(L1))-L1(1
.
Since the output of DeltaList(
is one element shorter, use augment(
to match dimensions; e.g., not(L1 and ~5>DeltaList(augment({0},L1
finds where L1 is 0 or decreases by at least 5.
Generally inferior to 0L1+X
, unless a list variable of the right dimensions is already available.
Use seq(
only for commands that are not vectorizable.
seq(
cannot be nested; use u
or, if possible, summation(
instead.
- Remove the
N
th element of a list:seq(L1(A-(A<N)),A,2,dim(L1
One- and two-argument forms can both be useful.
Matrices are expensive to define, index, and manipulate. When your matrix has two rows, consider using a complex list instead.
Strings are expensive to index and manipulate, since inString(
, sub(
, length(
and string variables are 2 bytes and require quote marks. 70% of the time, it is optimal to just convert an input string to a list at the start of a program:
seq(inString("VXLCDM",sub(Ans,N,1)),N,1,length(Ans
If you need a For(
loop anyway and only use one character at a time, store to a real variable inside the loop:
inString("BCDEF",sub(Str1,X,1->N
Empty strings cannot be used in string commands (except =
, !=
). See Routines for the shortest way to build strings.
inString(Str1,Str2
returns the first position of Str2
as a substring of Str1
. inString(Str1,Str2,N
starts searching at position N
in Str1
, which can be useful in the rare case when strings are not converted to lists.
inString(
returns 0 for no match, which means the first character of Str1
can often be left off.
Str1
can be permuted to simplify expressions later on in the program.
Prompt
and Input
do not update Ans
. Input
used on its own prompts the user to select a point on the graphscreen, then sets the X
and Y
variables accordingly.
Arrow keys and DEL (23) are the only autorepeating keys.
The arrow keys <, ^, >, v are codes 24, 25, 26, 34
.
-
Tell if an arrow key was pressed:
K=34 or 2>abs(K-25
-
Move a cursor around the screen:
iPart([i]^int(168ln(K-1
maps the<, ^, >, v
arrow keypresses to-1,i,1,-i
and 0 to0
. Using20
instead of168
maps to-1,i,1,-i
. -
Read a single number key:
- 1-9:
remainder(K,13
- 0-9:
remainder(remainder(K,13),11
- 0-9, returning the key code on non-numeric keys:
K(102!=K)-remainder(K,13)(2>abs(5-abs(5-abs(K-83
- 1-9:
Rarely useful unless they exactly fit a challenge.
To decide whether to use graphscreen points or pixels:
-
pxl-Test(
exists, butpt-Test(
does not. - Pixel commands accept only positive integers in
$[0,62] \times [0,94]$ , whereas point commands automatically round to the nearest pixel and do nothing if it would be offscreen. - When using points, keep in mind the cost of a friendly graphing window; if possible, rework the rest of your program to avoid changing the window.
In all boolean commands, the calculator interprets real 0 as false, and nonzero reals as true.
A one-line If
statement saves 4 bytes over If:Then:End
, and 6 bytes over If:Then:Else:End
.
If
is especially handy for leaving a value in Ans
.
If C
becomes false during If C:Then:[body]:End
, use While C:[body]:End
instead.
Sometimes, multiple If
statements can be combined in non-standard ways.
-
Short-circuiting
not(C) or D
:If C If D [body]
-
If:Else
:If C:Then [body1] End If not(C) or not(D:Then [body2] End //can be If C:Then: If D:Else End
A While C
loop checks if C
is true, then runs the body while C
is true. A Repeat C
loop always runs the body at least once, stopping when C
is false.
When writing While C
or Repeat C
, consider whether Repeat not(C
or While not(C
would fit better.
For(X,A,B:[body]:End
evaluates its bounds once, then repeatedly executes body
, and increments X
until it passes the bounds. Understand why:
For(X,1,10:End:X
returns11
10:For(X,1,Ans:0:End:X
returns11
For(X,3.5,1,~1.5:End
returns.5
For(X,1,10:20->X:End
returns21
For(X,1,10:~5->X:End
is an infinite loop
Remember the fourth "step" argument; it is often, but not always, useful.
For(X,1,|E9
counts up near-infinitely.
Goto
and Lbl
are niche commands, since the If
, Lbl
, and Goto
lines take a minimum of 8 bytes.
Also rare, since a For(
loop usually accomplishes the intended purpose in fewer bytes.
Subprograms are often an alternative to Y1
or u
. By PPCG rules, splitting code into two files costs one additional byte.
Since all variables are global, recursion has limited utility, but it is still sometimes the answer.
Parentheses, linebreaks, and variable access waste bytes without adding much meaningful code or data to your program. An expression, especially an arithmetic one, can often be shorter when condensed into one line. When an expression contains an opening parenthesis, consider if a function can go there instead---it's essentially free. If there are closing parentheses, try to rearrange the expression so they can be removed.
- Hash function generator
- Optimal expression generator (slow for >6 byte expressions)
To generate functions that map
int(NfPart(Mf(X
where f(
is a sufficiently "random" function (ln(
, sqrt(
, tan(
, etc.). Use this program to generate M
.
In particular, a function from
- List indexing (22 bytes):
{1,2,3,2,1,2,3,4,2:Ans(X
- String indexing (19 bytes):
expr(sub("123212342",X,1
- Base conversion (17 bytes):
int(10fPart(.012321234210^(X
- Arithmetic (16 bytes):
min(X,1+min(19-2X,abs(X-5
- Hashing (12 bytes):
int(6fPart(Mcosh^-1(X
, where finding the 7-digit numberM
is left as an exercise.
Considering different f
and slight variations on this form can save a byte or two, or allow mapping 0 to a nonzero value.
- To map to
{0,1}
with a distribution of 63.7% 0s and 37.3% 1s, useint(sin^-1(fPart(Mf(X
.
When N
is fairly small but K
is too large, consider reducing the domain by using clever math. Failing that, it's possible to chain hashes together in a technique similar to modulo chains.
int(NfPart(KfPart(f1(int(LfPart(f2(int(...
Fully optimizing hashes with large K
often involves exploiting even more degrees of freedom, and can be computationally infeasible. Use the optimal expression generator if your search space is fairly small, say under 6 bytes.
When N
is fairly small but K
is too large, consider reducing the domain by using clever math.
10^(DeltaList(log(L1
gets ratios between elements.2=10^(DeltaList(log(L1
gets where an element is double the next element.
- Likewise,
10^(cumSum(log(L1
is the nonexistentcumProd(
.
-
DeltaList(DeltaList(L1
gets the second-order differences. -
not(DeltaList(DeltaList(L1
checks for three-term arithmetic progressions inL1
. If the domain ofL1
is restricted, this sometimes means having three adjacent equal elements. -
max(2=10^(abs(DeltaList(log(abs(DeltaList(DeltaList(e^(L1
searches for the pattern{X,Y,X,X}
or{X,X,Y,X}
in the integer listL1
with elements in$[0,20]$ .
- If X is known to be nonzero,
If X>1
can beIf log(X
. 1+NC
can be(N-1)^C
when N is a constant.cos(piC
maps 0 to 1 and 1 to -1; it is shorter than[i]^^2^n
or(~1)^C
or1-2C
.
{1,2,3,4}
can betimeCnv(93781
.timeCnv(
is 2 bytes, so this doesn't always save bytes.{5,5
can bedim(identity(5
These substitutions often let you avoid storing X to a variable.
X>=4 and X<8
(7 bytes) ->1=int(4^^-1X
(5 bytes)X>=1 and X<8
(7round(^^-1(+X(10 bytes) ->
1=int( bytes; still net -1 when you can eliminate->X
)X>=4 and X<=8
(7 bytes) ->2<=abs(6-X
(6 bytes)
"
While C
Ans->Str1
...
<next part of string>
If length(Str1
Str1+Ans
End
Footnotes
-
Exception:
1-Var Stats
and2-Var Stats
. ↩