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>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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
123
wasm.cpp
|
@ -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
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