diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4ea656 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# kdevelop +.kde* +*.kdev4 +# other +*.zip +*.wasm +*.lst +*.map +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b1be6d9 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +CC = clang +CX = clang++ +CODE ?= wasm + +MOBJS = calc.yy.o calc.tab.o calculator.o + +ifeq ($(CODE),wasm) +include wasm.mk +else +include unix.mk +endif + +OBJS = $(MOBJS) $(MAIN) +CFLAGS += -Wno-unused-function + +all: $(PR) +%.o: %.cpp + $(CX) -std=c++14 -c $(CFLAGS) -fno-exceptions -fno-rtti $< -o $@ +%.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ +calc.tab.o: calc.tab.c + $(CX) -std=c++14 -c $(CFLAGS) -Wno-deprecated -Wno-writable-strings -fno-exceptions -fno-rtti $< -o $@ +$(PR): $(OBJS) $(WALIB) + $(LD) $(LFLAGS) $(OBJS) -o $(PR) $(LDLIBS) +calc.yy.cpp: calc.l calc.tab.h + flex calc.l +calc.tab.c calc.tab.h: calc.y + bison -d calc.y +clean: + rm -f *.o *.yy.* *.tab.* +distclean: clean + rm -f $(PR) +.PHONY: all clean distclean diff --git a/bin/index.html b/bin/index.html new file mode 100644 index 0000000..237e5bd --- /dev/null +++ b/bin/index.html @@ -0,0 +1,46 @@ + + + + + CALC + + + + +
+
+
+ + + +
+
+
+

Kalkulátor s grafickým výstupem.

+

Když jsem přepisoval z nudy syntax highlighter pro C++ z pythonu do C++, zjistil jsem, že regulární výrazy + jsou kupodivu v tom pythonu efektivnější. V tomto ohledu je STL knihovna asi dost naprd. Ale vzpomněl jsem si + na prastarý pár flex a bison, který umí nejen regulární výrazy, ale jde s tím parsovat dost jednoduše gramatika. + Mělo by to jít i v C++, ale příklady na webu byly dost zamotané a bylo nutné použít STL, kterou jsem pro tento + účel neměl k dispozici. Vyřešilo se to jednoduše - vygenerovaný C-čkový kód se přeloží jako C++, přičemž je + nutné povypínat něktetré warningy. +

+

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 + jsou sin(), cos(), exp(), log() (přirozené).Na konci výrazu musí být ENTER. +

+

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 přikládám. Pro kompilaci je použit jen clang a jím kompilovaná C-čková knihovna + newlib. +

