note 102126 deleted from language.types.float by danbrown
| From: | danbrown@php.net | Date: | Sat, 02 Feb 2013 15:11:53 +0000 |
| Subject: | note 102126 deleted from language.types.float by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-193500@lists.php.net to get a copy of this message | ||
Note Submitter: Nstiac (info at nstiac dot com)
----
There are many scripts/functions to convert a Hex string to a Floating point number, but i
could'nt find any usable function to convert a float2hex (float number to hexadecimal) .. so i
went on an made one! .. to my surprise.. it didn't matched the other existing functions results
exactly due to different methods used on each .. so i went on an created a complementary function to
have both results match float2hex32n<->hex2float32n.
<?php
/** Complementary functions to CONVERT PHP FLOATING POINT NUMBERS or DECIMALS
* (IEEE 754 single-precision 32 bit) TO HEXADECIMAL AND BACK.
*
* @author NSTIAC (Jorge D. Baigorri Salas) http://www.nstiac.com http://www.n2works.com
* @created on 28/Jan/2010 / time spent: 2hours approx.
* @special thanks to Thomas Finley's article "Floating Point"
* http://tfinley.net/notes/cps104/floating.html
*
* These functions allow to convert any php floating point numbers with the
* notation 1.234 (or fixed point numbers) into their corresponding 8 digits
* hexadecimal notation. (i.e.- 1557897.40 -> 49BE2C4B <- 1557897.40) by
* disregarding their implicit format and treating them at will as either
* integer, decimals, binary numbers, hexadecimal values, or plain text.
*
**/
/** FLOAT2HEX32n
* (Convert php float numbers or decimals (single-precision 32bits) to 8 digit Hexadecimal)
* Accepts only fixed point notation decimal numbers or fractions on a string (i.e.-
"1.23456")
* @usage:
* float2hex32n("-1557897.13"); returns "c9be2c49"
**/
function float2hex32n($number) {
//Convert non-decimal to decimal.
$number=number_format($number,23,'.','');
//Get the integer portion of $number
if ($number>0) {
$intnumber=substr($number,0,strpos($number,"."));
} else {
//Check whether is a negative number to remove - sign.
$intnumber=substr($number,1,strpos($number,"."));
}
//Convert integer to binary
$binint=decbin($intnumber);
//Get the decimal fraction of the number
$pointnumber=substr($number,strpos($number,"."));
//Add a 0 to treat as single decimal fraction
$pointnumber="0".$pointnumber;
//Convert decimal values to base 2
$tmppoint=number_format($pointnumber*2,23,'.','');
for ($i=0; $i<23; $i++) {
$binpoint.=substr((string)$tmppoint,0,1);
$tmppoint=substr((string)$tmppoint,1);
$tmppoint=number_format($tmppoint*2,23,'.','');
}
//Gather both values to get base 2 binary fraction
$scibin=$binint.".".$binpoint;
//Find fraction separator "." position
$exp=strpos($scibin,".");
//Transform to scientific notation (1.x^exp)
$scibin=substr($binint,0,1).".".substr($binint,1).$binpoint;
//Create mantissa
if ($scibin>1) {
$mantissa=substr($scibin,2);
} else {
$mantissa=substr($scibin,1);
}
//Fill mantissa to 23 bit value
$fill23=23-strlen($mantissa);
for ($i=0; $i<$fill23; $i++) {
$mantissa.="0";
}
//Convert fraction separator position to exponent value
if ($exp>0) { $exp--; }
//Adjust to binary notation exponent value
$exp+=127;
//Convert to 8 bit binary
$exp=decbin($exp);
//Find 1 bit sign value
if ($number>0) { $sign=0; } else { $sign=1; }
//Compose final binary value
$binfinal=$sign.$exp.$mantissa;
//Reorganizae number into 4digit/bits packets and
//finally convert to decimal value and to hex.
$hexfinal.=dechex(bindec(substr($binfinal,0,4)));
$hexfinal.=dechex(bindec(substr($binfinal,4,4)));
$hexfinal.=dechex(bindec(substr($binfinal,8,4)));
$hexfinal.=dechex(bindec(substr($binfinal,12,4)));
$hexfinal.=dechex(bindec(substr($binfinal,16,4)));
$hexfinal.=dechex(bindec(substr($binfinal,20,4)));
$hexfinal.=dechex(bindec(substr($binfinal,24,4)));
$hexfinal.=dechex(bindec(substr($binfinal,28,4)));
return $hexfinal;
}
/** Using either function will return a value which can be used on the other function
* to return the original input. (Hope it helps =)
**/
?>
Second function (HEX2FLOAT32n) converts Hexadecimal 8 digit strings to fixed decimals float numbers.
(complementary to FLOAT2HEX32n above)
<?php
/** Complementary functions to CONVERT PHP FLOATING POINT NUMBERS or DECIMALS
* (IEEE 754 single-precision 32 bit) TO HEXADECIMAL AND BACK.
*
* @author NSTIAC (Jorge D. Baigorri Salas) http://www.nstiac.com http://www.n2works.com
* @created on 28/Jan/2010 / time spent: 2hours approx.
* @special thanks to Thomas Finley's article "Floating Point"
* http://tfinley.net/notes/cps104/floating.html
*
* These functions allow to convert any php floating point numbers with the
* notation 1.234 (or fixed point numbers) into their corresponding 8 digits
* hexadecimal notation. (i.e.- 1557897.40 -> 49BE2C4B <- 1557897.40) by
* disregarding their implicit format and treating them at will as either
* integer, decimals, binary numbers, hexadecimal values, or plain text.
*
**/
/** HEX2FLOAT32n
* (Convert 8 digit hexadecimal values to fixed decimals float numbers (single-precision 32bits)
* Accepts 8 digit hexadecimal values on a string (i.e.- F1A9B02C) and single integer to fix number
of decimals
* @usage:
* hex2float32n("c9be2c49",2); returns -> "-1557897.13"
**/
function hex2float32n($number,$nd) {
//Separate each hexadecimal digit
for ($i=0; $i<strlen($number); $i++) {
$hex[]=substr($number,$i,1);
}
//Convert each hexadecimal digit to integer
for ($i=0; $i<count($hex); $i++) {
$dec[]=hexdec($hex[$i]);
}
//Convert each decimal value to 4bit binary and join on a string
for ($i=0; $i<count($dec); $i++) {
$binfinal.=sprintf("%04d",decbin($dec[$i]));
}
//Get sign 1bit value
$sign=substr($binfinal,0,1);
//Get exponent 8bit value
$exp=substr($binfinal,1,8);
//Get mantissa 23bit value
$mantissa=substr($binfinal,9);
//Convert & adjunt binary exponent to integer
$exp=bindec($exp);
$exp-=127;
//Assign mantissa to pre-scientific binary notation
$scibin=$mantissa;
//Split $scibin into integral & fraction parts through exponent
$binint=substr($scibin,0,$exp);
$binpoint=substr($scibin,$exp);
//Convert integral binary part to decimal integer
$intnumber=bindec("1".$binint);
//Split each binary fractional digit
for ($i=0; $i<strlen($binpoint); $i++) {
$tmppoint[]=substr($binpoint,$i,1);
}
//Reverse order to work backwards
$tmppoint=array_reverse($tmppoint);
//Convert base 2 digits to decimal
$tpointnumber=number_format($tmppoint[0]/2,strlen($binpoint),'.','');
for ($i=1; $i<strlen($binpoint); $i++) {
$pointnumber=number_format($tpointnumber/2,strlen($binpoint),'.','');
$tpointnumber=$tmppoint[$i+1].substr($pointnumber,1);
}
//Join both decimal section to get final number
$floatfinal=$intnumber+$pointnumber;
//Convert to positive or negative based on binary sign bit
if ($sign==1) { $floatfinal=-$floatfinal; }
//Format float number to fixed decimals required
return number_format($floatfinal,$nd,'.','');
}
/** Using either function will return a value which can be used on the other function
* to return the original input. (Hope it helps =)
**/
?>