1<?php 2 3// Mirrored from https://github.com/Danack/HexFloat 4 5require_once __DIR__ . "/FloatInfo.php"; 6require_once __DIR__ . "/Float32Info.php"; 7 8use HexFloat\FloatInfo; 9use HexFloat\Float32Info; 10 11/** 12 * Returns a string containing a hexadecimal representation of the given float, 13 * using 64 bits of info 14 * 15 * @param float $number 16 * @return string 17 */ 18function floathex(float $number) 19{ 20 return strrev(unpack('h*', pack('d', $number))[1]); 21} 22 23/** 24 * Returns a string containing a hexadecimal representation of the given float, 25 * using 32 bits of info 26 * 27 * @param float $number 28 * @return string 29 */ 30function floathex32(float $num) 31{ 32 return strrev(unpack('h*', pack('f', $num))[1]); 33} 34 35/** 36 * Convert a floating point number to a FloatInfo object, 37 * which contains string representations of the float's sign, 38 * exponent and mantissa 39 * @param float $num 40 * @return FloatInfo 41 */ 42function float_info(float $num) 43{ 44 $float64 = floathex($num); 45 46 //Sign bit: 1 bit 47 //Exponent: 11 bits 48 //Significand precision: 53 bits (52 explicitly stored) 49 50 $chars = str_split($float64); 51 52 53 // 3 bits from this 54 $byte1 = hexdec($chars[0]); 55 // 4 bits from this 56 $byte2 = hexdec($chars[1]); 57 58 // 1 bit from this 59 $byte3 = hexdec($chars[2]); 60 61 $sign = '0'; 62 63 if ($byte1 >= 8) { 64 $sign = '1'; 65 } 66 67 $exponentString = substr($float64, 0, 3); 68 $exponentValue = hexdec($exponentString) & 0x7ff; 69 $exponent = sprintf("%b", $exponentValue); 70 $exponent = str_pad($exponent, 11, '0', STR_PAD_LEFT); 71 72 $mantissa = substr($float64, 2); 73 $mantissa = hexdec($mantissa) & 0xfffffffffffff; 74 $mantissa = sprintf("%b", $mantissa); 75 $mantissa = str_pad($mantissa, 52, '0', STR_PAD_LEFT); 76 77 return new FloatInfo( 78 $sign, 79 $exponent, 80 $mantissa 81 ); 82} 83 84/** 85 * Convert a floating point number to a Float32Info object, 86 * which contains string representations of the float's sign, 87 * exponent and mantissa 88 * 89 * @param float $num 90 * @return Float32Info 91 */ 92function float_info_32(float $num) 93{ 94 $float32 = floathex32($num); 95 $chars = str_split($float32); 96 97 // 3 bits from this 98 $byte1 = hexdec($chars[0]); 99 // 4 bits from this 100 $byte2 = hexdec($chars[1]); 101 102 // 1 bit from this 103 $byte3 = hexdec($chars[2]); 104 105 $sign = '0'; 106 107 if ($byte1 >= 8) { 108 $sign = '1'; 109 } 110 $exponent3Bits = ($byte1 & 0x7); 111 $exponent4Bits = $byte2; 112 $exponent1Bit = ($byte3 & 0x8) >> 3; 113 $exponent = ($exponent3Bits << 5) | ($exponent4Bits << 1) | $exponent1Bit; 114 115 $exponent = sprintf("%b", $exponent); 116 $exponent = str_pad($exponent, 8, '0', STR_PAD_LEFT); 117 118 $mantissa = substr($float32, 2, 6); 119 $mantissa = hexdec($mantissa) & 0x7fffff; 120 $mantissa = sprintf("%b", $mantissa); 121 $mantissa = str_pad($mantissa, 23, '0', STR_PAD_LEFT); 122 123 return new Float32Info( 124 $sign, 125 $exponent, 126 $mantissa 127 ); 128} 129 130/** 131 * Produce a debug string that shows the Sign, Exponent and Mantissa for 132 * two floating point numbers, using 64bit precision 133 * 134 * 135 * @param float $value1 136 * @param float $value2 137 * @return string 138 * 139 * Example result 140 * ┌──────┬─────────────┬──────────────────────────────────────────────────────┐ 141 * │ Sign │ Exponent │ Mantissa │ 142 * │ 0 │ 01111111011 │ 1001100110011001100110011001100110011001100110011010 │ 143 * │ 0 │ 10000011001 │ 0111110101111000010000000100000000000000000000000000 │ 144 * └──────┴─────────────┴──────────────────────────────────────────────────────┘ 145 * 146 */ 147function float_compare(float $value1, float $value2) 148{ 149 $float_info_1 = float_info($value1); 150 $float_info_2 = float_info($value2); 151 152 //Sign bit: 1 bit 153 //Exponent: 11 bits 154 //Significand precision: 53 bits (52 explicitly stored) 155 156 $output = "┌──────┬─────────────┬──────────────────────────────────────────────────────┐\n"; 157 $output .= "│ Sign │ Exponent │ Mantissa │\n"; 158 159 $format_string = "│ %s │ %s │ %s │\n"; 160 161 $output .= sprintf($format_string, $float_info_1->getSign(), $float_info_1->getExponent(), $float_info_1->getMantissa()); 162 $output .= sprintf($format_string, $float_info_2->getSign(), $float_info_2->getExponent(), $float_info_2->getMantissa()); 163 164 $output .= "└──────┴─────────────┴──────────────────────────────────────────────────────┘\n"; 165 166 return $output; 167} 168 169 170/** 171 * Produce a debug string that shows the Sign, Exponent and Mantissa for 172 * two floating point numbers, using 32bit precision 173 * 174 * @param float $value1 175 * @param float $value2 176 * @return string 177 * 178 * Example result 179 * ┌──────┬──────────┬─────────────────────────┐ 180 * │ Sign │ Exponent │ Mantissa │ 181 * │ 0 │ 01111011 │ 10011001100110011001101 │ 182 * │ 0 │ 10011001 │ 01111101011110000100000 │ 183 * └──────┴──────────┴─────────────────────────┘ 184 * 185 */ 186function float_compare_32(float $value1, float $value2) 187{ 188 $float_info_1 = float_info_32($value1); 189 $float_info_2 = float_info_32($value2); 190 191 $output = "┌──────┬──────────┬─────────────────────────┐\n"; 192 $output .= "│ Sign │ Exponent │ Mantissa │\n"; 193 194 $format_string = "│ %s │ %s │ %s │\n"; 195 196 $output .= sprintf($format_string, $float_info_1->getSign(), $float_info_1->getExponent(), $float_info_1->getMantissa()); 197 $output .= sprintf($format_string, $float_info_2->getSign(), $float_info_2->getExponent(), $float_info_2->getMantissa()); 198 199 $output .= "└──────┴──────────┴─────────────────────────┘\n"; 200 201 return $output; 202} 203