Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Zaokrouhlování v jazyku C

Aktivity
Avatar
Peta
Člen
Avatar
Peta:6.10.2015 21:38

Ahoj, nevíte někdo prosím, jak mám udělat tento úkol?
Vytvořte program, který po načtení desetinného čísla a přesnosti vypíše zadané
číslo po zaokrouhlení na zadanou přesnost.
Př:
Číslo: 8.2483
Přesnost: 0.01
Zaokrouhleno: 8.25

 
Odpovědět
6.10.2015 21:38
Avatar
Pjanus
Člen
Avatar
Odpovídá na Peta
Pjanus:6.10.2015 21:51

No mohl by si to třeba udělat tak že bys vydělil zadané číslo přesností 8.2483 / 0.01 = 824.83 poté bych si tu hodnotu uložil a převedl to číslo z desetinného na celé. Takže v paměti jsou dvě čísla, ty bych od sebe odečetl (float)824.83 - (int)824 z čehož by vznikl výsledek 0.83 který se dá jednoduše porovnat jestli je větší nebo roven 0.5. Podle toho by se rozhodlo jestli se číslo (int) zvýší o jedna. Na konci procesu stačí vynásobiz výsledek v tomto případě 825 původní přesností 0.01 což nám 825 * 0.01 = 8.25. Ale taky je možný že to dělám příšerně složitě ale mohlo by ti to alespoň dát nápad ;)

 
Nahoru Odpovědět
6.10.2015 21:51
Avatar
Sony Nguyen
Tvůrce
Avatar
Sony Nguyen:6.10.2015 22:23

Přikládám také moje řešení :).
číslo = 8.2483
přesnost = 0.01
toCoSmažeme = číslo % přesnost

pokud je toCoSmažeme / přestnost větší nebo rovno 0.5, tak číslo += přesnost
jinak nic nedělej

číslo = číslo - číslo % přesnost

implementace v Pythonu 2.7

def zaokrouhli(cislo, presnost):
        zbytek = cislo % presnost

        if zbytek / presnost >= 0.5:
                cislo += presnost
        return cislo - zbytek

Přesnost by měla být vždy typu float/double
ale není to ošetřeno proti nevalidním vstupům
PS. Snad pomohlo :), uznávám, že je to trochu magické :D

Editováno 6.10.2015 22:24
 
Nahoru Odpovědět
6.10.2015 22:23
Avatar
coells
Tvůrce
Avatar
Odpovídá na Sony Nguyen
coells:7.10.2015 0:05

Sony, jsi blízko, ale modulo se považuje za pomalou operaci.
Kód se dá zjednodušit, v případě pythonu 3 by to bylo:

def zaokrouhli(cislo, presnost):
    return int(cislo / presnost + .5) * presnost

Plus je ještě nutné vzít v úvahu záporná čísla.

 
Nahoru Odpovědět
7.10.2015 0:05
Avatar
David Novák
Tvůrce
Avatar
Odpovídá na coells
David Novák:7.10.2015 8:36

Jen bych podotkl, že dělení je naprosto stejně pomalé jako modulo (obě se provádí zároveň při každé instrukci DIV) :)

Nahoru Odpovědět
7.10.2015 8:36
Chyba je mezi klávesnicí a židlí.
Avatar
Odpovídá na Peta
Libor Šimo (libcosenior):7.10.2015 8:55

Úloha je veľmi jednoduchá:

#include <stdio.h>

int main(void)
{
    float f = 8.2483;
    printf("%.2f\n", f);
    return 0;
}
;-)
Nahoru Odpovědět
7.10.2015 8:55
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):7.10.2015 8:58

Poprípade trošku rozšírené:

#include <stdio.h>

int main(void)
{
    float f;

    printf("Zadajte desatinne cislo: ");
    scanf("%f", &f);
    printf("%.2f\n", f);

    return 0;
}
Nahoru Odpovědět
7.10.2015 8:58
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
coells
Tvůrce
Avatar
Odpovídá na David Novák
coells:7.10.2015 19:21

Překvapivě to není pravda pokud budeme mluvit o celočíselném dělení.
Modulo je opravdu pomalejší - a ano, vím, jak fungují instrukce div a idiv.
U posuvné řádové čárky je na to speciální instrukce, takže by to snad mělo být stejně rychlé, ale to jsem nikdy nezkoušel.

 
Nahoru Odpovědět
7.10.2015 19:21
Avatar
David Novák
Tvůrce
Avatar
Odpovídá na coells
David Novák:7.10.2015 19:45

Vidíš to - FPU dělení / modulo jsem nebral v potaz...

Zajímalo by mě ale, jak může být při použití DIV modulo pomalejší, když jedna operace vrací oba výsledky.. Vysvětlíš?

Nahoru Odpovědět
7.10.2015 19:45
Chyba je mezi klávesnicí a židlí.
Avatar
coells
Tvůrce
Avatar
Odpovídá na David Novák
coells:7.10.2015 20:11

