napraviRazlomak() problem

vozdra :smiley: napravio sam osnovnu funkciju koja pretvara decimalni broj u razlomak, no problem je što kod nekih ne želi skratiti uopće… Napravio sam log koji mi ispiše $brojnik/$x = rješenje (cijeli broj: TRUE/FALSE), i isto za nazivnik. Kad naprimjer stavim 2.26 dobijem rješenje 226/100, dok bi trebalo biti 113/50, javi mi da 226/2 i 100/2 nisu cijeli brojevi :S može neko probati, pa mi javi di fulam… :slight_smile:

skripta:
[php]<?php

// ne brinite, ovo je osnova, usavrsit cu ju, nekritizirajte “sigurnost” i princip rada funkcije
function napraviRazlomak($broj = 0)
{
if (is_float($broj))
{
// zaokruzujem na dve decimale, nema smisla vise
$broj = round($broj, 2);

    // brojim decimale, kasnije ce biti zamjenjeno sa regularnim izrazima
    $brojDecimala = strlen(str_replace('.', '', strrchr($broj, '.')));
    
    // potenciram desetku na broj decimale, sto ide u nazivnik
    $potencijaDesetke = pow(10, $brojDecimala);

    // dobivam brojnik i nazivnik
    $brojnik = $broj * $potencijaDesetke;
    $nazivnik = &$potencijaDesetke;
    
    // provjeravam je li veci brojnik ili nazivnik
    $veci = ($brojnik > $nazivnik) ? $brojnik : $nazivnik;
    
    // brojevi s kojima ce se kratit razlomak na kraju skripte
    $brojnikX = 1;
    $nazivnikX = 1;
    
    for ($x = 1; $x <= $veci; $x++)
    {
        // skripta ide sve dok ne nade broj koji kad se djele brojnik i nazivnik s njim daje cijeli broj
        if (cijeliBroj($brojnik / $x) === TRUE AND cijeliBroj($nazivnik / $x) === TRUE)
        {
            $brojnikX = $x;
            $nazivnikX = $x;
        }
    }
    
    // djelim razlomke s tim brojem
    $brojnik /= $brojnikX;
    $nazivnik /= $nazivnikX;

    return $brojnik . '/' . $nazivnik;
}
else
{
    return 'broj mora realan i decimalan';
}

}

function cijeliBroj($int)
{
return (is_numeric($int) === TRUE) ? ((int)$int == $int) ? TRUE : FALSE : FALSE;
}

echo napraviRazlomak(2.25);
[/php]

Pa brojnikX i nazivnikX ti uvijek ispadaju 1 i šta god da dijeliš s jedan nećeš dobiti drugo nego taj brojkoji dijeliš, zato ti ne skraćuje ništa.

Zanimljivo je to da se to događa samo kada ukucaš 2.26, sa svim ostalim brojevima radi.

Slažem se, isprobao sam puno brojeva, no samo tu ne želi skraiti…

[quote=“jcrnkovic”]vozdra :smiley: napravio sam osnovnu funkciju koja pretvara decimalni broj u razlomak, no problem je što kod nekih ne želi skratiti uopće…
javi mi da 226/2 i 100/2 nisu cijeli brojevi [/quote]

Onda je vjerojatno problem u tome kako ta funkcija ispituje je li neki broj cijeli.
Možda umjesto te funkcije možeš koristiti neku drugu ili nešto izmijeniti u njoj?

Ili kad ideš dijeliti a/b, da prvo onaj a pretvoriš u integer, možda ga tu nešto mota…

Ja to onako napamet, a inače ni ne znam taj programski jezik… :slight_smile:

išao sam ovim redom: broj mora biti decimalan, onda prebrojim decimale, potenciram desetku na taj broj decimali, pomnozim sa brojem (tako da dobijem cijeli broj) i onda imam brojač koji gleda koji je najveći broj s kojim se dijeli brojnik i nazivnik tako da je rezultat cijeli broj…

vjerojatno je greška u cijeliBroj(), kao što si rekao :slight_smile: no is_int() ne radi pošto je ta varijabla string, a ne broj… :frowning:

Skužila sam ja tu logiku.
No, to što mi ljudi tim računom dobivamo cijeli broj, ne znači da i računalo zaista dobije cijeli broj, možda je on umjesto 126 dobio 125.9999… I onda kad podijeli, isto ne dobije cijeli…

Ne kužim baš kako se ne može primijeniti nešto popt INT (zaravo, nešto što bi ga zaokružilo na najbliže cijelo), a može se ići dijeliti taj broj sa 2… Ako može jedan račun, zašto ne može drugi…
Ali taj dio ti sigurno znaš bolje od mene.

I još jedan detalj:
U petlji u kojoj tražiš najveći zajednički djelitelj, ne moraš ići do većeg broja, nego do manjeg (između brojnika i nazivnika). Zajednički djelitelj ne može biti veći od toga koji je manji. :slight_smile:

S obzirom da si rekao da je funkcija u izradi i da ne komentiramo izvedbu, počet ću s tim. :slight_smile:

-1-

Uoči da umjesto potenciranja broja 10, možeš u petlji množiti s 10.

-2-

Pošto ulazni argument u jednom trenutku implicitno pretvaraš u string i tako ga manipuliraš, onda uoči da množenje s potencijom broja 10 kako bi izgubio decimalnu točku možeš vrlo jednostavno izvesti tako da iz tekstualnog prikaza broja naprosto ukloniš znak decimalnog separatora.

-3-

