64bit Hex Float in Dezimal Float

benurb

Mitglied
Hallo Community :)

Habe im Moment folgendes Problem. Ich habe diese Hex Repräsentation einer Zahl:
0x3FF199999999999A
Laut dieser Seite (http://babbage.cs.qc.edu/IEEE-754/64bit.html) handelt es sich hierbei um den Wert 1.1 im Dezimalsystem. Leider schaffe ich es aber nicht dieses Ergebnis in PHP zu reproduzieren. Hat vielleicht jemand eine Funktion, die das macht? Bin auf meiner Suche bisher nicht wirklich fündig geworden. Wie man von Binären Float Repräsentationen in Dezimal Floats umrechnet weiß ich aus der Uni. Jedoch glaube ich nicht, dass es sonderlich effektiv ist den Hex Float erst in einen Bin Float (was ich im übrigen nicht weiß wie es geht) umzuwandeln um ihn danach wieder in Dec zu konvertieren :D

Danke schon mal im Voraus
 
Zu diesem Thema findest du etwas im IEEE Standrad 754 dort steht genau wie ein Float Wert aufgebaut ist und daraus kannst du dann eine Umrechnung entwickeln. In diesem Zusammenhang wird das Horner Schema sicherlich auch interessant sein.
MfG, Andy
 
Ok bin nun bei der Berechnung darauf gestoßen, dass PHP keine 64 bit Integer unterstützt was mir die ganze Berechnung zerhaut. Habe nun eine ziemlich verpfuschte Funktion geschrieben, die das ganze im Endeffekt auf 5 Stellen nach dem Komma genau berechnet. Das Ergebnis ist korrekt, aber vielleicht geht das ganze auch etwas eleganter :D
Kann ja vielleicht mal jemand drüberschauen:
PHP:
function hex2float($hex)
{
	//Hex String auf die ersten 8 Zeichen kürzen, damit man nicht die 32bit Grenze sprengt
	$hex = substr($hex, 0, 8);
	
	//3 Nullen an den Binärstring anhängen, damit die Mantisse auf eine Bitanzahl von 23 kommt - nicht zwingend nötig, aber schöner
	$bin = decbin(hexdec($hex))."000";
	
	//Falls vorne nullen abgeschnitten wurden werden sie nun wieder hinzugefügt - der gesamte binärstring hat nun eine Länge von 35
	$diff = 35 - strlen($bin);
	for($i = 0; $i < $diff; $i++) $bin = "0".$bin;
	
	//Vorzeichen, Exponent und Mantisse werden extrahiert, wobei der Exponent um 3 Zeichen zu lang ist (wegen dem vorhergehenden 64 bit Hex, der auf 32 bit gekürzt wurde)
	$vorzeichen = substr($bin,0,1);
	$exponent = substr($bin,1,8);
	$mantisse = substr($bin,12);
	
	//Berechnung
	$exponentDec = bindec($exponent);
	$exponentFertig = $exponentDec - 127;
	$mantisseVorKomma = "1".substr($mantisse,0,$exponentFertig);
	$mantisseNachKomma = substr($mantisse, $exponentFertig);
	$ergebnis = bindec($mantisseVorKomma);
	for($i = 0; $i < strlen($mantisseNachKomma); $i++)
	{
		$ergebnis += $mantisseNachKomma{$i} * pow(2,(-1) * ($i + 1));
	}
	return round($ergebnis, 5);
}

EDIT: Ok der Code ist vollkommen falsch. Für andere Hex Werte kommt nichts gescheites raus.
 
Zuletzt bearbeitet:
So habe nun alles mit BC_Math gelöst.

Falls es noch einer brauchen sollte poste ich den Code mal hier rein :) Funktionieren tut nun alles einwandfrei.

PHP:
function hex64ToFloat64($hex)
{
	//Den 64bit Hex String in einen 64bit Decimal String umwandeln
	$hexdec = hex64ToDec64($hex);
	//Den 64bit Decimal String in einen 64bit Binär String umwandeln
	$decbin = dec64ToBin64($hexdec);
	
	//Überprüfen ob der Binär String 64 Zeichen lang ist - wenn nicht werden vorne so viele Nullen angehängt wie nötig
	$diff = 64 - strlen($decbin);
	for($i = 0; $i < $diff; $i++) $decbin = "0".$decbin;

	//Berechnung
	//Bit 63 - Vorzeichen
	$vorzeichen = $decbin{0};
	//Bit 62 - 52 Exponent
	$exponentHex = substr($decbin, 1, 11);
	$exponentDec = bindec($exponentHex);
	$exponent = $exponentDec - 1023;
	//Bit 51 - 0 Mantisse
	$mantisse = substr($decbin, 12);
	$mantisseVorKomma = "1".substr($mantisse,0,$exponent);
	$mantisseNachKomma = substr($mantisse, $exponent);
	//Berechnung des Ergebnisses
	$ergebnis = bindec($mantisseVorKomma);
	for($i = 0; $i < strlen($mantisseNachKomma); $i++)
	{
		$hoch = bcpow(2, (-1) * ($i + 1), 64);
		$zwischenergebnis = bcmul($mantisseNachKomma{$i}, $hoch, 64);
		$ergebnis = bcadd($ergebnis, $zwischenergebnis, 16);
	}
	
	//Das Ergebnis kann hier optional noch gerundet werden
	return $ergebnis;
}

function hex64ToDec64($hex)
{
	$ergebnis = '0';
	for($i = 0; $i < strlen($hex); $i++)
	{
		$hoch = bcpow('16', strlen($hex) - $i - 1);
		$stelle = hexdec($hex{$i});
		$zwischenergebnis = bcmul($stelle, $hoch);
		$ergebnis = bcadd($ergebnis, $zwischenergebnis);
	}
	return $ergebnis;
}

function dec64ToBin64($dec)
{
	$zwischenergebnis = '';
	$running = true;
	while($running)
	{
		$div = bcdiv($dec, 2);
		$mod = bcmod($dec, 2);
		$zwischenergebnis .= $mod;
		$dec = $div;
		if($dec <= 0) $running = false;
	}
	
	$ergebnis = '';
	for($i = strlen($zwischenergebnis) - 1; $i >= 0; $i--)
	{
		$ergebnis .= $zwischenergebnis{$i};
	}
	
	return $ergebnis;
}
 
Zurück