Stránka 1 z 1

počet jedniček v C

Napsal: 29 říj 2014 21:06
od tiempo
Zdravím, potřeboval bych poradit s programem, který nemůžu rozjet a nevím si už rady. Potřebuju program, který najde počet jedniček v binární soustavě v poli.

Zde je můj zdroják, na co sem zatím přišel.

#include <stdio.h>
int cislo[5];
int poc;
int j,i;
int main(int argc, char **argv)
{
for (j=0;j<5;j++)
cislo[j]=rand(1000);
for (i=0;i<5;i++)
{
for (cislo[i];cislo[i]>0;cislo[i] div 2)

{

if ((cislo[i] div 2 = 0) || ((cislo[i]==1) ;poc++));
}
printf("Pocet jednicek v cisle %d je: %d%d" ,cislo[i], poc);
}
return 0;

Re: počet jedniček v C

Napsal: 29 říj 2014 21:21
od Oxxid
Cecko sice neumim, ale mas tam chyby v syntaxi, stredniky za if, chybejici zavorky....

Re: počet jedniček v C

Napsal: 29 říj 2014 21:29
od Tekayi
Pisu z telefonu, ale chybi ti tam hlavne i knihovny. <stdlib.h> a <time.h>. Taky si tam pridej srand(time(NULL)) pred ten rand. Co chces delat pomoci toho rand(1000)?

Edit: Chapu dobre funkci programu.. vstup je cislo v binarni soustave, z takoveho cisla chces vypsat pocet jednicek?

Re: počet jedniček v C

Napsal: 29 říj 2014 21:34
od tiempo
Vypište počet jedniček v binární reprezentaci každého čísla v poli, například pro pole 1,8,0,255,3 bude výstup 1,1,0,8,2. ... toto je zadání co vlastně chci udělat/nebo se snažím dělat.

Re: počet jedniček v C

Napsal: 29 říj 2014 21:42
od faraon
Napadají mě dvě možnosti:

  1. Máš pět náhodných čísel, a počítáš kolik z nich má hodnotu jedna.
  2. Máš pět náhodných čísel, ty prohlížíš číslici po číslici, a počítáš kolik z nich je jednička.
To "div 2" má asi znamenat dělení dvěma, jenže to je operátor z Pascalu, v Céčku integery stačí normálně dělit lomítkem. Podle tohohle bych řekl že se pokoušíš spočítat jedničky v jejich binární podobě, a ne v desítkové, mám pravdu?

Aha, byl jsi rychlejší a vysvětlil to než jsem tohle dopsal :-)

Takže si nejdřív zkus ty jedničky spočítat v jednom čísle, a teprve potom pro jednotlivá čísla v poli. Jak na to?
Pokud ta čísla nebudeš k ničemu dalšímu potřebovat, tedy je možné je zničit, můžeš to provádět v cyklu současně s dělením dvěma (nebo bitovým posunem), dokud bude číslo nerovno nula. Pokud je v tom poli chceš zanechat, prostě si to zpracovávané okopíruj do pracovní proměnné.
A test na liché/sudé (tedy že končí 1/0) se dá udělat buď pomocí modulo (v Céčku operátor %) nebo binárním and (číslo & 1).

Re: počet jedniček v C

Napsal: 29 říj 2014 21:46
od Tekayi
Fungují v C stringy? Nebo to už je výsada C++ o.o (Už je to dlouho..)

Re: počet jedniček v C

Napsal: 29 říj 2014 23:14
od CZechBoY
K čemu stringy u čísel? Samozřejmě, že jsou v Céčku znaky …

Program by měl bejt jednoduchej.

Třeba takhle

Kód: Vybrat vše

#include <stdio.h>

int main(void) {
   
   int cislo = 255;
   int pocet = 0;
   int mocnina = 1;
   int i = 0;
   
   for (i = 0; i < sizeof(cislo) * 8; i++) {
      if (cislo & mocnina) {
         pocet++;
      }
      
      mocnina = mocnina << 1;
   }
   
   printf("pocet jednicek u cisla %d je %d\n", cislo, pocet);
   
   return 0;
}

http://ideone.com/fCRLbf

Re: počet jedniček v C

Napsal: 29 říj 2014 23:25
od tiempo
Tady v tom nějak nechápu co to dělá v tom ifu a pak v tom mocnina = mocnina << 1? Zatím sem na svoje řešení nepřišel furt se to snažím dat prvně nějak do kupy pro to jedno číslo. Ale začínám s tím, tak to spíš potřebuju nějak jednodušeji.

--- Doplnění předchozího příspěvku (29 Říj 2014 23:33) ---

A ještě proč je v tom foru sizeof *8? díky moc

Re: počet jedniček v C

Napsal: 30 říj 2014 07:51
od faraon
Proč sizeof *8? Protože sizeof(cislo) ti dá počet bytů testovaného typu, a ty ho musíš vynásobit osmi, abys získal celkový počet bitů.
Prostě základní jednotky, bit a byte, a převod mezi nimi.

Každopádně k tomu potřebuješ jednu proměnnou navíc, CZechBoY jí použil jako masku ve které posouvá jedničku, a testuje jestli se mu potkala s jedničkou ve zpracovávaném čísle.

Já bych na to šel opačně, použil bych jí jako pracovní, ve které se bude posouvat to číslo, a testoval jestli má jedničku úplně na konci. A protože to probíhá v cyklu jenom dokud v čísle nějaké jedničky jsou (tedy není nula), bude to ve většině případů rychlejší. Tedy u všech kladných čísel, příčinu najdeš v odstavci o zobáčcích.

