Nauka C++, pętla for, liczby nieparzyste


(Korn Ik5) #1

Witam

Od nie dawna zacząłem z własnej nieprzymuszonej woli naukę C++. W kursie "Od zero do hackera" w temacie o pętlach for było zadanie żeby

To akurat jest proste, ale chciałem dać trochę więcej "bajeru" programowi i wymyśliłem żeby nie ograniczać się tylko od 0 do 10 ale żeby w czasie programu ustalić zakres zbioru. Problem polega na tym, że jeżeli początek zbioru zdefiniujemy liczbą nieparzystą to program dalej pokazuje tylko właśnie liczby nieparzyste. Wyjaśnieniem jest instrukcja wykonywana po każdym uruchomieniu pętli tzw n=n+2. Z logicznego punku widzenia jest to raczej prawidłowe, ponieważ faktycznie co druga liczba jest parzysta. Moje brzmi następująco: co mam wstawić żeby program prawidłowo pokazywał liczby parzyste bez względu na początek zbioru. Jestem niemal 100% pewny że rozwiązanie tkwi w użyciu instrukcji if ,ale w żaden sposób nie umiem wymyśleć jak mam ją opisać. Normalnie w życiu, w algebrze, liczbę można sprawdzić czy jest parzysta czy nie dzieląc ją przez 2, jeżeli wynik będzie całkowity no to liczba jest parzysta, jeżeli ułamek no to nie.

Oto kod

#include 

#include 


main()

{

      int n, x, a; //deklaracja zmienncyh

      cout<<"Witam!\n";

      cout<<"Ten program ma za zadanie ukazac wszytskie liczby parzyste\n";

      cout<<"w zdefiniowanym przez Ciebie zbiorze\n";

      cout<<"Podaj od jakiej liczby ma zaczynac sie zbior: ";

      cin>>a; //definiowanie liczby rozpoczynajacej zbior

      cout<<"\nA teraz na jakiej ma sie zakonczyc: ";

      cin>>x; //definiowanie liczby konczacej zbior

      cout<<"W zbiorze od "<
      for (n=a; n<=x; n=n+2)/*przypisanie n zdefiowanej zmiennej a (pocztake zbioru)

      ;ostatnia liczba TRUE(koniec zbioru); zmienna n jest

      zwiekszana za kazdym razem o 2*/

      {

          cout<
          cout<
      }

      getch();

}

[/code]

Z góry wielkie dziękuje za pomoc!!

POZDRO :twisted:


(Grzegorz Ch) #2

W praktyce do sprawdzenia, czy liczba jest parzysta czy nieparzysta, używa się koniunkcji logicznej.

przykładowy kod sprawdzający czy liczba jest parzysta.

#include 

void main()

{

int liczba;

cin >> liczba;

if (liczba & 1)

cout << "Liczba jest nieparzysta/n";

else

cout << "Liczba jest parzysta/n";

}

(Korn Ik5) #3

WOW!! :o Nie spodziewałem się tak szybkiej odpowiedzi, wielki dzięki, zaraz sprawdzę co z tym mogę zrobić :slight_smile:

EDIT:

Samo sprawdzanie liczby czy jest parzysta czy nie działa jak należy :smiley: .Teraz jedynie muszę wykombinować co z tą liczbą nieparzystą zrobić, ale z tym powinienem sobie sam poradzić.

Wielkie Dziękuje za pomoc :smiley:


(Fiołek) #4

Można też przy wyświetlaniu liczby sprawdzać czy jest modulo 2 równe 0. Np. tak:

for(int i = a; i <= x; i +=2)

{

   if( (i % 2) != 0)

      i++;

   cout << i << endl;

}

Albo tak:

for(int i = a; i <= x; i++)

{

   if( (i % 2) == 0)

      cout << i << endl;

}

(Grzegorz Ch) #5

kornik13 sprawdzasz parzystość liczby, jeśli jest nieparzysta, to dodajesz lub odejmujesz, w zależności od potrzeb, liczbę 1 i masz parzystą.


(Korn Ik5) #6

Witam

Fiołek Twój kod pewnie również działa, jednak jestem zwolennikiem prostoty ponad wszystko, ale bardzo dziękuje za odpowiedź :smiley:

grzegorzch Dokładnie to samo wymyśliłem :smiley: , oto gotowy kod

#include 

#include 


main()

