Programátorský víceboj 1. díl - Máme rádi matematiku

Místo pro dotazy a rady ohledně programovacích jazyků (C++, C#, PHP, ASP, Javascript, VBS..) a tvorby webových stránek

Moderátor: Mods_senior

cpp
nováček
Příspěvky: 41
Registrován: červen 17
Pohlaví: Muž

Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod cpp » 20 čer 2017 11:22

Ahoj kolegové,

minulý díl pro mě byl velkým zklamáním. Navzdory bouřlivé diskuzi nepředstavil nikdo kromě faraona své řešení.

Za neúspěch můžu nadávat jen sám sobě. Nemálo lidí odradily striktně specifikované zadání. Proto bude dnešní díl pojatý trošku jinak. Nebudete tvořit celý program, ale pouze doplňovat kód funkcí.

Dobrý programátor musí umět používat knihovny. Občas ale není na škodu si cvičně něco zkusit sám.

Zadání

Kód: Vybrat vše

// Kod v jazyce C
float my_pow(float x, const int n, int *err);
float my_sqrt(float x, int *err);


Funkce my_pow počítá n-tou mocninu (zadanou parametrem n, n je celé číslo) reálného čísla zadaného parametrem x. Funkce vrací reálné číslo.
Funkce my_sqrt počítá druhou odmocninu z reálného čísla zadaného parametrem x. Funkce vrací reálné číslo.

I tentokrát je nachystaný bonusový úkol:

Kód: Vybrat vše

 // Kod v jazyce C
float my_nth_root(float x, static int n, int *err)


Funkce my_nth_root počítá n-tou odocninu (zadanou parametrem n, n je celé číslo) reálného čísla zadaného parametrem x. Funkce vrací reálné číslo.

U všech funkcí je jako parametr ukazatel *err, který slouží pro vyjádření úspěchu či neúspěchu operace z důvodu chybných vstupních hodnot (0 úspěch, 1 neúspěch).

Předpokládejte, že existuje globální konstantní proměnná const flooat e, která je inicializovaná na určitou hodnotu určující maximální přípustnou chybu výpočtu (například 1e-12). Tam, kde je to vhodné ji použijte.
Zamyslete se a napište do komentářů, jaké výhody a nevýhody přináší použití globální konstantní proměnné místo #define.

Řešení
Dopuručený je opět jazyk C. Pokud vám nevyhovuje, v klidu použíjte jiný jazyk. Je zakázáno použití funkcí matematických knihoven.

V případě použití jiného jazyka si smíte zadání v nutné míře upravit. Vaše úpravy však musíte řádně popsat.
Nejčastěji se to bude týkat jazyků, které neumožňují práci s ukazateli/referencemi. V takovém případě navrhněte jiný vhodný způsob řešení.

Kód posílejte do komentářů nebo přes pastebin, github, whatever...

Vzorové řešení bude později uveřejněno. Nedočkavci si mohou říci o zaslání kódu do soukromých zpráv.

Mnoho zdaru při řešení!
Naposledy upravil(a) cpp dne 20 čer 2017 19:03, celkem upraveno 1 x.



Reklama
Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 5966
Registrován: prosinec 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod faraon » 20 čer 2017 17:56

cpp píše:maximální přípustnou chybu výpočtu (například 0.1e12)

Eh, tohle jsem si musel nacvakat do kalkulačky, abych uvěřil tomu co vidím. Jako že maximální přípustná chyba může být 100000000000? A jak se tohle popasuje s floatem, který má po převodu do desítkové soustavy sedm platných číslic?

Teda měl jsem vždycky za to, že exponenciální zápis slouží k odstranění přebytečných nul před i za číslem, takže správný tvar může začínat pouze číslicemi 1..9. Ale člověk se holt učí celý život, asi podle těchhle novot radši sluníčkářsky hyperkoretně vyhodím svojí sbírku zastaralých a xenofobních logaritmických pravítek, která spolehlivě sloužila čtyři století, žádné z nich totiž nulu na stupnici nemá a vůbec jí nepotřebuje :lol:

Mimochodem, posílání návratových hodnot přes parametry nepatří ke známkám dobrého programátorského stylu, ale spíš ke známkám špatného návrhu ;-)