+
+ + diff --git a/bin/index.js b/bin/index.js new file mode 100644 index 0000000..ead361f --- /dev/null +++ b/bin/index.js @@ -0,0 +1,126 @@ +var gWASM; // globální proměnná + elementy stránky +const Outs = document.getElementById('stdout'); +const Btnt = document.getElementById('buttonTest'); +const Canvas = document.getElementById('canvas'); +// async/await z příkladu na webu +window.onload = async function() { + Btnt.disabled = true; + Outs.value = 'Compiling ...¨\n'; // presets + // Build WebAssembly instance - WebAssembly.instantiateStreaming problem + const memory = new WebAssembly.Memory({ initial: 4 }); + const importObject = { + env: { memory }, // nutné pro práci a pamětí + imports: { // importované funkce do wasm + printout : (ptr, len) => { + // pohled do paměti - ptr je vlastně číslo + const view = new Uint8Array (memory.buffer, ptr, len); + const utf8decoder = new TextDecoder(); + Outs.value += utf8decoder.decode(view); // to String + }, + memoryGrow : (len) => { + console.log ('Growing the memory by ' + len.toString() + '. 64K blocks'); + memory.grow (len); // patrně to jde volat přímo z C/C++ kódu, ale tohle funguje + }, + drawPoints : (px, py, len, pj, jl) => { + const xview = new Float32Array (memory.buffer, px, len); + const yview = new Float32Array (memory.buffer, py, len); + const view = new Uint8Array (memory.buffer, pj, jl); + const utf8decoder = new TextDecoder(); + const obj = JSON.parse (utf8decoder.decode(view)); + // console.log (obj); + if (!obj) obj = '{"name":"nothing"}'; + polyLine (xview, yview, len, obj); + }, + }, + }; + const response = await fetch('./module.wasm'); + const bytes = await response.arrayBuffer(); + const module = await WebAssembly.instantiate(bytes, importObject); + gWASM = { + asm : module.instance.exports, + mem : memory, + }; + gWASM.asm.init(memory.buffer.byteLength); + Btnt.onclick = () => { + Outs.value = ''; + const expression = document.getElementById('input').value; + // console.log(expression); + stringToModule (expression, gWASM.asm.compute); + }; + Outs.value = 'Module compiled - [insert formula and] press button Submit\n'; + Btnt.disabled = false; + // console.log (gWASM); + window.addEventListener('resize', resizeCanvas, false); + resizeCanvas(); + getFile ('test.txt'); + Splash (); +}; +function stringToModule (str, mfunc) { + const utf8EncodeText = new TextEncoder(); + const bytes = utf8EncodeText.encode(str); + // alokovat pamet v modulu je nutne, aby bylo kam kopirovat + const cArrayPointer = gWASM.asm.cAlloc(bytes.length); + if (!cArrayPointer) return; + const cArray = new Uint8Array(gWASM.mem.buffer, cArrayPointer, bytes.length); + cArray.set(bytes); // naplnit dekodovanym stringem + mfunc (cArrayPointer, cArray.length); +} +function resizeCanvas () { + const width = canvas.clientWidth; + const height = canvas.clientHeight; + canvas.width = width; + canvas.height = height; + // console.log (width, height); + gWASM.asm.resizeCanvas (width, height); +} +function drawLine (ctx, line, x, y) { + ctx.beginPath(); + ctx.moveTo(line.b[0], line.b[1]); + ctx.lineTo(line.e[0], line.e[1]); + ctx.lineWidth = line.w; + ctx.strokeStyle = line.color; + if (line.lbl) { + //console.log (line.lbl); + ctx.fillStyle = line.color; + ctx.fillText (line.lbl, line.b[0] + x, line.b[1] - y); + } + ctx.stroke(); +} +function polyLine (ax, ay, len, obj) { + // console.log (ax, ay); + const ctx = canvas.getContext("2d"); + 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; + for (let n=0; n +#include "calc.tab.h" +#include "calculator.h" +%} +%option outfile="calc.yy.cpp" header-file="calc.yy.h" +%option case-sensitive +%option array + +D [0-9] +E [Ee][+-]?{D}+ + +%% +pi { return MATHPI; } +sin { return FCESIN; } +cos { return FCECOS; } +exp { return FCEEXP; } +log { return FCELOG; } +[a-zA-Z]+ { yylval.svalue = strdup (yytext); return IDENT; } +{D}+ { yylval.svalue = strdup (yytext); return INTEGER; } +{D}*\.{D}+({E})? { yylval.svalue = strdup (yytext); return DOUBLE; } +{D}*\.{D}*({E})? { yylval.svalue = strdup (yytext); return DOUBLE; } +\{.*\} +[ \t]+ /* ignored */ +\n { return ENDLINE; } +. { return yytext[0]; } +%% +void prevent_unused (void) { + (void) yyunput; +/* (void) input; */ +} diff --git a/calc.y b/calc.y new file mode 100644 index 0000000..f979fb5 --- /dev/null +++ b/calc.y @@ -0,0 +1,68 @@ +%{ +#include +#include "calculator.h" +int yylex (void); +int yyerror (char *); +%} +%language "C" +%union { + char * svalue; + double dvalue; + class Expression * evalue; +} + +%token ENDLINE +%token DOUBLE +%token INTEGER +%token MATHPI +%token FCESIN +%token FCECOS +%token FCEEXP +%token FCELOG +%token IDENT +%token TEXT +%left '+' '-' +%left '*' '/' +%left '^' + +%type ENDLINE DOUBLE INTEGER IDENT line lines +%type expr +%type constnt +%start input +%% + +input: /* empty */ + | lines + ; +lines: line + | lines line + ; +line: ENDLINE + | IDENT '=' expr ENDLINE { addVariable ($1, $3->eval()); free ($1); } + | IDENT '=' expr ',' expr ',' expr ENDLINE { addRange ($1, $3->eval(), $5->eval(), $7->eval()); free ($1); } + | expr ENDLINE { addExpression ($1); } + | error ENDLINE { printf ("what:%s\n", $$); } + ; +constnt: DOUBLE { $$ = str_to_double ($1); free ($1); } + | INTEGER { $$ = str_to_long ($1); free ($1); } + | MATHPI { $$ = 3.14159265359; } + ; +expr: constnt { $$ = new Constant ($1); } + | IDENT { $$ = new Variable ($1); free ($1); } + | '-' expr { $$ = new Unary ($2, UNARY_MINUS); } + | expr '+' expr { $$ = new Binary ($1, $3, BINARY_PLUS); } + | expr '-' expr { $$ = new Binary ($1, $3, BINARY_MINUS);} + | expr '*' expr { $$ = new Binary ($1, $3, BINARY_MULT); } + | expr '/' expr { $$ = new Binary ($1, $3, BINARY_DIV); } + | expr '^' expr { $$ = new Binary ($1, $3, BINARY_POW); } + | '(' expr ')' { $$ = $2; } + | FCESIN '(' expr ')' { $$ = new Unary ($3, UNARY_SIN); } + | FCECOS '(' expr ')' { $$ = new Unary ($3, UNARY_COS); } + | FCEEXP '(' expr ')' { $$ = new Unary ($3, UNARY_EXP); } + | FCELOG '(' expr ')' { $$ = new Unary ($3, UNARY_LOG); } + ; +%% +int yyerror(char * err) { + printf("Error:\"%s\"\n", err); + return 0; +} diff --git a/calculator.cpp b/calculator.cpp new file mode 100644 index 0000000..4eccc2a --- /dev/null +++ b/calculator.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include "calculator.h" + +double str_to_double (const char * str) { + return strtod (str, NULL); +} +long str_to_long (const char * str) { + return strtol (str, NULL, 10); +} + +static double u_minus (const double x) { return -x; } +const unary_function unary_function_table [UNARY_max] = { + u_minus, + sin, cos, exp, log, +}; +static double b_plus (const double a, const double b) { return a + b; } +static double b_minus (const double a, const double b) { return a - b; } +static double b_multiply (const double a, const double b) { return a * b; } +static double b_divide (const double a, const double b) { return b !=0.0 ? a / b : 1.0; } +const binary_function binary_function_table [BINARY_max] = { + b_plus, b_minus, b_multiply, b_divide, pow, +}; +static CommonData * main_data = nullptr; +void addVariable (const char * str, const double x) { + printf ("\"%s\"\t= %g\n", str, x); + if (main_data->list == nullptr) { + main_data->list = new VariableList (str, x); + return; + } + main_data->list->add(str, x); +} +void addRange (const char * str, const double x, const double e, const double s) { + printf ("\"%s\"\t= [%g:%g],%g\n", str, x, e, s); + if (main_data->list == nullptr) { + main_data->list = new VariableList (str, x, e, s); + return; + } + main_data->list->add(str, x, e, s); +} +static Range zero = {0.0, 0.0, 0.0}; +Variable::Variable(const char * name) { + data = main_data->list->find (name); + if (!data) { + printf("variable \"%s\" not assigned, zero used\n", name); + data = & zero; + } +} +extern void emitData (double * x, double * y, const int len); +void addExpression (Expression * e) { + if (main_data->root) delete main_data->root; + main_data->root = e; + + VariableList * vl = main_data->list->find_ranged(); + if (!vl) { + printf("f() = %g\n", e->eval()); + return; + } + Range * r = vl->get(); + const double x0 = r->value, x1 = r->end, s = fabs (r->step); + int n = (x1 - x0) / s; + 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; ivalue = x; + const double y = e->eval(); + vx[i] = x; vy[i] = y; + } + emitData (vx, vy, n+1); + delete [] vx; delete [] vy; +} +void initData () { + main_data = new CommonData(); +} +void finiData () { + delete main_data; +} + diff --git a/calculator.h b/calculator.h new file mode 100644 index 0000000..55d3576 --- /dev/null +++ b/calculator.h @@ -0,0 +1,121 @@ +/* inclusion guard */ +#ifndef __CALCULATOR_H__ +#define __CALCULATOR_H__ +#include +#include +extern double str_to_double (const char * str); +extern long str_to_long (const char * str); +extern void addVariable (const char * str, const double x); +extern void addRange (const char * str, const double x, const double e, const double s); + +extern void initData (); +extern void finiData (); + +class Expression { + public: + virtual double eval () = 0; + virtual ~Expression () {} +}; +class Constant : public Expression { + double data; + public: + explicit Constant (const double x) : data (x) {} + explicit Constant (const long x) : data (x) {} + double eval () override { /*printf("c=%g", data);*/ return data; } + virtual ~Constant() {} +}; +extern void addExpression (Expression * e); +enum UNARY_FNCS { + UNARY_MINUS = 0, UNARY_SIN, UNARY_COS, UNARY_EXP, UNARY_LOG, UNARY_max +}; +enum BINARY_FNCS { + BINARY_PLUS = 0, BINARY_MINUS, BINARY_MULT, BINARY_DIV, BINARY_POW, BINARY_max +}; +typedef double (*unary_function) (const double); +typedef double (*binary_function) (const double, const double); +extern const unary_function unary_function_table [UNARY_max]; +extern const binary_function binary_function_table [BINARY_max]; +class Unary : public Expression { + Expression * m_expr; + unary_function m_f; + public: + explicit Unary (Expression * e, const UNARY_FNCS nf) : m_expr(e), m_f (unary_function_table[nf]) {} + double eval () override { /*printf("(*%p)(%p)", m_f, m_expr);*/ return (m_f (m_expr->eval())); } + virtual ~Unary () { delete m_expr; } +}; +class Binary : public Expression { + Expression * m_l, * m_r; + binary_function m_f; + public: + explicit Binary (Expression * l, Expression * r, const BINARY_FNCS nf) : m_l(l), m_r(r), m_f(binary_function_table[nf]) {} + double eval () override { /*printf("{%p}[%p]{%p}", m_l, m_f, m_r);*/ return (m_f (m_l->eval(), m_r->eval())); } + virtual ~Binary() { delete m_l; delete m_r; } +}; +struct Range { + double value, end, step; +}; +class VariableList { + VariableList * next; + char * name; + Range data; + public: + explicit VariableList (const char * _name, const double _value) : next(nullptr) { + name = strdup (_name); + data.value = _value; + data.end = _value; + data.step = 0.0; + } + explicit VariableList (const char * _name, const double _value, const double _end, const double steps) : next(nullptr) { + name = strdup (_name); + if (_value > _end) { + data.value = _end; + data.end = _value; + } else { + data.value = _value; + data.end = _end; + } + if (steps != 0.0) data.step = (data.end - data.value) / steps; + else data.step = 1.0; + } + ~VariableList () { + if (next) delete next; + free (name); + } + void add (const char * _name, const double _value) { + if (!next) next = new VariableList (_name, _value); + else next->add (_name, _value); + } + void add (const char * _name, const double _value, const double _end, const double steps) { + if (!next) next = new VariableList (_name, _value, _end, steps); + else next->add (_name, _value, _end, steps); + } + Range * find (const char * _name) { + if (!strcmp (name, _name)) return & data; + if (next) return next->find (_name); + return nullptr; + } + VariableList * find_ranged () { + if (data.step) return this; + if (next) return next->find_ranged(); + return nullptr; + } + Range * get () { return & data; } +}; +class Variable : public Expression { + Range * data; + public: + explicit Variable (const char * name); + double eval() override { return data->value; } + virtual ~Variable () {} +}; +struct CommonData { + VariableList * list; + Expression * root; + explicit CommonData() : list(nullptr), root(nullptr) {} + ~CommonData () { + if (list) delete list; + if (root) delete root; + } +}; + +#endif /* __CALCULATOR_H__ */ diff --git a/heap.c b/heap.c new file mode 100644 index 0000000..ce93675 --- /dev/null +++ b/heap.c @@ -0,0 +1,46 @@ +#include "heap.h" +extern void IMPORT(memoryGrow) (const int block); +extern char __heap_base; +typedef __SIZE_TYPE__ size_t; + +static const char * _HEAP_START = &__heap_base; +char * _HEAP_MAX = &__heap_base; + +void * sbrk (unsigned long size) { + static const char * heap_ptr; + const char * old_heap_ptr; + static unsigned int init_sbrk = 0; + /* heap_ptr is initialized to HEAP_START */ + if (init_sbrk == 0) { + heap_ptr = _HEAP_START; + init_sbrk = 1; + } + old_heap_ptr = heap_ptr; + /* Tohle je jen zkusmo, uvidíme, zatím se zdá, že to chodí. + * Těžko říct, co to udělá, když dojde paměť, ale pár MiB to zvládne. + */ + if ((heap_ptr + size) > _HEAP_MAX) { + const int blocks = (((heap_ptr + size) - _HEAP_MAX) >> 16) + 1; + memoryGrow (blocks); + _HEAP_MAX += blocks << 16; + } + heap_ptr += size; + return (void *)old_heap_ptr; +} +/* Následující je někde použito v parseru, ale nemusí to moc fungovat. + */ +int write(int fd, const void * b, size_t l) { + if ((fd == 1) || (fd == 2)) printout(b, l); + return l; +} +// formátování pro long double asi nebudu používat +extern void exit (int x)__attribute__((noreturn)); +void _exit (int x) __attribute__ ((noreturn)); +void _exit (int x) { exit(x); } +double __trunctfdf2(long double a) { return (double)(a); } +int isatty () { return 1; } + +void close (int fd) {} +int read (int fd, void * b, size_t l) { return l; } +size_t lseek(int fd, size_t offset, int whence) { return 0; } +int fstat(int fd, void * statbuf) { return 0; } diff --git a/heap.h b/heap.h new file mode 100644 index 0000000..edf8002 --- /dev/null +++ b/heap.h @@ -0,0 +1,15 @@ +#ifndef _HEAP_H +#define _HEAP_H +#define EXPORT(name) __attribute__((used, export_name(#name))) name +// "imports" odpovídá importObject.imports v JS, default je to importObject.env +#define IMPORT(name) __attribute__((import_module("imports"),import_name(#name))) name +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + extern void IMPORT(printout) (const char * ptr, const int len); // external javascript function + extern void * sbrk (unsigned long size); + extern char * _HEAP_MAX; +#ifdef __cplusplus +}; +#endif //__cplusplus +#endif // _HEAP_H diff --git a/newdel.cpp b/newdel.cpp new file mode 100644 index 0000000..5c59a3e --- /dev/null +++ b/newdel.cpp @@ -0,0 +1,23 @@ +#include + + +void* operator new (unsigned long size) { + return calloc(1,size); +} +void operator delete (void* p) { + free (p); +} + +void* operator new[] (unsigned long size) { + return calloc(1,size); +} + +void operator delete[] (void* p) { + free (p); +} + +void operator delete (void* p, unsigned size) { + (void) size; + free (p); +} + diff --git a/symbols.txt b/symbols.txt new file mode 100644 index 0000000..01a14a0 --- /dev/null +++ b/symbols.txt @@ -0,0 +1,3 @@ +printout +memoryGrow +drawPoints diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..36e8f30 --- /dev/null +++ b/test.txt @@ -0,0 +1,3 @@ +x=2,8,20 +y=1 +y*x^2 + 5*y*x + 1 diff --git a/unix.cpp b/unix.cpp new file mode 100644 index 0000000..cf07c78 --- /dev/null +++ b/unix.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "calc.yy.h" +#include "calculator.h" + +extern void yyparse (); +extern "C" int yywrap () { + return 1; +} + +static char * from_file (const char * filename) { + struct stat statbuf; + int r = stat (filename, & statbuf); + if (r) return nullptr; + char * buffer = (char*) malloc (statbuf.st_size + 1); + FILE * in = fopen (filename,"r"); + r = fread (buffer, 1, statbuf.st_size, in); + if (r != statbuf.st_size) { + free (buffer); + fclose (in); + return nullptr; + } + buffer [r] = '\0'; + fclose (in); + return buffer; +} +void emitData (double * x, double * y, const int len) { + for (int n=0; n +#include +#include +#include +#include +#include "calculator.h" +#include "heap.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); +extern "C" void EXPORT(resizeCanvas)(int x, int y); +extern "C" void IMPORT(drawPoints) (float * x, float * y, int len, char * json, int jl); +extern "C" void __wasm_call_ctors (); +extern "C++" { + typedef struct yy_buffer_state * YY_BUFFER_STATE; + extern int yyparse(); + extern YY_BUFFER_STATE yy_scan_string(const char * str); + extern void yy_delete_buffer(YY_BUFFER_STATE buffer); +}; +extern "C" int yywrap () { + return 1; +} +void init (const int memlen) { + _HEAP_MAX = reinterpret_cast(memlen); + __wasm_call_ctors(); + printf("Module initialized\n\n"); +} +int cAlloc (int len) { + return int (malloc(len + 1)); +} +void compute (char * ptr, int len) { + ptr [len] = '\0'; + + initData(); + YY_BUFFER_STATE result = yy_scan_string(ptr); + yyparse(); + yy_delete_buffer(result); + 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 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 0 and canvas.xt(0.0) < canvas.width ? canvas.xt(0.0) : 0.0; + const double pos0y = canvas.yt(0.0) > 0 and canvas.yt(0.0) < canvas.height ? canvas.yt(0.0) : canvas.height; + n += snprintf(json + n, json_max - n, "{ \"name\":\"axes\", "); + n += snprintf(json + n, json_max - n, "\"x\":{ \"color\":\"#%06X\", \"w\":%d, ", xColor, 2); + n += snprintf(json + n, json_max - n, "\"b\": [%g,%g], ", 0.0, pos0y); + n += snprintf(json + n, json_max - n, "\"e\": [%g,%g] }, ", canvas.width, pos0y); + n += snprintf(json + n, json_max - n, "\"y\": { \"color\":\"#%06X\", \"w\":%d, ", yColor, 2); + n += snprintf(json + n, json_max - n, "\"b\": [%g,%g], ", pos0x, 0.0); + n += snprintf(json + n, json_max - n, "\"e\": [%g,%g] }, \"xdots\": [", pos0x, canvas.height); + for (double dx=sx.b; dx