{

      int n, x, a; //deklaracja zmienncyh

      cout<<"Witam!\n";

      cout<<"Ten program ma za zadanie ukazac wszytskie liczby parzyste\n";

      cout<<"w zdefiniowanym przez Ciebie zbiorze\n";

      cout<<"Podaj od jakiej liczby ma zaczynac sie zbior: ";

      cin>>a; //definiowanie liczby rozpoczynajacej zbior

      cout<<"\nA teraz na jakiej ma sie zakonczyc: ";

      cin>>x; //definiowanie liczby konczacej zbior

      cout<<"W zbiorze od "<
      if (a & 1) a++; //jezeli liczba jest nieparzysta to zwieksz a o 1 i wykonaj for

            for (n=a; n<=x; n=n+2)/*przypisanie n zdefiowanej zmiennej a (pocztake zbioru)

                                  ;ostatnia liczba TRUE(koniec zbioru); zmienna n jest

                                  zwiekszana o 2*/

               {

                cout<
               }

      getch();

}[/code]

Tak patrząc na kod to w sumie program nie powinien działać, jeżeli jako początek zbioru zdefiniuje liczbą parzystą. Jak widać jest tylko określone co ma robić jeżeli zdefiniuje liczbą nieparzystą. Podejrzewam, że jeżeli wpisze liczbę parzystą to uznaje to za błąd i olewa sobie if, i jedzie dalej :slight_smile:

Jeszcze raz wielkie dzięki za pomoc


(Fiołek) #7

Ale mój kod jest prosty nad wszystko :wink: Tam jest różnica taka, że liczba jest sprawdzana za każdym obiegiem pętli i nie ma prawa być wyświetlona liczba nieparzysta, zresztą w tym co podał grzegorzch też nie ma takiej możliwości.

PS. Pomyliła mi się jedna literka, już poprawiam.


(Grzegorz Ch) #8

ta linia sprawdza czy liczba jest nieparzysta, jeśli tak to zwiększa a o 1 i tyle. pętla for() wykonywana jest zawsze bez względu na wynik sprawdzania powyższego warunku.


(Korn Ik5) #9

Fiołek Dopiero zacząłem naukę w C++, więc ważne dla mnie są rozwiązania proste w zapisie. W pełni rozumiem Twój kod i w 100% robi to co robić powinien, ale w moim prostym programie nie ma potrzeby, żeby sprawdzać za każdym razem czy liczba jest nieparzysta. Rozwiązanie grzegorzch jest dla mnie bardziej odpowiednie, bo szybciej zrozumiałem zasadę jego działania. Ale bardzo dziękuje za sugestie :smiley: Na pewno kiedyś, w jakimś programie wykorzystam Twoje rozwiązanie :smiley:

EDIT

grzegorzch No mniej więcej to miałem na myśli :slight_smile:

POZDRO :twisted:


(Vion91) #10

Nie bardzo to rozumiem.

To znaczy że gdyby kod wyglądał tak:

if (a & 2)

To by sprawdzała czy liczba jest parzysta ? :stuck_out_tongue:


(Wojtano) #11

Vion podam Ci przykład.

Załóżmy, że a=5;

Wiadomo, że 5%2=1

Wiemy, że 0=false, reszta to true.

My otrzymaliśmy wynik 1, więc jest true i warunek jest spełniony.

Dlatego, jeżeli "true" to zwiększ liczbę "a" o jeden.

Jeżeli byśmy podstawili a=6 (6%2=0), program nie zwiększyłby liczby "a", gdyż warunek nie byłby spełniony.

Tym sposobem można rozpoznać czy liczba jest parzysta, czy nie.


(Vion91) #12

Wiem że znak % daje jako wynik resztę z dzielenia, ale tam jest znak & a na razie doczytałem że to jest iloczyn bitowy. Ale to może to ma te same/podobne znaczenie ? :roll: Jeszcze tego nie wiem bo wciąż się uczę.


(Wojtano) #13

Można powiedzieć, że mają podobne znaczenie.

Polega to na tym, że program pobiera pierwszy bit z jednej zmiennej i pierwszy bit z drugiej i wykonuje koniunkcję pomiędzy nimi. W wyniku otrzymujemy 0 albo 1. Wynik ten wstawia do pierwszego bitu zmiennej końcowej i robi to po kolei z każdymi następnymi bitami. Może być to dla Ciebie nie zrozumiałe, dlatego wolałem pokazać Ci przykład na prostym modulo :wink:


(Ryan) #14

Nie. Żeby to zrozumieć musisz rozumieć jak zapisywana jest liczba.

Liczba zapisywana jest binarnie, czyli każda kolejna jedynka (lub zero) to potęga dwójki. Potęgi dwójki: 1, 2, 4, 8, 16, 32, 64, 128,... Bity na PC zapisywane są od prawej, więc:

1:

00000001 = 1*1

5:

00000101 = 1*4 + 0*2 + 1*1

6:

00000110 = 1*4 + 1*2 + 0*1

a & b daje w wyniku wartość, która stanowi iloczyn bitów na wszystkich pozycjach. Mówiąc inaczej wartość na pozycji 1 z obu liczb jest poddawana operacji, później osobno na pozycji 2, 4, 8, 16 itd.

