home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / C / APMTEST / FUNCTION < prev    next >
Text File  |  1993-12-01  |  16KB  |  451 lines

  1. APM
  2. apmInit(init, scale_factor, base)
  3. long init;
  4. int scale_factor;
  5. short base;
  6. {}
  7.   This routine initializes a new APM value.  The 'init' parameter is a long
  8.   integer that represents its initial value, the 'scale_factor' variable
  9.   indicates how this initial value should be scaled, and 'base' is the base of
  10.   the initial value.  Note that the APM value returned by this routine is
  11.   normally a reclaimed APM value that has been previously disposed of via
  12.   apmDispose(); only if there are no previous values to be reclaimed will this
  13.   routine allocate a fresh APM value (see also the apmGarbageCollect()
  14.   routine).
  15.  
  16.   Bases can be 2 - 36, 10000, or 0, where 0 defaults to base 10000.
  17.  
  18.   If the call fails, it will return (APM)NULL and 'apm_errno' will contain a
  19.   meaningful result.  Otherwise, a new APM value will be initialized.
  20.  
  21.   For example, assume that we want to initialize two APM values in base 10000,
  22.   the first to 1.23456 and the second to 1 E20 ("one times 10 to the 20th
  23.   power"):
  24.  
  25.       APM apm_1 = apmInit(123456L, -5, 0);
  26.       APM apm_2 = apmInit(1L, 20, 0);
  27.  
  28.   As a convenience, the following macro is defined in apm.h:
  29.  
  30.       #define apmNew(BASE)    apmInit(0L, 0, (BASE))
  31.  
  32. int
  33. apmDispose(apm)
  34. APM apm;
  35. {}
  36.   This routine disposes of a APM value 'apm' by returning it to the list of
  37.   unused APM values (see also the apmGarbageCollect() routine).  It returns
  38.   an appropriate status which is also put into 'apm_errno'.
  39.  
  40. int
  41. apmGarbageCollect()
  42. {}
  43.   When APM values are disposed of, they remain allocated.  Subsequent calls to
  44.   apmInit() may then return a previously allocated but disposed APM value.
  45.   This is done for speed considerations, but after a while there may be lots of
  46.   these unused APM values lying around.  This routine reclaims the space taken
  47.   up by these unused APM values (it frees them).  It returns an appropriate
  48.   status which is also put into 'apm_errno'.
  49.  
  50. int
  51. apmAdd(result, apm1, apm2)
  52. APM result;
  53. APM apm1;
  54. APM apm2;
  55. {}
  56.   This routine adds 'apm1' and 'apm2', putting the sum into 'result', whose
  57.   previous value is destroyed.  Note that all three parameters must have been
  58.   previously initialized via apmInit().
  59.  
  60.   The 'result' parameter cannot be one of the other APM parameters.
  61.  
  62.   The return code and the 'apm_error' variable reflect the status of this
  63.   function.
  64.  
  65. int
  66. apmSubtract(result, apm1, apm2)
  67. APM result;
  68. APM apm1;
  69. APM apm2;
  70. {}
  71.   This routine subtracts 'apm2' from 'apm1', putting the difference into
  72.   'result', whose previous value is destroyed.  Note that all three parameters
  73.   must have been previously initialized via apmInit().
  74.  
  75.   The 'result' parameter cannot be one of the other APM parameters.
  76.  
  77.   The return code and the 'apm_errno' variable reflect the status of this
  78.   function.
  79.  
  80. int
  81. apmMultiply(result, apm1, apm2)
  82. APM result;
  83. APM apm1;
  84. APM apm2;
  85. {}
  86.   This routine multiplies 'apm1' and 'apm2', putting the product into 'result',
  87.   whose previous value is destroyed.  Note that all three parameters must have
  88.   been previously initialized via apmInit().
  89.  
  90.   The 'result' parameter cannot be one of the other APM parameters.
  91.  
  92.   The return code and the 'apm_errno' variable reflect the status of this
  93.   function.
  94.  
  95. int
  96. apmDivide(quotient, radix_places, remainder, apm1, apm2)
  97. APM quotient;
  98. int radix_places;
  99. APM remainder;
  100. APM apm1;
  101. APM apm2;
  102. {}
  103.   This routine divides 'apm1' by 'apm2', producing the 'quotient' and
  104.   'remainder' variables.  Unlike the other three basic operations,
  105.   division cannot be counted on to produce non-repeating decimals, so
  106.   the 'radix_places' variable exists to tell this routine how many
  107.   digits to the right of the radix point are to be calculated before
  108.   stopping.  If the 'remainder' variable is set to (APM)NULL, no
  109.   remainder is calculated ... this saves quite a bit of computation time
  110.   and hence is recommended whenever possible.
  111.  
  112.   All APM values must have been previously initialized via apmInit() (except,
  113.   of course the 'remainder' value if it is to be set to NULL).
  114.  
  115.   Division by zero creates a zero result and a warning.
  116.  
  117.   The 'quotient' and 'remainder' variables can't be one of the other APM
  118.   parameters.
  119.  
  120.   The return code and the 'apm_errno' variable reflect the status of this
  121.   function.
  122.  
  123. int
  124. apmCompare(apm1, apm2)
  125. APM apm1;
  126. APM apm2;
  127. {}
  128.   This routine compares 'apm1' and 'apm2', returning -1 if 'apm1' is less than
  129.   'apm2', 1 if 'apm1' is greater than 'apm2', and 0 if they are equal.
  130.  
  131.   It is not an error if 'apm1' and 'apm2' are identical, and in this case the
  132.   return value is 0.
  133.  
  134.   The 'apm_errno' variable contains the error code.  You must check this value:
  135.   if it is set to an error indication, the comparison failed and the return
  136.   value is therefore meaningless.
  137.  
  138. int
  139. apmCompareLong(apm, longval, scale_factor, base)
  140. APM apm;
  141. long longval;
  142. int scale_factor;
  143. short base;
  144. {}
  145.   This routine works just like apmCompare(), but it compares the 'apm' value to
  146.   'longval', scaled by 'scale_factor' in 'base'.  The 'apm_errno' variable
  147.   contains the error code.
  148.  
  149. int
  150. apmSign(apm)
  151. APM apm;
  152. {}
  153.   This routine returns the sign of the 'apm' value: -1 for negative, 1 for
  154.   positive.  The 'apm_errno' variable contains the error code.  You must check
  155.   'apm_errno': if it's non-zero, the function return value is meaningless.
  156.  
  157. int
  158. apmAbsoluteValue(result, apm)
  159. APM result;
  160. APM apm;
  161. {}
  162.   This routine puts the absolute value of 'apm' into 'result', whose previous
  163.   value is destroyed.  Note that the two parameters must have been previously
  164.   initialized via apmInit().
  165.  
  166.   The 'result' parameter cannot be the other APM parameter.
  167.  
  168.   The return code and the 'apm_errno' variable reflect the status of this
  169.   function.
  170.  
  171. int
  172. apmNegate(result, apm)
  173. APM result;
  174. APM num;
  175. {}
  176.   This routine puts the additive inverse of 'apm' into 'result', whose previous
  177.   value is destroyed.  Note that the two parameters must have been previously
  178.   initialized via apmInit().
  179.  
  180.   The 'result' parameter cannot be the other APM parameter.
  181.  
  182.   The return code and the 'apm_errno' variable reflect the status of this
  183.   function.
  184.  
  185. int
  186. apmReciprocal(result, radix_places, apm)
  187. APM result;
  188. int radix_places;
  189. APM num;
  190. {}
  191.   This routine puts the multiplicative inverse of 'apm' into 'result', whose
  192.   previous value is destroyed.  Note that the two APM parameters must have been
  193.   previously initialized via apmInit().  Since taking the reciprocal involves
  194.   doing a division, the 'radix_places' parameter is needed here for the same
  195.   reason it's needed in the apmDivide() routine.
  196.  
  197.   Taking the reciprocal of zero yields zero with a warning status.
  198.  
  199.   The 'result' parameter cannot be the other APM parameter.
  200.  
  201.   The return code and the 'apm_errno' variable reflect the status of this
  202.   function.
  203.  
  204. int
  205. apmScale(result, apm, scale_factor)
  206. APM result;
  207. APM apm;
  208. int scale_factor;
  209. {}
  210.   This routine assigns to 'result' the value of 'apm' with its radix point
  211.   shifted by 'scale_factor' (positive 'scale_factor' means shift left).  The
  212.   'scale_factor' represents how many places the radix is shifted in the base of
  213.   'apm' unless 'apm' is in base 10000 ...  in this special case, 'scale_factor'
  214.   is treated as if the base were 10.
  215.  
  216.   This is a very quick and accurate way to multiply or divide by a power of 10
  217.   (or the number's base).
  218.  
  219.   The 'result' parameter cannot be the other APM parameter.
  220.  
  221.   The return code and the 'apm_errno' variable reflect the status of this
  222.   function.
  223.  
  224. int
  225. apmValidate(apm)
  226. APM apm;
  227. {}
  228.   This routine sets 'apm_errno' and its return status to some non-zero value if
  229.   'apm' is not a valid APM value.
  230.  
  231. int
  232. apmAssign(result, apm)
  233. APM result;
  234. APM num;
  235. {}
  236.   This routine assigns the value of 'apm' to 'result', whose previous value is
  237.   destroyed.  Note that the two parameters must have been previously
  238.   initialized via apmInit().
  239.  
  240.   It is not considered an error if 'result' and 'apm' are identical; this case
  241.   is a virtual no-op.
  242.  
  243.   The return code and the 'apm_errno' variable reflect the status of this
  244.   function.
  245.  
  246. int
  247. apmAssignLong(result, long_value, scale_factor, base)
  248. APM result;
  249. long long_value;
  250. int scale_factor;
  251. short base;
  252. {}
  253.   This routine assigns a long int to 'result'.  Its second through fourth
  254.   parameters correspond exactly to the parameters of apmInit().  The only
  255.   difference between the two routines is that this one requires that its result
  256.   be previously initialized.  The 'long_value' parameter is a long that
  257.   represents the value to assign to 'result', the 'scale_factor' variable
  258.   indicates how this value should be scaled, and 'base' is the base of the
  259.   value.
  260.  
  261.   Bases can be 2 - 36, 10000, or 0, where 0 defaults to base 10000.
  262.  
  263.   For example, assume that we want to assign values to two previously
  264.   initialized APM entities, apm_1 and apm_2.  The base will be base 10000, the
  265.   first value will be set to 1.23456 and the second will be set to 1 E20 ("one
  266.   times 10 to the 20th power"):
  267.  
  268.       int ercode;
  269.  
  270.       ercode = apmAssignLong(apm_1, 123456L, -5, 0);
  271.       ...
  272.  
  273.       ercode = apmAssignLong(apm_2, 1L, 20, 0);
  274.       ...
  275.  
  276.   The return code and the 'apm_errno' variable reflect the status of this
  277.   function.
  278.  
  279. int
  280. apmAssignString(apm, string, base)
  281. APM apm;
  282. char *string;
  283. short base;
  284. {}
  285.   This routine takes a character string containing the ASCII representation of
  286.   a numeric value and converts it into a APM value in the base specified.  The
  287.   'apm' parameter must have been previously initialized, 'string' must be
  288.   non-NULL and valid in the specified base, and 'base' must be a valid base.
  289.  
  290.   The return code and the 'apm_errno' variable reflect the status of this
  291.   function.
  292.  
  293. int
  294. apmConvert(string, length, decimals, round, leftjustify, apm)
  295. char *string;
  296. int length;
  297. int decimals;
  298. int round;
  299. int leftjustify;
  300. APM apm;
  301. {}
  302.   This routine converts a APM value 'apm' into its ASCII representation
  303.   'string'. The 'length' parameter is the maximum size of the string (including
  304.   the trailing null), the 'decimals' parameter is the number of decimal places
  305.   to display, the 'round' parameter is a true-false value which determines
  306.   whether rounding is to take place (0 = false = no rounding), the
  307.   'leftjustify' parameter is a true-false value which determines whether the
  308.   result is to be left justified (0 = false = right justify; non-zero = true =
  309.   left justify), and the 'apm' paramter is the APM value to be converted.
  310.  
  311.   The 'string' parameter must point to an area that can hold at least 'length'
  312.   bytes.
  313.  
  314.   If the 'decimals' parameter is < 0, the string will contain the number of
  315.   decimal places that are inherent in the APM value passed in.
  316.  
  317.   The return code and the 'apm_errno' variable reflect the status of this
  318.   function.
  319.  
  320. int
  321. (*apmErrorFunc(newfunc))()
  322. int (*newfunc)();
  323. {}
  324.   This routine registers an error handler for errors and warnings.  Before any
  325.   of the other APM routines return to the caller, an optional error handler
  326.   specified in 'newfunc' can be called to intercept the result of the
  327.   operation.  With a registered error handler, the caller can dispense with the
  328.   repetitious code for checking 'apm_errno' or the function return status after
  329.   each call to a APM routine.
  330.  
  331.   If no error handler is registered or if 'newfunc' is set to NULL, no action
  332.   will be taken on errors and warnings except to set the 'apm_errno' variable.
  333.   If there is an error handler, it is called as follows when there is an error
  334.   or a warning:
  335.  
  336.       retcode = (*newfunc)(ercode, message, file, line, function)
  337.  
  338.   where ...
  339.  
  340.       int retcode;      /* returned by 'newfunc': should be 'ercode' */
  341.       int ercode;       /* error code */
  342.       char *message;    /* a short string describing the error */
  343.       char *file;       /* the file in which the error occurred */
  344.       int line;            /* the line on which the error occurred */
  345.       char *function;    /* the name of the function in error */
  346.  
  347.   Note that your error handler should normally return 'ercode' unless it does a
  348.   longjmp, calls exit(), or in some other way interrupts the normal processing
  349.   flow.  The value returned from your error handler is the value that the apm
  350.   routine in error will return to its caller.
  351.  
  352.   The error handler is called after 'apm_errno' is set.
  353.  
  354.   This routine returns a pointer to the previously registered error handler or
  355.   NULL if one isn't registered.
  356.  
  357. int
  358. apmCalc(result, operand, ..., NULL)
  359. APM result;
  360. APM operand, ...;
  361. {}
  362.   This routine performs a series of calculations in an RPN ("Reverse
  363.   Polish Notation") fashion, returning the final result in the 'result'
  364.   variable.  It takes a variable number of arguments and hence the
  365.   rightmost argument must be a NULL.
  366.  
  367.   Each 'operand' is either a APM value or a special constant indicating
  368.   the operation that is to be performed (see below).  This routine makes
  369.   use of a stack (16 levels deep) similar to that in many pocket
  370.   calculators.  It also is able to access a set of 16 auxiliary
  371.   registers (numbered 0 through 15) for holding intermediate values.
  372.  
  373.   The stack gets reinitialized at the start of this routine, so values
  374.   that have been left on the stack from a previous call will disappear.
  375.   However, the auxiliary registers are static and values remain in these
  376.   registers for the duration of your program.  They may also be
  377.   retrieved outside of this routine (see the apmGetRegister() and
  378.   apmSetRegister() routines, below).
  379.  
  380.   An operand that is an APM value is automatically pushed onto the stack
  381.   simply by naming it in the function call.  If the stack is full when a
  382.   value is being pushed onto it, the bottommost value drops off the
  383.   stack and the push succeeds; this is similar to how many pocket
  384.   calculators work.  Also, if the stack is empty, a pop will succeed,
  385.   yielding a zero value and keeping the stack empty.  The topmost value
  386.   on the stack is automatically popped into the 'result' parameter after
  387.   all the operations have been performed.
  388.  
  389.   An operand that is one of the following special values will cause
  390.   an operation to be performed.  These operations are described in the
  391.   following list.  Note that the values "V", "V1", and "V2" are used
  392.   in the following list to stand for temporary values:
  393.  
  394.     APM_ABS        pop V, push absolute value of V
  395.     APM_NEG        pop V, push -V
  396.     APM_CLEAR    empty the stack
  397.     APM_DUP        pop V, push V, push V
  398.     APM_SWAP    pop V1, pop V2, push V1, push V2
  399.     APM_SCALE(N)    pop V, push V scaled by N [ as in apmScale() ]
  400.     APM_PUSH(N)    V = value in register N, push V
  401.     APM_POP(N)    pop V, store it in register N
  402.     APM_ADD        pop V1, pop V2, push (V2 + V1)
  403.     APM_SUB        pop V1, pop V2, push (V2 - V1)
  404.     APM_MUL        pop V1, pop V2, push (V2 * V1)
  405.     APM_DIV(N)    pop V1, pop V2, push (V2 / V1) with N radix places
  406.             [ as in apmDivide() ], remainder goes into register 0
  407.     APM_RECIP(N)    pop V, push 1/V with N radix places
  408.             [ as in apmReciprocal() ]
  409.  
  410.   Since register 0 is used to hold the remainder in a division, it is
  411.   recommended that this register not be used to hold other values.
  412.  
  413.   As an example, assume that APM values "foo", "bar", and "baz" have
  414.   been initialized via apmInit() and that "foo" and "bar" are to be used
  415.   to calculate "baz" as follows (assume that divisions stop after 16
  416.   decimal places have been calcluated):
  417.  
  418.     baz = 1 / ((((foo * bar) + foo) / bar) - foo)
  419.  
  420.   The function call will be:
  421.  
  422.     bcdCalc(baz, foo, APM_DUP, APM_POP(1), bar, APM_DUP, APM_POP(2),
  423.         APM_MUL, APM_PUSH(1), APM_ADD, APM_PUSH(2), APM_DIV(16),
  424.         APM_PUSH(1), APM_SUB, APM_RECIP(16), NULL);
  425.  
  426.   Note that the value of "foo" is stored in register 1 and the value of
  427.   "bar" is stored in register 2.  After this call, these registers will
  428.   still contain those values.
  429.  
  430. int
  431. apmGetRegister(regvalue, regnumber)
  432. APM regvalue;
  433. int regnumber;
  434. {}
  435.   The value in auxiliary register number 'regnumber' is assigned to APM
  436.   value 'regvalue'.  The 'regnumber' parameter must be between 0 and 15,
  437.   inclusive.  The 'regvalue' parameter must have been previously
  438.   initialized via apmInit().
  439.  
  440. int
  441. apmSetRegister(regvalue, regnumber, newvalue)
  442. APM regvalue;
  443. int regnumber;
  444. APM newvalue;
  445. {}
  446.   The value in auxiliary register number 'regnumber' is assigned to APM
  447.   value 'regvalue', and then the APM value 'newvalue' is stored in that
  448.   same register.  The 'regnumber' parameter must be between 0 and 15,
  449.   inclusive.  The 'regvalue' and 'newvalue' parameters must have been
  450.   previously initialized via apmInit().
  451.