niedziela, 26 stycznia 2014

C++: Mały błąd, duży problem

Strasznie dawno mnie tu nie było ...

Dziś do szybkiego przemyślenia coś, co potrafi wprawić w osłupienie gdy niewinne parę linijek kodu blokuje działanie dużego modułu, który nie ma nic wspólnego z matematyką.

EDIT Po poście Sebastiana uprościłem kod do absolutnego minimum, aby uwidocznić problem
Oto i on!
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cmath>
 
unsigned long long int suma = 0;
 
int main()
{
 srand( time ( NULL ) );

 unsigned long long int losowa = rand() << 10 | rand() << 5 | rand();

 for ( int i = 63; i >= 0; i-- )
 {
  if ( ( (1<<i) & losowa ) > 0  )
  {
   suma += ( 1<<i );
  }
 }
 std::cout << "Suma: " << suma << std::endl;
 std::cout << "Losowa: " << losowa << std::endl;
 return 0;
}

3 komentarze:

  1. Trochę wstyd z takim błędem. :P

    1. Zapisujesz do jednej zmiennej, czytasz z innej (dlatego wynik się nie zgadza).
    2. Czytasz poza zakresem tablicy.

    Nie wiem czy dobrze zrozumiałem to "zawieranie". Nie chodzi Ci po prostu o to, czy dany bit jest aktywny/włączony/wysoki/etc.?

    Poprawne rozwiązanie:
    for (int i = 0, iend = sizeof(losowa) * 8; i < iend && losowa > 0; ++i)
    {
    if (losowa & 1)
    cout << "2^" << i << " zawiera sie w losowej" << endl;
    losowa >>= 1;
    }

    OdpowiedzUsuń
    Odpowiedzi
    1. Uprościłem, ogołociłem.. próbuj :)

      Usuń
    2. No teraz widzę trzeci błąd. Liczysz na węższych typach i dlatego całość się rozpada. Niestety promocja działa z "lekkim" opóźnieniem, w tym przypadku dopiero w momencie porównywania. Nie powiem, że cały czas o tym myślałem pisząc swoje rozwiązanie, ale jednak takie rzeczy trzeba mieć z tyłu głowy (wzorce jednak się przydają :)). To tak samo jak z dzieleniem, trzeba pamiętać aby ręcznie zrzutować zmienną za wczasu, albo przy mnożeniu węższych typów danych, kiedy spodziewamy się wartości bliskich ekstremum.

      W sumie ciekawsze jest umiejscowienie błędu. Na pewno bardzo ciekawym doświadczeniem musiało być otrzymywanie nieprawidłowej odpowiedzi losowo. :)

      W sumie to mogłeś podać rozwiązanie od razu. Dzięki, że wyczyściłeś kod, tamte błędy od razu dyskwalifikowały całe rozwiązanie jako mogące działać, więc nie było nad czym dalej się rozwodzić.

      Usuń