我正在尝试将十六进制数据添加到十六进制字符串,并且需要使用其IEEE表示法向该字符串添加浮点数。对于整数,这很简单:
SET params = CONCAT(params,
CASE
WHEN type IS 'int' THEN LPAD(HEX(CAST(value AS SIGNED INTEGER)), 8, '0')
WHEN type IS 'long' THEN LPAD(HEX(CAST(value AS SIGNED INTEGER)), 16, '0')
WHEN type IS 'double' THEN LPAD(HEX(CAST(value AS DECIMAL)), 16, '0')
WHEN type IS 'float' THEN LPAD(HEX(CAST(value AS DECIMAL)), 8, '0')
ELSE 0
END);
[value是数字的VARCHAR,params是包含十六进制字符串的VARCHAR。此技巧适用于整数,但适用于十进制,它将截断小数部分并将整数部分转换为十六进制整数。给定十进制的大小是固定的(java float还是double),如何将值转换为十进制数字的IEEE浮点表示形式的十六进制?
所以一段时间后,我得到了一个解决方案,该解决方案由两个函数和一个存储过程组成(这也可以作为函数实现,但我喜欢过程。
这是基于此python脚本,https://www.geeksforgeeks.org/python-program-to-represent-floating-number-as-hexadecimal-by-ieee-754-standard/
并使用以下方法
检查数字是正还是负。将正负号另存为0,将负号另存为1,如果负数则将其转换为正数。
将浮点数转换为二进制。
首先使用的功能。
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `decimal_converter`(num INTEGER) RETURNS decimal(10,10)
DETERMINISTIC
BEGIN
DECLARE outnum DECIMAL(10,10);
SET outnum = num/10;
label1: WHILE outnum > 1 DO
SET outnum = outnum / 10;
END WHILE label1;
RETURN outnum;
END$$
DELIMITER ;
也需要
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `float_bin`(number float
, places INT) RETURNS text CHARSET utf8mb4
DETERMINISTIC
BEGIN
DECLARE whole INT;
DECLARE dec1 INT;
DECLARE res TEXT;
IF places = NULL THEN SET places = 3; END IF;
SELECT
SUBSTRING_INDEX(REPLACE(CAST(TRIM(TRAILING '.' FROM TRIM(TRAILING '0' from (number))) as CHAR(90)),',','.'), '.', 1) INTO @a;
SELECT
SUBSTRING_INDEX(REPLACE(CAST(TRIM(TRAILING '.' FROM TRIM(TRAILING '0' from (number))) as CHAR(90)),',','.'), '.', -1) iNTO @b;
SET whole = @a;
SET dec1 = @b ;
SET res = BIN(whole);
SET res = CONCAT(res , '.');
while 0 < places do
SELECT
SUBSTRING_INDEX(REPLACE(CAST(TRIM(TRAILING '.' FROM TRIM(TRAILING '0' from (decimal_converter(dec1) * 2))) as CHAR(90)),',','.'), '.', 1) INTO @a;
SELECT
SUBSTRING_INDEX(REPLACE(CAST(TRIM(TRAILING '.' FROM TRIM(TRAILING '0' from (decimal_converter(dec1) * 2))) as CHAR(90)),',','.'), '.', -1) INTO @b;
SET whole = @a;
SET dec1 = @b;
SET res = CONCAT(res , whole) ;
SET places=places-1;
end while;
RETURN res;
END$$
DELIMITER ;
和最终存储过程
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `IEEE754`(
IN n FLOAT
)
BEGIN
DECLARE sign Integer;
DECLARE whole TEXT;
DECLARE dec1 TEXT;
DECLARE p INT;
DECLARE exponent INT;
DECLARE tmpstr VARCHAR(60);
DECLARE exponent_bits INT;
DECLARE exponent_bitsstr TEXT;
DECLARE mantissa TEXT;
DECLARE finally TEXT;
DECLARE hexstr TEXT;
#check if number is negative
SET sign = 0;
IF n < 0 Then
SET sign = 1;
SET n = n * -1;
END IF;
SET p = 30 ;
# convert float to binary
SET dec1 = float_bin (n, p);
# separate the decimal part
# and the whole number part
SELECT
SUBSTRING_INDEX(REPLACE(CAST(dec1 as CHAR(90)),',','.'), '.', 1) INTO @a;
SELECT
SUBSTRING_INDEX(REPLACE(CAST(dec1 as CHAR(90)),',','.'), '.', -1) iNTO @b;
SET whole = @a;
SET dec1 = @b ;
# calculating the exponent(E)
SET tmpstr = CAST(whole as CHAR(60));
SET exponent = LENGTH(tmpstr) - 1;
SET exponent_bits = 127 + exponent;
SET exponent_bitsstr = BIN(exponent_bits);
# finding the mantissa
SET mantissa = SUBSTRING(tmpstr,2,exponent);
SET mantissa = CONCAT(mantissa,dec1);
SET mantissa = SUBSTRING(mantissa,1,23);
# the IEEE754 notation in binary
SET finally = CONCAT(sign,exponent_bitsstr,mantissa );
SET hexstr = CONV(finally,2,16);
SELECT hexstr;
END$$
DELIMITER ;
这将为您提供以下结果:
call IEEE754(263.3);
4383A666
call IEEE754(10.9);
412E6666
这在MySQL中无法完成。甚至不是全新的(8.0.17):
CAST(UNHEX('412E6666') AS FLOAT)
此外,由于CAST
或HEX
的任何形式都只采用一个字符串,即“ 10.9”,而不是10.9的位/字节/十六进制,因此也没有其他方向。
如果可以备份一步,也许可以通过其他方式实现更大的目标。