Matematikai függvény-ábrázoló

Írj be egy vagy több kifejezést (pl. sin(x)/x, 2x^2 - 3, (cos(t), sin(3t)), r = 1 + cos(θ), x^2 + y^2 = 4) - a szerver PHP-ben, egy SAJÁT, kézzel írt kifejezés-parserrel (tokenizálás → szintaxisfa → biztonságos, fehérlistás kiértékelés) értelmezi és mintavételezi a görbéket. Nincs eval(): a bemenet SOSEM válik futtatott kódká.

A ténylegesen lefutó PHP-kód (kivonat)
// Elsőbbség: az unáris mínusz a hatvány FÖLÖTT él, a kitevő jobbra köt
//   unary := ('-'|'+') unary | power
//   power := postfix ('^' unary)?        // -2^2 = -4, 2^3^2 = 512
// Implicit szorzás (2x, 3sin(x), (x+1)(x-1)) a '*'-gal azonos szinten:
if ($this->startsPrimary($this->current())) {
    $node = Node::binary('*', $node, $this->parsePower(), true);
}

// Fehérlistás dispatch - SOSEM dinamikus "$name(...)" hívás vagy eval()
return match ($name) {
    'sin' => sin($x),
    'gamma' => SpecialFunctions::gamma($x),
    'log' => count($a) === 1 ? log10($x) : self::logBase($a[0], $a[1]),
    // ...
};

// Szakadás-keresés: ha két szomszédos minta közt nagy az ugrás, felezzük
for ($k = 0; $k < 44; $k++) {
    $mid = ($xl + $xr) / 2;
    $ym = $f($mid);
    if (abs($ym - $yl) >= abs($yr - $ym)) { $xr = $mid; $yr = $ym; } else { $xl = $mid; $yl = $ym; }
}
// az ugrás nem csökkent: pólus vagy ugrás, a két ág NEM kapcsolódik

Függvények

Tizedes tört: pont (0.5), vagy függvényhíváson kívül vessző is (0,5). Függvényargumentumok elválasztója: , vagy ;
-10-8-6-4-20246810-4-2024
Görgő vagy csípés: nagyítás. Húzás: mozgatás. Koppintás / egér a görbe fölött: pontérték. Billentyűk: nyilak, +, -, 0.

Elemzés

Zérushelyek
Szélsőértékek
Metszéspontok
Derivált görbe
Határozott integrál

Nézet

Példák

Parabola
Harmadfokú
Reciprok (1/x)
Gyök és négyzet
Abszolútérték
exp, ln és y = x
Harang és erf
A megszakadó vonal ott van, ahol a függvény nincs értelmezve (nullával osztás, negatív gyök...). Aszimptotánál a két ág sosem kapcsolódik össze: a szerver a szakadást intervallum-felezéssel keresi meg. A teljes állapot (kifejezések, paraméterek, nézet, elemzés) a link részét képezi.

Implicit szorzás

2x, 3sin(x), (x+1)(x-1), 2pi

Hatvány (jobbra köt)

x^2, x**2, x², 2^3^2 = 512, -x^2 = -(x²)

Abszolútérték, faktoriális

|x - 1|, 5!, x!

Gyök, Unicode

√(x+1), π, ×, ·, −, ≤, ≥, ≠

Feltétel, darabonként

if(x<0, -x, x^2), piecewise(x<-1, -1, x<1, x, 1)

Összehasonlítás, logika

0 < x < 5, x>0 and x<3, not x==2

Tartomány-megszorítás

x^2 {x > 0}, sin(x) {0 <= x <= 3}

Paraméteres görbe

(cos(t), sin(3t))

Polár görbe

r = 1 + cos(θ)

Implicit görbe

x^2 + y^2 = 4

Összeg, szorzat

sum(k, 1, 20, sin(k*x)/k)

Paraméterek (csúszka)

a*sin(b*x + c)

Magyar és angol nevek

tg, ctg, arctg, sh, ch, lg, ln, log(2, 8)

Hogyan lehet biztonságosan kiértékelni egy felhasználó által beírt képletet?

A legegyszerűbb, de veszélyes megoldás az eval() lenne: ez a beírt szöveget közvetlenül PHP-kódként futtatná le, ami tetszőleges kód végrehajtását tenné lehetővé a szerveren - ez az oldal ezért soha nem használ eval()-t.

A biztonságos megoldás egy saját kifejezés-parser: a szöveget tokenekre bontja (számok, operátorok, függvénynevek, zárójelek, Unicode jelek), majd szintaxisfát épít belőle, amely a precedenciát (a -x^2 jelentése -(x²), a 2^3^2 jobbról köt), az implicit szorzást (2x, 3sin(x)) és az abszolútérték-jelet is helyesen kezeli. A fenti matematikai előnézet pontosan ezt a szerver által épített fát rajzolja ki.

A kiértékelés a fát bejárva csak egy szigorúan fehérlistás függvénykészletet enged meg - egy ismeretlen név azonnal hibát dob (és megmondja, hol, sőt azt is, mire gondolhattál). Minden numerikus bemenet szorított: legfeljebb 8 kifejezés, 200 karakter egyenként, korlátos mintaszám, rácsméret és időkeret.

A szakadásokat a szerver felismeri: ahol a függvény nincs értelmezve, a vonal megszakad; az aszimptotánál (1/x, tan x) és az ugrásnál (floor) az intervallum-felezés kideríti, hogy a két mintapont közt valódi szakadás van-e, és ha igen, nem köti össze őket. A sin(x)/x a 0-ban a kétoldali határértékből pótolódik. A gyököket bisection-nel, az implicit görbéket marching squares-sel, az integrált Gauss-Legendre kvadratúrával számolja.