Diskuze: Zaokrouhlování v jazyku C
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
Zobrazeno 18 zpráv z 18.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
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
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é
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.
Jen bych podotkl, že dělení je naprosto stejně pomalé jako modulo (obě se provádí zároveň při každé instrukci DIV)
Úloha je veľmi jednoduchá:
#include <stdio.h>
int main(void)
{
float f = 8.2483;
printf("%.2f\n", f);
return 0;
}
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;
}
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.
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íš?
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.
Hádám kolega z UPOL? (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é
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.
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.
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..
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
No jednak tam existuje přímo nasm.. Ale i v gas se to dá snadno nastavit
.intel_syntax noprefix
Přesnost musí být očividně volitelná (resp. zadaná až za běhu programu uživatelem)!
Zobrazeno 18 zpráv z 18.