1/3
@end example
-All numbers occuring in GiNaC's expressions can be converted into floating
-point numbers with the @code{evalf} method, to arbitrary accuracy:
+Exact numbers are always retained as exact numbers and only evaluated as
+floating point numbers if requested. For instance, with numeric
+radicals is dealt pretty much as with symbols. Products of sums of them
+can be expanded:
+
+@example
+> expand((1+a^(1/5)-a^(2/5))^3);
+1+3*a+3*a^(1/5)-5*a^(3/5)-a^(6/5)
+> expand((1+3^(1/5)-3^(2/5))^3);
+10-5*3^(3/5)
+> evalf((1+3^(1/5)-3^(2/5))^3);
+0.33408977534118624228
+@end example
+
+The function @code{evalf} that was used above converts any number in
+GiNaC's expressions into floating point numbers. This can be done to
+arbitrary predefined accuracy:
@example
> evalf(1/7);
> a=Pi^2+x;
x+Pi^2
> evalf(a);
-x+9.869604401089358619L0
+9.869604401089358619+x
> x=2;
2
> evalf(a);
-11.869604401089358619L0
+11.869604401089358619
@end example
Built-in functions evaluate immediately to exact numbers if
@example
> lsolve(a+x*y==z,x);
y^(-1)*(z-a);
-lsolve([3*x+5*y == 7, -2*x+10*y == -5], [x, y]);
+> lsolve([3*x+5*y == 7, -2*x+10*y == -5], [x, y]);
[x==19/8,y==-1/40]
> M = [[ [[1, 3]], [[-3, 2]] ]];
[[ [[1,3]], [[-3,2]] ]]
@end example
You can differentiate functions and expand them as Taylor or Laurent
-series (the third argument of @code{series} is the evaluation point, the
-fourth defines the order):
+series in a very natural syntax (the second argument of @code{series} is
+a relation defining the evaluation point, the third specifies the
+order):
@cindex Zeta function
@example
> diff(tan(x),x);
tan(x)^2+1
-> series(sin(x),x,0,4);
+> series(sin(x),x==0,4);
x-1/6*x^3+Order(x^4)
-> series(1/tan(x),x,0,4);
+> series(1/tan(x),x==0,4);
x^(-1)-1/3*x+Order(x^2)
-> series(gamma(x),x,0,3);
-x^(-1)-EulerGamma+(1/12*Pi^2+1/2*EulerGamma^2)*x
-+(-1/3*zeta(3)-1/12*Pi^2*EulerGamma-1/6*EulerGamma^3)*x^2+Order(x^3)
+> series(Gamma(x),x==0,3);
+x^(-1)-gamma+(1/12*Pi^2+1/2*gamma^2)*x+
+(-1/3*zeta(3)-1/12*Pi^2*gamma-1/6*gamma^3)*x^2+Order(x^3)
> evalf(");
-x^(-1.0)-0.5772156649015328606+(0.98905599532797255544)*x
--(0.90747907608088628905)*x^2+Order(x^(3.0))
-> series(gamma(2*sin(x)-2),x,Pi/2,6);
--(x-1/2*Pi)^(-2)+(-1/12*Pi^2-1/2*EulerGamma^2-1/240)*(x-1/2*Pi)^2
--EulerGamma-1/12+Order((x-1/2*Pi)^3)
+x^(-1)-0.5772156649015328606+(0.9890559953279725555)*x
+-(0.90747907608088628905)*x^2+Order(x^3)
+> series(Gamma(2*sin(x)-2),x==Pi/2,6);
+-(x-1/2*Pi)^(-2)+(-1/12*Pi^2-1/2*gamma^2-1/240)*(x-1/2*Pi)^2
+-gamma-1/12+Order((x-1/2*Pi)^3)
@end example
Here we have made use of the @command{ginsh}-command @code{"} to pop the
but also on other parameters, for instance what value for @env{CXXFLAGS}
you entered. Optimization may be very time-consuming.
-Just to make sure GiNaC works properly you may run a simple test
-suite by typing
+Just to make sure GiNaC works properly you may run a collection of
+regression tests by typing
@example
$ make check
@end example
-This will compile some sample programs, run them and compare the output
-to reference output. Each of the checks should return a message @samp{passed}
-together with the CPU time used for that particular test. If it does
-not, something went wrong. This is mostly intended to be a QA-check
-if something was broken during the development, not a sanity check
-of your system. Another intent is to allow people to fiddle around
-with optimization. If @acronym{CLN} was installed all right
-this step is unlikely to return any errors.
+This will compile some sample programs, run them and check the output
+for correctness. The regression tests fall in three categories. First,
+the so called @emph{exams} are performed, simple tests where some
+predefined input is evaluated (like a pupils' exam). Second, the
+@emph{checks} test the coherence of results among each other with
+possible random input. Third, some @emph{timings} are performed, which
+benchmark some predefined problems with different sizes and display the
+CPU time used in seconds. Each individual test should return a message
+@samp{passed}. This is mostly intended to be a QA-check if something
+was broken during development, not a sanity check of your system.
+Another intent is to allow people to fiddle around with optimization.
Generally, the top-level Makefile runs recursively to the
subdirectories. It is therfore safe to go into any subdirectory
int main()
@{
- numeric two(2); // exact integer 2
- numeric r(2,3); // exact fraction 2/3
- numeric e(2.71828); // floating point number
- numeric p("3.1415926535897932385"); // floating point number
-
+ numeric two(2); // exact integer 2
+ numeric r(2,3); // exact fraction 2/3
+ numeric e(2.71828); // floating point number
+ numeric p("3.1415926535897932385"); // floating point number
+ // Trott's constant in scientific notation:
+ numeric trott("1.0841015122311136151E-2");
+
cout << two*p << endl; // floating point 6.283...
// ...
@}
@cindex @code{Pi}
@cindex @code{Catalan}
-@cindex @code{EulerGamma}
+@cindex @code{gamma}
@cindex @code{evalf()}
Constants behave pretty much like symbols except that they return some
specific number when the method @code{.evalf()} is called.
@item @code{Catalan}
@tab Catalan's constant
@tab 0.91596559417721901505460351493238411
-@item @code{EulerGamma}
+@item @code{gamma}
@tab Euler's (or Euler-Mascheroni) constant
@tab 0.57721566490153286060651209008240243
@end multitable
symbol x("x"), y("y");
ex foo = x+y/2;
- cout << "gamma(" << foo << ") -> " << gamma(foo) << endl;
+ cout << "Gamma(" << foo << ") -> " << Gamma(foo) << endl;
ex bar = foo.subs(y==1);
- cout << "gamma(" << bar << ") -> " << gamma(bar) << endl;
+ cout << "Gamma(" << bar << ") -> " << Gamma(bar) << endl;
ex foobar = bar.subs(x==7);
- cout << "gamma(" << foobar << ") -> " << gamma(foobar) << endl;
+ cout << "Gamma(" << foobar << ") -> " << Gamma(foobar) << endl;
// ...
@}
@end example
expression that may be really useful:
@example
-gamma(x+(1/2)*y) -> gamma(x+(1/2)*y)
-gamma(x+1/2) -> gamma(x+1/2)
-gamma(15/2) -> (135135/128)*Pi^(1/2)
+Gamma(x+(1/2)*y) -> Gamma(x+(1/2)*y)
+Gamma(x+1/2) -> Gamma(x+1/2)
+Gamma(15/2) -> (135135/128)*Pi^(1/2)
@end example
@cindex branch cut
the @code{.subs()} method show how objects of class relational are used
as arguments. There they provide an intuitive syntax for substitutions.
They can also used for creating systems of equations that are to be
-solved for unknown variables.
+solved for unknown variables. More applications of this class will
+appear throughout the next chapters.
@node Archiving, Important Algorithms, Relations, Basic Concepts
symbol v("v"), c("c");
ex gamma = 1/sqrt(1 - pow(v/c,2));
- ex mass_nonrel = gamma.series(v, 0, 10);
+ ex mass_nonrel = gamma.series(v==0, 10);
cout << "the relativistic mass increase with v is " << endl
<< mass_nonrel << endl;
cout << "the inverse square of this series is " << endl
- << pow(mass_nonrel,-2).series(v, 0, 10) << endl;
+ << pow(mass_nonrel,-2).series(v==0, 10) << endl;
// ...
@}
ex mechain_pi(int degr)
@{
symbol x;
- ex pi_expansion = series_to_poly(atan(x).series(x,0,degr));
+ ex pi_expansion = series_to_poly(atan(x).series(x,degr));
ex pi_approx = 16*pi_expansion.subs(x==numeric(1,5))
-4*pi_expansion.subs(x==numeric(1,239));
return pi_approx;
@}
@end example
-When you run this program, it will type out:
+Note how we just called @code{.series(x,degr)} instead of
+@code{.series(x==0,degr)}. This is a simple shortcut for @code{ex}'s
+method @code{series()}: if the first argument is a symbol the expression
+is expanded in that symbol around point @code{0}. When you run this
+program, it will type out:
@example
2: 3804/1195