Aloin työstämään ohjelmaa, jolle syötetään merkkijonona funktio (esim. (x^2)*sin(x)-1, yhden muuttujan funktiot näin aluksi) ja ohjelma osaisi esim. numeerisesti integroida tietyltä väliltä tai derivoida sen. Nyt aluksi oli tarkoitus perehtyä muiden tekemiin valmiisiin vastaavanlaisiin luokkiin, joista saisi hyviä vinkkejä miten itse voisi toteuttaa esim luokan Funktio tai funktioparser työkalun. Netti on pullollaan java appletteja, jotka esim piirtävät kuvaajan kun niihin syöttää funktion ja näistä on aika hyvin applettien lähkekoodejakin tarjolla. Usein kuitenkin juuri ne luokat jotka minua kiinostaisi on näissä saatavilla olevissa koodeissa vain importattuja ja niiden toteutus jää hämärään. Onko joku työskennellyt vastaavanlaisten ohjelmien parissa? Kiinnostaisi kuulla mihin toteutusratkaisuun on päädytty tai mitä valmiita luokkia on käytetty.
Lisäksi derivaatta työkalun toteutus kiinnostaisi. Tarkoitus ei ole tehdä mitään kaiken kattavaa, mutta kunhan yleisempien funktioiden kohdalla toimisi. Ja jos haluaa ohjelman piirtävän funktion, onko järkevää vain käyttää drawline metodia ja määrätä pisteiden väli niin, että tulos näyttää hyvältä? Vai onko tähän joku yleisesti käytössä oleva työkalu?
Merkkijonossa olevan laskutoimituksen voi laskea melko suoraviivaisesti toteuttamalla rekursiivisen metodin. Jos laskutoimituksessa on sulkuja, metodi laskee ensin niiden sisällä olevan laskutoimituksen tuloksen rekursiivisesti. Sitten metodi laskee peruslaskutoimitukset oikeassa järjestyksessä (esim. kertolaskut ennen yhteenlaskuja). Funktiot lisäävät hieman koodin määrää, mutta periaate pysyy samana.
Tein äskettäin Java-koodin, joka laskee yhteen- ja kertolaskuja sekä sulkuja sisältävän laskutoimituksen:
http://koti.mbnet.fi/pllk/Laskutoimitus.java
Funktion kuvaajan piirtäminen lyhyistä viivoista on toimiva ratkaisu.
Itse aikoinaan lähdin saman tapaista systeemiä rakentamaan oheisen linkin kirjaston päälle: http://muparser.sourceforge.net/
Myös minä pohdin tällaista ja lopulta sain aikaiseksi rekursiivisen metodin joka laski peruslaskut. Tein ohjelman joka piirtää suoran annetun yhtälön mukaisesti, tosin potenssiin korottaminen desimaaliluvulla ei ikinä toiminut. Olisin tarvinnut syvällisempää tietoa potenssilaskuista. Rekursiivisuus kannattaa!
Oppikirjaratkaisu on ns. Shunting-yard-algoritmi ja sen yksinkertaisemmat versiot. Algoritmi parsii lausemerkkijonon lausekepuuksi, jota voi sitten pyöritellä haluamallaan tavalla. Esimerkiksi symbolinen derivointi ja yksinkertaiset lausekkeen sievennykset on mahdollista toteuttaa käyttäen tätä lähestymistapaa. Pitää vain olla vähän tarkkana varsinkin, jos lausekeessa on useampi muuttuja, jonka suhteen derivoidaan, sekä potenssilaskujen kanssa. Lausekepuuta on myös vähän tehokkaampi ja luontevampi evaluoida useammassa pisteessä esimerkiksi käyrän piirtämistä varten - verrattuna siis siihen vaihtoehtoon, että tulos laskettaisiin joka pisteessä merkkijonosta. Symbolisen derivoinnin lisäksi derivaatan laskemiseen voidaan käyttää jänniä vaihtoehtoisia tapoja.
Tilli: "desimaalilukujen" potenssiinkorotus määritellään muodossa xy = ey ln x (missä ey ja ln x määritellään muulla tavoin, esimerkiksi sarjakehitelmän avulla) ja se toimii lähtökohtaisesti "hyvin" ainoastaan siinä tapauksessa, että x > 0. Jos taas y on kokonaisluku, voidaan laskutoimitus määritellä tutummalla tavalla jolloin se myös toimii kaikilla x. Käytännössä kaikkien (järkevien) ohjelmointikielten standardikirjastosta tietty löytyy kyseiselle laskutoimitukselle myös valmis funktio: xy = pow
(x,y), joka on toivon mukaan myös niin fiksu, että se osaa handlata automaattisesti molemmat tapaukset.
Kiitos vinkeistä.
Toistaiseksi olen kyhännyt rekursiivisen metodin, joka onnistuneesti laskee funktion arvon annetussa pisteessä. sin,log yms. merkinnätkin se tunnistaa ja laskee kuten pitää, vaikkakin koodissa niiden etsiminen on hieman tönkösti toteuttettu tekemällä jokaisesta erillinin "if" rivi. Jonkun verran on myös mennyt aikaa siihen, kun olen yrittänyt saada ohjelmaa tunnistamaan taipuuko annettu merkkijono syntaksin mukaisesti funktioksi ja palauttamaan merkkijonon indeksi, jossa se ensimmäisen virheen havaitsee. Tähän liittyen funktion tuli osata muuttaa että esim. 2sin(3x)=>2*sin(3*x), jotta laskettaessa ei virheitä tule.
Seuraava isompi haaste tulee olemaan todennäköisesti tuo symbolinen derivointi. Perehdyn siihen päästyäni sitten tarkemmin noihin linkkeihin!
Aihe on jo aika vanha, joten et voi enää vastata siihen.