Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: CSS, HTML, PHP: Newtonin menetelmä

kayttaja-2791 [22.07.2005 11:54:52]

#

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&nbsp;&nbsp;<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>

tsuriga [23.07.2005 15:54:09]

#

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 ;)?

kayttaja-2791 [31.07.2005 15:47:35]

#

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 ;)

Ceez [04.08.2005 11:29:29]

#

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.

phadej [06.08.2005 14:03:11]

#

tai mielummin 2h menetelmällä jota laskimet käyttää...

f'(x) = [f(x+h) + f(x-h)] / (2h)

kayttaja-2791 [06.08.2005 15:58:20]

#

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.

Metabolix [13.12.2011 22:47:00]

#

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ä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta