Problem bei C++ Programmierung (natürliche Zahl umrechnen in binäre Zahl)?

3 Antworten

Dass die Zahlen rückwärts ausgegeben werden, ist klar, da du die Einerstelle zuerst hinschreibst.

Mögliche Abhilfe:

Zusatzvariablen "ergebnis" und "stellen" werden vor der while-Schleife auf 0 bzw 1 gesetzt.

in der While-Schleife nach Berechnung von b:

ergebnis = ergebnis + b * stelle

stelle = stelle * 10

nach der while-Schleife ergebnis ausgeben.

claudi979797 
Fragesteller
 11.03.2018, 16:16

Hallo gfntom

Vielen Dank für die schnelle Antwort!

Ich habe erst vor 2 Wochen angefangen zu programmieren und kann dein Code super nachvollziehen!

Das einzige kleine Problem das ich noch habe ist:

Wenn ich eine grosse Zahl wie z.B 4'000'000'000'000 umrechnen will kommt als ausgabe: -2081420235059197952 anstelle von 11101110011010110010100000000000

Wo liegt das Problem?

Ich habe auch für "ergebnis" und "stelle" einen long long int genommen.

0
gfntom  11.03.2018, 16:36
@claudi979797

ja, darauf wollte ich zuvor schon hinweisen, dachte aber, dass du nicht an die Grenzen stösst:

long long int kann "nur" Zahlen bis 9.223.372.036.854.775.807 abspeichern, dein "Bitstring" 11101110011010110010100000000000 ist wesentlich größer als diese Zahl, so dass es dadurch zu Fehlern kommt.

Das "ergebnis" sieht nämlich nur aus wie eine Binärzahl, ist es aber nicht.

Eine andere Methode wäre noch, die einzelnen bits im einen char-Array an der korrekten stelle abzuspeichern (und nicht vergessen: nicht benutzte stellen mit '0' füllen!) und dies dann auszugeben.

1
gfntom  11.03.2018, 16:47

Eine ander Möglichkeit: Shift-Befehele (ich gehe davon aus, dass du nur positive Zahlen behandeln willst):

Du gehst alle 64 bits von n durch.

Du überprüfst ob n negativ ist (= höchstes bit gesetzt), wenn ja gibst du 0 aus, ansonsten 1.

Du schiebst n um ein bit nach links (mit n = n << 1)

und springst wieder nach oben zur überprüfung und Ausgabe, so lange, bis alle 64 Bits durch sind.

1

Dann lege die Elemente doch erst in einem Aggregat (z.B. einem Vector) ab und Iteriere über dieses nochmals rückwärts für deine Ausgabe.

Cynob  11.03.2018, 13:40

Genau das ist aber kein schöner Programmierstil Experte

Es liegt daran das er die Schleife von hinten nach vorne durchläuft aber das Ergebnis anhängt. Da das ganze nachm FIFO Prinzip arbeitet kommen die binären Stellen verkehrt herum raus.

0
regex9  11.03.2018, 14:16
@Cynob

Was passiert, ist doch bereits klar. Nach einer einfachen Lösung war aber gefragt.

1
claudi979797 
Fragesteller
 11.03.2018, 16:19

Hallo regex9

Vielen Dank für deine Antwort, da ich erst seit 2 Wochen programmiere kenn ich mich leider noch nicht mit Vector aus. Wie lege ich genau die Elemente in einem Aggregat ab?

0
regex9  11.03.2018, 17:05
@claudi979797

Wenn du noch nicht so weit bist, denke ich, solltest du dich erst einmal noch auf Arrays etc. konzentrieren.

Der Vector würde es dir ermöglichen, einfacher Elemente dynamisch anzufügen:

#include <iostream>
#include <vector>

int main() {
  std::vector<long long int> numbers;
  numbers.push_back(1);
  numbers.push_back(2);
  numbers.push_back(3);

  for (
    std::vector<long long int>::reverse_iterator iterator = numbers.rbegin();
    iterator != numbers.rend();
    ++iterator) {
    std::cout << *iterator;
  }
}

Mit der Schleife (ich habe für ihren Kopf mehrere Zeilen genutzt, da dieser so lang ist) wird der Vector rückwärts ausgegeben.

1

Du könntest den Wert einfach mit einem Bit maskieren, das von Links nach Rechts durchläuft:

#include <iostream> // cerr, cout
#include <limits> // numeric_limits
#include <sstream> // stringstream
#include <type_traits> // is_integral, make_unsigned

template <typename T>
::std::string int2bin(const T val) {
  using namespace ::std;

  static_assert(
    is_integral<T>::value,
    "only integer types supported"
  );

  using ull = unsigned long long;

  static_assert(
    2 == numeric_limits<ull>::radix,
    "only binary platforms supported"
  );

  constexpr ull mask {
    ~static_cast<ull>(0)
  };
  const ull raw { val & mask };

  stringstream result;

  using U = typename make_unsigned<T>::type;
  size_t i = numeric_limits<U>::digits;

  bool ones = false;

  while (i--) {
    constexpr ull one { 1 };
    const ull masked = (one << i) & raw;

    if (masked) {
      ones = true;
    }

    if (0 == i || ones) {
      result << (masked ? '1' : '0');
    }
  }

  return result.str();
}

int main(void) {
  using namespace ::std;

  cout << "[unsigned 0 ... +8]" << endl;
  for (unsigned i = 0; i <= 8; ++i) {
    cout << i << ": " << int2bin(i) << endl;
  }

  cout << endl;

  cout << "[short 0 ... -8]" << endl;
  for (short i = 0; i >= -8; --i) {
    cout << i << ": " << int2bin(i) << endl;
  }

  cout << endl;

  cout << "[signed char +4 ... -4]" << endl;
  for (signed char i = 4; i >= -4; --i) {
    cout << static_cast<int>(i) << ": " << int2bin(i) << endl;
  }
}

Den ganzen Klimmbimm drum herum kannst du erst mal ignorieren, wenn du erst vor zwei Wochen mit C++ angefangen hast. Aber dank des Templates kannst sämtliche Integer-Typen jeglicher Breite nutzen, egal ob mit oder ohne Vorzeichen.

Außerdem gibt die Template-Funktion int2bin() keine überflüssigen Nullen auf der linken Seite aus, sodass "4" wirklich nur "100" ausgeben wird.

Aber egal ... das kann dir alles egal sein. Versuche einfach die while-Schleife und vor allem die Zeile zu verstehen, in der "masked" deklariert wird. :)