Nejdřív ze všeho musíš vědět co se s binárním číslem děje při násobení/dělení dvěma. V desítkové soustavě se posouvá desetinná čárka při násobení/dělení deseti, a úplně stejně se posouvá ve dvojkové, akorát že pri násobení/dělení dvěma.

Kód: Vybrat vše

Násobení 2 = posun vlevo:
00001001 = 9
00010010 = 18
00100100 = 36
01001000 = 72

Kód: Vybrat vše

Dělení 2 = posun vpravo:
01001000 = 72
00100100 = 36
00010010 = 18
00001001 = 9

Pro jednoduchost je to pouze osmibitové číslo, nejnižší bit s hodnotou 1 je vpravo, tak jak jsme zvyklí psát i v desítkové soustavě.

A teď je jasné že při tom posouvání vpravo (dělení 2) se jednička na konci objeví vždy, když je číslo liché. Naopak, sudé číslo dělitelné 2 beze zbytku má na konci nulu, stejně tak jako jí má v desítkové soustavě číslo dělitelné beze zbytku 10, tyhle věci fungují vždy stejně v každé poziční soustavě s libovolným základem, u počítačů se používá ještě osmičková a šestnáctková, i v nich je to takhle.

Teď si nasimulujeme celý cyklus, když už jsem začal s číslem 72, použijeme ho zase:

Kód: Vybrat vše

01001000 = 72
00100100 = 36
00010010 = 18
00001001 = 9
00000100 = 4
00000010 = 2
00000001 = 1
00000000 = 0

A tady cyklus končí, protože dál není co zkoumat.

Když si teď prohlédneš ten poslední sloupec, tak v něm máš zhora dolů číslo 00010010. To je těch původních 72, akorát že pozpátku, a v něm chceš spočítat ty jedničky, pomocí bitového AND:

Kód: Vybrat vše

01001000 & 1 = 0
00100100 & 1 = 0
00010010 & 1 = 0
00001001 & 1 = 1
00000100 & 1 = 0
00000010 & 1 = 0
00000001 & 1 = 1
00000000 & 1 = 0

Tobě teď už stačí jenom spočítat kolikrát byla podmínka pravdivá, a po skončení tohohle cyklu vypsat to co v počítadle máš. Akorát ho nezapomeň už před cyklem vynulovat, jinak bys sečetl všechny jedničky ve všech číslech která by jím prošla!

Teď jsou důležité ty zobáčky na které ses ptal. Operátor << je bitový posun vlevo, neboli násobení 2. Operátor >> je bitový posun vpravo, neboli dělení 2. A tady můžeš tvrdě narazit, protože v zadání není určeno jestli jsou všechna vždy čísla kladná nebo mohou být záporná. On totiž ten posun probíhá jinak u znaménkových a jinak u bezznaménkových proměnných, pokud bys to skusil s proměnnou signed int, tak by tě záporné číslo dostalo do nekonečného cyklu! Proto musíš pracovat s unsigned int, kde se posouvá i nejvyšší bit, zvaný znaménkový, který jinak ukazuje jestli je číslo kladné/záporné.

A tohle je kód pro jednotlivé číslo, dokážeš ho použít v cyklu pro celé pole?

Kód: Vybrat vše

#include <stdio.h>

int main(void)
    {
    int cislo, jednicek;
    unsigned int temp;

    cislo = 72;

    for (jednicek = 0, temp = cislo; temp != 0; temp = temp >> 1)
        if (temp & 1)
           ++jednicek;

    printf("%d\t%d\n", cislo, jednicek);

    return 0;
    }


Ale máš-li jistotu že budeš pracovat pouze s kladnými čísly, můžeš použít místo těch zobáčků obyčejné aritmetické dělení 2, program se tím zjednoduší, jenom kdybys třeba jednou programoval nějakou šíleně náročnou hru se super grafikou, tak je dobré vědět že i když takhle procesor provádí na první pohled úplně stejnou věc, dělá to jinak, a trvá mu to trochu déle. Ale program se tím trochu zjednoduší, takže si nemusíš dělat starosti se signed a unsigned:

Kód: Vybrat vše

#include <stdio.h>

int main(void)
    {
    int cislo, jednicek, temp;

    cislo = 72;

    for (jednicek = 0, temp = cislo; temp != 0; temp = temp / 2)
        if (temp & 1)
           ++jednicek;

    printf("%d\t%d\n", cislo, jednicek);

    return 0;
    }


Má to ovšem jeden háček, když mu teď omylem zadáš záporné číslo, tak spočítá jedničky poze v jeho kladné podobě, tu nejvyšší která dělá znaménko ignoruje! Je to jako bys pracoval s jeho absolutní hodnotou. V některých případech to nemusí být na závadu, ale častěji by to mohlo způsobit velmi vážný problém...

Ještě na závěr, samozřejmě bys místo testování pomocí & mohl použít zbytek po dělení (modulo), v Céčku se značí operátorem % a vypadalo by to takhle:

Kód: Vybrat vše

    for (jednicek = 0, temp = cislo; temp != 0; temp = temp / 2)
        if (temp % 2)
           ++jednicek;

Jediná změna je v podmínce toho if(), zbytek programu zůstává stejný. Ale zase je dobré vědět že dělení je velmi pomalá aritmetická operace prováděná matematickým koprocesorem, zatímco bitové porovnání se provádí přímo v ALU procesoru několikanásobně rychleji. Takže modulo má smysl když potřebuješ zbytek po dělení jakýmkoliv jiným číslem než jsou mocniny dvojky, ale zrovna v tomhle speciálním případě je mnohem výhodnější právě to bitové and.

Re: počet jedniček v C

Napsal: 30 říj 2014 22:47
od tiempo
Strašně moc díky za pomoc. Pole se mi podařilo přidat. Moc díky za vysvětlení.