Umwandlung einer Binär-Zahl im Zweikomplement

Hallo Leute,

ich bekomme Daten die im Zweikomplement vorliegen.
Wie wandle ich sie korrekt „zurück“?

Die Umwandlung einer Zahl in das zweite Komplement soll so passieren:

Converting a negative decimal number (ie: -3) into binary takes 3 steps:
1) convert the positive version of the decimal number into binary (ie: 3 = 0011)
2) flips the bits (ie: 0011 becomes 1100)
3) add 1 (ie: 1100  + 0001 = 1101)

Versuche mich hier seid Stunden den Prozess „umzukehren“…:confused:

Wie funktioniert das?

Joachim

Worauf bezieht sich die Beschreibung ?

Normalerweise schaut dies so aus:
Zweierkomplement – Wikipedia

Somit solltest du auch mit unpack zu einem sinnvollen Ergebnis kommen.
Allerdings zeigt dein Beispiel nur ein Nibble und kein Byte.
Eigentlich wäre ja -3 => 11111101bei einem Byte. Und das Beispiel zeigt nur die unteren 4 Bits => 1101

Als Byte liefert unpack mit
var_dump(unpack(„c“,$Byte));
auch das korrekte Ergebnis.
Michael

Unter der Annahme, das es sich um eine 8Bit Komplement handelt läuft das im einzelnen so ab

<?php
$v=-3; //Ausgangswert
$v1=abs($v); //positive Zahl
$v2=(~$v1) &255; //Bits negieren und auf 8Bit beschränken 
$v3=$v2+1; eins addieren

printf("%d,%d,%08b,%08b,%08b,%d
",$v,$v1,$v1,$v2,$v3,$v3);
?>

ergibt

-3,3,00000011,11111100,11111101,253

oder einfach wenn immer $v negativ ist


print ($v1+256); //256=255+1

Wenn es sich um ein 16Bit komplement handelt, dann einfach die Basis auf 65536 ändern.

Tommi

Vielen Dank erst einmal!

Ich weiß nicht, ob ich mich richtig verständlich gemacht habe oder ich es nur immer noch nicht verstehe…:confused:

So kommen die Daten an (binär):

Sie sind aufgeteilt in drei Bytes. Ist die Zahl im positiven Bereich ist das nicht mein Problem, aber sehr wohl wenn sie in den negativen Bereich geht.
Um die Daten und das Vorzeichen zu „isolieren“ habe ich so gemacht:

$Value = (($MeasurementData[1] & 2) << 16) | ($MeasurementData[2] << 8) | $MeasurementData[3];

Aber was muss jetzt gemacht werden?

Negieren mit ~$Value?
1 dazuzählen oder abziehen?
Ich habe schon so ziemlich alles probiert, leider noch nicht erfolgreich…:frowning:

Joachim

Hallo Joachim,

eventuell kommst du mit der MCP3424 C-Library for Arduino weiter.

Gruss
Bernd

long MCP3424::measure(){

long _resultat=0;

while(isConversionFinished()==1);

switch (_resolution){

case 12:
 _resultat = (((long)_buffer[0] & 0x0F) << 8) | ((long)_buffer[1] & 0xFF); 
 _resultat |= long(_buffer[0] & 0x80) << 24;
 _resultat = _resultat*1000.0/_PGA;
 break;

 case 14: 
_resultat = (((long)_buffer[0] & 0xBF) << 8) | ((long)_buffer[1] & 0xFF); 
_resultat |= long(_buffer[0] & 0x80) << 24;
_resultat = _resultat*250/_PGA;
 break;

case 16:
_resultat = (((long)_buffer[0] & 0x7F) << 8) | ((long)_buffer[1] & 0xFF); 
_resultat |= long(_buffer[0] & 0x80) << 24;
_resultat = _resultat*62.5/_PGA;
 break;

case 18:
_resultat = (((long)_buffer[0] & 0x01) << 16) | (((long)_buffer[1] & 0xFF) <<8) | ((long)_buffer[2] & 0xFF); 
_resultat |=((long)_buffer[0] & 0x80) << 24;
_resultat = _resultat*15.625/_PGA;
 break;
}

…schaue ich mir die Beispiele für negative Werte an, dann würde ich $Value zunächst
$Value = ~$Value; // negieren
$Value = $Value + 1;
$Value = $Value * Multiplikator;

Funktioniert aber aus irgendeinem Grund nicht? Vielleicht weil das nicht mit der „Summe“ der Bytes gemacht werden muss, sondern zunächst mit den einzelnen Bytes?

Joachim

…mal zur Demonstration:
Hier mal mit Daten die am Eingang sind:

$MeasurementData[1] = 249;
$MeasurementData[2] = 199;
$Value = (($MeasurementData[1] & 15) << 8) | $MeasurementData[2];
$Value = ~$Value;
echo $Value;

Das Ergebnis ist -2504

Es müßte aber etwas in der Höhe von ca. -1592 herauskommen…:confused:

Joachim

Nachtrag: Irgendwie macht dieses ~$Value nicht das was ich erwarte:
2503 wäre bitweise gesehen genau das Gegenstück von 1592, stattdessen wird aus 2503 „nur“ -2504…

…zur Verdeutlichung:
2503 = 100111000111
1592 = 011000111000

Leider macht "~"2503 nicht 1592…

Die Erklärung hier:
~ $a Nicht Die Bits, die in $a nicht gesetzt sind, werden gesetzt und umgekehrt.

Wo liegt der Fehler?

Joachim

Invertier mal den ersten Wert. Vielleicht kommst du da weiter.

$MeasurementData1 = 249;
$MeasurementData[2] = 199;
$Value = ((~$MeasurementData1 & 15) << 8) | $MeasurementData[2];  // Wert1 invertieren

$Value = ~$Value;
echo $Value;  


Hallo Rainer,

vielen Dank für den Beitrag.
Ich habe jetzt so viel probiert, versuche mir jetzt mal mit dieser Funktion zu behelfen:

private function bitnot(int $Value)
	{
	   	// Umwandlung in einen Binär-String
		$bin = decbin($Value);
	   	$not = "";
	   	// Umstellung der Binär-Strings
		for ($i = 0; $i < strlen($bin); $i++)
	   		{
	      		if($bin[$i] == 0) { $not .= '1'; }
	      		if($bin[$i] == 1) { $not .= '0'; }
	   	}
		// Rückgabe als Integer
	return bindec($not);
	}
	

Konnte es jetzt noch nicht ausprobieren. Problem bei der „Not“-Funktion ist wohl, - wenn ich das richtig verstanden habe - dass sie 32-Bit erwartet…

Ich teste das jetzt erst einmal so…

Joachim