The functions described here operate on symbolic formulas in the Calculator.
calc-selection-cache-num
contains the number of
the stack entry involved (equal to num if you specified it);
calc-selection-cache-entry
contains the stack entry as a
list (such as calc-top-list
would return with entry
as the selection mode); and calc-selection-cache-comp
contains
a special "tagged" composition (I/O and Formatting Functions 参照 )
which allows Calc to relate cursor positions in the buffer with
their corresponding sub-formulas.
A slight complication arises in the selection mechanism because
formulas may contain small integers. For example, in the vector
`[1, 2, 1]' the first and last elements are eq
to each
other; selections are recorded as the actual Lisp object that
appears somewhere in the tree of the whole formula, but storing
1
would falsely select both 1
's in the vector. So
calc-prepare-selection
also checks the stack entry and
replaces any plain integers with "complex number" lists of the form
`(cplx n 0)'. This list will be displayed the same as a
plain n and the change will be completely invisible to the
user, but it will guarantee that no two sub-formulas of the stack
entry will be eq
to each other. Next time the stack entry
is involved in a computation, calc-normalize
will replace
these lists with plain numbers again, again invisibly to the user.
setcar
to modify
the formula in-place.
calc-prepare-selection
has been
called already. If the cursor is not actually on any part of the
formula, this returns nil
.
eq
to some sub-formula
of the stack element, or nil
to unselect the formula.
The stack element's appearance in the Calc buffer is adjusted
to reflect the new selection.
calc-find-nth-part
with
n equal to four will return `d'.
eq
to the `c+1' term of expr, then this function
will return `(c+1)*d'. If part turns out not to be a
sub-formula of expr, the function returns nil
. If
part is eq
to expr, the function returns t
.
This function does not take associativity into account.
calc-find-parent-formula
, except that
(unless j b has been used) it continues widening the selection
to contain a complete level of the formula. Given `a' from
`((a + b) - c) + d', calc-find-parent-formula
will
return `a + b' but calc-find-assoc-parent-formula
will
return the whole expression.
nil
.
If part is eq
to expr, it returns t
. This
function does not take associativity into account.
eq
to old replaced by new.
calc-simplify
) command uses. This
always returns a copy of the expression; the structure expr points
to remains unchanged in memory.
More precisely, here is what simplify
does: The expression is
first normalized and evaluated by calling normalize
. If any
AlgSimpRules
have been defined, they are then applied. Then
the expression is traversed in a depth-first, bottom-up fashion; at
each level, any simplifications that can be made are made until no
further changes are possible. Once the entire formula has been
traversed in this way, it is compared with the original formula (from
before the call to normalize
) and, if it has changed,
the entire procedure is repeated (starting with normalize
)
until no further changes occur. Usually only two iterations are
needed: one to simplify the formula, and another to verify that no
further simplifications were possible.
math-living-dangerously
to t
(using a let
form) and calling simplify
.
Dangerous simplification rules are written to check this variable
before taking any action.
math-simplifying-units
to t
while calling simplify
.
defun
or defmath
. If funcs is a symbol
(like +
or calcFunc-sqrt
), this simplification rule is
applied to the formulas which are calls to the specified function. Or,
funcs can be a list of such symbols; the rule applies to all
functions on the list. The body is written like the body of a
function with a single argument called expr
. The body will be
executed with expr
bound to a formula which is a call to one of
the functions funcs. If the function body returns nil
, or
if it returns a result equal
to the original expr
, it is
ignored and Calc goes on to try the next simplification rule that applies.
If the function body returns something different, that new formula is
substituted for expr in the original formula.
At each point in the formula, rules are tried in the order of the
original calls to math-defsimplify
; the search stops after the
first rule that makes a change. Thus later rules for that same
function will not have a chance to trigger until the next iteration
of the main simplify
loop.
Note that, since defmath
is not being used here, body must
be written in true Lisp code without the conveniences that defmath
provides. If you prefer, you can have body simply call another
function (defined with defmath
) which does the real work.
The arguments of a function call will already have been simplified before any rules for the call itself are invoked. Since a new argument list is consed up when this happens, this means that the rule's body is allowed to rearrange the function's arguments destructively if that is convenient. Here is a typical example of a simplification rule:
(math-defsimplify calcFunc-arcsinh (or (and (math-looks-negp (nth 1 expr)) (math-neg (list 'calcFunc-arcsinh (math-neg (nth 1 expr))))) (and (eq (car-safe (nth 1 expr)) 'calcFunc-sinh) (or math-living-dangerously (math-known-realp (nth 1 (nth 1 expr)))) (nth 1 (nth 1 expr)))))
This is really a pair of rules written with one math-defsimplify
for convenience; the first replaces `arcsinh(-x)' with
`-arcsinh(x)', and the second, which is safe only for real `x',
replaces `arcsinh(sinh(x))' with `x'.
nil
.
For example, if called on `6x + 9y + 12z', it would return 3, since
3 is a common factor of all the terms.
(math-defsimplify calcFunc-sqrt (let ((fac (math-common-constant-factor (nth 1 expr)))) (and fac (not (eq fac 1)) (math-mul (math-normalize (list 'calcFunc-sqrt fac)) (math-normalize (list 'calcFunc-sqrt (math-cancel-common-factor (nth 1 expr) fac)))))))
common-constant-factor
. Note that the standard
gcd
function uses the LCM to combine the denominators.
equal
to
expr, apply func again until eventually it does return
expr with no changes. Then, if expr is a function call,
recursively apply func to each of the arguments. This keeps going
until no changes occur anywhere in the expression; this final expression
is returned by map-tree
. Note that, unlike simplification rules,
func functions may not make destructive changes to
expr. If a third argument many is provided, it is an
integer which says how many times func may be applied; the
default, as described above, is infinitely many times.
compile-rules
calls
for that same variable can return immediately. If there are problems
with the rules, this function calls error
with a suitable
message.
nil
if no rules
matched, or if the only rules that matched did not actually change
the expression. The heads argument is optional; if is given,
it should be a list of all function names that (may) appear in
expr. The rewrite compiler tags each rule with the
rarest-looking function name in the rule; if you specify heads,
apply-rewrites
can use this information to narrow its search
down to just a few rules in the rule set.
apply-rewrites
, as discussed above.
map-tree
to apply the
rules throughout expr up to many (default infinity)
times.
nil
) match any of the patterns in pat.
nil
, the presence of undifferentiable
functions in expr instead cancels the whole differentiation, and
deriv
returns nil
instead.
Derivatives of an n-argument function can be defined by
adding a math-derivative-n
property to the property list
of the symbol for the function's derivative, which will be the
function name followed by an apostrophe. The value of the property
should be a Lisp function; it is called with the same arguments as the
original function call that is being differentiated. It should return
a formula for the derivative. For example, the derivative of ln
is defined by
(put 'calcFunc-ln\' 'math-derivative-1 (function (lambda (u) (math-div 1 u))))
The two-argument log
function has two derivatives,
(put 'calcFunc-log\' 'math-derivative-2 ; d(log(x,b)) / dx (function (lambda (x b) ... ))) (put 'calcFunc-log\'2 'math-derivative-2 ; d(log(x,b)) / db (function (lambda (x b) ... )))
deriv
, except that variables other than var are not
assumed to be constant with respect to var.
math-defsimplify
.
The main difference is that here body is the body of a function
with a single argument u
which is bound to the argument to the
function being integrated, not the function call itself. Also, the
variable of integration is available as math-integ-var
. If
evaluation of the integral requires doing further integrals, the body
should call `(math-integral x)' to find the integral of
x with respect to math-integ-var
; this function returns
nil
if the integral could not be done. Some examples:
(math-defintegral calcFunc-conj (let ((int (math-integral u))) (and int (list 'calcFunc-conj int)))) (math-defintegral calcFunc-cos (and (equal u math-integ-var) (math-from-radians-2 (list 'calcFunc-sin u))))
In the cos
example, we define only the integral of `cos(x) dx',
relying on the general integration-by-substitution facility to handle
cosines of more complicated arguments. An integration rule should return
nil
if it can't do the integral; if several rules are defined for
the same function, they are tried in order until one returns a non-nil
result.
math-defintegral
, except that body
is written as the body of a function with two arguments, u and
v.
nil
if the equation cannot be solved. The variable
var must appear at least once in lhs or rhs. Note that
the return value is a formula which does not contain var; this is
different from the user-level solve
and finv
functions,
which return a rearranged equation or a functional inverse, respectively.
If full is non-nil
, a full solution including dummy signs
and dummy integers will be produced. User-defined inverses are provided
as properties in a manner similar to derivatives:
(put 'calcFunc-ln 'math-inverse (function (lambda (x) (list 'calcFunc-exp x))))
This function can call `(math-solve-get-sign x)' to create a new arbitrary sign variable, returning x times that sign, and `(math-solve-get-int x)' to create a new arbitrary integer variable multiplied by x. These functions simply return x if the caller requested a non-"full" solution.
solve-for
takes an expression which will
typically be an equation or inequality. (If it is not, it will be
interpreted as the equation `expr = 0'.) It returns an
equation or inequality, or nil
if no solution could be found.
nil
value if var occurs as a subexpression
of expr.
This function might seem at first to be identical to
calc-find-sub-formula
. The key difference is that
expr-contains
uses equal
to test for matches, whereas
calc-find-sub-formula
uses eq
. In the formula
`f(a, a)', the two `a's will be equal
but not
eq
to each other.
nil
if there are no occurrences.
nil
if expr
contains only constants and functions with constant arguments.
lambda
forms specially with respect
to the dummy argument variables, so that the effect is always to return
expr evaluated at old = new.
expr-subst
, except that old and new
are lists of expressions to be substituted simultaneously. If one
list is shorter than the other, trailing elements of the longer list
are ignored.
nil
unless expr, when expanded out by a x
(calc-expand
), would consist of a sum of terms in which var
appears only raised to nonnegative integer powers. Note that if
var does not occur in expr, then expr is considered
a polynomial of degree 0.
nil
if expr is not a polynomial in var. If degree is
specified, this will not consider polynomials of degree higher than that
value. This is a good precaution because otherwise an input of
`(x+1)^1000' will cause a huge coefficient list to be built. If
loose is non-nil
, then a looser definition of a polynomial
is used in which coefficients are no longer required not to depend on
var, but are only required not to take the form of polynomials
themselves. For example, `sin(x) x^2 + cos(x)' is a loose
polynomial with coefficients `((calcFunc-cos x) 0 (calcFunc-sin
x))'. The result will never be nil
in loose mode, since any
expression can be interpreted as a "constant" loose polynomial.
mpb-top-expr
(a global name for
the original expr) is a suitable polynomial in subexpr.
The default predicate uses `(polynomial-p mpb-top-expr subexpr)';
you can use pred to specify additional conditions. Or, you could
have pred build up a list of every suitable subexpr that
is found.
is-polynomial
) in a linear combination with coefficient expressions
ac and bc. The result is a (not necessarily simplified)
polynomial list representing `ac a + bc b'.
calc-collect
) command uses is-polynomial
to turn an
expression into a coefficient list, then build-polynomial-expr
to turn the list back into an expression in regular form.
nil
.
t
, the entire
expression is searched. If sub-exprs is nil
, this
checks whether expr is directly a units expression.
nil
. If expr contains
two or more units, return the symbol wrong
.
nil
, use Calc's native base units. Otherwise, which
can specify a units system, which is a list of two-element lists,
where the first element is a Calc base symbol name and the second
is an expression to substitute for it.
Go to the first, previous, next, last section, table of contents.
利用度数