add multi expression
This commit is contained in:
parent
c8d704a06c
commit
c9594c48ce
6 changed files with 124 additions and 99 deletions
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
123
wasm.cpp
|
@ -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
61
wasm.h
Normal 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
|
Loading…
Reference in a new issue