"The Missing Manual" User notes on the HP 49g Series (48gII/49g+/50g) palmtop calculator/computer Norman Brenner, L-3/DPA, 2007 XII, 2008 V-VIII, 2009 II, 2009 IV, 2009 XI, 2010 V, 2010 VI, 2011 X, 2012 II [Merge command notes into HLP49.pdf] [Enter functions for: IL2W creation, PARSEAPL, flashcards, Faulhaber, CNUM & all in APLUTIL, & CREATE for library creation at points marked by [[]], PARSEAPL tranliteration, A~LL, V~LL, S~L, S~LW, new BEXP] ============================================================================== Emulation of APL functions The list operations ("parallel operations") operate similarly to APL semantics. In fact, the HP48/49/50g series is virtually a pocket APL computer, but with suffix rather than infix notation. Therefore, I have built a draft parser to execute APL statements with (near-)standard APL symbols. Cf. PARSEAPL, infraa. The current parser lacks full support for matrices, requires explicit list notation braces instead of catenation with blank, requires explicit splitting of strings and "each" applied with some functions to lists. It could also be sped up if the parsing function were rewritten in System RPL. (Parsing of an APL notation statement into User RPL takes up to 10 seconds for a statement of moderate length.) Alternately, one can translate APL in one's head to User RPL, making use of my APL-like functions in workspace APLUTIL, such as BSEL, GETL, IOTA, RESHAPE, TAKE &c. APL has functions (like up-arrow ["Take"] and comma ["Catenate"]) which work equally well on lists (APL "vectors"), strings and arrays; however, it is often necessary in User RPL to write explicit code for each case. A single function can however test the type of the input and apply the appropriate code. Also, empty items and scalar numbers are often treated as errors by User RPL functions, and need special checks. Quad-IO is permanently set to 1, to agree with HP usage, and the use of blanks to create APL vectors is augmented by HP's requirement of enclosing curly braces. Also, APL functions treat strings sometimes as a single item (e.g. iota search) and sometimes as a vector of single characters (e.g. epsilon membership). For consistency, I treat strings always as unitary, but also provide conversion between strings and lists of single characters. While list elements can be of any type, the elements of RPL vectors and matrices (collectively called "arrays") can only be numbers or algebraics. In particular, strings cannot be array elements. By contrast, APL permits strings as array elements. My replacement is lists of strings. Lists (but not arrays) can be indefinitely nested, and so are the equivalent of APL2 nested arrays. When an APL-like function takes a list argument as input (including a list of characters), an "L" is appended to its name. Also, some of my functions have names mimicking APL which would replace built-in HP functions, so I append the letter "a" to them (e.g. "DROPa" to implement the APL down arrow, whose name would otherwise clash with the built-in HP DROP function). Since I have made the full Greek alphabet available in the standard fonts, I use Greek letters in place of some unusual APL characters (e.g. "alpha" instead of "maximum/ceiling"). The "/" simulator uses the built-in functions SigmaLIST and PiLIST for speed, if the function to be iterated is "+" or "*", respectively. [??POSN vs. POSL?? If not found, POSN returns {}, but POSL returns {0}. Fix this, perhaps by merging the two functions.] [Are built-ins, like SIZE, called "commands" or "functions"?] Following is a list of functions, both built-in and of my devising, and how they correspond to the APL function set. -- Arithmetic functions (+, -, mult, div): these are built in to HP when both arguments are scalar numbers or lists of numbers. In addition, array + or - array is built in, as is scalar * array, array * scalar, and array / scalar. To perform other cases (such as array * array element-wise), the arguments are converted to lists of lists temporarily. -- BEXP (APL Boolean Expand, "mask\", on lists): Enter the data, then the Boolean (0 or non-zero) mask list, and run: << SWAP -> d << << IF THEN d HEAD d TAIL 'd' STO ELSE 0 END >> MAP >> >> For strings, the 0 must be replaced by a blank; and MAP must be replaced by [DOLIST?]--check if TYPE is 2 initially. APL2 has generalized this function: if the mask contains integers larger than 0 or 1, then that many replicants of the corresponding element are inserted: << ?? [new BEXP] >> -- BSEL (APL Boolean Select, a.k.a. Compress, "mask/", on lists): Enter the data, then the Boolean (0 or non-zero) mask list, and run: << 2 << IF NOT THEN DROP END >> DOLIST >> Note that IF treats a non-zero input as True. If the mask of Booleans be replaced by integers, then perform a DOLIST using dyadic RESHAPE (or NDUPN) on the 2 lists. Since, by a design flaw, DOLIST dies if it runs on an empty list, it is necessary to explicitly check for and produce an output of an empty list: << IF DUP 0 + 0 + SigmaLIST THEN 2 << IF NOT THEN DROP END >> DOLIST ELSE DROP2 {} END >> -- BSPL: Partition function which splits a string or list as per a Boolean mask into a list of shorter items. Caution: a leading 0 will lose all input items until the first 1. -- CAT (APL Catenate, ","; better than "+"): Use "+" on lists and strings, but catenate to a vector (type=29) by converting to lists then back: << -> x y << IF x TYPE 29 == THEN x OBJ-> EVAL 'x' STO y OBJ-> EVAL x + ->ARRY ELSE x y + END >> >> CAT still doesn't catenate matrices, for which one must use the built-in COL+ or ROW+. Use ROW-> or COL-> to convert a stack of vectors into a matrix. Also, it is not pervasive into a list, the way that "*" or "/" can combine a scalar with a list. Cf. ENLIST, RAV and ENLIST. -- CONS (Equivalent to CONS in Lisp) always creates a list of its two items. (How is this related to APL2 vector notation?) Cf. CAT, RAV and ENLIST. -- DISJ (APL Set Disjunction or Subtraction, dyadic "~", on lists): Enter the two list arguments: << OVER POSL NOT BSEL >> The result is a list of those elements in the first list which do not appear in the second list. (An empty list output is possible.) Cf. INTS. -- DOLIST (APL subscript vector feature): A[3 5 9 15]<-20 30 40 50 can be done by a DOLIST on the subscript list and the data, where the function includes the name of the main vector and uses GET or PUT to copy data from/to individual list elements. DOLIST fails on an empty list. -- DOLIST, DOSUBS (APL Each, down one level). Since the default listcount/framewidth is 1 (unless the function is << >> enclosing more than one built-in), only the main argument and the function (enclosed in << >>) is needed. With DOSUBS, a local variable NSUB is available holding the current index value. Note than no built-in commands pervade to the elements of a string, and very few to those of a array (vector or matrix). Cf. MAP, which does EACH pervasively to the element level in lists of lists or arrays. Note that if MAP is told to DROP its argument, it returns NOVAL, so that its output's length is the same as its input's. On the other hand, both DOLIST and DOSUBS can remove an argument without trace, so that they can produce an output list shorter than the input. In particular, the output of either can be nothing at all on the stack, causing an error in subsequent execution. This case of 0 length output must be checked for explicitly. One trick is to ensure that the first element of the input will a result in the output list; then apply TAIL to that result list. Also, MAP is inconsistent; it works with some functions, but fails to do anything with function arguments like << DTAG >> and many others. MAP's problems are a minor design flaw. Also, MAP makes internal use of the "current variable", which is X by default. If this variable is in use, it will be purged by the MAP function (which asks permission first). Under undetermined circumstances, both DOLIST and DOSUBS also seem to require the use of the current variable, but less often than MAP. More discussion about looping in the "Under-documented" section below. -- DROPa (APL down-arrow): [Similar program to TAKE; NOTE: the name DROP is already taken by a built-in.] Note that 1 DROPa can be accomplished by built-in TAIL. Cf. TAKE. DROPa should be extended to 2 dimensions, like TAKE. -- Each (APL diaeresis): this can be implemented by DOLIST, and if penetration to individual elements at any depth is desired, by MAP. Cf. supra, DOLIST. -- ENLIST (APL monadic epsilon): ravel a general array (list of lists) into a single level list containing the original objects in (row-major) order. Cf. RAV. -- EVAL or STR-> (APL execute): if a string is inside single quotes '', then EVAL will execute it; if inside double quotes "", then STR-> will evaluate it. EVAL on a list will stack the items; if the list is 0 long, then no output will be produced (design flaw or correct result?). Cf. LIST->, OBJ-> and ->STR. -- GETL (APL Subscript Extract, "<-[]"): looping with GET on a list of integer indices. The GET and POS built-in commands need to be extended. The long argument could be any of S (string as a unit), C (characters stored in a string), L (list of items, whether characters, strings or numbers). Note that the list of items must be stored in a local variable, say l, so that the operator of a DOLIST is 1 << l SWAP GET >>. Even simpler: << SWAP -> l << l SWAP GET >> MAP >> >> Since the long first argument might be a string, we prefix a clause to use SUB in that case: << SWAP IF DUP TYPE 2 == THEN -> l << l SWAP DUP SUB >> MAP >> ELSE SPL -> l << l SWAP GET >> MAP >> >> This is faster on long strings instead of first splitting the string into a list. Note that GET issues an error message if its argument is out of range, whereas SUB uses the lower and upper index values. To emulate APL's behavior, SUB must be replaced by a range-checking SUBa. -- IOPROD (APL Inner or Outer Product). (APL Inner Product,"x f.g y"): Enter the two lists or vectors, then the function names, and run: << SWAP -> f << EVAL f STREAM >> >> With list inputs, a list of lists is output; vector inputs will yield a matrix output--if the function f can be performed between a vector and a scalar (in that order). [THIS IS WRONG--WHERE IS FUNCTION g? It's on the stack!] (APL Outer Product, "x o.f y"): Enter the two lists or vectors, then the function, and run: << -> x y f << y << x f EVAL >> MAP >> >> With list inputs, a list of lists is output; vector inputs will yield a matrix output--if the function f can be performed between a vector and a scalar (in that order). The final list of lists should be converted into a matrix with LL->A. This outputs a list of lists: perhaps a matrix would be more appropriate? However, elements of a matrix can only be numeric or algebraic, not string. For speed, built-in HP functions are used. MATRIX * LIST does an outer product, as does LIST * MATRIX, and MATRIX / LIST does an outer quotient (but not LIST / MATRIX). Similarly, DOT performs an inner product on vectors, while * does the same for matrices. -- INTS (Intersection of sets). << DUP UNROT POSL BSEL >> Cf. DISJ. -- IOTA (APL monadic Iota; cf. POS for dyadic Iota and POSN for Iota-underbar): Given an integer, construct the list { 1 2 3 .. } thru that integer: << j j 1 4 ROLL 1 SEQ >> Note that "j" might refer to an outside variable. This must be prevented. To ignore external "j": << -> j << 'j' 'j' 1 j 1 SEQ >> >> The input length is stored in the local "j", which then becomes an index variable. Also, single quotes are required around the arguments to SEQ, as shown. Equivalent and even shorter is: << 'j' 'j' 1 4 ROLL 1 SEQ >> The most compact formulation is << 'omega' SWAP REPT >> where 'omega' is the internal loop variable of REP. -- MAP (APL2 Each, but fully pervasive). Many arithmetic functions operate element-by-element on lists, (and some also on vectors), but for many (e.g. LN, ->NUM), MAP is required. MAP's use is tricky (and it appears on no softmenu). To make ->NUM apply to each item in a list, one can write either << ->NUM >> MAP or << N2 >> MAP where N2 contains << ->NUM >>. However, the following fails: 'N2' MAP Note that the function argument will operate on the scalar elements, at the deepest level in a list of lists. MAP fails to execute upon an unknown but large set of functions. Cf. DOLIST/DOSUBS above. -- NOT (APL Boolean Invert, monadic "~", on lists): The input list is Boolean (0 or non-0); 0 will change to 1, ? will remain ?, all others to 0. (Note that ternary logic is used in the HP.) Equivalent to: << << 0 == >> MAP >> -- PARSEAPL: translate a subset-APL string into a User RPL program. Basic arithmetic symbols are +, -, *, %, ^. APL-unique symbols are represented with low frequency characters from the HP character set. Some common function symbols can be entered with alternate characters: left arrow ("assign") is represented by angle (ALPHA -> 6) or by HP's left arrow; "each" is represented by either @ (ALPHA -> ENTER) or by HP's diaeresis. A few symbols are replaced entirely (e.g. "alpha" and "omega" are used for "ceiling" and "floor"), but other APL symbols (such as "iota") are included in a replacement font. As not all of the APL characters are available in the default HP character font, I have created an enhanced font. Briefly, characters of little utility (such as commercial fractions like 1/2) are replaced by Greek letters in order to make up the full (Homeric) Greek alphabet. Then, in PARSEAPL, APL expressions can be entered with Greek letters or ASCII special characters according to the following transliteration scheme: Char Monadic meaning Dyadic meaning .. The following APL functions are still unassigned to any character: .. The following characters are still available for assignment: .. -- + (partially APL "+", partially APL ","): it was a poor idea (copied from the C language) to use "+" indiscriminately for both addition or catenation. To be certain of addition (as for lists), one must use << NEG - >> instead. But there is no certain built-in replacement to perform catenation (so I wrote CAT and ENLIST). -- POS (APL dyadic Iota): Seeks item in a list, or substring in a string. Cf. POSL and POSN. -- POSL (APL Epsilon/dyadic Iota (membership) on input list): MAP with a function that performs POS on the long list. [Cf. POSN above.] As for GETL, a string must be converted initially into a list of characters. << SPL SWAP -> l << l SWAP POS >> MAP >> XQ >> The output list of integers can be changed into a Boolean mask by 0 >. Cf. POS and POSN. -- POSN (APL iota-underbar): Find all positions of a short string in a longer string. Enter the arguments in the stack, long string ("sss") followed by short string ("s"), then: << 0 {} -> sss s p l << WHILE sss s POS DUP REPEAT DUP p + 'l' STO+ s SIZE + DUP 1 - 'p' STO+ 10000 SUB 'sss' STO END DROP l XQ REVLIST >> >> ("p" is a temporary variable holding the number of characters lopped off the beginning of the string before the current iteration; "l" is the list, built up in reverse order.) The result is a list of index positions (origin 1) showing where the short string was found in the long one. If not found, then the list will be empty. Cf. POS and POSL. -- PRED (APL Partial Reduce, "f\"): The APL "+\" computes partial sums, returning a list containing the first item, then the sum of the first 2, then the sum of the first 3, &c. Similarly for any dyadic function f. << -> l f << l << OVER f EVAL >> STREAM l SIZE ->LST >> >> Perhaps a more compact function would use SEQ, which produces a list directly (but may need to take input from the stack). -- PUTL (APL Subscript Insert, "[]<-"): Similar to GETL, but with PUT or REPL. Cf. STOL. -- QuadAV (APL list of the 256 ASCII characters). Built-ins NUM/CHR will toggle between ASCII and small integers. (Only the HEAD of a string will be converted.) S->H (String To Xenidenary) and H->S or H-> and ->H are also useful. Since numbers occupy at least 7 bytes each (binary integers up to twice that), it can save storage to convert lists of small integers to character strings. Cf. NUM2, CHR2, NUM2L and CHR2L below. -- RAND, RANM (APL "?" for Random number generation): Generate a single random number (real, in [0.,1.]) or a matrix of random integers (in [-9,+9] with 0 doubly likely; apply ABS after RANM to force equal probability in [0,9]). Cf. NRAND16. -- RAV (APL monadic ","; ravel a list of single characters to a string): A very short and fast formulation for a list of strings is: SigmaLIST However, SigmaLIST signals error if the list length is 0 or 1; it leaves the list intact in these cases. Also, SigmaLIST becomes very slow if used on a long list of lists. Much faster for the latter is DOLIST or DOSUBS with a listcount/framewidth of 1 and the function << EVAL >>. << DUP SIZE -> n << EVAL "" "" << + >> 'j' 0 n 1 SEQ >> Numbers may be mixed with characters, but the resulting character string will include imbedded sums of adjacent groups of the number items (sums, because "+" operates differently on strings than on numbers). << IF DUP TYPE DUP 5 == SWAP 29 == OR THEN OBJ-> { 1 } + PiLIST ->LIST END DUP SIZE -> n << CASE n 0 == THEN DROP "" END n 1 == THEN EVAL END IF DUP TYPE 5 == THEN IF DUP HEAD TYPE DUP 2 == SWAP 5 == OR THEN SigmaLIST END END END >> >> RAV may be called iteratively on an object to return a flat list of all the member items, or just use ENLIST. RAV unrolls matrices into lists in row-major order. Cf. RAVW and ENLIST. -- RESHAPE (APL dyadic rho). First, it linearizes the input argument, then it replicates elements to the full required length, and lastly it folds the data into the requested shape (vector or matrix). However, since characters cannot be members of arrays, SHAPE returns them in strings or in lists of strings. A one-dimensional version of SHAPE is very simple; it outputs a list, and can be described as "object y replicated x times": enter y, then x and run: NDUPN ->LIST The order of the arguments is the same as for Y^X, which is natural, as the latter argument is the number of repetitions (like X, the number of multiplications of the base). The result is a list. To create a vector, use NDUPN ->ARRY. Note that strings cannot be made elements of an array (vector or matrix). More generally, the new shape may be a list of length 2, so that the output must be a matrix (or a list of lists, for character input). Also, the input data may be non-scalar, so that it must be replicated cyclically; e.g. "ABC" 7 SHAPE should output "ABCABCA". << OVER RAV OVER CARD OVER CARD 4 PICK { 1 } + PILIST 0 -> o0 n0 o cn co ntot n2 << IF ntot co <= THEN o ntot TAKE ELSE IF co 0 == THEN o PROTO 'o' STO END IF co 1 <= THEN o ntot NDUPN ->LIST IF o TYPE 2 == THEN RAV END ELSE o ntot co / CEIL NDUPN ->LIST RAV ntot TAKE END END IF cn 1 > THEN 'o' STO IF o PROTO " " == THEN n0 TAIL EVAL 'n2' STO << o j j n2 + 1 - SUB >> 'j' 1 ntot n2 SEQ ELSE o IF DUP TYPE 28 ~= THEN OBJ-> DROP END n0 ->ARRY END ELSE IF o0 TYPE 29 == THEN V~L END END >> >> Alternately, CON will create a constant array (not a list); the arguments are in reverse order, and the size must be a list, which can be used to create a multidimensional object. RDM also (re-)creates matrices, as do ROW->, COL->, ->ARRY. An odd behavior of RDM is that [1 2 3] {4 5} RDM outputs {[4 4 4] [5 5 5]}. I don't understand the logic here. For repetitive execution, cf. REPT. To quickly create strings of a given length, use MAKESTR from the Development Library 256; however, the contents will only be a cyclic repetition of "ABCDEFG\n". To create a string of repetitions of some other string, use SHAPE and SigmaLIST. -- REVLIST (APL monadic Reverse): Reverses the items in the list argument. SREV (in the APPS/Development Library) reverses a string. -- SAME (APL dyadic identity). Used in place of "==" between objects of different types. -- SHAPE (APL monadic rho). Same as "SIZE", except on multidigit integers, for which it returns 1 while SIZE returns the number of digits (or 0, for input 0). Its output is always a list, while the similar CARD returns a bare integer. Cf. CARD. Several functions exist, one which precisely imitates monadic rho, such that it returns an empty list for the shape of a scalar, and a list for all lists and arrays [this is SHAPE], and another function which returns the number of items at the top level of the input [this is CARD]. And a third function, which returns the total number of items in the input, including all levels. [The latter is ENLIST CARD.] By contrast, the built-in SIZE returns a real, not integer value, not in a list for input lists or input scalars, but in a list of SIZE 1 for input arrays. A design flaw is that SIZE upon a non-binary integer returns the number of digits. Even more surprisingly, when the input is the integer 0, the result is 0. Cf. SHAPE and CARD. Also, cf. BYTES, which returns both the internal storage requirement for the object and a check sum for it. -- SORT (APL Upgrade): List argument. To grade downward, REVLIST after SORT. -- SPL (split a string into a list of characters; like APL tranpose of a vector of characters): << -> s << << s j j SUB >> 'j' 1 s SIZE 1 SEQ >> >> This extracts one character at a time (with SUB); it also computes SIZE repeatedly. Faster and shorter is << -> s << << s omega omega SUB >> s SIZE REPT >> >> Note that "omega" is the internal index variable of REPT. Also note that APL treats a character string as either a unit (e.g., left argument of dyadic iota) or a vector of characters (e.g. right arg of dyadic iota). In RPL, the distinction must be made explicitly. So we must conditionally convert a string to a list of its individual characters: << IF DUP TYPE 2 == THEN -> s << << s omega omega SUB >> s SIZE REPT >> END >> Cf. RAV and SPLW. -- STOL (APL Subscript Insert, "[]<-"): Use the subscript notation on the named variable; e.g. <> where the subscript "(1)" is looped over. Cf. PUTL. -- ->STR (APL format): convert the number in the stack into a double quoted "" string. Only the decimal digits on display are included. (Cf. EVAL.) -- STREAM (APL Reduce, "f/"): Enter list, then function, then run STREAM. It fails if the list length is less than 2. -- TAKE (APL up-arrow): HEAD is the same as 1 Take. Let o be the object, and n the number of items to take, and let o and n be placed in the stack. If n is known to be positive and less than the SIZE of o, then do << 1 SWAP SUB >> If n can be positive or negative (the latter takes items from the tail), then << -> o n << IF n 0 >= THEN o 1 n ELSE o o SIZE EVAL DUP n + 1 + SWAP END SUB >> >> The object o can be a vector, string or list, while n is the number of items to take. As usual, positive n extracts initial items, while negative n extracts trailing items. If n is longer than the SIZE of the object, it will be limited to SIZE (i.e. no "overtake", which, in APL, appends zeroes or blanks to the output). TAKE can be used on lists and strings without restriction on the numeric argument, but when used on vectors ("arrays"), n must not be 0. Also, HEAD and TAIL fail on vectors, so they should not be used as shortcuts inside TAKE. << -> o n << CASE n o SIZE > THEN o o PROTO DUP n o SIZE - NDUPN ->LIST SWAP IF " " == THEN SigmaLIST END + END n o SIZE NEG < THEN o PROTO DUP o SIZE n + NEG NDUPN ->LIST SWAP IF " " == THEN SigmaLIST END o + END n 0 >= THEN o 1 n SUB END o o SIZE EVAL DUP n + 1 + SWAP SUB END >> >> Cf. DROPa. TAKE should be extended to 2 dimensions, so that it can operate upon both matrices and GROBs. Also for them, an axial form of TAKE should be permitted, so that one number specifies the number of rows (or columns) to take. -- == (APL test for equality): The two arguments must be of the same type and length. Do not use single equals sign, which is used with DEFINE to create functions or algebraic expressions. Cf. SAME, which tests for absolute identity. -- + (similar to APL Catenate, ","). For lists and strings, but not vectors. Beware: to add lists arithmetically, use the sequence NEG - or the built-in function "ADD". -- + (Union of sets): Same as catenation: "+" on lists. [NOTE: duplicate items are not removed.] Cf. INTS and DISJ for intersection & difference of sets. -- !, COMB, PERM (APL "!" for Factorial, Combinations and Permutations): ============================================================================== Programming examples -- Here are some programming examples. A pair of equivalent programs: << -> x << x SQ >> >> << -> x 'x^2' >> Notice that the localization of x with -> causes it be stored from the stack into a temporary location; it must be reloaded into the stack as needed. A useful convention is that local variables are indicated by lower case. -- Looping program: << -> x << WHILE 'x>2' REPEAT x SQRT ->NUM DUP 'x' STO END >> >> Notice that the truth conditional is an algebraic expression (viz., in single quotes). Alternately write x 2 >. -- An algebraic expression can be checked for being a particular form, e.g. "0", with SAME. Writing 'P=0' where 'X^2+1' 'P' STO fails with "UNKNOWN ARGUMENT" (viz. the value of X), because numeric evaluation is done by "=". -- A simple loop with START/NEXT: << 1 4 START 2 + DUP NEXT >> If n is in the stack, it creates n+2, n+4, n+6 in the stack. The same loop with an iterating index << 1 4 FOR i 2 + DUP NEXT >> -- To create a list, use SEQ. For an example, see IOTA. -- For input {1 2 3}, this function: << << DUP >> MAP >> outputs {{1 1}{2 2}{3 3}}. For input {1 2 3}, this function: << << DUP >> STREAM >> outputs 1 2 2 3 3 in the stack. Note that the first item is not duplicated. 3 IOTA << IOTA >> MAP outputs {{1} {1 2} {1 2 3}}, while replacing MAP with STREAM splits this list into the stack. -- Faulhaber coefficients (Compute formula by recursion from previous formula): The formula for a Faulhaber coefficient is a difference equation whose coefficients are either fixed or taken from the previous formula. [[ Insert FAULHABER code here ]] -- NRAND16 (Generate a list of 16 normally distributed random numbers): The built-in function RAND generates a random number evenly in the range [0,1]. If 16 such numbers are added together, they will be distributed on a Gaussian bell curve with mean 0 and standard deviation SQRT(16/12). [How to prove this?] The standard deviation can be altered by multiplication of a constant on each item, and the mean can be altered by subtraction of a constant from each item. An Hadamard-Walsh matrix contains orthogonal rows of +1 and -1, so that multiplying it by a vector of RAND-generated numbers will yield normally distributed random numbers. (The first row is a pure addition, so its sum must have its mean (viz., 8) subtracted out.) First, we need a function to create new H-W matrices: << -> h << h h 1 COL+ h NEG h 1 COL+ AUGMENT >> >> 'HW2x' STO Given an H-W matrix of any size, this doubles its dimensions. The smallest H-W matrix may now be doubled in size three times: [[1 1] [1 -1]] HW2x HW2x HW2x 'HW16' STO Now multiply this matrix with a row vector of flatly distributed random numbers; correct the leading term and leave a list of length 16 in the stack: << HW16 << RAND >> 'j' 1 16 1 SEQ OBJ-> ->ARRY * OBJ-> EVAL ROLL 8 - 16 ->LIST >> Another approach to generate many random numbers is to start with RANM, which generates a matrix of random integers from -9 thru +9, evenly distributed except that 0's are twice as likely. Note that the ABS of this matrix then has equal probabilities for all integers 0 thru 9. -- POL->: PROOT requires an input vector, not a list, of coefficients, but there is no built-in command to convert an algebraic to such. (E.g. convert 'X^3+2*X+3' to {1, 0, 2, 3}.) Since such lists or arrays of coefficients are input or output for a few commands (such as PCOEF and PROOT), such a conversion command would be helpful. I have built one using the HORNER command to repeatedly divide the given polynomial by X-0: << -> p << WHILE 0 p SAME NOT REPEAT p 0 HORNER SWAP DROP SWAP 'p' STO END >> >> The coefficients are left in the stack (e.g. 3 2 0 1 for the above). An expanded program that creates a list {1 0 2 3} instead: << 0 -> p n << WHILE 0 p SAME NOT REPEAT p 0 HORNER SWAP DROP SWAP 'p' STO 'n' INCR DROP END n ->LIST REVLIST >> >> Note that 0 is stored as the initial value of local variable "n", while the input stack argument is stored in local "p". Also, as with HORNER, it splits on powers of the default variable in "VX". A variable changing program is given below. Another function that does this: << DUP DEGREE -> n << 1 n FOR j 0 HORNER SWAP DROP SWAP NEXT n 1 + ->LIST REVLIST >> >> Shorter is: << DUP 0 SWAP DEGREE -> n << HORNER 3 ROLLD >> 'j' 1 n 1 SEQ + + REVLIST TAIL >> >> which leaves both the polynomial quotient and a 0 on the stack after each iteration. Still shorter: << DUP DEGREE -> n << 0 HORNER NIP SWAP >> 'j' 1 n 1 SEQ + REVLIST >> >> Note that the polynomial quotient is left on the stack after each iteration. The n iterations create n coefficients in the stack. Since the final list must include all n+1 coefficients, a final "+" is required. The quotes around 'j' are required to insulate against a global variable of that ilk. This function slightly errs on constant polynomials, returning a two element list {0 constant}; the error is with SEQ, which returns {0} (the index starting value, left on the stack) if it does not run at all. A constant input should produce just {constant}, while input 0 should produce {}. The final version of POL-> is then: << DUP DEGREE << 0 HORNER NIP SWAP >> 'j' -1 4 ROLL 1 SEQ + REVLIST TAIL TAIL >> >> This function followed by a simple EVAL ->ARRY will produce such a vector of coefficients. Its output is pure numeric. Cf. FACTOR which produces the symbolic roots of a polynomial. HORNER fails if its arguments are both constant, and the first is real; use my HORNERa instead. (Cf. SYST2MAT which extracts the coefficients of a set of linear equations, and returns them in a matrix.) -- ->POL: The reverse problem, of converting a list of numerical coefficients into a polynomial in a variable, is easy: << 0 0 ROT + + << SWAP 'V' * + >> STREAM EVAL >> where 'V' is the name of the new variable. Note that STREAM must be given an input list of SIZE at least 2 in length. -- I know of no command which returns the name of the main variable of a polynomial. Since DEGREE returns the highest power in a polynomial in an algebraic, while LNAME returns a list of names of all variables in it, perhaps a search for "^" followed by the degree can determine the main variable. -- VX-> (Replace a polynomial's variable with the current variable): First stack the polynomial and then its independent variable, and then substitute the current default variable for it by VX->: << "'" SWAP "=" PUSH {HOME CASDIR} EVAL VX POP "'" + + + + STR-> EVAL SUBST >> Note that EVAL of a list of directories acts as a GOTO, while STR-> EVAL evaluates an algebraic inside a string. RCLVX and STOVX access the current variable name stored in directory CASDIR, so, eliminating the PUSH/POP directory switching, << "'" SWAP "=" RCLVX "'" + + + + STR-> EVAL SUBST >> -- A~LL (Array <-> List of lists) .. -- S~L (String of characters <-> List) .. -- S~LW (String of characters <-> List of words) .. -- V~L (Vector [1-dimensional array] <-> List) .. -- CARD: count of the top-level items in a list. For a count of all objects at all depths, do ENLIST first. Cf. SHAPE. Note that CARD returns 1 for strings while SHAPE will return its length. Also, CARD returns integer 1 for all scalar input, while SHAPE returns {} (empty list) for scalars. Cf. SHAPE. -- RAVW (Ravel a list of words to a string with an argument string between each word): This is simple, except that the special cases of 0 and 1 words in the list must be handled explicitly: << -> l p << l << DUP SIZE -> n << EVAL CASE n 1 > THEN << p SWAP + + >> 'j' 2 n 1 SEQ END n 0 == THEN "" END END >> >> >> Note the use of "==" instead of the erroneous "=", and that the case n=1 is defaulted to "do nothing after the EVAL". It can be done more briefly by prefixing a blank to each with MAP, then doing SigmaLIST, and finally using TAIL to drop the leading blank. However, on lists of length 0, this returns no result (not even an empty list). STREAM permits a compact solution, after checking if the list has 2 or more items: << -> l p << IF l SIZE 1 <= THEN l RAV ELSE l << p SWAP + + >> STREAM END >> >> Cf. RAV and SPLW. -- REPT. An iteration command with the same notation as RHO-- "function y executed x times". Enter y (an expression), then x (an integer) and run: SWAP 'j' 1 4 ROLL 1 SEQ The first argument can be an expression (in either algebraic '' or RPL <<>> form); see IOTA and SPL for examples. This generalized RHO is a useful building block in programs when the output result is a list of known size, but there is no input list of that size (for which MAP, DOLIST or DOSUBS could be used); e.g. IOTA, or functions upon IOTA, such as 'omega^3' 5 REPT which creates a list of cubes. Design flaw: SEQ always iterates at least once, so that an argument of 0 or less must be explicitly checked for. On the actual calculator, the local variable has been named omega (the lower case greek letter) to avoid local name conflicts. Note that the expression is evaluated by SEQ. A string as input will produce a variable of that name, or that variable's value. -- SOFTTOGL: Many menus can be displayed as either softkeys or in a popup change box, depending on the setting of system flag -117. However, the HELP which is available for many commands is only available when the change box is displayed. To display help for commands when they appear on softkeys, I must look them up in the CAT menu. I wrote a user key to toggle flag -117: << IF -117 FC?C THEN -117 SF END >> If we wish to toggle multiple flags, a Boolean mask must be created. E.g. an alternate way to toggle system flag -117 is: << RCLF { # 0h # 0h # 10000000000000h # 0h } XOR STOF >> (Note the 13 consecutive 0's in the 3rd constant; this puts the 1 bit at a distance of 53 [huh?] bits from the end of the mask, and 64+53 = 117.) -- SPLW (Split a string into a list of words separated by an argument string): << -> l p << CASE l SIZE 0 == THEN {} END p SIZE 0 == THEN l SPL END l p + 0 -> s n << WHILE s SIZE REPEAT s p POS s 1 ROT 1 - SUB LASTARG + 1 + s SIZE SUB 's' STO 1 'n' STO+ END n ->LIST >> END >> [Can DOLIST be used?] An arbitrary delimiter could be supplied as an argument, in place of " ". However, a set of delimiters, such as punctuation marks, would be harder to implement. Cf. SPL and RAVW. -- Dictionary lookup. To create the list which converts letter position to word position, input the raveled string: DUP SIZE IOTA 2 << RHO >> DOLIST << EVAL >> DOLIST Given a list of strings Eng2Lak, first prepare a grand ravel of it in variable E with RAV. Next get the lengths of the item strings: << SIZE >> MAP >> 'L' STO Now compute the offsets of each word in the grand ravel: 0 L HEAD L << + DUP >> STREAM DROP L SIZE ->L 'O' STO E.g. if the original dictionary were { "Tom" "Dick" "Harry" }, then L would be { 3 4 5 } and O would be { 0 3 7 } Finally, construct a look-up list, for which the position of each letter is mapped to its corresponding word: O L 2 << IOTA NEG - >> DOLIST 'IL2W' STO ???? For our example, IL2W would be: { 1 1 1 2 2 2 2 3 3 3 3 3 } Because IL2W will be much larger than the original dictionary string, it is useful to save storage by converting each number (which will less than 16384) into a two byte string, and then raveling them all. By experiment, it is only slightly longer to look up and convert the integer from this table than to use the true integer list IL2W, and it will be only 2/7 the storage. The functions for conversion of integer between two byte strings are: [[.. (F & FI)]] Another possible method of fast lookup is to compare a position in the long string to the offset table. However, either << > >> MAP or a WHILE loop is many times longer running than the simple lookup above. Then, to look up a substring in any of the item strings, and see the list of matching items, enter the substring in "" and do: E SWAP POSN :#: IL2W EVAL SWAP GETL DUP Eng2Lak SWAP GETL Lak2Eng ROT GETL -- Flashcards. Import two lists, one of foreign words, one of their English meanings. Let us use Chinese characters, stored as GROB's. To use it, create a list of integers (FLIST) which point to the subset of characters to be flashed. Each character will be displayed until the user presses a key. Then the English meaning and the integer index will be displayed. The user can then press one of four softkeys: FLARAN, to display another character, randomly selected from the current set; FLADIS, to redisplay the lowest character in the stack; FDEL, to delete the just seen character's index from the set; and FAPP, to append another copy of the just seen index to the set, so that it will recur more frequently. Here are the functions. FLARAN: << 0 -> I << CLEAR :2: HANN500 EVAL FLIST DUP SIZE RAND * 1 + FLOOR GET DUP 'I' STO GET EVAL ->LCD 0 WAIT :2: HENG999 EVAL I GET 1 >> FLADIS: [[ Insert FLADIS ]] FAPP: << 'FLIST' STO+ FLIST SIZE NEG >> FDEL: << 0 -> I << FLIST SWAP POS 'I' STO I IF THEN FLIST 1 I 1 - SUB FLIST I 1 + 1E4 SUB + 'FLIST' STO FLIST SIZE NEG END >> >> (FDEL returns the new size of the current set, but negates it so that an accidental double press of FDEL will not remove this size from the set.) One can create a temporary menu in the flashcard program with { FLAHAN {} FAPP {} {} FDEL} TMENU STO -1 WAIT Then, when WAIT is interrupted, execute the key number, perhaps with KEYEVAL. The clock line shows thru the ->LCD display, so it must be turned off first. System flag -40 toggles the clock. [Built-in CLK in HP48.] -- MF2SF: convert a minifont to an editable System 6 font. Library 256 must be attached, and also the library (999) containing SPL & al. << ->H 13 10000 SUB -> mf << << mf j j 5 + SUB >> 'j' 1 1536 6 SEQ >> 1 << SPL << "0" SWAP + + >> STREAM "00000" + >> DOLIST SigmaLIST FONT6 ->H 1 34 SUB SWAP + H-> >> It is approximately twice as fast to convert the minifont characters (e.g. "123456") to a system character (e.g. "1020304050600000") by generating the integer indexes and using SUB and REPL. However, the indices, unless kept in a stored list, are time-consuming to generate. This function runs in about 2 minutes. -- SF2MF: convert an editable System 6 font to a minifont. << ->H 35 10000 SUB -> mf << << mf j j 15 + SUB >> 'j' 1 4096 16 SEQ >> 1 << { 1 3 5 7 9 11 } GETL >> DOLIST SigmaLIST MINIFONT-> ->H 1 12 SUB SWAP + H-> >> This function runs in about 1 minute. -- ELAP: measure elapsed time of a function: << TICKS -> t << EVAL TICKS 't' RCL - B->R 8192 / '1_s' * >> >> where the built-in function TICKS returns a binary integer that changes 8192 times/sec. ============================================================================== Inefficient naming -- On the TOOLS menu, the two softkeys on the second page are CASCMD and HELP, but they perform the identical function (show help for the CAS command subset). -- On the S.SLV menu, the last two softkeys on the first page both display as SOLVE; in fact, their full names are SOLVEVX and SOLVE. Since they are in fact different (tho related) commands, it is confusing to see their labels being identical. Similarly, TAN2SC and TAN2SC2 display the same on the keys. [Use rightshift-downcursor to show the full names] -- TAYLOR0 is a subset of TAYLR, and both are subsumed by SERIES; ASN is a subset of STOKEYS; DERIV is the same as the backbending delta; STEQ is the same as 'EQ' STO and RCEQ is 'EQ' RCL; FACTOR is similar to FACTORS; EXPAN vs. EXPND -- PTAYL. Shifts the origin of a polynomial. [Unconnected with Taylor series.] -- INTVX, RISCH, INT, longS all do symbolic integration. Apparently the only difference is that they take 0, 1, 2, 3 arguments, respectively, viz. the variable of integration, and the point to evaluate it at. The defaults are the previous argument or the VX default variable. The longS symbol takes three arguments, the lower and upper limits preceding the integrand, and the variable following. -- DERVX, backdelta, DERIV all do symbolic differentiation. The first one does it with respect to the VX default variable; the second requires 1 argument, which names the variable; the third permits either one or a list of variables, to be partial differentiated by. The "partial" (script backbending lower case "delta") symbol in fact performs a "total derivative". -- FACT is identical to !, but both are restricted to real arguments. GAMMA permits complex arguments, and on real, is identical to (x-1)! -- MAP, STREAM, DOSUBS and DOLIST are similar, as are SEQ and START/STEP, FOR/NEXT, WHILE/REPEAT/END. All perform loops. MAP applies a defined function to each element in a complex list. It is "pervasive": on a list of lists, it operates down on the lowest, element by element, level. On lists of scalar elements, it is the APL "each". It seems to ignore the current stack, unlike the other looping built-ins. STREAM reduces a single list with a specified function; if the function is + or *, then it is the same as SigmaLIST or piLIST, respectively. DOSUBS applies a multiargument function to consecutive "frames" of elements from a single list. If the frame width is 1, it is just the APL "each". If the frame width is 2, it is just STREAM. Its internal index value, NSUB, can be used in expressions. DOLIST applies a multiargument calculation to corresponding elements in several lists. If only 1 list, it is just the APL "each", and is the same as DOSUBS with a frame of 1. delLIST is equivalent to 2 <<->> DOSUBS NEG. STEP or NEXT can go with either START or FOR; if the increment to STEP is 1, then it is the same as NEXT. SEQ is an abbreviated form of FOR/NEXT, and produces a list. REPT is a compact form of it. See elsewhere for quirks of their usage. -- MAP operates successfully on null lists, returning a null list. STREAM, DOLIST and DOSUBS all fail on a null list argument. Try: {} << 1 - >> MAP vs. {} 1 << 1 - >> DOLIST -- GET retrieves a single item from a list or array, while SUB retrieves a list of consecutive items from any object. Similarly, PUT stores a single item, while REPL inserts a list of consecutive items. To extract or replace a single character in a string, do DUP SUB instead of just GET. SREPL seeks and replaces one string with another. -- VISIT & VISITB are identical in function to EDIT & EDITB; the only difference is that their argument is the variable's name, and the result of editing replaces the initial value of the variable. -- NDUPN & CON perform similar functions, one to the stack, the other to an array. ============================================================================== Improving the Documentation -- The split of the on-line documents into "Manual", "Guide", and "Advanced Reference" is confusing; in fact, the Manual is redundant because it is a subset of the Guide. However, I must still search both the Guide and the Reference for information. Also, the "Manual" and the "Guide" are .PDF files with wastefully wide white borders, which hinders both display and printing. (I narrowed the margins with Adobe Acrobat.) -- Where are primers from HP for this calculator? All the material I have seen (User's Manual/Guide and User Reference) are at least at semi-reference level. How about a simple introduction with examples of the remarkable set of list commands, which effectively mimic parallel processing? How about a set of pictures of the stack window, showing the many combinations of MODE DISP settings? NOTE: There is a user-written primer, ^The Definitive User's Guide to HP 48g/49g/50g Calculators^, by Tom Barber, and some books by Gilbert Urroz, none of which have I seen. These notes could be expanded into a post-primer. -- Initial testing of a 50g implies that it operates indistinguishably from a 49g+ which has been loaded with a recent ROM. [Some CAS bugs have been fixed, though; the keyboard is softer [or just less worn?]; 4 AAA batteries provide longer power than only 3 AAA.] -- HORNER splits on powers of the default variable in "VX". This should be documented. Detto for all other such built-in commands (?like PROOT, PCOEF). -- Help menus are available for only the CAS commands (perhaps 35% of all the built-in commands). It would be very useful to have pop-up help for the great majority of commands. (Many commands in the CAS menu were obviously added later, because they overlap the non-help commands in either name or function.) -- Connecting the 49g+ by cable to a PC is very tricky. In particular, two of the instructions are easily overlooked: 1) to start the modem program on the calculator, one must click AND RELEASE the right shift before pressing the cursor-right key; 2) the last step is the highly unusual--"Disconnect the cable for a second or two, then reconnect it". Both should be highlighted. If Conn4X cannot connect to the calculator after it is turned on and in XModem Server, make sure that you have installed the USB software drivers, found in X:/Program Files/Hewlett Packard/Conn4X/USBDriver. [Where are these connect instructions? Now, I just connect the cable normally.] -- To copy an object between the calculator and the PC, invoke Conn4X, which will display a tree view of the calculator's directories, then open My Computer, for a similar view of the PC's files, and finally copy and paste between them. Conn4X does not seem to be able to copy to or from the extended memory ports, however. -- The use of "->" in functions is obscure; apparently, it stores the stack contents into the following list of variables, and makes them local. Also, other RPL commands can precede it, but none can follow after it before the "<<" marking the start of program. However, it can be used repeatedly, provided it is followed by a function definition, enclosed either with <<>> or with ''. -- To create local variables in a function, examine this example: << 0 -> a n << .. >> >> The 0 is stored as the initial value of local variable "n", while the input stack argument is stored in local "a". [And yes, the order of a and n is correct.] -- "Compiled local variables" are explained very obscurely in Ch. 1 of the Reference. Actual use of "<-n" seems to create a local variable of that name and purging it after use. Then variable <-n can be used in all subfunctions called inside the defining function. Sort of a semi-global variable, or one of dynamic scope inside the defining function. -- The use of ENTRY to change from ALG to PROG mode while entering is obscure. It permits the typing of algebraic elements onto the lowest stack line. A similar command is INPUT, which takes two arguments, a string for an invitation, and a list containing an initial entry string and/or a list of integers for positioning the cursor. -- In the EQW, I can find no way to copy in an algebraic from the stack. [Perhaps use RCL or some softkey?] There is a hint that a highlit expression can be copied to the stack, though. -- It might be mentioned that RPN is essentially postfix notation, similar to the prefix notation used by the programming language Lisp, but with reversed direction. E.g. Lisp (+ (* A B) (* C D)) is identical to HP's A B * C D * +. In particular, the use of "<< >>" is equivalent to Lisp's "lambda" notation. Note that HP's RPN does not need parentheses, since the number of arguments is fixed for each function. It might be noted that the compound looping & conditional statements, like IF THEN END and WHILE REPEAT END, use prefix notation rather than postfix (since e.g. the test-clause follows IF instead of preceding it). The low and high index values precede both START and FOR, but the index name follows FOR (and it must be unquoted; cf. SEQ, which requires a quoted index name). Similarly STEP differs from NEXT by being followed by a step value. The "->" marker for local variables inside a function definition also precedes its arguments. -- A histogram showing which are the most frequently used built-in commands would be helpful for directing learning effort. Because all commands from earlier HP symbolic algebra calculators are retained, there are numerous partial overlaps (e.g. TAYLR, TAYLOR0, SERIES). -- The most important TYPEs to check for are 2 (string), 5 (list), 28 (integer), 29 (array, i.e. vector or matrix). -- In the Guide, ch. 6, the Development Library, it should be clarified that the Saturn is the older microprocessor (developed by HP), and the newer ARM (developed by Acorn) emulates it; hence the separate modes of operation. Also, separators are from ASCII code "32 downwards" (not "below 32"), since 32 is the blank and is a separator. -- It should be made clear that programming can be done in any of 6 languages: User RPL (the normal high level sequence of built-in postfix operations); System RPL (also a postfix notation like User RPL, but with basic operations specific to narrowly defined object types, e.g. short integer vs. long integer); Saturn Assembler Language (vertical syntax using the basic machine operations of the HP Saturn microprocessor); ARM Assembler Language (vertical syntax using the basic machine operations of the Acorn RISC Machine microprocessor); and HP GCC (the GNU Compiler for a dialect of the C language, outputting one of the previous languages). User RPL is the easiest to program of all these, and also the slowest. The Saturn ran at 4 MHz, and the ARM runs at 75 MHZ, but Saturn code is emulated on the ARM. GCC is the highest level to program at (if one can abide the many warts and infelicities of C's syntax) but it lacks support in certain areas, such as I/O. According to the FAQ, a new language called HP Basic is included. This is more or less an algebraic version of User RPL, but considerably slower. Sample code is shown below: FOR(i,1,100) DISP(i,1); IF I+1-5==50 THEN DISP("Hello World",2) ELSE DISP("I'm off",2) END STEP(1) -- Neither DOLIST nor DOSUBS iterates thru the characters of a string nor to the elements of a vector. One must either convert to a list first or else loop and use DUP SUB (or GET). -- Very few built-ins pervade to the elements of a vector or array; I find only -, *, /, and the comparison operators. For others, one must use MAP or, more often, DOLIST or DOSUBS. -- Convert the head character of a string to/from its ASCII position with CHR/NUM. For iterating thru a string, adapt my SPL by inserting NUM XQ after SUB. -- How to assign a single built-in function to a user key with ASN? Entering DROP 21 ASN fails because DROP is executed. << DROP >> 21 ASN does assign, but the << >> are retained in the RCLKEYS string. (They can be removed by editing the RCLKEYS string, if desired.) Entering 'DROP' 21 ASN is a syntax error. [Cf. StringWriter?] -- ANS recovers the last argument or arguments. It is especially useful immediately after an erronous PURGE or STO. -- The "Last Stack" check box on MODES controls whether the last arguments are saved for ANS (which seems to be identical to LASTARG). (Message "LAST STACK DISABLED" is given if UNDO is clicked with this box unchecked.) This check box is apparently not saved in any system flag. (The system flags which seem to be related are -55 and -94.) -- Flag -74 toggles right/left justification of the stack display. -- The ANS command is described as able to retrieve ancient arguments, but only in algebraic mode. Why not also in RPL mode? -- To rearrange items in a directory in a particular order, go into FILES, and use the SORT command. Then press and hold down ENTER to mark the items from top to bottom and press ORDER. Only directories in Home can be permanently rearranged. However, the reordering display persists while in FILES. -- When using RENAME in FILES, the line is automatically in upper case mode. However, when entering the name for a NEW object in FILES, the line is in function mode, and ALPHA must be held down. -- Very few keys autorepeat when held down. The ENTER key in the FILES display does, and the cursor keys while editing. Most function and letter keys are single entry only, as are the SKIP-> &c. keys in the editor. -- The picture in the Guide for editing (in Ch. 2) shows softkeys apparently from the TOOLS key, but the middle two are shown as "RCL" and "STO" instead of the current "STACK" and "RCL". -- The Reference manual lists many time-related built-in commands as being accessible viaa the -> TIME TOOLS menu. In fact, there is no TOOLS menu under -> TIME, which has the built-ins directly. ============================================================================== Un- or under- documented behavior. -- Comments (text preceded by "@") may be appended to functions. They are apparently stripped from the stored definition, which vitiates their purpose as in-line documentation. (A final "@" is needed if the comment ends before the end of the physical line.) -- +/- (NEG) will toggle a choice on menus, but not on the system flags menu. -- When MAP runs, the current stack is ignored. It also leaves no stack results behind, which is shown as NOVAL. [Huh?] -- << SIZE >> MAP run on a list of lists applies SIZE to the innermost elements, not to the sublists. Similarly, << 7 + >> MAP run on a list of numeric lists will add the 7 to each element, rather than append it to each sublist. DOLIST or DOSUBS must be used for operating on the sublists. -- ENDSUB (used in DOSUBS) is not well-explained; it appears to be a number, the length of the original list minus the length of the sublist, plus 1. -- One must not use "=" in an IF command, but rather "==". Both this and the ambiguity of "+" are obviously modeled after the wretched syntax of the C language. -- The comparison operators (<, >, &c.) are all immediate execution keys, returning 1 (true) or 0 (false), except for "=". This latter produces an algebraic with the two arguments (e.g. "8=9"). Like the arithmetic functions ("-,*,/" but not "+"), the comparators work item-by-item. To compare scalars, one must create an algebraic with "==" in the center, and then EVAL it. -- More complicated are "!=" and "=" on lists. "!=" produces a single Boolean result (0 or 1) by comparing the lists as wholes; e.g. lists of different lengths will compare different (0). "=" is completely different; if the lists are of different length, it trips an error, else it produces a list whose members are algebraics 'A=B', taking item by item from the two lists. If item-by-item comparison for equality or inequality is desired, one must do: 2 << == >> DOLIST -- Factoring is flaky. ABS(X^2-1) cannot be factored, but without ABS(), it can. FACTORS on the equation 16*X^5-20*X^3+5*X+1=0, which is satisfied by X=COS(pi/5), produces { 'X+1' 1. '4*X+(-1+SQRT(5))' 2. '4*X-(1+SQRT(5))' 2. 4 -2. } Whence come the final "factors" of 4^(-2)? -- Certain variable names are reserved, especially "e" and "i", in addition to the list in App. D ("EQ", "STACKENV", &c.) They should have been marked with a special intial character, e.g. "$". -- The keyboard is very (almost fiendishly) complex. Permissible key combinations are: 1) press a key; 2) press one of the three shift keys (ALPHA, <-, or ->) and then press a key; 3) press ALPHA, then either the <- or the -> shift key, then a key; 4) press <- ALPHA (called "USER"), then one of the previous key combinations. Further, there is often a difference between: A) click and RELEASE a shift key, then click and release another key; and B) click and HOLD DOWN a shift key, then click and release another key, then release the shift key. E.g. right shift and the SPC key produces comma ",", while pressing and holding the right shift before pressing SPC produces semicolon ";". Although there is an appendix listing most such key combinations, there should be frequent warnings about this. (The shortcut reordering key combinations inside FILES are listed nowhere, nor are shift + cursor keys for rapid movement while editing.) -- The key combinations <- softkey to store into the name on the softkey, and -> softkey to recall it should be reversed, since the RCL function is located above (and in the left-shift key's blue color) to the STO button. However, a partial mnemonic for the current procedure is "Recall = red(dish)"; better, perhaps, is "Right = recall", "Left = leave (in storage)". -- ALPHA <- 7, 8 or 9 apply diacritics (` ^ " respectively) to the preceding letter, and so do ALPHA -> 7, 8 or 9 (' ~ x). A few letters (e.g. "a" and "o") permit all 6 diacritics. ("x" represents a diacritic which depends on the preceding character: ring, cedille, slash, &c.) -- Most characters can be used in constructing names; not permitted are any of the punctuation or function characters (such as capital Sigma) nor those with NUM values less than 32 (which usually have no graphic representation anyway). -- It is difficult to type certain characters. E.g. capital Sigma, as used in the built-in SigmaLIST, can only be typed by -> S within quotes; outside quotes, it executes immediately. Similarly for partial, integral, not equal, less than or equal, greater than or equal. Slash can only be typed by ALPHA -> Z, while +, -, * are just ALPHA plus that key. -- A solitary double quote (created by ALPHA -> *) begins string entry in the stack; a closing double quote will be automatically supplied. Normally, the pair of double quotes is created initially, and the cursor will be positioned between them. Similarly, single quote (ALPHA -> ') commences an algebraic. -- Insert/Overwrite while typing is toggled by the INS softkey in the line editor. -- ALPHA ALPHA locks the keyboard into upper case, while ALPHA ALPHA <- ALPHA locks the keyboard into lower case. Left shift used therein will produce the other case, while right shift will produce Greek letters. Similarly, <- ALPHA <- ALPHA locks into user-shift keyboard mode. A system flag can permit locking by only a single entry of the otherwise twinned keystrokes. -- The CAT list of all currently available commands is very long. A quick way to scroll down it is to enter the first few letters of a command. There must be very little pause between successive characters. Also, <- preceding the up or down cursor scrolls by a whole screen, and -> preceding up or down goes immediately to the top or bottom, respectively, of the whole list. -- Single brackets (of any of the four flavors) can be created by entering the matched pair, and then deleting the current or prior character. Alternately, unmatched double angle symbols (used for function enclosure) are also available at the bottom of the CAT list (use -> downcursor to get there quickly). Also, an unmatched single quote can be entered by ALPHA -> ', an unmatched double quote by ALPHA -> ", while ALPHA <- . will produce an unmatched colon. -- When typing characters inside double quotes, a double quote may be entered preceded by a backslash; viz. ALPHA -> 5 ALPHA -> *. Inside the editor, where the outer quotes are removed, a double quote may be entered by itself. (Backslashes preceding any other character seem to just produce that character.) -- Lists are more generally useful than vectors (arrays): they can be searched, "mapped" (operated on item by item), catenated, &c. They can hold numerics, alphabetics or functions. Arrays can hold numerics or algebraics, but not alphabetics. For matrix arithmetic, however, arrays are required. It is also probable that arrays run faster than lists because of their rigid construction. A scalar can only be multiplied by a vector (i.e. in that order on the stack); a vector can be multiplied or divided by a scalar (in that order); addition, multiplication, evolution &al. cannot be done between a vector and scalar in either order. Lists and scalars can, however, be combined with most operations in either order. -- It is easy to convert a vector to a list, by ARRY-> EVAL ->LIST. From list to vector is LIST-> ->ARRY. Cf. AXL. -- EVAL on a list merely enstacks the items (like OBJ->, but without the final count); it does no further evaluation. V-> does the same to a vector. To convert a string to stacked single characters requires a function; cf. SPL above. Additionally, EVAL will execute defined functions in the list; beware! -- AXL. Converting a matrix to a list of lists is easy; the reverse might not work, because of differing lengths of the sublists. -- NUM & CHR convert Ascii characters to/from their ordinal integer equivalents. Note that NUM on a string operates only on its head. -- MAXR is the largest number, and MINR, the smallest. (Do not confuse MAXR with "infinity", which is not a number.) -- Some shortcut functions: NIP is SWAP DROP. ROT is 3 ROLL. DUP2 copies the lowest two items in the stack--it is different from DUP DUP; however, DROP2 is the same as DROP DROP. -- Units (e.g. meter-kilogram-second). Creating new units is tricky. Consider creating a new unit of length equal to the earth's radius (e.g. for use in rocketry). Because the kilometer was defined originally as 1/40,000 of the earth's circumference, the new unit (call it 'Re') can be created by 4E4_km/(2*PI) 'Re' STO One can then write the diameter of the earth as 2_Re. However, this unit cannot be converted to standard MKS values with UBASE because it involves symbolic computation. One must insert ->NUM before 'Re' above to make it convertible. Also, to put it on a softkey so that it has the same three-way utility as the built-in units [push to multiply by it, right-shift and push to divide by it, left-shift and push to convert to it], one must place a value including it (such as 1_Re or 2_Re) in a list in the CST variable, and then load that variable into the softkeys with CUSTOM. Note that CST must not contain merely the name of the new unit (e.g. 'Re'), for then the custom softkey will treat it as an ordinary variable, and it can be overwritten with left-shift push. -- ?? An algebraic expression with a leading unit will (sometimes) evaluate a trigonometric expression of a variable, if that variable has a numeric value, but will not alter other expressions of numeric values. E.g. 1_d*SIN(X) is annoyingly changed to its numeric value, losing the symbolic nature; however, '(1_d)*SIN(X)' stays unchanged. [?? Cannot reproduce this] -- Addition vs catenation. Using "+" for both addition and catenation was a design flaw, following in the mistaken footsteps of languages like C. To permit unambiguous catenation, two more built-in functions were then provided, "ADD" and "AUGMENT". Even so, these three overlap inconsistently in their functionality. "+" adds arithmetically on scalars, algebraics and arrays, but catenates lists and strings. The description in the reference for "+" is coy about the fact that it performs catenation rather than arithmetic on lists and strings. The text never mentions it, tho the examples illustrate it. ADD is supplied for arithmetic addition of same length numeric lists, but in fact, it is just "+" applied down 1 level on sublists. Cf. these examples: {"A"} "B" + produces {"A" "B"} {"A"} "B" ADD produces {"AB"} {1 2} {3 4} + produces {1 2 3 4} {1 2} {3 4} ADD produces {4 6} {{1 2} 3 4} 7 + produces {{1 2} 3 4 7} {{1 2} 3 4} 7 ADD produces {{1 2 7} 10 11} {{1 2} 3 4} 1 << 7 + >> DOLIST produces {{1 2 7} 10 11} {{1 2} 3 4} << 7 + >> MAP produces {{8 9} 10 11} {{1 2 {3 4}} 5 6} << 7 + >> MAP produces {{8 9 {10 11}} 12 13} However, going another sublist level deeper, {{1 2} 3 4} 1 << 7 ADD >> DOLIST produces {{8 9} 10 11} {{1 2 {3 4}} 5 6} 1 << 7 ADD >> DOLIST produces {{8 9 {3 4 7}} 12 13} In short, ADD sometimes adds and sometimes catenates. A certain way to perform addition to a list is to subtract a NEG'ed (+/-) argument (scalar or simple list). However, if any list argument contains sublists, then a simple built-in operation like "+" or "-" fails, and MAP or DOLIST must be used. AUGMENT catenates its two arguments. However, it fails if its arguments are a vector and a list, but succeeds if those arguments are swapped. It also fails if the lower argument is a scalar. A better name would be "APPEND", which carries no hint of arithmetic. I can find no single operation to catenate scalars or vectors. "AUGMENT" stacks vector arguments into a matrix, "+" adds them numerically, "COL+" applies only to matrices. Either the vectors must be converted to lists, then "+"'ed or "AUGMENT"'ed, then back to a vector, or they must be converted to 1 row matrices, and then joined with "1 COL+". See "CAT", which I wrote to perform catenation and never addition. -- List and array elements can be algebraics (e.g. 'SIN(X)' or 'X=0'). Strings can be elements of lists, but not of arrays. -- The stack can be displayed in either the selected large font or in the selected mini-font. However, the display of line 1 (the lowest) is controlled separately from the other lines. System flag -80 controls which font to display line 1 in, while system flag -72 controls the font of all other lines. -- MODE DISP permits selecting a display font. But altho "Browse.." is an option, and the manuals hint that user-created fonts can be loaded, no technical descriptions can be found which detail how to build such a customized font. (A font with a non-Western alphabet might be handy.) The following information was determined by trial and error. Two fonts are loaded and in use at any one time. The smaller font has characters 4 pixels wide by 6 high; it is always used for softkey labels, in the MODE display screens and in the FILES manager. As an object, the smaller font comprises 774 bytes (stored 3 bytes apiece per character). The larger font has characters 6 pixels wide by either 6, 7, or 8 high. It comprises 2065 bytes (at 8 bytes per character). Either font can be loaded or saved at will (with built-in commands ->MINIFONT, MINIFONT-> for the smaller, and ->FONT, FONT-> for the larger) and can be declared for display use in the stack or the various editors (on the MODE DISP screen). Characters of the larger font can be easily modified by a built-in character editor (inside EDITB or down-cursor). The smaller font must be converted by a program into a temporary 6x6 larger font before it can be edited that way. (Cf. my MF2SF and SF2MF programs.) Font objects can be created as follows. First, select the base font that you will be modifying; display it with MODE DISP CHOOSE OK OK. If it already resides inside a font object, then RCL the font object to the stack and execute ->FONT. Next, execute the CHARS command to display all 256 of the font's characters. Move the cursor to the character to be redesigned, and press softkey F4 (MODIF). This permits the period key (.) to toggle the pixel under the cursor. ENTER will save the modified character. After modifying any number of characters, exit the CHARS display with the ENTER key. Now execute command FONTx, where x is the size of the font that was just altered (x=6, 7, or 8). (Or FONT->.) The modified font object is placed into the stack and may be STO'red under any name. Characters are all 6 wide, and their height is indicated by the name of the font (6, 7 or 8). Even more simply, place the font object in the stack and edit it by pressing down arrow. After editing characters, save the object for later use. Again, the mini-font can only be edited by first converting it to a standard font with my function MF2SF, editing it as described above, and then applying my function SF2MF. NOTE: the current loaded fonts will be replaced by default fonts when a warm-start (ON & F3) is done, so save your modified font before that happens. Once created and stored in RAM or flash memory, it can be reloaded automatically after a warm start by putting << fontname ->FONT >> into the system variable STARTUP. Finally, the built-in command UFL1->MINIF will convert a "Universal Font Library 1 font" into a minifont. [See the HP48 UFL in the hpcalc.org collection, and also StringWriter, for entering foreign alphabets.] I have found no technical information about these fonts. Any size of font can be converted into a senidenary string with the H-> command of library 256. After a short header (34 nybbles for the large font, 12 for the small), the characters are represented in a manner very similar to that of GROBs. [Should check how close the similarity is.] User keyboard keys can be ASN'ed with 1 character strings, so that pressing them will insert that character into the current entry line. The ASCII code points from 1 thru 28 are not in use, and can be filled with a new alphabet. Also, a score of characters in the ASCII range between 128 and 192 are of dubious utility (e.g. the fractions and superscripts), and can be replaced with new characters. I have modified the default fonts to include the complete Greek alphabet, and have assigned them systematically to the ALPHA keys on the programmable USER keyboard. Finally, the styles option for strings (available on the softkeys in the main editor) can produce Bold, Italic and Underlined variations on characters; they are apparently created algorithmically from the base characters. -- The system 7 font has a design flaw, in that many of the characters were seemingly created by clipping off the top row of the corresponding system 8 font characters. Also, scattered characters in the various fonts are poorly drawn; e.g. "pi" and "Pi" in the standard minifont have a gap in the left leg; "at" in the minifont is illegible. I have corrected all the flaws I have found. -- The chess pieces in the user area C program are 7x7 bits plus a 0 border to right and below, so that they exactly fit into 8 bytes each, like a FONT8. -- Where in the font is the character of two vertical pixels, used to indicate multiplication in large fonts? Also, where is the icon of square root of x used in CHARS to indicate how to create the root character? And how is square root of square root drawn? [And the heavy brackets for array display.] Are these characters available to the user? -- The display area height can be altered by two commands: ->NDISP sets the height of the display (up to 12, instead of the default 9), while HEADER->/->HEADER can be 0, 1 or 2, to leave room for the header icons. 12 ->NDISP should be placed into the reserved variable STARTUP, which is executed at warm-start, while header size could be changed in STARTED, the editor initialization object, and restored in EXITED. However, the CHARS display never uses the top 2 lines. -- Reserved variables alphaENTER and betaENTER are executed before and after, respectively, the press of the ENTER key. Reserved variable STARTUP contains commands to be run immediately after a warm-start. These variables are best placed in the HOME directory; use ORDER in FILES to place them inconspicuously after all other items. [I cannot get them to work.] -- Object names are sought down the current path to the Home directory automatically. In addition, objects in any directory are accessible with list notation (see below). So are backup objects, kept in port memories :0:, :1:, :2: and :3: (respectively RAM, Extended RAM, flash and SD card). Just prefix the port number (or initial) tag to the object name when referring to it. (:H: refers to HOME.) :&: will search all ports for the object. Both RCL and STO can be used on simple object names prefixed by port numbers. -- Note that the SD card (port address :3:) has enormous storage capacity (1 Gbyte), more than a thousand times as large as the other ports combined. Although they may take longer to retrieve, large objects should be stored on the SD card. They can only be STO and RCL accessed in the top directory, however, altho whole subdirectories can also be stored there. (Beware however of accidentally reformatting the SD card, by pressing FORMA in the FILES tree display.) However, libraries may not usefully be stored on it, and it does not appear on the LIB menu; it can only be examined from inside FILES. -- I referenced :2:{FONTS grk8font}, but directory FONTS was not on :2:, so the home directory object {FONTS grk8font} was retrieved instead. This appears to be an undocumented search down a path toward home. [Did not occur on another object that was on both ports.] -- On the 50g calculator, the documentation claims that objects on the SD card (port :3:) may have a complete descending path, with names separated by back-slashes, e.g. :3:"UTIL/PHI" RCL or :3:"UTIL/PHI" EVAL, but may not use the name list form, viz. :3:{UTIL PHI} RCL. [By experiment, I cannot make back-slashed path work on either my 49g+ or my 50g; using '/' instead fails by trying to perform division. Also, neither single nor double quote works. I use list notation instead.] -- I can EVAL functions on :3:, but cannot RCL their definitions. Both work for :2:. -- The various restrictions on storing, recalling, editing, and building subdirectories on the various ports make them unsuitable for normal use. In general, they are useful only for back-up storage, and for execution or recall of large objects. But port :0: should never be used, since it steals RAM from the HOME directory. :1: is also RAM, but is only useful for backup and storage of library objects (such as CRLIB creates). Large object retrieval from :1: is no faster than from :2:, even tho :1: is RAM and :2: is flash memory. :1: should be redesigned out of existence, and the RAM given to HOME. And :3: should be given the same functionality as :2:. This overcomplex scheme of :0:, :1: and :2: seems to be an atavism of the old HP48 memory partitition design. -- A function in any directory can be executed, but clumsily. E.g. to execute IOTA in directory APLUTIL: { APLUTIL IOTA } EVAL However, the current directory will be reset to APLUTIL. To prevent this: PUSH { APLUTIL IOTA } EVAL POP Alternately, functions on other ports can be executed without changing the current path: :3: IOTA EVAL or :2: {APLUTIL IOTA} EVAL Values can be similarly retrieved from any of the ports (:1:, :2:, or :3:), by inserting the disk and name, and then EVAL. In addition, a name list can be executed from any port (including :3: with the latest ROM); e.g. 8 :3:{APLUTIL IOTA} EVAL. [The name list feature on :3: fails intermittently.] -- A user-written function can be added to the catalog, making it generally available, by building a library holding it, and then attaching the library to the HOME directory. (Or, attaching the library to another directory makes it only available to that directory. This is parallel to the way a function in the HOME directory is available everywhere, but not a function in another directory.) A library is created with CRLIB from inside a specific directory, and then STO'red to and port, except, apparently, 3. In practice :0: should never be used, and :1: or :2: is preferred. Then (usually while in the home directory), issue ### ATTACH, where the library number must agree with variable $ROMID. Include a list in $VISIBLE and a title in $TITLE (starting with a 5 letter softkey label). Note that CRLIB is available only by attaching library 256, which apparently can only be attached to HOME. Note that library 256 is not visible under FILER, but it can always be ATTACH'ed. A simple user function to (re-)create a library from a directory is [[CREATE]] Warning: when creating a library, the error message "$VISIBLE INVALID" means that some name listed in variable $VISIBLE does not exist. Detto for $HIDDEN. The documentation claims that by placing a library variable into either :0: or :1: that it will automatically be attached at warm boot time. (Don't use :0:, tho, for the reasons stated elsewhere.) How to make a library autoattaching? :1: is a good place to store library variables, since it is otherwise nearly useless. Bad design flaw: when creating a new version of a library, with additional objects, previously created defined functions (as on user keys) may suddenly point to different objects within the library. Apparently, pointers to numerical positions in a library are compiled (as "XLIB ##") and if the library subsequently changes, then the function definitions referring to them must be reopened and then closed anew. The objects affected are those which follow the newly inserted one in the $VISIBLE list. Therefore, only add items to the end of the $VISIBLE list when recreating a library; do not delete items in the middle of the list. Otherwise, the already compiled pointers will point to the wrong items in the list. If this happens, you must edit and correct the names of library functions in functions that call them (the names will have been changed). The order of items in the $VISIBLE list can be changed and the library recreated, but only if all functions that invoke those items are first saved in string format. This is simple but tedious: RCL a whole directory (as by -> and then pressing the directory softkey), apply ->STR to the directory display string, and then save it under a temporary name. After the library has been recreated and attached, the string must be converted back with STR-> and saved into the directory name. Be sure to convert user keyboard definitions as well as explicit functions. More simply, download the entire library and all code that uses objects from that library to a PC. Then edit the $VISIBLE list on the PC file, and upload back to the HP calculator. Also when a library is recreated, running of programs that use functions from it may fail, showing the name of a library function with single quotes around it, as tho it were the name of a variable. The correction is to re-edit and re-store the program definition; apparently, this recognizes the new ?internal ?addresses of all the library functions. -- Instead of a library, one can create a CUSTOM menu which invokes functions stored in back-up directories on the ports. -- In RPN mode, PI COS ENTER displays -1, while in ALG mode, COS(PI) is displayed without numeric evaluation. -- ->STR on a number only saves the displayed portion, not the hidden decimal places. -- The default variable named in CASDIR/VX is immediately accessible with the built-in commands RCLVX and STOVX. Also, STEQ is the same as 'EQ' STO and RCEQ is 'EQ' RCL, but they reference variable EQ only in the current directory. -- ARCHIVE does backup of the HOME directory, the user-key assignments and more in a fixed object. But is there a more general command, perhaps named BACKUP? -- TABVAL is just SUBST of a list of values for the current variable into an algebraic. -- MENU saves the argument list into CST and then displays it on the soft keys. TMENU just displays it. -- The 48gx included RULES and user-defined patterns for symbolic manipulation. Is there any replacement for these in the 49g+? [They do not appear in the Emu48 emulator, either.] [Yes, they do exist--|^MATCH and |vMATCH, for simplification and expansion, respectively. However, they only work on patterns which are adjacent in the internal binary tree structure of the algebraic, which can be shown by turning on flag -52 ("display redundant parentheses"). E.g. if 2*SIN(X)*COS(X) will be recognized as a pattern, then 2*B*SIN(Z)*COS(Z) will not, because of the intruding "*B". Partial solution: create patterns only for single terms, like { SIN(&X) SIN(2*&X)/(2*COS(&X) }, which will replace a single SIN() term by the double angle formula.] [NOTE: create character "&" by ALPHA <- ENTER.] -- The Conn4x software, which up/downloads objects viaa a USB cable between a PC and the 49g+, can transfer objects in either binary or text mode. The latter format is quite readable and writable. After a simple header line "%%HP T(..)F(,..)A(..)", the objects are written out with simple ASCII. Special characters are marked with a backslash, preceding either a number from 0 to 255 or preceding a digraph, such as \<< and \>> for program enclosers. The binary format is as yet undeciphered. An example of an uploaded function: %%HP: T(3)A(R)F(.); \<< { 'Re=(40000._km)/(2*\pi)' 'Me=5.977E24_kg' 'Se=\pi*2_Re/d' 'G=.00000006668_dyn*cm^2/g^2' 'g=G*1_Me/Re^2' '\Gm=g*1_Re/Se^2' } \>> NOTE: "\Gm" is Greek lower case "mu". Many other backslash abbreviations exist. An example of an uploaded list: %%HP: T(3)A(R)F(.); { 2047 '-11974437/691' '31092673/691' '-22432587/691' '-7706534/691' '6399960/691' } Such files can be readily created on the host, and then downloaded. Binary files can also be created on the host, but their internal format is unknown. -- The Conn4x connection software may fail during an up- or download with messages like "Canceled by user" or "Missing variable". The cause is probably that the Home port (the main RAM storage area) has too little storage left for its operations (less than 80K say). Since objects can only be up- or downloaded viaa Home, do not overfill it, and transfer objects a few at a time. -- In the FILES tree display, the CHDIR softkey (after XSEND) resets the current directory outside to the directory being examined herein (i.e. the directory as listed in the header). CHDIR on entry to FILES will set the current directory to the one pointed to by the cursor. The built-in key UPDIR moves the vantage point up one directory, as does left cursor, while cursor right on a directory entry moves the display down into that directory. Other useful but undocumented key combinations exist. To reorder ("SORT") the display of the objects: right shift forward alphabetizes, left shift backward alphabetizes, when followed by N, S, or T (by Name, Size, Type, respectively). S and T alone also reorder, but N by itself does nothing. Also, shift of the cursor keys permits fast scrolling and jumping to top and bottom (except in VIEW). Others are MODE (=HEADER), VAR (=LIST), +/- (=ENTER), and the numbers 0, 1, 2, 3, which show the contents of the respective port. HLT suspends the FILES display and shows the stack; to return, one must push CONT (continue), which is <- ON. There is also no way to open a directory on port :3:; it must be copied to home to be examined. -- VIEW is a read-only listing of an object, without editing capability. Even the fast cursor movements are unavailable. [Do not confuse VIEW with VISIT, which is an editor.] -- Editing a directory object permits global searches and changes to it. However, it can only be saved to a directory with an unused name. When EDIT is done to a directory inside FILES, then attempted exit will just leave it in the stack with the intended name. Afterwards, the old directory can be PURGE'd and the new directory RENAME'd. (Note that a non-empty directory can be PURGE'd only inside FILES; from the stack, it will be an error.) -- Right shift and left shift of the right and left cursor keys jump to end or beginning of the text or line, respectively. Right shift of the up/down cursor keys moves the cursor to the top or bottom of the screen or, if already there, scrolls the screen. Left shift of the up/down cursor keys moves the cursor to the beginning or end of the current item, respectively. Similar effects occur inside the FILES display. Right shift and left shift of the SKIP and DEL keys in the line editor will skip or delete to the end or beginning of the item. -- Fast cut and paste can be done by not setting the hilight boundaries with -> BEGIN and -> END. Clicking -> COPY when no bounds have been set will clear the clipboard. Then, clicking -> CUT removes the whole current line (like the tool key "DEL L") and appends it to the current clipboard contents. This can be repeated, to catenate several lines. -- If SEQ finds the starting index value exceeds the final value, then it returns a list holding just the starting value. -- SEVAL. Evaluate an algebraic except at the highest level. -- SHOW. For a given name, make implicit references to it into explicit references. -- SIZE of an object returns a real number, which is noxious, since use of a real number [ending with a decimal point] instead of an integer in an algebraic prevents many symbolic operations. (In fact, using a variable with a numeric value in an algebraic also prevents their use.) Convert a real number to an integer by XQ. Further, SIZE of a vector is a list of a real number, which may be converted to a scalar by EVAL. Real numbers 0.0 and 1.0 are also returned by the comparison and Boolean operators. SIZE returns the number of items of a list or vector, but on an integer, it returns the number of denary digits; SIZE on a floating point number is 1. SIZE returns 1 for binary integers, but for regular (indefinite precision) integers, SIZE returns the number of digits. Further, SIZE of 0 is 0, while SIZE of #0d and of 0.0 is 1. -- SORT. Reorders lists of lists by the 1st element of each sublist. This permits reordering the rows of a table by its first element. -- SST is not in the index to the Reference; its description must be sought viaa a mechanical search. It is in fact a softkey used in debugging to single step thru a calculation, and is found in the PRG/RUN menu (menu 41). -- 'B' 'A' STO has a quasi-synonym effect: now any changes to B will appear when A is evaluated. However changes to A will NOT affect B, so this is not a true synonym feature. Cf. ByVal and ByRef in VB, or assigning a function to a name in Javascript. However, if a name is stored inside a variable which is referred to in a function definition, then it must be explicitly EVAL'ed when so used. -- For RCL (but not for STO), a directory name can precede an object name in the argument list. E.g. {CASDIR EPS} RCL. (This does not reset the current path.) So variables anywhere can be referenced. The leading directory name may have to be HOME, as otherwise the current directory is used as a starting point. These name lists can be prefixed by port numbers. By experiment on my 49g+ and my 50g, :3:, the SD card, has subdirectory referencing, but it is unreliable; e.g. I can retrieve :3: {FONTS grk8font} but not :3: {FONTS GRKAB}. [Many nonreproducible failures in doing RCL upon path lists to functions, both on HOME and on :2:. EVAL seems always to work, however. Also, RCL of objects always seems to work.] -- Matrix and vector notation is permissible in algebraics: e.g. 'V(I)' will EVAL from or STO into the I'th element of a stored vector or list named V. I can be a variable name or an integer constant. EVAL is the same as << 'V' I GET >>, while STO is the same as << 'V' I ROT PUT >>. Matrix elements can also be indicated, e.g. 'M(2,3)' or 'M(I,3)'. RCL cannot be used. Vector notation works on a list of numbers, but fails on a list of strings. The APL notation "[I;J]" could be interpreted as subscripts for either arrays or lists (or lists of lists). More generally, an integer list or vector can appear in place of scalar subscripts in order to indicate a subvector/list. -- Arrays can contain numbers or algebraics (in single quotes); they cannot hold (doubly) quoted strings. -- Lists and strings can be empty (i.e. SIZE = 0), but vectors cannot. Many built in functions fail on empty lists or strings, and some iterators (e.g. STREAM) fail on singletons (i.e. SIZE = 1). -- One cannot GET a member of a list stored in a port. This means that the whole list must be first brought onto the stack before GET will work, which can use up a lot of storage unnecessarily. Better to store large objects in a directory on a port instead of inside a list on a port. -- One cannot store into lists or directories on a port. They must be copied to HOME, updated, and copied back to the port. -- STORE evaluates, while STO doesn't (?) -- STO+, STO-, STO*, STO/. Updates the named stored variable. The variable name and the stack value are combined in that order. Note that the named variable can occur in either position. [I keep getting "ARG TYPE ERR" for many attempted STOf executions.] -- STO+ &c. are fussy about their arguments. Scalars are OK, but lists are not. -- SNEG, SINV, SCONJ. Applies one of the inversion operations to a stored variable of a given name. Cf. STO+ &c. -- ->Q (on CONVERT/REWRITE) is peculiar. In particular, it tries to approximate only the visible digits of a number to a fraction. E.g. display pi in FIXED 6 format, and ->Q will output 355/113. ->Qpi can detect simple square roots, but not square roots plus constants, e.g. phi (= SQRT(5/4)+1/2). -- XNUM & XQ convert rational expressions to/from real numbers. They are slightly more powerful than ->NUM & ->Q. ("X" represents "convert".) -- EPSX0 converts tiny numbers (smaller than {CASDIR EPS}) to true 0. -- The GROB command must be followed (not preceded) by three arguments: the width in pixels, the height in pixels, and a string of senidenary "nybbles". For example, consister a "bend sinister", a line running from top-right to bottom-left, inside a 9x9 pixel box. To represent it for GROB, first expand its width to the next larger multiple of 8 by padding each line on the right with 0's. (1 means on, 0 off.) Then break each row into groups of 4 bits. The top row will be 0000 0000 1000 0000, the 2nd row 0000 0001 0000 0000, down to the bottom (9th) row, which is 1000 0000 0000 0000. Now replace each group of 4 bits by a senidenary digit, a "nybble", from the set {0, 1, 2, .., 9, A, B, C, D, E, F}. However, the nybble is the binary representation of the group of 4 bits in reverse order; e.g. 0001 is replaced by 8, 0010 by 4, 1010 by 5, &c. Catenate the nybbles in all rows, from left to right, then top to bottom. The complete command will then be GROB 9 9 008001000200040008001000200040008000. A GROB can be converted from its graphic to its numeric form by making it into a list of length 1 (execute 1 ->LIST), and then editing the list. The senidenary string may then be edited directly while inside the list. Apply EVAL to the list to convert the GROB back to a scalar. Even more simply, apply ->STR to a GROB, edit the resulting string, and apply STR-> to recreate a GROB. -- A label or icon (of shape GROB 21 8) can be put into a menu by a sublist, with the label preceding the function for the softkey. -- A number of built-in functions can manipulate and display GROBs. E.g., GROBADD catenates two GROBs together vertically. To catenate two GROBs horizontally, one can use GXOR to OR the 2nd GROB onto the 1st at a specific pixel coordinate. LCD-> and ->LCD will display and read back a GROB; however, the read back GROB is always in shape 131 wide by 80 high, and must be trimmed of its excess 0 (blank) pixels. -- CHARS displays below the 2 header lines; even if not filled, it does not use them for display. Also, the MOD'ify feature is not available when CHARS is invoked inside an editor. -- TOOLS displays different menus, depending on whether the stack line is being edited. If it is, the editing menu is shown (with SKIP->, DEL->, &c.) Else, it puts up a mostly redundant menu (see below). It does nothing inside EDIT, despite the existence of a TOOLS softkey therein. -- Some built-ins violate normal postfix notation (VP) or violate normal quoting notation (VQ) or both. E.g. the localizing arrow (VP, VQ); IF (VP); FOR (VP, VQ); GROB (VP) -- Tags (decorative strings) may be applied with ->TAG and discarded with DTAG. A tag on a number is ignored by arithmetic operations, by GET and by PUT, but it must be discarded before executing POS. -- EDIT always uses the text editor on an object; EDITB will use the Best editor (e.g. the Matrix Writer for an array, or the Equation Writer for an algebraic or the CHARS/MODIFY editor for a system font). On a font object, EDIT simply displays the font title, but EDITB permits editing of every character. -- FILER (the file manager program, also invoked by the key combination <- FILES) has some undocumented softkeys: SLOW/FAST, EXEC, TOOLS, HALT. HALT interrupts the editor, and <- CONT will resume. SLOW/FAST controls the speed of the cursor. EXEC appears to enter a hilit region into the stack, altho quoted algebraics are in error. TOOLS brings up a blank softkey menu, suggesting that the user can supply the key definitions. (If so, how?) Also, the EDIT key will recursively edit a hilit region, but leave the results in the stack, not returning them to the original site. There are also the FIND/REPLACE and GOTO features. -- DOLIST and DOSUBS (?and SEQ) may produce NO output instead of a list with 0 elements. This empty list case must be checked for explicitly. By contrast, MAP will produce NOVAL as a placeholder if no value is computed. One trick is to force the first element to result, then apply TAIL to the output list. DOLIST, DOSUBS and other commands give errors if the input list has 0 elements. They should produce an output list of length 0. -- HEAD on an empty list causes an error. Either execute HEAD inside IFERR or else append {} or "" to the argument of HEAD first. However, TAIL on an empty list outputs an empty list. -- [!!] Integer arithmetic can have an unlimited number of digits; floating point arithmetic is limited to 12 significant digits. Note that R->B passes thru floating point internally, because no more than 12 denary digits are converted. -- << "aa" PROMPT >> will invite the user to enter an expression, which will immediately be executed. << "aa" "" INPUT >> will invite the user to enter a string, which will be left in the stack. (Exactly parallel to APL Quad vs Quote-Quad input.) -- TYPE of an array will be 3, 4 or 29, depending on its elements (all float, all complex, any integer). Similarly, a number will be TYPE 0, 9, 10 or 28 as it is (float, complex, binary, integer). -- VTYPE vs TYPE: the former returns a number for the variable named inside the quotes; the latter is the type of the item itself. -- OBJ-> on 'X+2' has TYPE 18, which is nowhere documented. -- What is the type named "GNAME"? [TYPE 6, a non-executible string 'name'.] -- Copying objects to port :1: (auxiliary RAM) places them in reverse order of insertion. They cannot be re-ordered, stored or edited, but can be recalled or executed. -- S~N (in the APPS/Development Library) toggles a quoted name between single and double quotes. -- ->S2 and ASM toggle a program between User RPL and System RPL. -- An odd behavior of RDM is that [1 2 3] {4 5} RDM outputs {[4 4 4] [5 5 5]}. -- Compute 5 99 ^ as a long integer, and then take LN of it; the result is immediately converted to 99*LN(5). However, nothing happens with LOG. -- In the MatrixWriter, the Enter key automatically moves focus to the right. Is there a simple key or key combination to start at the left of a new row? -- EVAL will open a list of objects into the stack, but will evaluate a non list expression. -- OBJ-> on a lambda expression (i.e. one enclosed in <<>>) and possibly on a single-quoted algebraic expression will stack a number of unlikely objects, including a bare "+", which is of TYPE 19. -- PICT is a very odd command, as it merely places the (unquoted) name PICT onto the stack, after which either STO or RCL can be used. The internal object of that name is apparently just a kind of GROB, and the built-in functions to display (PVIEW or PICTURE) it are overlapped by the (newer?) functions that work with GROBs. -- EDITB is equivalent to down arrow, and will graphically edit a GROB on the stack. Use EDIT instead to edit a GROB as a character string. In the graphic editor, -> and the arrow keys will quickly emplace the cursor at the borders of the display. However, the only way to exit is viaa CANCEL, and that always extend the GROB to a size of 131 by 80. -- ->LCD displays a GROB on the display, but for only a flashing moment. It must be followed by a WAIT command to extend the time of display. Best is 0 WAIT, since that will only return when a key has been pressed, and the key may be used to trigger a function. The clock should be turned off, as it will overwrite the display. (System bit -40). -- If a line in the stack editor has unclosed punctuation pair (e.g. no final quote, parenthesis, bracket or brace), one will be supplied automatically. Either blanks or commas can be used to separate items within brackets of all kinds. -- []*{} and []%{} perform (undocumented) fast combination of the vector by each element in the list. -- The Boolean functions NOT, AND, OR, XOR operate on character strings and binary integers on a bit by bit basis. Either type offers compact storage of binary data. [Packing & unpacking?] -- Pressing ALPHA inside FILER toggles something called "SEARCH MODE". What is it? -- A new command in the 50g, semicolon (";"), acts like DROP unless nothing is in the stack, in which case it quietly does nothing. ============================================================================ Quirks of built-in functions -- S~N (in the APPS/Development Library 256) toggles a quoted name between single and double quotes. [However, the single quoted string is NOT an algebraic expression of TYPE 9, but a mere name of TYPE 6. However, it can be an element of an array, which (double-quoted) strings cannot. Also, it can include all characters, even those illegal in an algebraic expression.] Algebraics can be created with ->ALG which takes its arguments from the stack, such as are produced by OBJ-> or COMP->. -- OBJ-> parses an algebraic at only one operation; COMP-> does a full decomposition. (The results are different however.) '2+3*4+5*6': OBJ-> replaces this by 4 objects in the stack: '2+3*4' '5*6' 2.00 '+', while COMP-> replaces this by 10 objects in the stack: 2 3 4 '*' '+' 5 6 '*' '+' 9.00 -- COMP-> ->LIST will parse an algebraic into a list. ->ALG does the reverse. -- A program <<>> or algebraic '' can be transformed to a list with ->LST, and thence to splayed items in the stack with OBJ->. The TYPE of each item can then be determined (e.g. 'COS' TYPE is 18, 'IF' TYPE is 19, except that '..' cannot be used this way). -- Characters with ASCII code < 32 can not be used in expressions or names. Maybe also ASCII 127. -- value 'OBJNAME(index)' STO works only for list and vector objects, not on matrices. However GET, PUT and SUB do permit linear indices for matrices, which are treated as being in row-major order. -- SIZE, used e.g. in DOTa, yields number of bytes when applied to a long integer; use CARD or SIZEa instead. Also the SIZE of 0 is 0; use SIZEa instead. -- {} EVAL leaves nothing on the stack -- EVAL n ROW-> to convert [?a list] to a matrix. [AXL is faster] -- "" STR-> is similar to '' EVAL , except that many expressions are not permitted by STR->. -- Anomalous edge behavior: HEAD and TAIL operate correctly on strings and lists of length >=0, but fail on scalar numbers and on algebraics. Sigma-LIST fails on lists of length <2. DOLIST and MAP fail on lists of length 0. [What of DOSUBS? STREAM?] [Use my MAPa, HEADa &al.] -- Neither TYPE nor VTYPE will determine the system type of a name in double quotes. I am writing one, called WTYPEa. How to get type 19 for "CLEAR", inter aliaa? [This is much harder than it seems; I cannot distinguish "commands" like IF or CLEAR from "functions" like TAN.] -- Where are these commands mentioned in the 50g Reference: MOLWT, TRG*, ->TRG? The entire RULES menu system for hand-manipulating subexpressions in the Equation Writer has now been made automatic. The trig identities are now under SIMP in the Equation Writer, but it is not clear how to invoke them explicitly. Other identities can be hand-crafted using /^MATCH; they can be executed against subexpressions inside the Line Editor by extering their name after the subexpression (in '') and then pressing EXEC in the Line Editor. Tedious but effective. Once, I pressed ENTER instead and it acted like EXEC. [MOLWT is apparently part of the HP Periodic Table Library.] -- All symbolic trigonometric identities are now commands, many of which are in the TRIG menu. They fall into pairs of commands which invert each other; the names do NOT indicate this. They are: Example of Identity Paired Commands --------------------------------------------------- sin(x) <> tan(x/2) HALFTAN TAN2SC2 tan(x) <> sin(x)/cos(x) TRIGTAN TAN2SC sin(x)^2 <> 1-cos(x)^2 TRIGSIN TRIGCOS cos(x)^4 <> cos(4x) TLIN SIMPLIFY sin(x+y) <> sin(x)cos(y) TCOLLECT TEXPAND exp(ix) <> cos(x)+isin(x) TRIG SINCOS asin(x) <> acos(x), atan(x) ASIN2C ACOS2S ASIN2T ATAN2S x^3 <> exp(3 ln(x)) EXP2POW exp(2x) <> exp(x)^2 TSIMP ln(x)+ln(y)<> ln(xy) LNCOLLECT -- Apparently, l'H“pital's Rule is built into the 'lim' command. -- DOLIST operates only on a list, not on a scalar. MAP can operate on either. -- MAP and some other functions use VX and will purge the variable named therein (default is 'X') when they run. Use my MAPa instead. -- Example in 49g Reference manual for TSIMP is gibberish. TSIMP(LN(X+X)) = (??) (LN(2)+LN(X))/(LN(5)+LN(2)) Onscreen help has a better example. -- << DUP NEG == >> or << DUP NEG SAME >> should determine if an array or list contains only zeroes. But it fails, because NEG changes (lengthens, in fact) the internal representation of 0 (and of all single digit integers) when used as elements. See this with ->H upon the list/array of zeroes both before and after applying NEG. NOT converts single digits used as elements back to the short form (and of course, only returns 0 or 1). My PROTO returns 0 if all elements of its argument are either 0 or 1, and " " otherwise. It was very tricky to write, partly because of the above "feature". [Detto, my Zero?] -- The basic arithmetic functions (+ - * /) only pervade down one level in nested lists. They will pervade to the individual elements only if MAPa is used. -- STR-> discards all characters with NUM values less than 32. -- Speed of CON (generate constant array) vs. NDUPN ->ARRY ? Similary, speed of MAKESTR (generate repeating alphabetic string) vs. DUP DUP DUP + + +? -- SREPL is find & replace (args: s3=the big string, s2=the sought string, s1=the replacement string) -- The converter from "system binary" to binary SB~B fails if the argument is larger than 2^20 - 1. Perhaps system binary numbers are only 20 bits long? In display, a binary is prefixed by "pound" #, while a system binary by twisted thread (or zeta, in my Greek font). -- Vectors and matrices (indicated by square brackets) are called "arrays" in the manual, but "MATRX" in FILER. They can hold integers, reals, algebraics, functions, and names, but not binary, strings, lists or arrays. Lists can hold anything. Rows of matrices must all be the same length. ============================================================================== Design Flaws -- How determine the current display base for binary numbers, so that it can be restored after a temporary change (to binary, say)? It can be done clumsily by creating a binary number, saving its last character, and later using a CASE statement to select one of the base changing functions. -- Arrays cannot be of length 0, nor can HEAD nor TAIL be used on them. Design flaw. -- Algebraic expressions should be treated like strings by some operations. -- Design flaw: integers (which can be indefinitely long) are truncated to 12 digits (39 bits) by command R->B when converting them to (internal) binary. This does not even preserve the full word size of 64 bits. -- EVAL on a list will merely stack the items; if the list is 0 long, then no output will be produced (design flaw). -- Can't use directory paths on :3: (the external flash memory). -- :0: is worse than useless, as it steals memory from Home, while :1: is only useful for storing objects (but not editing or recalling them from directories). -- Execution of MAP requires the PURGEing of the current variable (usually X). And sometimes the same for DOLIST and DOSUBS. -- Suddenly, I can no longer attach the equation libraries 226 and 227. [Press APPS, then up twice, and press to go to the EQLIBS menu.] -- The newest simulator refuses to display the keyboard (after briefly doing so), showing instead only a blowup of the upper half of the front panel. -- Both of the new V simulators seem to uninstall themselves over the first night. -- SIZE upon a non-binary integer returns the number of digits. Use my CARD instead. -- When creating a new version of a library, with additional objects, previously created defined functions (as on user keys) may suddenly point to different objects within the library. Reason: internally, code points to the position of the function in the library string $VISIBLE. If this order is altered, previously "compiled" functions pointing into it will now point at the wrong function. (Sometimes the name of the library function is replaced by a string like XLIB 999 17, meaning the 17'th item in $VISIBLE for library number 999.) The solution is to save all such functions as strings and recompile them (by converting strings into executables). The easiest way to do this is to download all code to a PC in text format, edit it there, and then upload back to the calculator. However, the lib must be detached before re-uploading it, and then it must be re-attached before uploading all dependent objects. -- 5 and 5. will compare identically with SAME and ==; however, if POS looks thru a list at them, they will not match. -- Either GET or SUB can be used on lists (to extract single elements or a substring, respectively). But only SUB is available for strings. -- HALT sets the TOOLS menu. [??] -- Sigma-LIST either ADDs or CATs, almost capriciously. This is caused by the inherent ambiguity of the "+" operator. -- VIEW ignores the fast -> + cursor key combination, making it slow to move around a large object. -- EDIT ignores the TOOL key. Why not assign it some function? [Perhaps it restores the default softkeys, beginning with <-SKIP. ??] -- MAP requires VX internally, apparently, destroying its previous value. It should be replaced by DOLIST everywhere. When the function to be repeated by DOLIST is a single operator, then a count is not needed. However, if the function has multiple operators, or the argument list has sublists, then 1 must come between the argument list and the argument function. Unfortunately, both DOLIST and DOSUBS also apparently use and destroy the current variable VX in some, tho not all, cases. Other built-in functions also use VX, such as SIMPLIFY(??). -- My POSL returns the empty list {} for \"\" -- On '5xSQRT(-1)', CONJ does not change the sign -- Reserved variables alphaENTER and betaENTER are ignored. -- GET issues an error message if its argument is out of range, whereas SUB uses the lower and upper index values. -- SIMPLIFY operates on lists or scalars, but not on items in arrays. The latter must be converted to a list of lists with A~LL first, then converted back. -- I cannot run CONN4X successfully on my Dell 3.2GHz computer. The calculator is never detected. On my Dell 500MHz computer, it is usually detected; if not, I reboot, and usually achieve connection. (Both run Win XP.) [May be an older version of CONN4X; the newest one, from 2009, runs fine on 2 of my XP computers.] -- Apparently, CONN4X cannot download objects to or upload from the ports (:1:, :2:, :3:). But HOME is too small for big objects. [So I should buy an SD card reader!] -- Algebraic expressions should be treated like strings by some operations. (Design flaw). They are instead treated like function definitions (??). -- User keyboard assignments are ignored inside FILER. -- HORNER fails if its arguments are both constant, and the first is real; use my HORNERa instead. -- If a program in a library refers to another program inside << >>, then the inner program must be in $VISIBLE, not in $HIDDEN. (Cf. HORNERa in POL->) -- Arrays (in []) have certain restrictions. They cannot be empty (tho lists can be, e.g. {}) and cannot contain TYPE 2 strings (tho they can contain TYPE 6 name strings). -- Numbers with the same value (e.g. 2 and 2.0) may compare equal with == but are considerered different (result 0.) with SAME. Binary numbers (e.g. #2d) never are equal to same-valued integers or real numbers. -- {1 2 3} 2. POS fails with 0., because 2. does not match 2 (presumably SAME is used instead of ==). -- Many list functions (e.g. DOLIST, SigmaLIST) fail on empty lists (i.e. {}), but MAP works on them (producing result {}). However, MAP also alters VX, the default symbolic value, and does not take a complicated defined function as a 2nd argument, the opposite of DOLIST in both cases. -- { "<<" "A" ">>" } STR-> fails with error message "XLIB 1792 15 Error: Invalid Syntax" -- There is apparently no RPL function to convert between an array of coefficients (e.g. [1,2,3]) and its corresponding algebraic form (viz. 'X^2+2*X+3'). SYST2MAT does a similar transformation, but only if the terms are marked by different variables (e.g. it converts ['X+2*Y+3*Z'] into [1 2 3]). I wrote POL~COEF to fill this need. -- XNUM changes mode to Approximate, while ->NUM leaves the mode alone. My XNUMa corrects this. -- Some commands use the current variable (viz. VZ, usually 'X'). Such commands include MAP, ?? -- 0 WAIT returns the numeric code of the key struck, but ignores the "&" (hold down) attribute; e.g. 41.61 is returned as 41.60. -- -31.1 KEYEVAL shows the variables in the softkeys, but does not update the path in the header; 2.01 MENU does both. (E.g. after a key to return to the home path) ============================================================================== Apparent design flaws (errors or limitations) in the CAS (Computer Algebra System) -- If the order of variables in $VISIBLE in a LIBRARY is changed, then all programs using objects from that library will now point to the wrong object. See the discussion under Un- documented behavior on how to fix this. -- Enter the algebraic expression 'LN(Y^X)'. Applying EVAL to it on my 49g+ calculator produces two different results: when either real mode or approximate mode is on (so that the annunciator on top of the screen shows either R or ~), the result is 'X*LN(Y)'. But if complex exact mode is on (shown as C= on the annunciators), then the result is 'LN(EXP(X*LN(Y)))'. The command SIMPLIFY has the same behavior as EVAL. Is this somehow related to the fact that LN() has multiple values (separated by 2*PI*I) in complex mode, similar to the multiple values of the arc-trigonometric functions? [EXP2POW, in the CONVERT/REWRITE menu, will convert EXP(X*LN(Y)) to Y^X, which is somewhat helpful.] [The 49g+ calculator has a VER of the CAS of 4.20060602, ie. level 4, date 2006.06.02. On my 50g, the result is 'X*LN(Y)' in exact mode, but is unchanged in numeric mode.] -- How to simplify ASIN(SIN(X)) to just X? The converse, SIN(ASIN(X)), is instantly reduced to X. Even COS(ASIN(X)) is instantly reduced. [Same problem on 50g, and also for ACOS(SIN(X)), for COS and TAN.] [EXP() and LN() cancel each other in either order, while SQ(SQRT(X)) and ACOS(COS(X)) are instantly reduced to X, but SQRT(SQ(X)) is reduced to |X|. Perhaps the multi-valuedness of the arc-trig is the problem?] [Changing to real or approximate mode does not fix the problem.] -- LN(Y*X) simplifies to LN(Y) + LN(X) only by using TEXPAND or TSIMP, not by using EVAL or SIMPLIFY. -- COS(ASIN(X)) does not simplify, nor does ASIN(SIN(X)); but SIN(ASIN(X)) instantly simplifies, as does COS(ACOS(X)). -- [Bravo!] SQRT of expressions with SQRT in them are reasonably well done. -- Applying the function << -> x 'x*EXP(-x+INV(x))' >> to a list fails with "Invalid dimension". However, the equivalent function << -> x 'x*EXP(INV(x)-x)' >> works correctly on a list. [Still fails on a 50g.] -- It is easy to split TAN(X) into SIN(X)/COS(X), and thence to an expression in TAN(X/2), but it is hard to undo these transformations and return to TAN(X). -- The integration INTVX(TAN(X)) is instantaneous, but INTVX(INV(TAN(X))) is incomplete; it becomes tedious to do the symbolic manipulation to finish it, even though the only difference is that SIN() and COS() are interchanged. -- The function X*LN(X) at X=0 baffles the CAS; it can neither take the limit nor compute a Taylor series. -- Distinguish EVAL from SIMPLIFY. EVAL & SIMPLIFY both try to substitute symbolic equations for symbolic variables in an expression; how to toggle this behavior (other than PURGE'ing the variables first)? Also, when trying to substitute, they inquire "Approx. mode on?" (Presumably, "may it be turned on?") What is the meaning of this? -- SEVAL substitutes for variables, but does not simplify at the highest level. -- FACTOR may simplify without substitution. PARTFRAC is similar but expands. -- Because EVAL, SIMPLIFY, SEVAL and most other CAS functions will attempt to substitute values for variables in an algebraic, it is often necessary to block this. Lacking any system flag to prevent substitution, I press UPDIR to change the current directory to HOME, which holds none of the dependent variables. After CAS manipulation, I press VAR and the name of the original directory and save the massaged algebraic. -- WHERE ("|") is a mysterious form of delayed SUBST, possibly with full EVAL of substituted variables. Cf. QUOTE. -- QUOTE claims to prevent variables from being replaced by their values during object evaluation, but it is unclear how to use it. -- TAYLR on the square root expression for eccentricity in the rocket problem, attempting to expand in terms of speed^2 to 2 terms fails with the error message: "Mode switch not allowed here". Try TAYLOR0 or SERIES instead. -- TAYLOR0 converts SQRT(X) into EXP(-1/(2*INV(-LN(X)))), which is equivalent, but is hardly a polynomial expansion. However, it does expand SQRT(1+X) correctly. -- EVAL can be used on subscript notation (e.g. 'V(I)'), as can STO, but RCL cannot. -- EPSX0 changes a term 1.E-11/(X-1) to 0/(X-1), but this new term is never removed by simplification. On the other hand, 1.E-11/7 turns to 0/7, which is removed. Is it the possibility that X might be 1? -- '50*X' '55*X' EGCD returns '50*X' as the GCD, instead of '5*X'. ============================================================================== Future projects, especially my APLg -- APL: PARSEAPL APARs: need looping, e.g. with "->" need (10 rho 10) top for ALLDIG to split integer into its digits need ,[1] and rotate[1] for MEDFILT Recreate: JulianDay, ALLDIG, BUNEK, hIST Converted: Nile Use monadic <> for enclose/disclose (or Greek Gamma and Psi) Subscript notation "[I;J]" on matrices or on lists of lists. New function for catenating at a high level (";", like blank in APL) when dyadic, or enlisting all items into one list/string when monadic (like ",") [Not easy; simpler is just to require braces around the list] Tokenize [] and {} expressions, which can be single objects "Each" operator fails on dyadic functions, e.g. A F" B The back quote should be the operator "[1]" Outer product could use fast builtin (undocumented) []*{} and []%{}. -- APL subscript notation is more compact than using GET/PUT or SUB/REPL. Is there built-in matrix subscript notation? [Yes: EVAL (but not RCL) or STO on 'V(I)' or 'M(I,J)'; however, there is no notation to select a single row or column of a matrix.] -- Binary searching of word lists. Cf. the search algorithm used in DICTIONARY. -- Boolean simplification by IBM algorithm (rewrite an expression as coefficients of one variable, in its positive and negated forms; recur) -- CAS bugs: which have been fixed in the 50g? [None] -- CHARS: which non-graphic chars mark italic, bold, &c.? [See the example in FONTS.] -- Chess in HPGCC -- Compression of strings by Huffman or Ziv-Lempel -- Continued fractions (e.g. for e, pi, square root, tangent), by keeping lists of the numerators and denominators. -- Contribute these notes & programs to hpcalc.org. Formatting might follow http://www.cs.tut.fi/~jkorpela/forms/file.html -- Convert between postfix notation (RPL) and algebraic notation. Can PARSEAPL be adapted for this? Does it exist as a built-in? -- Correlation error value for the 1/3-2/3 graphical construction of the Least Squares line -- Dictionary: add Basque, Georgian, Hindi. Build an input form GUI. -- Dictionary objects (associative arrays) -- Document (& rename) the various built-in operations for loops, factoring, expansion, integration, series -- Donut shaped planetary orbits -- Elliptic sine & cosine double periodicity display -- FFT Composite Prime (Good-Winograd) Algorithm -- Finite state machine, e.g. to convert English words to Pig Latin -- FFT of data extended by zeroes--what effects? -- FLASHCARD: add Tamil, Tibetan, hiragana, Chinese etymons of kana -- FREECELL should be sped up -- Graphic editor by displaying, permitting modification with built-in functions, and saving the new graph. E.g. a flashcard editor can be built by applying EDITB to a GROB, using the EDIT suite therein to add or remove pixels, and then pressing CANCEL to place the new display in the stack as a large GROB. GROB functions, including GROB trim, GROB shift, GROB catenate horizontally. E.g. create a BLANK of the desired size, and GOR the existing GROB onto it; the resulting GROB will be trimmed or padded to the size of the BLANK. Also, the position of the GROB can be placed at any displacement from 0 to shift it. Lastly, GOR of two GROBs will catenate them. SUB and REPL can be used to cut and paste. TAKE and DROP can be done by GOR against a larger or smaller blank GROB. A useful graphic function not built-in is RESIZE, whereby pixels will be created or destroyed to enlarge or diminish the image. E.g. many Chinese characters are formed by two full-size characters reduced to half-width, and placed side by side. The heart of a new graphic editor could be ->LCD 0 WAIT and/or EDITB. For editing a character font, there must be a command to copy an existing character GROB as a template for a new character. -- HANNTZYH SHOW function (lookup English or Hann or phonetics) -- Hash coding and searching of word lists -- HP-25 programs, especially 2 person Blackjack (?with card images) [Don't bother--there are user-contributed Blackjack programs like :2:BJF] [But BJF fails to treat aces as either 1 or 11, and misconstrues any total of 21 as "Blackjack".] -- L'Hopital's rule. [Split off the denominator with OBJ->] -- List & tree structures -- Lists of length 0 and 1 must be accommodated correctly by all functions. -- Long integer arithmetic functions for square root (by Newton-Raphson). Save the operand in N, and leave a starting estimate in the stack. Each step of the following will leave a better approximation to SQRT(N) in the stack: << -> x << N x / FLOOR x + 2 / FLOOR >> >> After this, build exp & trig functions (by continued fractions). -- Matrix commands must be critiqued [???] -- NSHAPE and NRESHAPE (shape of nested array) in APLg -- NOVAL removal from lists produced by MAP. NOVAL fails to participate in most functions, including MAP. However, TYPE on it returns 19, and DOLIST can apply TYPE to a list. -- PARETO program to time a program and find its "hot spots", where most of the time is consumed. Use RCL upon the function name (S~N puts algebraic single quotes around it) and insert ELAPSE-like code every so often. [I did this by hand for the SF2MF function in FONTS.] -- Pluto-Neptune resonance: check the derivation of each equation (using patterns involving f,E,M). Perhaps use MUSER. -- Primitive root finding for a given modulus (e.g. powers of 3 for mod 7) -- Primitives devised by me (e.g. CAT, BSEL, CHR2L) would be much faster in System RPL or AL or HPGCC -- Procedural programming language with better syntax than HPGCC (? PL/0 or PL/8) -- Rader-Brenner Reduced Multiplication FFT error analysis -- RAV should also ravel matrices into lists. -- Recurrence relation for even Bernoulli numbers [i.e. without the odd B(1)], perhaps based on the coefficients of X/TAN(X) = SUM(B(2*J)*(-4*X^2)*J/(2*J)!), or possibly on the continued fraction expansion of the latter. -- Reordering by fast algorithm vs. built-in SORT? -- Rocket distance function for small initial values should be compared to a parabolic arc. -- Rocket distance function should be 3-D plotted -- Symbolic proof that partial derivative of the sum of powers with respect to the upper limit is the next lower power [use the Psi function] -- SNOBOL (or regular expression) or LIKE (SQL function) pattern search of strings -- Space war -- SPLW should work on any punctuation mark -- Stack ops: PUSHV, POPV and PEEKV to storage. Use IFERR to catch uninitialized variables. Recursive execution automatically stacks local variables, and may make these utilities unnecessary. -- Statistics functions & graphing -- Symbolic proof that cos(pi/5) = phi/2 -- Symbolic proof by induction that sum(k^3) = (sum(k))^2 -- System RPL programming. When I try the ASM command from the Development Library, it cannot find the System RPL built-ins. Only very scanty documentation is found on-line. [Use two commands in the APPS/Development Library, viz. ->S2 to disassemble a User RPL program to System RPL, and ASM to do the reverse. Also, a 638 page PDF is available describing System RPL Programming.] It would be useful to rewrite the timing hotspots in PARSEAPL into System RPL (a short string is parsed in 6 sec; the longer NILE2 string in 28 sec). -- Tensor product -- Ternary Logic (the built-in functions use 1,0,? to represent "true", "false", "maybe") -- Three-dimensional arrays -- UFL1 (Universal Font Library 1)? It is input to the UFL1->MINIF built-in command? [See the HP48 UFL in the hpcalc.org collection; also StringWriter for entering foreign alphabets.] -- Write & document ENCL, RANDPERM, ROTa, TRANSP, SUBa, REALKEY, SWAPKEYS, my latest user keyboard ============================================================================ Improving APLg -- Rewrite critical parts into a faster language--SysRPL or Assembly Language. -- Could the speedy COMP-> somehow be used to parse an APLg expression? If all functions could be rapidly changed to "^" (which operates strictly right to left), and all monadic and named functions could be identified, then it might be feasible. -- Perhaps include features from APLX (www.microapl.co.uk/apl) or APL*PLUS or A or J or K or A+. -- Test all APLUTIL functions against all arguments: scalar (integer, binary, real), list (empty, singleton, plain, list of lists), vector, matrix (row vector, column vector, full matrix), strings (empty, singleton, containing quotes or backslopes), and arrays (real, complex, algebraic). Note: arrays cannot be empty, or contain strings. -- TYPE 29. == is used in many functions; replace it by Array? -- How to indicate index [i] on an operator, so that e.g. 3-D "matrices" (i.e. deep lists) can be summed? -- Running times (in centiseconds [cs]): POS of a 1 byte string in a 60 byte string: up to 2 cs IF THEN ELSE END doing very little: 4 cs APLg: 100 cs for 1 token, 130 for 2, 160 for 3, .. 2000 cs for 43 (i.e. 30 cs per token initially, but 45 cs on long input strings) [It seems to drop in time per byte for long input strings.] TOKENIZE (new): 7.5 cs per token ForV?: 4 cs for function token (cat=0), 10 to 17 cs for a name token (cat=1) -- FuseB has problems with nested brackets (e.g. [[1][2]] or {{3}{4}}). a. It runs much slower. Stopgap: if only 1 left bracket, use a shortcut. (Ideally, only 1 bracket might appear, if statements are separated first by line-end characters.) b. Disentangling the inner items is tedious and slow; mostly only numbers or names appear in them. Stopgap: treat the outermost level brackets as single tokens (and several outer level ones can appear in a string). This approach is correct for the examples shown above. -- The new-line character is used to mark the end of APL statements, but can also appear inside quotes or inside guillemets. So defer searching for new-line tokens until after Tokenize has marked quoted and bracketed fields. -- To use a built-in HP command of two variables in APLg, write it with the 2nd argument to the left of the function name, or else enclose it in single quotes and write parentheses around the arguments. E.g. to round a number A to N decimal places, either "A RND N" or 'RND(N,A)' is correct. -- Maybe build a fast SPL with S->H, H->S, ->H and H->. (& MAKESTR?) [Alas, this is MUCH slower. Creating SPL with a SEQ runs in sub-linear time; using SUB in START is faster for string size < 60, but runs in linear time.] -- Fix INDEX/RCL to set the shape of the result to the shape of the input. -- APLg runs 5% to 10% faster with all DUBUG invocations removed. -- Program FACR (recursive factorial) runs 5 times faster with function o2a (makes arguments compatible) removed. Still 50 times slower than built-in !. -- In APLg, if a string ("A" or 'A') is categorized as a letter (cat=1), then FORV recategorizes it wrongly as a function (cat=0); so treat it as a number (cat=2). -- The arguments to the outer product IOPROD must be SWAP'ped first, or the result TRANsposed afterward; ensure that SWAP isn't/is in the function argument. Beware of SWAP applied to all dyadic functions; e.g. not to <- or / or .. For speed, the outer product will remove CAT from the function argument, and assume that the input arguments are to be swapped. -- Axis indication (using forward and back quotes) is ignored on most functions, except for those which have specific symbols in APL2. Thus rotate on either axis exists [No, it doesn't!!], but catenate does not. Nor is +[1] nor /^[1] (i.e. Take). ============================================================================== Emulators -- Almost every key on the Yorke 49g+ emulated keyboard can be typed from the real (QWERTY) keyboard. The latter is much faster for alphabetic entry. However, neither "-" nor "*" are QWERTY enterable. Also, "CAT" and "EVAL" are swapped on the hp49g+ image, and so are "'" and "EQW". -- The newer HPVApple emulator permits the use of the keypad "-" and "*" keys, and also saves and restores the exit state, both user-friendly improvements. -- On the Yorke emulator with the 49g+.ROM, 'e^(3/2)/e^3' does not SIMPLIFY. Substituting any other variable for 'e', such as 'X' or 'PI', does permit simplification, to just the 3/2 power. On the real 49g+ with the 2.06 ROM, this problem does not occur. Oddly, the dates & serial number of the two ROMs are identical, yet their behaviors differ. -- On the Yorke emulator, one can right click on the display area and get a pop-up of commands. Where is their explanation? In particular, how does one use "Object/Load on stack"? -- The VApple emulator is a "cycle hog"--it grabs over 90% of the available machine time. Now it is using only 8%, but after only a few uses, the VApple emulator will now only display in Maximum mode, showing just the emulated pixel display filling the screen. It still operates, but without showing the keyboard. How to recover the keyboard display? On other computers, it either runs without problems, or it auto-uninstalls itself. ============================================================================== Timing & Storage -- Timing of functions on lists of length 100, 200, 300, 400 yielded these running times on an HP49g+: IOTA: (N+60) * 4.1 msec SQ: (N-40) * 6.4 msec NxN matrix multiplication: N^3 * 3.5 msec FAULHABER: (N^2+N+1)/6 sec Each function was tested by << InputList function >> 'F' STO and the number of seconds was measured by ELAP. -- Tests on a list of 1000 words showed that POS ran in less than a second to find an item. When the words were catenated into a 7000 character string, POS still ran fast in finding a substring. However, all the list operations tested on a related integer list ran in 10-20 seconds; e.g. 5200 <, << 5200 < >> MAP, and a STREAM. Only NEG and REVLIST ran fast on this list. [Would root finding on a table-defined function run faster?] -- SigmaLIST on a list of lists to ravel all the elements works well for a short list, but slows down dramatically for a long one. Much faster is DOLIST or DOSUBS with arguments of 1 << EVAL >>. (Not MAP with << EVAL >>, which does nothing.) They were timed at 12 sec to ravel a list (1005 long) of sublists (the total number of elements being 7853). For the same input, SigmaLIST ran for several minutes without finishing. -- Pressing power ON turns on the display in less than 1/4 second, unless a 1 Gbyte SD memory card is installed, in which case about 2 seconds elapse. (Is the SD card being initialized?) -- Vector vs list: Same storage? [Yes] Faster processing? [Perhaps] -- VTYPE vs TYPE: is the former faster? [They operate differently, the former on the name, the latter on the object itself.] -- Implicit function operation on list (e.g. NEG) vs. explicit SEQ or MAP vs. explicit loops with index FOR or START--what are relative speeds? -- Hadamard-Walsh transforms are done much faster by a matrix multiply than by looping with nested SEQ's. See "NRAND" above. -- Lists of integers are stored at about 7 bytes per item. The use of "binary integers" does not save much. Despite setting the Word Size to 16, a list was stored at 13 bytes per number. Subtracting #2 (binary 2) from it reduced it to "only" 6 bytes per number. On the other hand, strings are stored at about 1 byte per character, so integers from 0 to 255 should be converted with CHR (and converted back with NUM) to save space. Non-binary integers are apparently stored in denary, as there is a measurable jump in storage when the largest item in a list goes from 9 to 10, or from 99 to 100, &c. A list of integers no bigger than 9 will be stored in about 3 bytes per number. -- The TRUTH plot command is extremely slow, as it re-evaluates the input function for every pixel. To its credit, the documentation does warn of this. ========================================================================== My dictionary data -- #128 JEU shows R134.09, except that R134 cannot find it. -- BIANN (R149) is simplified (the "jeantzyh"). ============================================================================ Customizing -- Submenus can be included on keys in the Custom menu by assigning a list to a key: { mdisplay { NN MENU } } where NN is the menu number, and "mdisplay" is shown as the key name. However, no little tab marks the key as a menu. -- The menu for any attached library may be displayed by "libnumber MENU". [How to display the number of the current softkey menu? RCLMENU] -- Some menus include functions which have no independent names. How to invoke them? The number of the menu followed by decimal point and the number of that menu page is the argument to command MENU, e,g. 256.04 MENU sets the top row soft keys. (The number of a menu is either listed in an Appendix to the Reference Manual, or else can be determined onscreen by RCLMENU; note that the number is the menu.page, not to be confused with the menu.keynumber). -- Editing the custom menu in variable CST with my EdCST function (on ->&STO) makes it far more usable. [Besides assigning to the top row of softkeys, it could also assign to relatively useless keys like HIST, SYMB and all the shifted keys that just display softmenus. Latter keys are assigned by my function EdCSK.] -- The four cursor keys can be ASN'ed to; their position numbers are 25 for up, and 34, 35, 36 for left, down, right. On the other hand, they are frequently used in both alpha and non-alpha mode, and there already exist some assignments of shifted cursor keys (e.g. <-down to show the soft keys). So, the best assignments would be alpha+shifted. -- It is not the best idea to assign to the keys with CUT, COPY & PASTE on them, since they are used in all modes. Similarly, don't assign to cursor keys, the new line key (on the bottom row), the Enter or the Cancel key. Also, don't assign to ALPHA& or to ALPHA-> which are used for Latin letters. -- When using ORDER to reorder the objects in a directory: order them first with the ->N, ->T, or <-N or <-T functions, then select them all with Enter and press ORDER. ORDER cannot reorder more than 99 objects, so it may be necessary to MOVE a number of objects to a temporary directory first, and then MOVE them back in; note that moved in objects are placed at the front of the object list. -- Strings apparently cannot be included in $VISIBLE for a library. So write a tiny function to display that variable whose name goes into $VISIBLE and put the string into $HIDDEN. -- I have written a function CREATE which makes it easy to create a library from a directory which has all the special $variables. ============================================================================ Editing -- The file manager program can be opened under the name FILER (same as key <-APPS). Object editing can be done with EDIT[B] and VISIT[B]. Suffix B means "best" and uses one of the specialized editors instead of just the text editor. -- Undocumented for the editor: press COPY and CUT, and the cursored line is placed into the clipboard. (A blank line is left behind; press CUT again to grab the line-end character, too.) To COPY it easily, press PASTE to restore it, then PASTE it again elsewhere. -- DEL L in FILER blanks out the current line, and apparently there is no way to restore it. (Neither UNDO nor LASTARG do that.) -- Inside FILER, Right enters a directory and Left leaves it. Why don't they also edit objects, too? -- ALPHA ALPHA toggles "SEARCH MODE" in FILER, in which typing the initial letter goes to the next item beginning with that letter. (Remember to hit ALPHA when it is found, so that other keys will work.) -- The TOOLS command inside the Line Editor seems to set the soft keys according to a reserved variable, like CST for the Custom Menu feature. But what is that variable named? -- Hitting any non-edit keys inside the line editor just enters that key name into the text. How to make a key executible? (Other than EXEC.) How also to quickly select the whole line? -- Inside the EQW, the softkeys can be set to any menu. Useful commands are the trig commands, which will work upon the hilit area, -- In the EQW, how to change a function symbol (like "+" to "-") without resorting to the (linear) EDIT? -- "LABELS" in the GOTO menu of the Line Editor in the File Manager (FILER) refers to names beginning with "*", which mark sections in HP Assembly Language programs; they are not used in User RPL programs. -- The menu number shown by FILER (showing "SKIP DEL ..") is 28, as usable in MENU. [How to invoke the EXEC key, number 11.10 of menu 28.03? It replaces a hilited expression with its value, while editing.] -- In FILER, the SRCH/FIND function permits "?" in strings to represent any single character. Whether any character represents an arbitrary string, I do not know, but "*" does not work that way. -- I cannot FILE string images of directories, either after EDIT or (more seriously) after an upload from a Windows PC viaa cable. The SYNTAX ERROR message is caused by any of the following: 1) a function by that name already exists in a library (so DETACH the library first); 2) fonts are included in the DIR string (remove them first, then COPY them back later); 3) possibly, unusual symbols are in strings, such as quoted square dot (used in my Freecell). -- In FILER (the line editor), ->BEG and ->END move to the beginning/end of the selection made with the BEGIN/END key commands. [Correct App. L of the hp50g Guide.] -- The choice of big font or mini-font during editing is shown both in FILER and while entering characters at the command line. After ENTER is pushed at the command line, however, minifont is selected for strings, but big font for numbers, independently of the editing font choice. -- The object editor will supply a missing final quote or bracket on closing. Sometimes this is an error. -- ->PRG converts a stack of items into a program (<< >>), but may leave off the enclosing guillemets. ============================================================================ Debugging, Commenting & Error recovery -- If erroneous data are stored, the previous contents can be recovered, but only if action is taken immediately. Do NOT press UNDO, but rather <- ANS; this will show the old contents and its name in the stack; after inspecting it, press STO. -- Can tags be used for comments? How about "Comment" DROP ? [Could define a function backwards-P containing only << DROP >>.] Display help with MSGBOX. [How include cross-references, as with real help?] Error messages can be displayed with DOERR. They should have the name of the function on the first line followed by a colon and new-line, then the message in Capitalized Words. -- Since SST\v does not step thru the function executed by DOLIST, put a HALT at its beginning; then you can use SST\v. To debug step thru at the top level of a function which calls many subfunctions, it is tedious to use SST\v, which will execute its way thru the subfns. However, using SST on << TOPFNNAME >> will just execute it. So, do 'TOPFNNAME' RCL, which brings up the code of that function, then SST thru it. -- SST|v does not step thru the kernel of a MAP or SEQ or DOLIST operation, hindering debugging. They must be rewritten into a FOR/NEXT loop so that SST debugging can be used. -- How to exit from just the current function? [KILL terminates all pending functions.] -- I put a string and the function call to the paragraph symbol (back-P) at the beginning of my functions. back-P will display the string in a box (with MSGBOX) if either nothing or just '?' is on the stack; else it will simply delete the string. This string serves as both a comment inside the code and a Help message for display outside. -- An error when executing from the CAT menu bounces me out of USR keyboard mode. Maybe I should not swap keys? [The same error when executed from the keyboard does NOT bounce out of USR keyboard mode. 864 of one, half a great gross of the other.] -- The "Last Stack" check box on MODES is apparently not saved in any system flag. (Message "LAST STACK DISABLED" is given if UNDO is clicked with this box unchecked.) ============================================================================== Miscellanea -- Apparently, a warm start does not change the current keys or flags. -- I have built a library (999) containing my most often used personally written programs, mostly based on APL models. They include IOTA, GETL, POSL. By ATTACH'ing the library to the HOME directory, all its (visible) items are added to the available catalog of functions. To assign them to user keys, they must be named within double angle brackets. -- I place my most common personal utilities onto user-shift keys. (They must either be in the current path, in an attached library, or be pointed to viaa the path list or port address mechanism.) I place the Greek alphabet and other useful characters (e.g. the arrows) onto user-shift alpha-shift keys. Since 3 keystrokes activate these shortcuts, user-shift keys should require considerably more keystrokes. Thus, it would not be efficient to place MAP onto a shortcut. [Hmmm. In fact, the <- USR combination is so frequent as to be almost unnoticeable, so that user-shift keys are essentially one key stroke.] My current selections for user-shift (i.e. <-ALPHA) keys: [OBSOLETE] user-A: ->ARRY user-B: IBERNOULLI user-C: << -117 TOGLF >> (Toggle between choice menus and softkeys) user-D: DOLIST (more useful than DOSUBS) user-E: << ELAPSE >> (Elapsed time) user-->E: << << EPSX0 >> MAP >> (Set tiny values to 0) user-F: FACTOR (Opposes PARTFRAC) user-<-F: ->FONT (Left shift stores) user-->F: FONT-> (Right shift recalls) user-I: << IOTA >> user-ALPHA->I: "iota" (one of the full Greek alphabet; cf. infra) user-L: << {1} + piLIST ->LIST >> (Ravel an array to a list) user-<-M: ->MINIFONT (Left shift stores) user-->M: MINIFONT-> (Right shift recalls) user-N: << <> MAP>> (EVAL enstacks lists, so I avoid it) user-O: << OBJ-> XQ >> user-P: PARTFRAC (Opposes FACTOR) user-R: << REPT >> (Iterates omega from 1 to arg on expression) user-S: << -73 TOGLF >> (Toggle font size before editing) user-->S: SigmaLIST (Ravels a non-null list of strings) user-T: TAYLOR0 (Taylor series to 4th power of variable named in VX) user-->T: DERVX (Differentiate w.r.t. variable named in VX) user-U: << UBASE ->NUM >> (Convert a units expression to MKS units) user-->U: INTVX (Integrate w.r.t. variable named in VX) user-Z: << SIZE XQ >> user-ALPHA->-: "highminus" user-ALPHA->2: "|^" (i.e. up-arrow) user-ALPHA->3: "|v" (i.e. down-arrow) user-+: << CAT >> (Catenate items into a list or vector) user-ALPHA<-0: "<-" (equiv to ALPHA->6 "angle"; parallel to ALPHA->0 "->") user-ALPHA<-.: "diaeresis" (Also called "umlaut") user-->NUM: << <<->NUM>> MAP>> In addition, all the lower case Greek letters are on user-ALPHA-> shifts (i.e. in user mode, ALPHA, then right shift, then the key), while the upper case Greek letters are on user-ALPHA& (i.e. in user-mode, ALPHA held down with the other key). Only "iota" is shown thusly in the list above. The order from A to Z is alpha, beta, chi, delta, epsilon, phi, gamma, eta, iota, psi, kappa, lambda, mu, nu, omicron, pi, theta, rho, sigma, tau, upsilon, wau, omega, xi, accent, zeta. The forward quote (for high pitch) is on user-ALPHA-->Y, the back quote (for rough breathing) on user-ALPHA&Y. Note that in user mode, all Latin and all Greek letters are available; e.g. user-ALPHA-S is "S", user-ALPHA&S is "Sigma", user-ALPHA-<-S is "s" (also the final small sigma), and user-ALPHA-->S is "sigma". Note that TAYLOR0, DERVX and INTVX all assume the default variable named in {CASDIR VX} (which is 'X' by default). They default all other parameters as well. Other built-in's I might consider for user-shift keys include: |^MATCH, |vMATCH, DOSUBS, << 41 MENU >> (Display the debug (RUN) menu), << VX-> >> (Replace polynomial variable with VX), << ABCab >> (Alphabet strings for search & replace), "multiply" (sans-serif "x"; for user-ALPHA-->*), "divide" (minus overstruck by colon; for user-ALPHA-->/), << 2 HEADER-> - ->HEADER >> (Toggle LCD 2 top lines on/off), SUBST. However, user keyboard assignments are ignored inside FILER. -- My variable STARTED removes the 2 line header when editing. My variable STARTUP does an ATTACH libraries 999 and 256, and installs the preferred fonts (both the large and the small ones). [How to make library ATTACH automatic?] -- If user-shift keys are set to functions in a library, and that library is recreated, the user-shift key (sometimes) does not work. (It may in fact have been set to a fixed address in the old library, which has now changed.) Reissuing the ASN (but perhaps not redoing STOKEYS) seems to reattach the user-shift key. -- My favorite display setting is with a large font line 1, and small lines for everything else. This is effectuated by setting main font to size 8, setting Stack:Small, clearing EQW:SmallStackDisp, setting flag -63 and clearing flag -57. [So, 4 flags are needed for this form of display.] The 2 line header is turned off during EDITing, and can be toggled off at other times by user-H. -- INPUT requests input from the command line; the cursor can be positioned and insert or overwrite chosen. Do not confuse it with ENTRY. Also, tags (marked with "::" on input, but only a trailing ":" on output) can be applied as decorators on stack lines, typically output values from user functions. E.g., the financial functions use tags. (Colons also mark port number prefixes.) (Use ->TAG to apply a tag, and DTAG to discard one.) -- While in the editing entry mode ("SKIP->" &al.), the cursor can be set to be inserting or overwriting (with "INS"). FIND and REPLACE string operations are available. Shift hold on SKIP-> or DEL-> will do that operation to the end of the item. -- In line editing, ->BEG and ->END position the cursor to the extremes of the BEGIN-END hilighted region. Specifically, ->BEG marks the cursor position as the beginning, while ->END marks the position just to the left of the cursor as the ending point of the area to be hilit. -- HIST and APPS are redundant buttons, as the function or menus they provide are all available elsewhere on the keyboard; they are free for reassignment. [But they cannot be redefined on the normal keyboard, only on the USR keyboard.) I would recommend that they be replaced by their left shifts, CMD and FILES, respectively. -- SYMB is a redundant button, except that some of its menus differ slightly from the separate commands, e.g. its EXPLN vs. EXP&LN. It should be replaced by its CAT function. -- TOOL is a mostly redundant button. It has one unique function: VIEW (not assignable), and two useful ones: PURGE (also available in FILES), and the STACK menu (also available under PROG). It should be replaced by just the VIEW function (which does not appear to have a programmable name). Tentatively, VIEW can be programmed by .01 MENU 12 KEYEVAL 0 WAIT DROP. However, if <<.01 MENU>> is executed as a function, it seems to recall the previous menu instead. -- Two games are included in the 2.09 ROM: Mines, which is insipid, and two versions of Tetris. They are "Easter eggs", and can only be invoked by secret commands, as documented at the www.hpcalc.org FAQ. Specifically, a too fast to play Tetris game appears when HpMad is entered into any form, e.g. in Edit/Find/Search. Another, playable, Tetris game is hidden in the ROM (versions later than 1.18 only). In the EquationWriter, type MINEISBETTER, highlight it, and choose SIMP. You will be rewarded with a better Tetris game. Control keys are {4 5 6 2} for both Tetris games, to perform {ShiftLeft RotateClockwise ShiftRight ShiftDown}, respectively. Other games, including Chess, have been written in C, and can be compiled from a user forum into the calculator's native ARM language. [I have installed MLChess and SOBA, but have been unable to install Freecell.] -- How to easily subtract a constant from one item of a row vector? [Perhaps use subscript notation and STO after computing it. Cf. STO- for a stored scalar.] -- How to catenate algebraics, specifically to prefix 'X=' to the value of X, for the argument to SUBST? [Tedious; look at VX->.] [Cf. EXLR, which splits to Left and Right of the "=" in an algebraic.] -- What do double -back quote `` (created by -> & ' [i.e. with shift holding]) do? They seem to be the same as single quotes ('') around an algebraic expression followed by immediate EVAL, plus the additional feature that items separated by blanks within it are multiplied together. [Is this related to algebraic mode?] -- Downarrow will edit the lowest item in the stack in the most appropriate editor, while the compound key <-&"Downarrow" (i.e. holding down left shift simultaneous with Downarrow) will edit the object in text mode. This is useful only for arrays. GROBs can be text edited by first enclosing them in a list, and then editing the list. -- If the backspace key becomes too loose, DROP and CLEAR can be assigned to recover two of its functions. No way apparently to replace single character delete or backspace. -- DEPTH returns the current stack size. -- CHARS has some bizarre graphics. For example, there is an underscored partial derivative, a small bullet and a large one, some reverse video numerals, &c. Where are they used? I have replaced many of them with the missing Greek letters. The twist of wire (ASCII 164, between the British pound symbol and the Japanese Yen symbol) appears in error in the stack when one tries to create a matrix of characters. -- An error occurs when converting a string with STR-> if it defines a function currently attached (e.g. a DIR definition). Detach its library, and try again. -- The built-ins TRAN and TRN both perform matrix transposition, but the latter also conjugates. (Poor naming; better would be CTRAN.) [A reverse mnemonic is that TR-A-N does NOT compute the Adjoint matrix, but TRN does.] -- The built-in PATH returns the current directory path. (Poor name; RCLPATH would be better.) -- ======================================================================= -- Why are beeps, when their flag is turned on, so quiet? -- When altering the display mode or length, surround it by PUSH and POP to restore the original values. [Does this preserve user flag values, too? Yes, but not the current variable nor the current fonts.] -- ->&7 is SOLVE. ->&Down is Visit (edit object whose name is stacked). -- In the 50g Reference manual, Ch. 4 has been merged with old Ch. 3. Unfortunately, all the hypertags have been removed from the revision of the old 49g+ Reference PDF. -- Why have TYPE 6 (Global name, in single quotes) at all? Its string functionality overlaps TYPE 2, and its algebraic functionality overlaps TYPE 9. -- Display a string with PROMPT, an error message with DOERR, a prompt plus input with PROMPSTO (for a single variable) or INPUT (for an arbitrary input string). PROMPT leaves an uncompleted HLT; MSGBOX instead shows a string and exits normally. DOERRa illustrates how to create a home-made error message popup. -- PCOEF returns the coefficients of a polynomial, given the roots. My ->POL converts the coefficients into the algebraic polynomial. -- Functions exist to convert among the many types; many are in Lib 256. E.g. R->I (real to indefinite length integer), COMP-> (function to stacked list), &c. -- MUSER declares a variable name to be "user-defined", presumably so that its use in a formula is not automatically replaced with its happenstance current value. [Use in my NeptPlut and in Rocket] HP undoc: "?" is also the 3rd value in ternary logic HP: if a LIB is recreated with a different order of $VISIBLE functions, then references to the old position look like "XLIB LLL NN" where LLL is the library number, and NN is a position number in the $VISIBLE list. HP: RANM generates random 0's 2x as frequently as other numbers. HP: sys keyboard is default inside FILER, but user keyboard can be used by clicking <-ALPHA EQ-> is the same as EXLR; COLCT & COLLECT; DUPDUP & DUP DUP; HELP & CASCMD; EXPAN & EXPAND; TAYLOR & TAYLR0 Dumb: EDIT a directory in FILER and try to store it back: get message "Directory Not Allowed". Solution: exit FILER and see the directory as a string, and the name of the directory. Change the name of the directory to anything else, and push STO. NOTE: when editing, use EDIT so that quotes are shown correctly, replace all fonts by {}, blank out all special characters (<32 ASCII). Also, temporarily rename any functions with the same names as functions in ATTACHed libraries (or else DETACH said libraries beforehand) ============================================================================