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
|Lcan be omitted when storing to a named list, so named lists are always shorter thanL1-L61. - Lists can be associated with formulas; store an expression that evaluates to a list to a named list instead of
uto 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(WevaluatesY1temporarily settingW->X, which is sometimes golfy.u,v,whave 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(Xcan 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(Xsuffers from rounding errors, butint(10^(round(fPart(log(Xis 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(Zcan 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(Nis the shortest way to create a new list of lengthN.int(Xrandis shorter thanrandInt(0,X.
randIntNoRep(M,N gets the list of integers between M and N.
randIntNoRep(M,Nis the shortest way to get the list of integers betweenMandNwhen order doesn't matter.2=sum(not(fPart(N/randIntNoRep(1,Nchecks whetherNis prime.
nCr and nPr have a precedence higher than (implied) multiplication.
Useful in computing advanced mathematical functions; otherwise usually too expensive.
-
cos(piNmaps evenNto 1 and oddNto -1; it is shorter than[i]^^2^nor(~1)^N. -
cos^-1(cos(XtakesXmodulo$\pi$ . -
tan^-1(tan(XmapsXinto the interval$[-\pi/2, \pi/2]$ .-
5/pitan^-1(tan(L1pi/5mapsXinto the interval$(-5,5)$ , throwing an error when$X \equiv 5 \mod 10$ .
-
-
sin^-1(sin(Xis 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(|E9Xis the sign function;tanh(|E9{0,~3.14,42is{0,~1,1}. -
cosh(sinh^-1(Xis$\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(Xmaps negatives to$-1$ and nonnegatives to$1$ (on color calcs, this works inDegreeorRadianmode.) -
Degree:pi!=angle(~1returns1on color calcs and0on 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+Yito-Yi(flip over the X-axis):conj(Z - Map
X+YitoX-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(L1andstdDev(L1return zero if all elements ofL1are 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 Statsor2-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(Ngets whether yearNis 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(L1removes the first element ofL1.cumSum(DeltaList(L1is 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
Nth 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-1maps the<, ^, >, varrow keypresses to-1,i,1,-iand 0 to0. Using20instead of168maps 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:Xreturns1110:For(X,1,Ans:0:End:Xreturns11For(X,3.5,1,~1.5:Endreturns.5For(X,1,10:20->X:Endreturns21For(X,1,10:~5->X:Endis an infinite loop
Remember the fourth "step" argument; it is often, but not always, useful.
For(X,1,|E9counts 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 numberMis 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(L1gets ratios between elements.2=10^(DeltaList(log(L1gets where an element is double the next element.
- Likewise,
10^(cumSum(log(L1is the nonexistentcumProd(.
-
DeltaList(DeltaList(L1gets the second-order differences. -
not(DeltaList(DeltaList(L1checks for three-term arithmetic progressions inL1. If the domain ofL1is restricted, this sometimes means having three adjacent equal elements. -
max(2=10^(abs(DeltaList(log(abs(DeltaList(DeltaList(e^(L1searches for the pattern{X,Y,X,X}or{X,X,Y,X}in the integer listL1with elements in$[0,20]$ .
- If X is known to be nonzero,
If X>1can beIf log(X. 1+NCcan be(N-1)^Cwhen N is a constant.cos(piCmaps 0 to 1 and 1 to -1; it is shorter than[i]^^2^nor(~1)^Cor1-2C.
{1,2,3,4}can betimeCnv(93781.timeCnv(is 2 bytes, so this doesn't always save bytes.{5,5can 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 Statsand2-Var Stats. ↩