add multi expression

This commit is contained in:
Kizarm 2023-11-27 15:14:06 +01:00
parent c8d704a06c
commit c9594c48ce
6 changed files with 124 additions and 99 deletions

View file

@ -33,13 +33,17 @@
</p> </p>
<p>Je to tedy jednoduchý kalkulátor, jde napsat výraz s normální notací (+-*/^), obsahující čísla (i desetinná), <p>Je to tedy jednoduchý kalkulátor, jde napsat výraz s normální notací (+-*/^), obsahující čísla (i desetinná),
který to normálně vyhodnotí. Postupně přibyly proměnné (jen písmenkové řetězce), které mohou mít i rozsah ve který to normálně vyhodnotí. Postupně přibyly proměnné (jen písmenkové řetězce), které mohou mít i rozsah ve
kterém se pak výraz zobrazí jako funkce. Komentáře jsou ve složených závorkách. Vložené matematické funkce kterém se pak výraz zobrazí jako funkce. Syntaxe je <br>
proměnná = dolní_mez , horní_mez , počet_bodů<br>
a použije se pro vodorovnou osu, poslední řádek je pak výraz, jehož hodnota je na svislé ose. Ostatní "proměnné"
jsou pak fakticky jen pojmenované konstanty. Zobrazovaných funkcí (výrazů) může být víc, první určí limity
zobrazení na ose "y". Komentáře jsou ve složených závorkách. Vložené matematické funkce
jsou sin(), cos(), exp(), log() (přirozené).<b>Na konci výrazu musí být ENTER.</b> jsou sin(), cos(), exp(), log() (přirozené).<b>Na konci výrazu musí být ENTER.</b>
</p> </p>
<p>Jsou v tom chyby, celé je to vlasně hloupost, celé by to šlo napsat v javascriptu mnohem jednodušeji, <p>Jsou v tom chyby, celé je to vlasně hloupost, celé by to šlo napsat v javascriptu mnohem jednodušeji,
ale v podstatě to funguje a jde si podle toho udělat představu, jak daná funkce vypadá. Zdrojáky v licenci ale v podstatě to funguje a jde si podle toho udělat představu, jak daná funkce vypadá. Odkaz na zdrojáky v licenci
MIT <a href="flex.zip">přikládám</a>. Pro kompilaci je použit jen clang a jím kompilovaná C-čková knihovna MIT <a href="https://code.nolog.cz/Kizarm/Calculator" target="_blank">přikládám</a>. Pro kompilaci je použit jen
<a href="https://sourceware.org/newlib/" target="_blank">newlib</a>. clang a jím kompilovaná C-čková knihovna <a href="https://sourceware.org/newlib/" target="_blank">newlib</a>.
</p> </p>
</div> </div>
</body> </body>

View file