A B A&B

0 0 0

0 1 0

1 0 0

1 1 1

And znaczy "i", "oraz" - muszą być spełnione oba warunki, np. wypiore gacie i zjem kromkę ze smalcem. Wykonasz obie czynności, by zdanie było prawdziwe. Zatem and dla dwóch liczb:

A = 10010110 = 128 + 16 + 4 + 2 = 150

B = 01110101 = 64 + 32 + 16 + 4 + 1 = 117

A & B:

10010110

01110101

-----------

00010100 = 16 + 4 = 20

Operacje o które pytałes to a & 1 i a & 2. W pierwszym przypadku będziesz miał ciąg zer i jedynkę lub zero (a więc 1 lub 0) w drugim ciąg zer i ciąg 10 albo 00 (czyli 0 lub 2). Jak widzisz nie definiuje to liczby parzystej. Aha, dlaczego to działa? Bo boolean przyjmujący wartości true/false to tak naprawdę "jakiś integer" (w uproszczeniu) dla którego false to zero a true to każda wartość, która zerem nie jest (a więc 1, 2, 3, 4, 5...). a & 1 zwróci Ci 1 jeśli liczba była nieparzysta (np. 1 "001", 3 "011", 5 "101", 7 "111", itd.). Przeciwną do liczby nieparzystej jest liczba parzysta, więc warunek to:

if (a & 1 == 0)

Bo a & 1 to tak naprawdę:

if (a & 1 != 0)

Dlaczego różne od zera? Bo warunek if spełniony jest gdy coś jest prawdą (true) a true to jak wcześniej napisałem liczba inna niż 0.


(Vion91) #15

A więc tak:

if(a&1)

Jeżeli a = 5 to :

A = 00000101

1 = 00000001

----------------

A&1 = 00000001 // liczba jest nie parzysta ponieważ zwróciło false.

A jeżeli a = 6 to :

A = 00000110

1 = 00000001

----------------

A&1 = 00000000 // liczba jest parzysta ponieważ zwróciło true.

Więc da się ustalić czy liczba jest parzysta czy nie. A gdyby było tak :

if(a&2)

To dla liczb parzystych raz by dawało true a raz false np. dla a = 4 dawałoby false a dla 6 true. Więc nie da się określić czy liczba jest parzysta czy nie.

Dobrze to zrozumiałem ? :stuck_out_tongue:


(Ryan) #16

Błąd - 00000001 to TRUE (nie zero) 00000000 to FALSE (zero). Zero (true) oznacza liczbę parzystą, ponieważ liczba stanowi wyłącznie sumę liczb parzystych (wśród potęg dwójki tylko 1 jest nieparzyste i to jedynkę badasz).

Przy pomocy a&2 nie określisz niczego istotnego. Chyba, że liczbę traktujesz jako zbiór flag, ale powiedzmy, że ten temat pominę. Generalnie jednak tak, dla 4 i 6 miałbyś różne wyniki (bo 6 to 4 + 2 a Ty wykrywasz, czy w sumie jest dwójka).

Aha taka bezużyteczna trivia. Od tej reguły true/false jest niestety odstępstwo. Typów zdolnych pomieścić wartości prawda/fałsz jest przynajmniej kilka (bool, BOOL, BOOLEAN, HRESULT) i jeden z tych typów (HRESULT) ma zdefiniowany fałsz (w tym wypadku S_FALSE) jako 1.


(Vion91) #17

O sorry pomyłka, z tym ze gdy 00000001 to zwróci False. Bo najpierw miałem napisać dla liczby parzystej, a później zapomniałem już zmienić. :oops:


(Kazuio) #18

Przykładowy kod - u mnie działa bez problemu.

#include

main()

{

int a,b,c;

cout << "Podaj dolny zakres: ";

cin >> a;

cout << "Podja górny zakres: ";

cin >> b;

for (c=a;c<=b;c++)

{

if (c%2==0)

{

cout << c << " ";

}}}

(Vion91) #19

1 = 00000001

a jak będzie np. 1.5 ? :stuck_out_tongue:


(somekind) #20

Zależy.

Czy chcesz reprezentować stało, czy zmiennoprzecinkowo, i w jakim kodzie (np. U1, U2, ZM)

Np. w ośmiobitowym zapisie U2 poszczególne cyfry w liczbie mają wagi:

2^3, 2^2, 2^1, 2^0, 2^-1, 2^-2, 2^-3, 2^-4

Daje to taki efekt, jakby po czwartym bicie był przecinek oddzielający część całkowitą od ułamkowej.

Zatem 1,5 będzie wyglądało tak:

00011000