-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
gen_function.lpr
139 lines (122 loc) · 4.41 KB
/
gen_function.lpr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
{
Copyright 2001-2024 Michalis Kamburelis.
This file is part of "gen_function".
"gen_function" is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"gen_function" is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with "gen_function"; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
----------------------------------------------------------------------------
}
program gen_function;
{
Old comments:
Problemy ideologiczne :
- Miejsca gwaltownego skoku funkcji (np. punkt x = 0 funkcji [x > 0])
nie zostana wykryte jako przerwy w wykresie - program
rysujac linie zawsze bedzie laczyl dwa sasiednie punkty.
W rezultacie wykres moze wygladac na ciagly w miejscach w ktorych
ciagly nie jest (bo wykres jest po prostu ciagiem punktow.
Nieciaglosc zostaje wykryta tylko gdy jest dziura w dziedzinie.)
Te problemy mozna ominac ogladajac wykres tylko jako punkty
(klawisz "q").
- Wszystko jest liczone jako wartosci zmiennoprzecinkowe.
Wiec badz gotow na ewentualne niedokladnosci.
}
{$apptype CONSOLE}
uses SysUtils, CastleScript, CastleUtils, CastleScriptParser, CastleParameters,
CastleFilesUtils, CastleTimeUtils, CastleApplicationProperties;
const
Version = '2.1.0';
var
expr: TCasScriptExpression;
expr_str: string;
x1, x2, xstep: float;
i: Int64;
X, Y: TCasScriptFloat;
begin
ApplicationProperties.ApplicationName := 'gen_function';
ApplicationProperties.Version := Version;
{ We use very simple approach to parsing parameters instead of using
our Parameters.Parse. This way parameters starting with '-', like '-1.0 + 2.0',
may be easily specified as mathematical expressions
(no need to specify '--' param before them). }
if (Parameters.High = 0) or
Parameters.IsPresent(['-h', '--help']) then
begin
Writeln(
'gen_function: Syntax: '+nl+
' gen_function <function> <x1> <x2> <xstep>'+nl+
'Outputs on stdout function graph for x in [<x1>; <x2>].' +nl+
'Graph is in format understood by glplotter.' +nl+
nl+
'Available options are:' +nl+
HelpOptionHelp +nl+
VersionOptionHelp +nl+
nl+
ApplicationProperties.Description);
Halt;
end else
if Parameters.IsPresent(['-v', '--version']) then
begin
Writeln(Version);
Halt;
end;
{ parse options }
Parameters.CheckHigh(4);
{ Replace nl with spaces.
CastleScriptParser has no problem with handling text with nl inside,
but ErrorWrite(...) call below assumes that text is 1 line only,
otherwise error messages looks strange. }
expr_str := StringReplace(Parameters[1], nl, ' ',[rfReplaceAll]);
x1 := StrToFloat(Parameters[2]);
x2 := StrToFloat(Parameters[3]);
xstep := StrToFloat(Parameters[4]);
X := TCasScriptFloat.Create(false);
try
X.Name := 'x';
{ do the actual job }
try
expr := ParseFloatExpression(expr_str, [X]);
except
on E: ECasScriptSyntaxError do
begin
ErrorWrite(ApplicationName+': error while parsing function_expression :' +nl+
E.Message +nl+
expr_str +nl+
StringOfChar('.', E.LexerTextPos-1) + '^');
Halt;
end;
end;
try
Writeln(Format(
'# File generated by %s on %s' +nl+
'# function = %s' +nl+
'# x1 = %g' +nl+
'# x2 = %g' +nl+
'# xstep = %g' +nl+
'name=%s',
[ ApplicationName, DateTimeToAtStr(Now),
expr_str, x1, x2, xstep, expr_str]));
i := 0;
repeat
{ licz x jako x1 + wielokrotnosc xstep.
To duzo lepszy sposob niz brac x i zwiekszac co krok o xstep - w ten
sposob unikamy kumulowania sie bledow dodawania. }
X.Value := x1+i*xstep;
if X.Value > x2 then break;
Inc(i);
Y := Expr.TryExecuteMath as TCasScriptFloat;
if Y <> nil then
Writeln(X.Value, ' ', Y.Value) else
Writeln('break');
until false;
finally expr.Free end;
finally FreeAndNil(X) end;
end.