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>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é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>
</p>
<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
MIT <a href="flex.zip">přikládám</a>. Pro kompilaci je použit jen clang a jím kompilovaná C-čková knihovna
<a href="https://sourceware.org/newlib/" target="_blank">newlib</a>.
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="https://code.nolog.cz/Kizarm/Calculator" target="_blank">přikládám</a>. Pro kompilaci je použit jen
clang a jím kompilovaná C-čková knihovna <a href="https://sourceware.org/newlib/" target="_blank">newlib</a>.
</p>
</div>
</body>

View file

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

View file

@ -2,6 +2,9 @@
max=10
x=-max,max,1000
a=1/4
z=10
omega=2*pi
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;
}
}
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) {
if (main_data->root) delete main_data->root;
main_data->root = e;
@ -63,17 +64,20 @@ void addExpression (Expression * e) {
if (n <= 0) return;
double * vx = new double [n + 1];
double * vy = new double [n + 1];
// printf("n=%d\n", n);
for (int i=0; i<n+1; i++) {
const double x = x0 + (double) i * s;
r->value = x;
const double y = e->eval();
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;
}
void initData () {
first = true;
main_data = new CommonData();
}
void finiData () {

123
wasm.cpp
View file

@ -5,6 +5,7 @@
#include <math.h>
#include "calculator.h"
#include "heap.h"
#include "wasm.h"
extern "C" void EXPORT(init) (const int memlen);
extern "C" int EXPORT(cAlloc) (int len);
extern "C" void EXPORT(compute) (char * ptr, int len);
@ -38,98 +39,14 @@ void compute (char * ptr, int len) {
free (ptr);
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;
void resizeCanvas (int x, int y) {
printf("resizeCanvas: x=%d, y=%d\n", x, y);
canvas.width = x;
canvas.height = y;
}
void emitData (double * x, double * y, const int len) {
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);
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];
static int CreateJSON (char * json, const int json_max, const Canvas & canvas,
Stepping & sx, Stepping & sy) {
int n = 0;
const uint32_t xColor = 0xffff00;
const uint32_t yColor = 0x00ffff;
@ -158,6 +75,33 @@ void emitData (double * x, double * y, const int len) {
json [n-2] = ' ';
n += snprintf(json + n, json_max - 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:
* 1. Přímé předání dat pomocí ukazatelů.
* 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í
* 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);
delete [] ix; delete [] iy;
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