Nevysvětlím, bohužel.
Dokonce jsem to zkoušel a na mém CPU jsou opravdu stejně rychlé.
Ale mám opačnou zkušenost z minula ze soutěží, kdy odstranění modula výrazně pomohlo.

 
Nahoru Odpovědět
7.10.2015 20:11
Avatar
Petr Valigura
Tvůrce
Avatar
Petr Valigura:7.10.2015 20:28

Hádám kolega z UPOL? :D (já jenom, že my jsme dostali úplně stejný úkol) Moje řešení

int main() {
        double cislo, zaokrouhleneCislo, presnost;
        printf("Zadej cislo: ");
        scanf("%lf", &cislo);
        printf("Zadejte presnost: ");
        scanf("%lf", &presnost);
        zaokrouhleneCislo = ((long int)(cislo / presnost + 0.5)) * presnost;
        printf("%f \n", zaokrouhleneCislo);
        system("pause");
        return 0;
}

Funguje jen u kladných, kdyby jsi chtěl i u záporných, tak to číslo prvně převeď na kladné (...*(-1)) a pak zase zpátky na záporné :)

Nahoru Odpovědět
7.10.2015 20:28
Občas je to tady dobrá klauniáda...
Avatar
David Novák
Tvůrce
Avatar
Odpovídá na coells
David Novák:7.10.2015 20:54

Ono asi hodně záleží na použitém jazyku a kvalitě překladače..

Pokud bychom například v C napsali:

int a,b;
int deleni = a / b;
int modulo = a % b;

Měl by z toho překladač se zapnutou optimalizací udělat něco takového:

mov eax, [a]
cdq
mov ebx, [b]
div ebx
mov [deleni], eax
mov [modulo], edx

Takže použití těchto dvou operací nad stejnými operandy by vůbec nemělo být zpomalující. Jak se k tomu staví jiné překladače a vyšší jazyky ale nevím, takže těžko říct no.. Možná se jednalo o nějakou chybu, která byla vyřešena. :)

Nahoru Odpovědět
7.10.2015 20:54
Chyba je mezi klávesnicí a židlí.
Avatar
coells
Tvůrce
Avatar
Odpovídá na David Novák
coells:7.10.2015 21:33

Spíš je to ještě složitější. Pokud totiž počítáš modulo přes konstantu, která je známá během kompilace, kompilátor se za každou cenu vyhne dělení, viz příloha. To by vysvětlovalo, proč je modulo pomalé v komplikovaném kódu, kde může blokovat další optimalizace.

 
Nahoru Odpovědět
7.10.2015 21:33
Avatar
David Novák
Tvůrce
Avatar
Odpovídá na coells
David Novák:7.10.2015 21:47

Aha.. Zajímavé..

Tak ono je fakt, že dělení je jedna z nejnáročnějších operací a proto je snaha se tomu vyhýbat..

Co se týče příkladu, mohl bys mi prosím vytáhnout část, která realizuje to modulo? Je to to, jak jsou tam posuny vpravo? A 'q' za instrukcí znamená přesně co..? 4 bajty? přiznávám, že jsem prakticky vždy pracoval s NASM syntaxí, takže v této se moc nevyznám.. :D

Nahoru Odpovědět
7.10.2015 21:47
Chyba je mezi klávesnicí a židlí.
Avatar
coells
Tvůrce
Avatar
Odpovídá na David Novák
coells:7.10.2015 22:15

Je to obyčejný while cyklus pro převod do K-ární soustavy, tedy mod-div-print.
0f14 začíná mod/div
0f33 plní argumenty pro printf

q znamená quad prefix instrukce.
NASM je o dost jednodušší, ale tu jsem na linuxu nikdy neviděl :-)

 
Nahoru Odpovědět
7.10.2015 22:15
Avatar
David Novák
Tvůrce
Avatar
Odpovídá na coells
David Novák:7.10.2015 22:20

No jednak tam existuje přímo nasm.. Ale i v gas se to dá snadno nastavit :)

.intel_syntax noprefix
Nahoru Odpovědět
7.10.2015 22:20
Chyba je mezi klávesnicí a židlí.
Avatar
Ma-TA
Člen
Avatar
Odpovídá na Libor Šimo (libcosenior)
Ma-TA:9.5.2021 13:48

Přesnost musí být očividně volitelná (resp. zadaná až za běhu programu uživatelem)! 8-)

 
Nahoru Odpovědět
9.5.2021 13:48
Avatar
DarkCoder
Člen
Avatar
DarkCoder:9.5.2021 15:50
double nPrecision(double n, double prec){
        return round(pow(10, prec) * n) / pow(10, prec);
}
Editováno 9.5.2021 15:50
Nahoru Odpovědět
9.5.2021 15:50
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 18 zpráv z 18.