Pro inspiraci a představu jak vlastně (od)mocniny fungují, nainstaluj si emulátor ZX Spectrum, což je nejlevnější mikropočítač z roku 1982, a vyzkoušej v něm takovýhle program:

Kód: Vybrat vše

10 INPUT n
20 PRINT n^(5/7)

Schválně jestli přijdeš na to co vypočítá...
Nejhroznější sen linuxáka: nabootuje počítač, a tam Windows.
Nejhroznější sen windowsáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen linuxáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen windowsáka: nabootuje počítač.

cpp
nováček
Příspěvky: 41
Registrován: červen 17
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod cpp » 20 čer 2017 19:35

Díky za upozornění, opraveno.

Co je na posílání návratových hodnot přes parametr špatného? Máš lepší řešení?

Netuším, co ZX vypíše, ale hádal bych, že ^ bude znamenat buď jako XOR (jako v C) a nebo jako označení pointeru. Ale možná taky ne.

Uživatelský avatar
ITCrowd
Tvůrce článků
Elite Level 11
Elite Level 11
Příspěvky: 13235
Registrován: březen 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod ITCrowd » 20 čer 2017 21:19

S mocninou by moc práce být nemělo:

Kód: Vybrat vše

Function MOCNINA (x, n)
If n = 0 Then
   MOCNINA = 1
   End Function
End If
If n = 1 Then
   MOCNINA = x
   End Function
End If
MOCNINA = x
For i = 2 To n Step 1
MOCNINA = MOCNINA * x
Next
End Function

Co se týče odmocniny (x=sqrt(y)), tam mě napadla iterace xi+1 = (xi+y/xi)/2. Zde je zajímavostí spíše určení prvního odhadu. Samozřejmě lze počítat od jedničky, ale tím naskočí počet cyklů. Nad tím ještě zkusím zapřemýšlet, když se mi bude chtít. Požadovaná chyba "e" by zde byla kontrolována abs(xi+1 - xi) < e.
Kromě toho si matně vzpomínám, že kdysi na základní škole nás učili vypočítat odmocninu pomocí dělení se zbytkem, ale to budu muset prohledat sešity, zda to najdu :-)
Zkusili jste to vypnout a zapnout? Problémy řeším pouze v tématech. Do SZ mi proto píšete zbytečně.
Základní diagnostika WiFi Jak na diagnostiku sítě Router jako switch Proč je nesmysl chtít router s velkým dosahem

Uživatelský avatar
Tomasb98
Level 4
Level 4
Příspěvky: 1011
Registrován: červen 13
Bydliště: Hradec Králové
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod Tomasb98 » 20 čer 2017 21:33

Ahoj, po delší době mám konečně trochu času se zase věnovat programování v mém oblíbeném jazyce C# a ověřil jsem si, že když něco delší dobu nepoužívám tak toho docela dost zapomenu. Nakonec jsme si na pár věci přeci jen vzpomněl :lol: a zkusil jsme si toto poměrně lehké zadání zpracovat v poměrně lehkém jazyce. (oproti C nebo když si vzpomenu na programování mikrokontrolérů v Assembleru, tak jsem rád, že jsem se vrátil k objektovému C#...)

