calc: Packing and Unpacking

 
 10.1 Packing and Unpacking
 ==========================
 
 Calc’s “pack” and “unpack” commands collect stack entries to build
 composite objects such as vectors and complex numbers.  They are
 described in this chapter because they are most often used to build
 vectors.
 
    The ‘v p’ (‘calc-pack’) [‘pack’] command collects several elements
 from the stack into a matrix, complex number, HMS form, error form, etc.
 It uses a numeric prefix argument to specify the kind of object to be
 built; this argument is referred to as the “packing mode.” If the
 packing mode is a nonnegative integer, a vector of that length is
 created.  For example, ‘C-u 5 v p’ will pop the top five stack elements
 and push back a single vector of those five elements.  (‘C-u 0 v p’
 simply creates an empty vector.)
 
    The same effect can be had by pressing ‘[’ to push an incomplete
 vector on the stack, using <TAB> (‘calc-roll-down’) to sneak the
 incomplete object up past a certain number of elements, and then
 pressing ‘]’ to complete the vector.
 
    Negative packing modes create other kinds of composite objects:
 
 ‘-1’
      Two values are collected to build a complex number.  For example,
      ‘5 <RET> 7 C-u -1 v p’ creates the complex number ‘(5, 7)’.  The
      result is always a rectangular complex number.  The two input
      values must both be real numbers, i.e., integers, fractions, or
      floats.  If they are not, Calc will instead build a formula like ‘a
      + (0, 1) b’.  (The other packing modes also create a symbolic
      answer if the components are not suitable.)
 
 ‘-2’
      Two values are collected to build a polar complex number.  The
      first is the magnitude; the second is the phase expressed in either
      degrees or radians according to the current angular mode.
 
 ‘-3’
      Three values are collected into an HMS form.  The first two values
      (hours and minutes) must be integers or integer-valued floats.  The
      third value may be any real number.
 
 ‘-4’
      Two values are collected into an error form.  The inputs may be
      real numbers or formulas.
 
 ‘-5’
      Two values are collected into a modulo form.  The inputs must be
      real numbers.
 
 ‘-6’
      Two values are collected into the interval ‘[a .. b]’.  The inputs
      may be real numbers, HMS or date forms, or formulas.
 
 ‘-7’
      Two values are collected into the interval ‘[a .. b)’.
 
 ‘-8’
      Two values are collected into the interval ‘(a .. b]’.
 
 ‘-9’
      Two values are collected into the interval ‘(a .. b)’.
 
 ‘-10’
      Two integer values are collected into a fraction.
 
 ‘-11’
      Two values are collected into a floating-point number.  The first
      is the mantissa; the second, which must be an integer, is the
      exponent.  The result is the mantissa times ten to the power of the
      exponent.
 
 ‘-12’
      This is treated the same as -11 by the ‘v p’ command.  When
      unpacking, -12 specifies that a floating-point mantissa is desired.
 
 ‘-13’
      A real number is converted into a date form.
 
 ‘-14’
      Three numbers (year, month, day) are packed into a pure date form.
 
 ‘-15’
      Six numbers are packed into a date/time form.
 
    With any of the two-input negative packing modes, either or both of
 the inputs may be vectors.  If both are vectors of the same length, the
 result is another vector made by packing corresponding elements of the
 input vectors.  If one input is a vector and the other is a plain
 number, the number is packed along with each vector element to produce a
 new vector.  For example, ‘C-u -4 v p’ could be used to convert a vector
 of numbers and a vector of errors into a single vector of error forms;
 ‘C-u -5 v p’ could convert a vector of numbers and a single number M
 into a vector of numbers modulo M.
 
    If you don’t give a prefix argument to ‘v p’, it takes the packing
 mode from the top of the stack.  The elements to be packed then begin at
 stack level 2.  Thus ‘1 <RET> 2 <RET> 4 n v p’ is another way to enter
 the error form ‘1 +/- 2’.
 
    If the packing mode taken from the stack is a vector, the result is a
 matrix with the dimensions specified by the elements of the vector,
 which must each be integers.  For example, if the packing mode is ‘[2,
 3]’, then six numbers will be taken from the stack and returned in the
 form ‘[[a, b, c], [d, e, f]]’.
 
    If any elements of the vector are negative, other kinds of packing
 are done at that level as described above.  For example, ‘[2, 3, -4]’
 takes 12 objects and creates a 2x3 matrix of error forms: ‘[[a +/- b, c
 +/- d ... ]]’.  Also, ‘[-4, -10]’ will convert four integers into an
 error form consisting of two fractions: ‘a:b +/- c:d’.
 
    There is an equivalent algebraic function, ‘pack(MODE, ITEMS)’ where
 MODE is a packing mode (an integer or a vector of integers) and ITEMS is
 a vector of objects to be packed (re-packed, really) according to that
 mode.  For example, ‘pack([3, -4], [a,b,c,d,e,f])’ yields ‘[a +/- b,
 c +/- d, e +/- f]’.  The function is left in symbolic form if the
 packing mode is invalid, or if the number of data items does not match
 the number of items required by the mode.
 
    The ‘v u’ (‘calc-unpack’) command takes the vector, complex number,
 HMS form, or other composite object on the top of the stack and
 “unpacks” it, pushing each of its elements onto the stack as separate
 objects.  Thus, it is the “inverse” of ‘v p’.  If the value at the top
 of the stack is a formula, ‘v u’ unpacks it by pushing each of the
 arguments of the top-level operator onto the stack.
 
    You can optionally give a numeric prefix argument to ‘v u’ to specify
 an explicit (un)packing mode.  If the packing mode is negative and the
 input is actually a vector or matrix, the result will be two or more
 similar vectors or matrices of the elements.  For example, given the
 vector ‘[a +/- b, c^2, d +/- 7]’, the result of ‘C-u -4 v u’ will be the
 two vectors ‘[a, c^2, d]’ and ‘[b, 0, 7]’.
 
    Note that the prefix argument can have an effect even when the input
 is not a vector.  For example, if the input is the number -5, then ‘c-u
 -1 v u’ yields -5 and 0 (the components of -5 when viewed as a
 rectangular complex number); ‘C-u -2 v u’ yields 5 and 180 (assuming
 Degrees mode); and ‘C-u -10 v u’ yields -5 and 1 (the numerator and
 denominator of -5, viewed as a rational number).  Plain ‘v u’ with this
 input would complain that the input is not a composite object.
 
    Unpacking mode -11 converts a float into an integer mantissa and an
 integer exponent, where the mantissa is not divisible by 10 (except that
 0.0 is represented by a mantissa and exponent of 0).  Unpacking mode -12
 converts a float into a floating-point mantissa and integer exponent,
 where the mantissa (for non-zero numbers) is guaranteed to lie in the
 range [1 ..  10).  In both cases, the mantissa is shifted left or right
 (and the exponent adjusted to compensate) in order to satisfy these
 constraints.
 
    Positive unpacking modes are treated differently than for ‘v p’.  A
 mode of 1 is much like plain ‘v u’ with no prefix argument, except that
 in addition to the components of the input object, a suitable packing
 mode to re-pack the object is also pushed.  Thus, ‘C-u 1 v u’ followed
 by ‘v p’ will re-build the original object.
 
    A mode of 2 unpacks two levels of the object; the resulting
 re-packing mode will be a vector of length 2.  This might be used to
 unpack a matrix, say, or a vector of error forms.  Higher unpacking
 modes unpack the input even more deeply.
 
    There are two algebraic functions analogous to ‘v u’.  The
 ‘unpack(MODE, ITEM)’ function unpacks the ITEM using the given MODE,
 returning the result as a vector of components.  Here the MODE must be
 an integer, not a vector.  For example, ‘unpack(-4, a +/- b)’ returns
 ‘[a, b]’, as does ‘unpack(1, a +/- b)’.
 
    The ‘unpackt’ function is like ‘unpack’ but instead of returning a
 simple vector of items, it returns a vector of two things: The mode, and
 the vector of items.  For example, ‘unpackt(1, 2:3 +/- 1:4)’ returns
 ‘[-4, [2:3, 1:4]]’, and ‘unpackt(2, 2:3 +/- 1:4)’ returns ‘[[-4, -10],
 [2, 3, 1, 4]]’.  The identity for re-building the original object is
 ‘apply(pack, unpackt(N, X)) = X’.  (The ‘apply’ function builds a
 function call given the function name and a vector of arguments.)
 
    Subscript notation is a useful way to extract a particular part of an
 object.  For example, to get the numerator of a rational number, you can
 use ‘unpack(-10, X)_1’.