Laskee funktion yhden likiarvon Newtonin menetelmällä kunhan syötät funktion ja sen derivaatan.
Täysi html-versio. Saa soveltaa kuten haluaa.
Kunhan et jaa tätä tai mitään osaa tästä koodista itse tekemänäsi.
Mikäli Newtonin menetelmä ohjelmoinnissa kiinnostaa niin muunmuassa siitä löydät keskustelua Ohjelmointiputkan koodivinkin kommenteista seuraavasta urlista:
https://www.ohjelmointiputka.net/koodivinkit/24716-php-neliöjuurilaskin
Tässä käytetään myös toista lähettemääni Ohjelmointiputkan koodivinkkiä, "Laskutoimitusten suorittaminen merkkijonosta":
https://www.ohjelmointiputka.net/koodivinkit/24771-php-laskutoimitusten-suorittaminen-merkkijonosta
--Versio 3 - 22.07.2005 - Final
<?php /* Laskee funktion yhden likiarvon Newtonin menetelmällä kunhan syötät funktion ja sen derivaatan. Täysi html-versio. Saa soveltaa kuten haluaa. Kunhan et jaa tätä tai mitään osaa tästä koodista itse tekemänäsi. Mikäli Newtonin menetelmä ohjelmoinnissa kiinnostaa niin muunmuassa siitä löydät keskustelua Ohjelmointiputkan koodivinkin kommenteista seuraavasta urlista: https://www.ohjelmointiputka.net/koodivinkit/24716-php-neli%C3%B6juurilaskin --Versio 3 - 22.07.2005 - Final */ ?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Newtonin menetelmä</title> <style type="text/css"> body { font: 90% verdana, sans-serif; } input { background: #e5f5ff; border: 1px solid black; margin: 3px; padding-left: 3px; text-align: left; } sub { font-size: 60%; } </style> </head> <body> <?php if (!$funktio = $_GET['funktio']) $funktio = "x^2 - 50"; if (!$derivaatta = $_GET['derivaatta']) $derivaatta = "2x"; if (!$iteraatioita = $_GET['iteraatioita']) $iteraatioita = 10; if (!$tarkkuus = $_GET['tarkkuus']) //Montako desimaalia $tarkkuus = 4; //Alkuarvaus, muuten ei paljoa väliä kunhan ei ole nolla ettei nimittäjä mene nollaksi if ($_GET['alkuarvaus']) $tulos = $_GET['alkuarvaus']; else $tulos = 2; ?> <h3>Newtonin menetelmä</h3> <p> Newtonin menetelmä on iteratiivinen, eli sitä ajetaan useita kierroksia ja sen saama likiarvo tarkentuu kierros kierrokselta. Siispä siinä lähdetään jostain alkuarvauksesta (tässä tapauksessa <?php echo $tulos; ?>) josta funktion todellinen arvo alkaa tarkentumaan yllättävän nopeasti. </p> <p> Menetelmä menee yksinkertaisuudessaan seuraavasti: <br /> x<sub>i+1</sub> = x<sub>i</sub> - f(x<sub>i</sub>) / f´(x<sub>i</sub>) </p> <p> Eli voit laskea yhden juuren mille tahansa funktiolle kunhan vain osaat laskea itse sen derivaatan. </p> <p> Oletuksena laskin laskee luvun 50 neliöjuuren. </p> <?php //Muuttaa stringin laskutoimitukset luvuksi, ei tue sulkuja. v.2.0 //Tämäkin löytyy aiemmin julkaistuna Ohjelmointiputkan vinkkinä //https://www.ohjelmointiputka.net/koodivinkit/24771-php-laskutoimitusten-suorittaminen-merkkijonosta function laskestring($laskutoimitus, $luku, $muuttuja = "x", $debug = false, $debughtml = true) { //Poistetaan turhat välilyönnit alusta ja lopusta, samoin muutetaan useiden välilyöntien sarjat vain yhdeksi välilyönniksi $laskutoimitus = preg_replace("/[ ]+/", " ", trim($laskutoimitus)); //Hyväksytään vain laskutoimitusmerkit sekä numerot ja välilyönnit $laskutoimitus = preg_replace("/[^\\+\\-\\/\\*\\^\\(\\)\\.{$muuttuja}0-9 ]/", "", $laskutoimitus); //Tarkastetaan että sulkeiden aloitusmerkkejä on yhtä paljon kuin sulkemismerkkejä, mutten palautetaan error if (substr_count($laskutoimitus, "(") != substr_count($laskutoimitus, ")")) { if ($debug) echo "Sulkujen määrä ei täsmää, tarkasta että olet sulkenut kaikki sulkeet\n"; if ($debughtml) echo "<br />"; return false; } //Tämä suorittaa itse laskun, tälläinen järjestely sulkujen takia, //aloitusviestillä voi antaa ensimmäisen viestin jossa näytetään laskettava lauseke if (!function_exists("suoritalasku")) { function suoritalasku($laskutoimitus, $luku, $muuttuja = "x", $debug = false, $debughtml = false, $aloitusviesti = "Laskutoimitus") { //Aloitustilanne debugtulostusta varten $debugtulostus[$aloitusviesti] = $laskutoimitus; //Sallitut laskumerkit $laskumerkit = "[\\+\\-\\/\\*\\^]"; //Tarkistetaan hieman syntaksia //Aloitus if (preg_match("/^([\\+\\/\\*\\^])/", $laskutoimitus, $virhe)) { $debugtulostus['Virheellinen aloitus'] = $virhe[0]; $virheitä = true; } //Lopetus if (preg_match("/($laskumerkit)$/", $laskutoimitus, $virhe)) { $debugtulostus['Virheellinen lopetus'] = $virhe[0]; $virheitä = true; } //Laskutoimitukset if (preg_match("/($laskumerkit)[ ]?($laskumerkit)/", $laskutoimitus, $virhe)) { $debugtulostus['Virheellinen laskutoimitus'] = $virhe[0]; $virheitä = true; } //Muuten ei virhettä, tehdään laskutoimitukset if (!$virheitä) { //Muunnetaan merkinnät 2x muotoon 2 * x $debugtulostus['Muunnos'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?$muuttuja/", "\\1 * $muuttuja", $laskutoimitus); //Sijoitetaan muuttuja $debugtulostus['Muunnos'] = $laskutoimitus = preg_replace("/$muuttuja/", $luku, $laskutoimitus); //Lasketaan potenssit $debugtulostus['Potenssi'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\^[ ]?([0-9.]+)/e", "pow(\\1, \\2)", $laskutoimitus); //Korottaa potenssiin //Lasketaan kerto- ja jakolaskut while (!$exit) { $edellinen = $laskutoimitus; $debugtulostus['Kertominen'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\\*[ ]?([0-9.]+)/e", "\\1 * \\2", $laskutoimitus); //Kertominen $debugtulostus['Jakaminen'] = $laskutoimitus = preg_replace("/([0-9.]+)[ ]?\\/[ ]?([0-9.]+)/e", "\\1 / \\2", $laskutoimitus); //Jakaminen //Mikäli ei ole enään jako- tai kertomerkkejä, tai loop on jäänyt junnaamaan (edellinen arvo sama kuin nykyinen) poistutaan while-silmukasta if (strpos($laskutoimitus, "/") == false && strpos($laskutoimitus, "*") == false or $edellinen == $laskutoimitus) $exit = true; } } //Exitiä käytetään vielä toisessa loopissa unset($exit); //Lasketaan plus- ja miinuslaskut while (!$exit) { $edellinen = $laskutoimitus; if (strpos($laskutoimitus, "-") === 0) $debugtulostus['Ynnäys'] = $laskutoimitus = preg_replace("/\\-[ ]?([0-9.]+)[ ]?(\\+|\\-)[ ]?([0-9.]+)/e", "-\\1 \\2 \\3", $laskutoimitus); else $debugtulostus['Ynnäys'] = $laskutoimitus = preg_replace("/^[ ]?([0-9.]+)[ ]?(\\+|\\-)[ ]?([0-9.]+)/e", "\\1 \\2 \\3", $laskutoimitus); if (!strpos($laskutoimitus, "+") && !strpos(substr($laskutoimitus, 1), "-") or $edellinen == $laskutoimitus) $exit = true; } //Tulostetaan debugit jos käyttäjä niin haluaa if ($debug) { if ($debughtml) echo "<pre>"; foreach ($debugtulostus as $toiminto => $laskutoimitus) { if ($debughtml) echo "$toiminto: \t $laskutoimitus\n"; else echo "$toiminto: $laskutoimitus \n"; } if ($debughtml) echo "</pre>"; } //Palautetaan vastaus mikäli laskutoimitukset meni ilman virheitä if (!$virheitä) return $laskutoimitus; else { return "false"; //Purkkaa ehkäpä, //palautetaan string false ja tarkastetaan sen sijainti itse koodissa alla, tämä siksi että //palautus tulee regexpin evaliin josta en osaa sen totuusarvoa tarkastaa :| } } //suoritakoodi() } //Annetaan se kaikkein alkuperäisin jos debugataan if ($debug) { if ($debughtml) echo "<b>Alkuperäinen muoto:</b> <code>$laskutoimitus</code> \n"; else echo "Alkuperäinen muoto: $laskutoimitus \n"; } //Sulkujen sisältä lasketaan ensin laskut while (!$exit) { $edellinen = $laskutoimitus; $laskutoimitus = preg_replace("/\\([ ]?([^\\(]*?)[ ]?\\)/e", "suoritalasku('\\1', $luku, $muuttuja, $debug, $debughtml, 'Suluista')",$laskutoimitus); if (strpos($laskutoimitus, "false") != false) return false; //Ja taas tätä loputonta debuggauskoodia if ($debug) { if ($debughtml) echo "<br />\n<b>Sulut poistettu, uusi muoto:</b> <code>$laskutoimitus</code>"."<br />\n"; else echo "\nSulut poistettu, uusi muoto: $laskutoimitus"."\n"; } //Mikäli on sulkuja vielä, tai looppi jää jostain syystä jauhamaan tyhjää keskeytetään se if (strpos($laskutoimitus, "(") == false && strpos($laskutoimitus, ")") == false or $edellinen == $laskutoimitus) $exit = true; } //Sitten kun sulut on poistettu niin lasketaan loputkin $laskutoimitus = suoritalasku($laskutoimitus, $luku, $muuttuja, $debug, $debughtml); //Palautetaan vastaus mikäli laskutoimitukset meni ilman virheitä if (!$virheitä && is_numeric($laskutoimitus)) return $laskutoimitus; else return false; }//Funktio suoritastring päättyy //Tulostetaan form print " <form action=\"$_SERVER[PHP_SELF]\"> \tf(x) = <input name='funktio' type=text value='".$funktio."' size=20> = 0 <br/> \tf´(x) = <input name='derivaatta' type=text value='".$derivaatta."' size=19> = 0 <br/> \tIteraatioita <input name='iteraatioita' type=text value='".$iteraatioita."' size=4> <br /> \tTarkkuus <input name='tarkkuus' type=text value='".$tarkkuus."' size=4> (desimaalia) <br /> \tAlkuarvaus <input name='alkuarvaus' type=text value='".$tulos."' size=4> <br /> \t <input type=submit value=Laske></form>"; for ($i = 1; $i <= $iteraatioita; $i++) { $uusiderivaatta = laskestring($derivaatta, $tulos); $uusifunktio = laskestring($funktio, $tulos); $tulos = $tulos - $uusifunktio/$uusiderivaatta; $tulokset[$i] = $tulos; } //Tulostetaan likiarvo echo "\n<p>\n\tNewtonin menelmän palauttama likiarvo: <b>",round($tulos, $tarkkuus),"</b>\n</p>"; //Tulostetaan iteraatio echo "\n\n<p>\n\t<b>Iteraatiot</b> <br />"; foreach ($tulokset as $nro => $tulos) { //Tässä muutetaan lukusijoitus 1 -> 01 tai 1 -> 001 riippuen iteraatioiden määrästä if ((strlen(count($tulokset)) - strlen($nro)) > 0) { while ((strlen(count($tulokset)) - strlen($nro)) > 0) $nro = "0".$nro; } //Tulostetaan tämän kierroksen tulos echo "\n\t",$nro,". ",round($tulos, $tarkkuus)," <br />"; } ?> </p> </body> </html>
Olisit laittanut vaikka pelkän funktion, tämä on puolet HTML-kuvausta puolet PHP-koodia. Demosivulle vaikka nuo kuinka sitä käytetään. Ja eikös tuo voisi itse laskea sen derivaatan ;)?
Ehkä tämä vinkki on sitten enemmän HTML:n ja PHP:n yhteiseloa koskeva :)
Voisihan se laskea derivaatankin, mietinkin sen tekoa, mutta en ole vielä saanut aikaan... Ehkä versiossa 4 ;)
Eihän ton tarvis ees derivaattaa laskea jos käyttäs menetelmää
x[n] = x[n-1] - f(x)*h / (f(x+h)-f(x))
Jossa h ilmaisee tarkkuuden.
tai mielummin 2h menetelmällä jota laskimet käyttää...
f'(x) = [f(x+h) + f(x-h)] / (2h)
Muuten hyvä mutta sitten se ei olisi Newtonin menetelmä :)
Noihin kyseisiin menetelmiin on helppo soveltaa tuota laskestring() funktiota. Tosin pistin pari päivää sitten alulle derivaatan laskimenkin, joten ehkä tätäkin vinkkiä tullaan vielä päivittämään.
On kyllä kohtalaisen sekava koodi. Newtonin menetelmä sinänsä olisi hyvä koodivinkki, mutta tällaisena megakoodina siitä ei kyllä ota mitään selvää (ellei osaa asiaa jo valmiiksi). :)
Jos suinkin viitsit, voisit korjata ainakin pahimmat ongelmat: määrittelemättömät muuttujat (jopa omatoimisesti unsetillä!), $_GET-taulukon isset-tarkistukset ja PHP_SELFistä johtuvan XSS-aukon. Muutenkin koodia pitäisi siistiä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.