Kada radiš skraćivanje, dovoljno je varijablu $x puštati do polovice broja. Naime, kada pređeš polovicu broja onda rezultat dijeljenja jednostavno više ne može biti cijeli broj. Razmisli. Onda razmisli dokle treba ići $x kada je $veci neparan. Kada i o tome promisliš, onda promisli bi li $veci zapravo mogao biti $manji.
Isto tako, nema nikakve potrebe započinjati s $X = 1.

-4-

U funkciji cijeliBroj nema nikakve dvojbe da će is_numeric uvijek vraćati istinu za sve argumente koje joj preda funkcija napraviRazlomak. Naravno, kao opća funkcija, onda tu provjeru treba imati, ali se postavlja pitanje koliko je smisleno izdvajati tu metodu u zasebnu funkciju - ne obiluje li algoritam s dovoljno detalja da izdvajanje ovog jednog u imenovanu funkciju neće pomoći dokumentiranju algoritma?

-5-

Neposredno ispod retka “$nazivnik /= $nazivnikX;” dodaj naredbu:[php]echo $potencijaDesetke . “
”;[/php]Objasni.

-6-

I konačno problem s 2.26. Ovdje se treba poslužiti debugiranjem.

Pokušaj neposredno ispod otvorene vitičaste zagrade od for-petlje dodati ovaj kôd:[php]echo "$brojnik / $x = " . $brojnik / $x . “
”;
echo "( int )($brojnik / $x) = " . ( int )($brojnik / $x) . “
”;
echo "gettype($brojnik / $x) = " . gettype($brojnik / $x) . “
”;
echo “


”;[/php]Kada se načudiš, onda idi na priručnik, poglavlje Integers i obrati pažnju na okvire pri dnu poglavlja naslovljene kao “Warning” i “Caution”.

Problem postoji i s 1.13, te bilo kojim umnoškom istog s potencijom broja 2. Broj 1.13 je iracionalan u binarnom brojevnom sustavu, tj. 1.13d = 1.00100001010001111010111b… (podebljano je slijed koji se ponavlja). Zbog toga što je broj bitova u registru procesora ograničen, taj broj nije moguće strojno prikazati točno, već samo kao najbliži mogući broj, ovisno o broju bitova koji se može prikazati. U slučaju 32-bitnog IEEE-754 prikaza 1.13d se prikazuje kao 1.00100001010001111010111 što je zapravo 1.1299999952316284108569480493239812023939785851558804562589081825389930924096533762921229540820995871d. Normalno, biblioteke za rad s binarnim brojevima bi se trebale služiti nekim tehnikama zaokruživanja, a što se čini da ovdje baš i ne funkcionira sasvim kako bismo htjeli.

[quote=“tsereg”]
-3-

Kada radiš skraćivanje, dovoljno je varijablu $x puštati do polovice broja. Naime, kada pređeš polovicu broja onda rezultat dijeljenja jednostavno više ne može biti cijeli broj. Razmisli. [/quote]

Ako dobro kužim o čemu je ovdje riječ, onda ipak nisi u pravu.
Npr. ako imamo brojeve 5 i 10, u traženju NZD nije dovoljno ići do polovice broja 5,kad je rješenje upravo broj 5, sa njime treba kratiti.
Jedino ako se tu misli na polovicu većeg broja, onda je ok.
No, ako bismo dopustili da su ulazne vrijednostui bilo koja dva broja, onda u slučaju jednakosti ulaznih brojeva opet ne funkcionira ovo da se ide samo do pola.

Onda manji od manjeg i polovice većeg?

Pa ja bih stavila jednostavno - manji ili jednak manjemu. To će ga natjerati da i u slučaju npr. 5/10, i u slučaju 10/10, radi dobro.

Može se naravno petljati i sa tom polovicom većega (što će ipak u nekim slučajevima osjetno smanjiti broj koraka u petlji, npr. u 99/100), no onda bi valjda prvo trebalo ispitati da nije brojnik=nazivniku (a ako je, rezultat je 1/1, tj. 1), a ako nije jednak onda se ide do min(manji,pola većega).

Tu se naravno provlači i pitanje je li moguće da se desi brojnik=nazivnik, ako je ulazna vrijednost decimalni broj. A zapravo je, jer korisnik može ukucati 1.0 ili 1.00, što će onda ovaj algoritam pretvoriti u 10/10 i 100/100…
Vjerojatnost da će netko tako ukucati je mala, ali moj prof. iz informatike nam je stalno ponavljao: “Korisnička glupost je neograničena!!!”… :slight_smile:

Ma može još kraće, ako već imamo volje imati i IF i petlju.
Prvo ispitamo da li je manji ujedno djelitelj od većega. Ako je, onda je NZD=manji, a ako nije onda se u petlji ide do manji/2.

pozz
ima taj php nekih kvaka. ja sam prije par godina imao slican slucaj sa funkcijom round(), koja u 10-tak % slucajeva nije dobro zaokruzivala brojeve.
onda sam mora sam napisat svoju funkciju koju sam koristija u aplikaciji.
bugovi…

[quote=“tango”]pozz
ima taj php nekih kvaka. ja sam prije par godina imao slican slucaj sa funkcijom round(), koja u 10-tak % slucajeva nije dobro zaokruzivala brojeve.
onda sam mora sam napisat svoju funkciju koju sam koristija u aplikaciji.
bugovi…[/quote]

LOL :smiley:


Copyright © 2020 WM Forum - AboutContact - Sponsored by: Mydataknox & Webmaster.Ninja