Zadání jsme si trochu poupravil:
    - Místo klasické proměnné float jsem použil decimal. (výsledky nebyly s použitím datového typu float moc přesné, možná je chyba v mém řešení...).
    - Nepoužívám žádné int *err, ošetření správných vstupu od uživatele mám klasicky (alespoň v C#) přes bloky try catch. V metodě pro druhou odmocninu samozřejmě nehledám výsledek pro záporný základ apod.
    - Vstupy od uživatele beru z argumentů při spuštění programu. (inspirovalo mě tvé minulé zadání...)

Zdrojový kód (odkaz vede na OneDrive)
(Určitě by to šlo napsat lépe... uvítám jakékoliv připomínky.)

V metodě pro mocninu problém nebyl. Sranda začala až implementací metody pro odmocninu. Nakonec pomohla stará dobrá Wiki...

Na bonusový úkol jsem se nedostal, ale mám tu jiný bonus: :lol: Při poslední instalaci Visual Studia jsem si stáhl i .Net Core a rovnou jsem to otestoval na Linuxu viz obrázek níže.
Nemáte oprávnění prohlížet přiložené soubory.

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 5966
Registrován: prosinec 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod faraon » 20 čer 2017 21:54

Znak ^ (v ASCII61 a ZX BASICu šipka nahoru) znamenal ve starých jazycích mocninu. Výjimečně se i v některých dialektech BASICu vyskytoval ještě starší fortranský symbol **.

Parametry jsou vstupní hodnoty, návratová hodnota je výstupní. Už to že funkce vrací víc hodnot než jednu je problém. Tady se hodí spíš globální proměnná v rámci jednoho modulu, která zároveň plní funkci flagu. Viz základní knihovna a C-bible.

ITCrowd: Ten iterační způsob je nejjednodušší a také nejpomalejší. Ale zvládne ho i školáček, byly doby kdy se takové věci na školách učily. Ne na těch obecných samozřejmě, tam došli tak maximálně k násobení na prstech, víc ani sedlák nepotřeboval. Čtverce se zbytkem jsou mnohem rychlejší, s nimi výsledek přibývá po dvou číslicích místo po jedné :)

Tomasb98: Chyba je v typu float, je prostě málo přesný. Běžně je dvaatřicetibitový, pro mantisu má obvykle 3 bajty = 24 bity, což dává rozsah +-8388608 krát exponent, který sežere čtvrtý bajt. Proto se používá jen tam kde na přesnosti nezáleží, všechno ostatní se počítá v double.
Nejhroznější sen linuxáka: nabootuje počítač, a tam Windows.
Nejhroznější sen windowsáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen linuxáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen windowsáka: nabootuje počítač.

cpp
nováček
Příspěvky: 41
Registrován: červen 17
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod cpp » 20 čer 2017 22:09

@ITCrowd

Ano, na odmocninu bys šel správně. Hodně dobrá úvaha je i o počátečním odhadu! Univerzálně výhodný počáteční odhad nemá smysl hledat, bude záležet, co budeš počítat. LUT pro počáteční aproximaci určitě nemá smysl. Než bys ji prohledal, tak bys měl výpočet hotový i tak.
Pro zajímavost doporučuji udělat si statistiku iterací pro různá čísla.

Ke kódu jenom pár poznámek:
  • mohl sis ušetřit podmínku, kde porovnáváš n s 1, tento případ pokryje podmínka ve for cyklu (cyklus vůbec neproběhne)
  • měl bys řešit případ 0^0(nula na nultou)

Ty máš schované sešity, ze ZŠ? :D :D

@Tomasb98

Tak jsme se na linuxu přece jen dočkali .NETu. :lol: Použití try-catch je také dobrý nápad. Dobré je, že znáš omezení typu float (i když pro většinu věcí je přesnost dostačující).