@ -28,7 +28,6 @@ window.onload = async function() {
const utf8decoder = new TextDecoder(); const utf8decoder = new TextDecoder();
const obj = JSON.parse (utf8decoder.decode(view)); const obj = JSON.parse (utf8decoder.decode(view));
// console.log (obj); // console.log (obj);
if (!obj) obj = '{"name":"nothing"}';
polyLine (xview, yview, len, obj); polyLine (xview, yview, len, obj);
}, },
}, },
@ -86,13 +85,16 @@ function drawLine (ctx, line, x, y) {
} }
ctx.stroke(); ctx.stroke();
} }
const colors = ['#00ff00', '#ff0000', '#00ffff', '#ff00ff'];
var colorIndex = 0;
function polyLine (ax, ay, len, obj) { function polyLine (ax, ay, len, obj) {
// console.log (ax, ay); // console.log (ax, ay);
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
if (obj.name === "axes") {
colorIndex = 0;
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = '16px serif'; ctx.font = '16px serif';
ctx.textAlign = 'left'; ctx.textAlign = 'left';
if (obj.name === "axes") {
drawLine (ctx, obj.x, 0, 0); drawLine (ctx, obj.x, 0, 0);
drawLine (ctx, obj.y, 0, 0); drawLine (ctx, obj.y, 0, 0);
const ndotsx = obj.xdots.length; const ndotsx = obj.xdots.length;
@ -106,7 +108,7 @@ function polyLine (ax, ay, len, obj) {
ctx.lineTo(ax[n], ay[n]); ctx.lineTo(ax[n], ay[n]);
} }
ctx.lineWidth = 3; ctx.lineWidth = 3;
ctx.strokeStyle = "#00ff00"; ctx.strokeStyle = colors [colorIndex++ % 4];
ctx.stroke(); ctx.stroke();
} }
async function getFile (name) { async function getFile (name) {

View file

@ -2,6 +2,9 @@
max=10 max=10
x=-max,max,1000 x=-max,max,1000
a=1/4 a=1/4
z=10
omega=2*pi omega=2*pi
phi=omega/4 phi=omega/4
1.e-8 * sin (omega*x - phi) * exp (-(x*a)^2) z * sin (omega*x + phi) * exp (-(x*a)^2)
z * exp (-(x*a)^2) {kladná obálka}
-z * exp (-(x*a)^2) {záporná obálka}

View file

@ -47,7 +47,8 @@ Variable::Variable(const char * name) {
data = & zero; data = & zero;
} }
} }
extern void emitData (double * x, double * y, const int len); static bool first = false;
extern void emitData (double * x, double * y, const int len, const bool first);
void addExpression (Expression * e) { void addExpression (Expression * e) {
if (main_data->root) delete main_data->root; if (main_data->root) delete main_data->root;
main_data->root = e; main_data->root = e;
@ -63,17 +64,20 @@ void addExpression (Expression * e) {
if (n <= 0) return; if (n <= 0) return;
double * vx = new double [n + 1]; double * vx = new double [n + 1];
double * vy = new double [n + 1]; double * vy = new double [n + 1];
// printf("n=%d\n", n);
for (int i=0; i<n+1; i++) { for (int i=0; i<n+1; i++) {
const double x = x0 + (double) i * s; const double x = x0 + (double) i * s;
r->value = x; r->value = x;
const double y = e->eval(); const double y = e->eval();
vx[i] = x; vy[i] = y; vx[i] = x; vy[i] = y;
} }
emitData (vx, vy, n+1); r->value = x0;
// printf("add expression first=%d, n=%d\n", (int) first, n);
emitData (vx, vy, n+1, first);
if (first) first = false;
delete [] vx; delete [] vy; delete [] vx; delete [] vy;
} }
void initData () { void initData () {
first = true;
main_data = new CommonData(); main_data = new CommonData();
} }
void finiData () { void finiData () {

123
wasm.cpp
View file

@ -5,6 +5,7 @@
#include <math.h> #include <math.h>
#include "calculator.h" #include "calculator.h"
#include "heap.h" #include "heap.h"
#include "wasm.h"
extern "C" void EXPORT(init) (const int memlen); extern "C" void EXPORT(init) (const int memlen);
extern "C" int EXPORT(cAlloc) (int len); extern "C" int EXPORT(cAlloc) (int len);
extern "C" void EXPORT(compute) (char * ptr, int len); extern "C" void EXPORT(compute) (char * ptr, int len);
@ -38,98 +39,14 @@ void compute (char * ptr, int len) {
free (ptr); free (ptr);
finiData(); finiData();
} }
struct Canvas {
double width, height;
double xscale, yscale;
double xofset, yofset;
float xt (const double x) {
return float (xscale * (x - xofset));
}
float yt (const double y) {
return float (height - yscale * (y - yofset));
}
};
static const char * multipliers [] = {"f","p","n","μ","m","","k","M","G","T","P"};
struct Stepping {
double b,e,s;
char fmtbuf [16];
explicit Stepping (const double from, const double to) {
double lp;
const double z = log10 (fabs (to - from));
const double fp = modf (z, & lp);
if (fp < 0.30103) s = 1.0;
else if (fp > 0.69897) s = 5.0;
else s = 2.0;
int ip = int (lp) - 1;
if (z < 0.0) ip -= 1;
s *= ::pow (10.0, double (ip));
do {
const int k = int (fabs(to - from) / s);
b = round (from / s) * s;
e = round (to / s) * s;
if (k > 50) s *= 10.0; // prevence přeplnění osy, nevím proč, ale tohle to odstraní
else break; // patrně log10() nedává přesně to, co bych čekal
} while (true);
}
void f () {printf("stepping = %g, b = %g, e = %g\n", s, b, e);}
char * ing (const double x, int n=0) {
if (fabs(x) < 0.5 * s) {
fmtbuf[n++] = ' ';
fmtbuf[n++] = '\0';
return fmtbuf;
}
if (x < 0.0) {
fmtbuf[n++] = '-';
return ing (-x, n);
}
if (x > 0.0) {
double ip;
const double fp = modf(log10(x), & ip);
int pi = ip, ofs = 5 * 3;
if (pi < -ofs) pi = -ofs;
if (pi > 18 ) pi = 18;
const div_t dt = div(pi + ofs, 3);
n += snprintf (fmtbuf + n, 16 - n, "%g%s", ::pow (10.0, fp + double (dt.rem)), multipliers [dt.quot]);
}
return fmtbuf;
}
protected:
};
static Canvas canvas; static Canvas canvas;
void resizeCanvas (int x, int y) { void resizeCanvas (int x, int y) {
printf("resizeCanvas: x=%d, y=%d\n", x, y); printf("resizeCanvas: x=%d, y=%d\n", x, y);
canvas.width = x; canvas.width = x;
canvas.height = y; canvas.height = y;
} }
void emitData (double * x, double * y, const int len) { static int CreateJSON (char * json, const int json_max, const Canvas & canvas,
double ymin = 1.0e100, ymax = -1.0e100; Stepping & sx, Stepping & sy) {
for (int n=0; n<len; n++) {
if (y[n] < ymin) ymin = y[n];
if (y[n] > ymax) ymax = y[n];
// printf("f(%g) = %g\n", x[n], y[n]);
}
const double xmin = x[0];
const double xmax = x[len - 1];
printf("xmin = %g, xmax = %g, ymin = %g, ymax = %g\n", xmin, xmax, ymin, ymax);
const double f = 1.0;
ymin *= f;
ymax *= f;
canvas.xofset = xmin;
canvas.yofset = ymin;
canvas.xscale = canvas.width / (xmax - xmin);
canvas.yscale = canvas.height / (ymax - ymin);
Stepping sx (xmin, xmax), sy (ymin, ymax);
// sx.f(); sy.f();
float * ix = new float [len]; // float32 stačí
float * iy = new float [len];
for (int n=0; n<len; n++) {
ix[n] = canvas.xt (x[n]); // přepočteno na velikost canvasu
iy[n] = canvas.yt (y[n]);
// printf("f(%d) = %d\n", ix[n], iy[n]);
}
const int json_max = 0x8000; // string bude poměrně dlouhý
char * json = new char [json_max];
int n = 0; int n = 0;
const uint32_t xColor = 0xffff00; const uint32_t xColor = 0xffff00;
const uint32_t yColor = 0x00ffff; const uint32_t yColor = 0x00ffff;
@ -158,6 +75,33 @@ void emitData (double * x, double * y, const int len) {
json [n-2] = ' '; json [n-2] = ' ';
n += snprintf(json + n, json_max - n, "] }\n"); n += snprintf(json + n, json_max - n, "] }\n");
// printf("%d\n", n); // printf("%d\n", n);
return n;
}
void emitData (double * x, double * y, const int len, const bool first) {
int n = 0;
const int json_max = 0x8000; // string bude poměrně dlouhý
char * json = new char [json_max];
if (first) {
double ymin = 1.0e100, ymax = -1.0e100;
for (int n=0; n<len; n++) {
if (y[n] < ymin) ymin = y[n];
if (y[n] > ymax) ymax = y[n];
// printf("f(%g) = %g\n", x[n], y[n]);
}
const double xmin = x[0];
const double xmax = x[len - 1];
printf("xmin = %g, xmax = %g, ymin = %g, ymax = %g\n", xmin, xmax, ymin, ymax);
canvas.xofset = xmin;
canvas.yofset = ymin;
canvas.xscale = canvas.width / (xmax - xmin);
canvas.yscale = canvas.height / (ymax - ymin);
Stepping sx (xmin, xmax), sy (ymin, ymax);
// sx.f(); sy.f();
n += CreateJSON (json, json_max, canvas, sx, sy);
} else {
n += snprintf(json + n, json_max - n, "{ \"name\":\"unknown\" }");
}
/* Pro kreslení na canvas se používají 2 metody: /* Pro kreslení na canvas se používají 2 metody:
* 1. Přímé předání dat pomocí ukazatelů. * 1. Přímé předání dat pomocí ukazatelů.
* Ukázalo se, že typ int nestačí, zaokrouhlení je kostrbaté, double je zbytečně velký, * Ukázalo se, že typ int nestačí, zaokrouhlení je kostrbaté, double je zbytečně velký,
@ -166,6 +110,13 @@ void emitData (double * x, double * y, const int len) {
* (3. zde nepoužito) Vytvoříme přímo javascript zdroják, který to celé vykreslí * (3. zde nepoužito) Vytvoříme přímo javascript zdroják, který to celé vykreslí
* a ten pak spustíme v javascriptu pomocí eval(). Funguje také, ale je to divné. * a ten pak spustíme v javascriptu pomocí eval(). Funguje také, ale je to divné.
* */ * */
float * ix = new float [len]; // float32 stačí
float * iy = new float [len];
for (int k=0; k<len; k++) {
ix[k] = canvas.xt (x[k]); // přepočteno na velikost canvasu
iy[k] = canvas.yt (y[k]);
// printf("f(%d) = %d\n", ix[n], iy[n]);
}
drawPoints (ix, iy, len, json, n); drawPoints (ix, iy, len, json, n);
delete [] ix; delete [] iy; delete [] ix; delete [] iy;
delete [] json; delete [] json;

61
wasm.h Normal file
View file

@ -0,0 +1,61 @@
#ifndef _WASM_H_DEF
#define _WASM_H_DEF
#include <stdio.h>
#include <math.h>
struct Canvas {
double width, height;
double xscale, yscale;
double xofset, yofset;
float xt (const double x) const {
return float (xscale * (x - xofset));
}
float yt (const double y) const {
return float (height - yscale * (y - yofset));
}
};
static const char * multipliers [] = {"f","p","n","μ","m","","k","M","G","T","P"};
struct Stepping {
double b,e,s;
char fmtbuf [16];
explicit Stepping (const double from, const double to) {
double lp;
const double z = log10 (fabs (to - from));
const double fp = modf (z, & lp);
if (fp < 0.30103) s = 1.0;
else if (fp > 0.69897) s = 5.0;
else s = 2.0;
int ip = int (lp) - 1;
if (z < 0.0) ip -= 1;
s *= ::pow (10.0, double (ip));
do {
const int k = int (fabs(to - from) / s);
b = round (from / s) * s;
e = round (to / s) * s;
if (k > 50) s *= 10.0; // prevence přeplnění osy, nevím proč, ale tohle to odstraní
else break; // patrně log10() nedává přesně to, co bych čekal
} while (true);
}
void f () {printf("stepping = %g, b = %g, e = %g\n", s, b, e);}
char * ing (const double x, int n=0) {
if (fabs(x) < 0.5 * s) {
fmtbuf[n++] = ' ';
fmtbuf[n++] = '\0';
return fmtbuf;
}
if (x < 0.0) {
fmtbuf[n++] = '-';
return ing (-x, n);
}
if (x > 0.0) {
double ip;
const double fp = modf(log10(x), & ip);
int pi = ip, ofs = 5 * 3;
if (pi < -ofs) pi = -ofs;
if (pi > 18 ) pi = 18;
const div_t dt = div(pi + ofs, 3);
n += snprintf (fmtbuf + n, 16 - n, "%g%s", ::pow (10.0, fp + double (dt.rem)), multipliers [dt.quot]);
}
return fmtbuf;
}
};
#endif // _WASM_H_DEF