Eigenmath/mag.cpp

159 lines
2.0 KiB
C++

/* Magnitude of complex z
z mag(z)
- ------
a a
-a a
(-1)^a 1
exp(a + i b) exp(a)
a b mag(a) mag(b)
a + i b sqrt(a^2 + b^2)
Notes
1. Handles mixed polar and rectangular forms, e.g. 1 + exp(i pi/3)
2. jean-francois.debroux reports that when z=(a+i*b)/(c+i*d) then
mag(numerator(z)) / mag(denominator(z))
must be used to get the correct answer. Now the operation is
automatic.
*/
#include "stdafx.h"
#include "defs.h"
void
eval_mag(void)
{
push(cadr(p1));
eval();
mag();
}
void
mag(void)
{
save();
p1 = pop();
push(p1);
numerator();
yymag();
push(p1);
denominator();
yymag();
divide();
restore();
}
void
yymag(void)
{
save();
p1 = pop();
if (isnegativenumber(p1)) {
push(p1);
negate();
} else if (car(p1) == symbol(POWER) && equaln(cadr(p1), -1))
// -1 to a power
push_integer(1);
else if (car(p1) == symbol(POWER) && cadr(p1) == symbol(E)) {
// exponential
push(caddr(p1));
real();
exponential();
} else if (car(p1) == symbol(MULTIPLY)) {
// product
push_integer(1);
p1 = cdr(p1);
while (iscons(p1)) {
push(car(p1));
mag();
multiply();
p1 = cdr(p1);
}
} else if (car(p1) == symbol(ADD)) {
// sum
push(p1);
rect(); // convert polar terms, if any
p1 = pop();
push(p1);
real();
push_integer(2);
power();
push(p1);
imag();
push_integer(2);
power();
add();
push_rational(1, 2);
power();
simplify_trig();
} else
// default (all real)
push(p1);
restore();
}
#if SELFTEST
static char *s[] = {
"mag(a+i*b)",
"(a^2+b^2)^(1/2)",
"mag(exp(a+i*b))",
"exp(a)",
"mag(1)",
"1",
"mag(-1)",
"1",
"mag(1+exp(i*pi/3))",
"3^(1/2)",
"mag((a+i*b)/(c+i*d))",
"(a^2+b^2)^(1/2)/((c^2+d^2)^(1/2))",
"mag(exp(i theta))",
"1",
"mag(exp(-i theta))",
"1",
"mag((-1)^theta)",
"1",
"mag((-1)^(-theta))",
"1",
"mag(3*(-1)^theta)",
"3",
"mag(3*(-1)^(-theta))",
"3",
"mag(-3*(-1)^theta)",
"3",
"mag(-3*(-1)^(-theta))",
"3",
};
void
test_mag(void)
{
test(__FILE__, s, sizeof s / sizeof (char *));
}
#endif