K samotnému kódu jenom pár drobných poznáme, protože je jinak pěkný:
  • totéž, co ITCrowd, měl bys řešit případ 0^0(nula na nultou)
  • proměnná značící přípustnou chybu by měla být konstatní a možná by bylo vhodné ji mít mimo funkci (na způsob #define)
  • proč má funkce Abs jako parametr a návratový typ decimal, když číslo n může být pouze celé číslo?

Jinak je dobře, že výpočet absolutní hodnoty jsi dal do zvláštní funkce.

@faraon

Nebudu se hádat, co je rychlejší, nad tím musím ještě popřemýšlet, ale některé algoritmy výpočtu (nejen) odmocniny jsou tak jednoduché, že jsou implementovány přímo v instrukčních sadách procesorů a mikrokontrolerů.

Nevím, kde jsi sebral definici, že parametry jsou vždy nutně jenom vstupní. Velké struktury také předáváš odkazem a ani nemrkneš.
Reference na proměnnou značící chybu se zcela běžně používají.

Použití globální proměnné je sice také možnost, ale do značné míry tím narušuješ možnost skrytí implementace funkce, což je problém hlavně u velkých projektů. V případě, že skládáš hodně modulů dohromady a jiný programátor si nazve v jiném modulu proměnnou stejně, máš dost závažný problém. A nemusí to být ani velký projekt, můžeš si zavařit i při používání nějaké knihovny. Proto jsou globální proměnné většinou fuj.
V C bohužel nejsou namespace.

A to ani nemluvím o možných komplikacích, pokud by ty funkce měly běžet paralelně.

Uživatelský avatar
ITCrowd
Tvůrce článků
Elite Level 11
Elite Level 11
Příspěvky: 13235
Registrován: březen 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod ITCrowd » 20 čer 2017 22:42

Zde výpis: https://cs.wikipedia.org/wiki/Umoc%C5%8 ... _na_nultou
00 = 1. Vyřešeno podmínkou testující n=0. Vycházím z vzorce pro derivaci mocniny.
cpp: - Mám schovány veškeré sešity z matematiky pátou třídou počínaje a 3. semestrem konče.
- podmínku si ušetřit nemůžu. Ještě pamatuju kompilátory, které by tento kód klidně zkously a cyklus for-next by se rozjel, až by nahlásil chybu.
Naposledy upravil(a) ITCrowd dne 20 čer 2017 22:55, celkem upraveno 1 x.
Zkusili jste to vypnout a zapnout? Problémy řeším pouze v tématech. Do SZ mi proto píšete zbytečně.
Základní diagnostika WiFi Jak na diagnostiku sítě Router jako switch Proč je nesmysl chtít router s velkým dosahem

cpp
nováček
Příspěvky: 41
Registrován: červen 17
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod cpp » 20 čer 2017 22:52

A já ti zase SŠ matikou dokážu, že 0^0 může být 2. Nebo 7... Nebo 666... Dobře, tvoje řešení lze také přijmout, záleží k jakému účelu se výpočet mocniny používá. Na druhou stranu lecco mohla napovědět přítomnost argumentu *err indikující případný chybový stav.

Výtka ke zbytečnosti této části zůstává:

Kód: Vybrat vše

If n = 1 Then
   MOCNINA = x
   End Function

Uživatelský avatar
ITCrowd
Tvůrce článků
Elite Level 11
Elite Level 11
Příspěvky: 13235
Registrován: březen 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod ITCrowd » 20 čer 2017 22:56

ITCrowd píše: - podmínku si ušetřit nemůžu. Ještě pamatuju kompilátory, které by tento kód klidně zkously a cyklus for-next by se rozjel, až by nahlásil chybu.

Ty těžko něco dokážeš.
00 se nejčastěji bere jako = 1, a pokud ne, pak =0. Jak lze výsledek odvodit najdeš v odkaze. Pro hnidopichy lze tuto hodnotu ponechat jako nedefinovanou, což neznamená ani 2, ani 666.
Zkusili jste to vypnout a zapnout? Problémy řeším pouze v tématech. Do SZ mi proto píšete zbytečně.
Základní diagnostika WiFi Jak na diagnostiku sítě Router jako switch Proč je nesmysl chtít router s velkým dosahem

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 5966
Registrován: prosinec 10
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod faraon » 20 čer 2017 23:50

cpp píše:
  1. některé algoritmy výpočtu (nejen) odmocniny jsou tak jednoduché, že jsou implementovány přímo v instrukčních sadách procesorů a mikrokontrolerů.
  2. Velké struktury také předáváš odkazem a ani nemrkneš.
  3. Reference na proměnnou značící chybu se zcela běžně používají.
  4. V případě, že skládáš hodně modulů dohromady a jiný programátor si nazve v jiném modulu proměnnou stejně...

  1. A instrukční sada je implementována v hradlech skládajících se z diod a tranzistorů. Zkus si něco takového sám navrhnout, je to dobrá zkušenost a pochopíš potom i to moje parsování parametrů z minula.
  2. Struktury předáváš ke zpracování, stejně jako swap(&a,&b), ale ta funkce přitom může vracet chybový stav. Jde o jiný případ, nebo tu chybovou proměnnou chceš také zpracovat?
  3. Ano, spousta prasáren se dělá zcela běžně. Udělej to v Lispu.
  4. Ty includuješ moduly do sebe? Nezkusil jsi oddělený překlad?
  5. 00 - nakresli si graf.
  6. Ale prd. Jakékoliv N/0=∞.
Naposledy upravil(a) faraon dne 21 čer 2017 00:04, celkem upraveno 2 x.
Nejhroznější sen linuxáka: nabootuje počítač, a tam Windows.
Nejhroznější sen windowsáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen linuxáka: nabootuje počítač, a tam Linux.
Nejkrásnější sen windowsáka: nabootuje počítač.

cpp
nováček
Příspěvky: 41
Registrován: červen 17
Pohlaví: Muž

Re: Programátorský víceboj 1. díl - Máme rádi matematiku

Příspěvekod cpp » 20 čer 2017 23:57

@ITCrowd

  • V jakém programovacím jazyce vlastně píšeš? Odhadnul jsem to na BASIC nebo Visual BASIC, ovšem v této podobě nepřeložitelný (chybí deklarace proměnných). Nebo je to nějaký dialekt od BASIC?
  • Kompilátor pro BASIC ani Visual BASIC, co jsem zkoušel popisované problémy nemá a není logický důvod, aby ostatní kompilátory problém měly (můžeš mě vyvést z omylu a dát sem konkrétní příklad). Podmínku sis klidně ušetřit mohl.
  • Proč bych nemohl dokázat, že se 0^0 rovná libovolnému číslu? (Pro hnidopichy je to matematická hříčka, stejně jako 0/0 = 2.)

@faraon

1. Znám CORDIC. A to parsování parametrů s tím má jakou souvislost?
2. Argument zcela mimo. Tu chybovou proměnnou vlastně zpracováváš. Buď zapíšeš 0, nebo 1 (či jiné číslo). To, že nečteš přece vůbec nevadí. Spoustu knihovních funkcí má čistě výstupní parametry, tedy takové, ze kterých se nečte, jen se do nich zapisuje. S čím máš problém?
3. LISP je deklarativní jazyk, čili něco úplně jiného. Chceš porovnávat neporovnatelné?
4. Oddělený překlad neřeší ani jeden z trojice zmíněných problémů. Douč se, jak funguje linker.
5. Je několik přístupů k tomu, jak rozhodnout, kolik je 0^0. Limita je jedním z nich. Použije se ten, který je pro daný případ nejvýhodnější.
6. S takovým výrokom opatrně, pro jakékoli N to neplatí. A potom ta známá hříčka: https://qph.ec.quoracdn.net/main-qimg-c ... 83800.webp Zdůrazňuji, matematická hříčka.
Naposledy upravil(a) cpp dne 21 čer 2017 01:06, celkem upraveno 1 x.


  • Mohlo by vás zajímat
    Odpovědi
    Zobrazení
    Poslední příspěvek
  • Programátorský víceboj 0. díl - Šifrujeme
    od cpp » 05 čer 2017 14:03 » v Programování a tvorba webu
    57
    2062
    od atari
    31 srp 2017 10:14
  • Programátorský víceboj 2. díl - Morseovka
    od cpp » 07 črc 2017 09:03 » v Programování a tvorba webu
    3
    307
    od ITCrowd
    07 črc 2017 20:13
  • World of warcraft uvidíme se s kamošem když mame rozdíl datadisku?
    od DomekCZE » 25 říj 2016 17:33 » v Hry
    2
    201
    od DomekCZE
    25 říj 2016 17:38
  • Reklamace a použitý díl
    od rychtara » 16 lis 2016 09:41 » v Reklamace a zákony
    2
    383
    od petr22
    16 lis 2016 09:48

Zpět na “Programování a tvorba webu”

Kdo je online

Uživatelé prohlížející si toto fórum: CommonCrawl [Bot] a 0 hostů