将MySQL十进制转换为浮点IEEE表示形式的十六进制

将MySQL十进制转换为浮点IEEE表示形式的十六进制,mysql,floating-point,hex,ieee-754,sql-function,Mysql,Floating Point,Hex,Ieee 754,Sql Function,我正在尝试将十六进制数据添加到十六进制字符串中,我需要使用它们的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

我正在尝试将十六进制数据添加到十六进制字符串中,我需要使用它们的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浮点或双精度),如何将值转换为十进制数的IEEE浮点表示形式的十六进制

这不能在MySQL中完成。甚至不是全新的(8.0.17):

此外,也没有其他办法,因为任何形式的
CAST
HEX
将只接受一个字符串,即“10.9”,而不是10.9的位/字节/十六进制


如果您可以备份一个步骤,也许可以通过其他方式实现更大的目标。

因此,经过一段时间后,我得到了一个解决方案,它包括两个函数和一个存储过程(这也可以作为函数实现,但我喜欢过程)

这是基于这个python脚本,

并使用以下方法

  • 检查数字是正数还是负数。将符号保存为0表示正数,1表示负数,如果是负数,则将数字转换为正数

  • 将浮点数转换为二进制

  • 将小数部分和整数部分分开
  • 计算指数(E)并将其转换为二进制
  • 找到尾数
  • 包含尾数、指数和尾数的符号。 将其转换为十六进制
首先是使用的函数

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 ;
虽然@nbk的想法是正确的,但他的实现不适用于次正常数,并且缺少双精度浮点的实现。这是他的答案的简化版本,支持单精度和双精度,并适用于次正常数。我个人不需要将逗号转换为小数点,因为y数据库语言是英文的,但在您的情况下,您可能不得不这样做

DELIMITER //

DROP FUNCTION IF EXISTS FLOAT_BIN//

CREATE FUNCTION FLOAT_BIN(number FLOAT, places INT)
RETURNS TEXT CHARSET utf8mb4 DETERMINISTIC
BEGIN
    DECLARE whole INT;
    DECLARE dec1 FLOAT;
    DECLARE res TEXT;

    SET whole = FLOOR(number);
    SET dec1 = number - whole;

    SET res = CONCAT(BIN(whole), '.');

    WHILE 0 < places DO
        SET dec1 = dec1 * 2;

        SET whole = FLOOR(dec1);
        SET dec1 = dec1 - whole;

        SET res = CONCAT(res, whole);
        SET places = places - 1;
    END WHILE;
    RETURN res;
END//

DROP FUNCTION IF EXISTS IEEE754;

CREATE FUNCTION IEEE754(n FLOAT) RETURNS CHAR(8)
BEGIN
    DECLARE sign INT;
    DECLARE whole VARCHAR(256);
    DECLARE dec1 VARCHAR(256);
    DECLARE exponent INT;
    DECLARE mantissa VARCHAR(256);

    # check if number is negative
    SET sign = 0;
    IF n < 0 THEN
        SET sign = 1;
        SET n = n * -1;
    END IF;

    # convert float to binary
    SET dec1 = FLOAT_BIN(n, 256); # good upper bound is twice the max exponent

    # separate the decimal part
    # and the whole number part
    SET whole = SUBSTRING_INDEX(dec1, '.', 1);
    SET dec1 = SUBSTRING_INDEX(dec1, '.', -1);

    # calculating the exponent(E)

    IF n >= 1 THEN
        SET exponent = LENGTH(whole) - 1;
        SET mantissa = CONCAT(SUBSTR(whole, 2), dec1);
    ELSE
        SET exponent = -1;
        WHILE SUBSTR(dec1, 1, 1) = '0' AND exponent > -127 DO
            SET exponent = exponent - 1;
            SET dec1 = SUBSTR(dec1, 2);
        END WHILE;

        IF exponent = -127 THEN
            SET mantissa = dec1;
        ELSE
            SET mantissa = SUBSTR(dec1, 2);
        END IF;
    END IF;

    RETURN CONV(CONCAT(sign, LPAD(BIN(127 + exponent), 8, '0'), RPAD(mantissa, 23, '0')), 2, 16);
END//

DROP FUNCTION IF EXISTS IEEE754_DOUBLE;

CREATE FUNCTION IEEE754_DOUBLE(n FLOAT) RETURNS CHAR(16)
BEGIN
    DECLARE sign INT;
    DECLARE whole VARCHAR(4096);
    DECLARE dec1 VARCHAR(4096);
    DECLARE exponent INT;
    DECLARE mantissa VARCHAR(4096);

    # check if number is negative
    SET sign = 0;
    IF n < 0 THEN
        SET sign = 1;
        SET n = n * -1;
    END IF;

    # convert float to binary
    SET dec1 = FLOAT_BIN(n, 4096);

    # separate the decimal part
    # and the whole number part
    SET whole = SUBSTRING_INDEX(dec1, '.', 1);
    SET dec1 = SUBSTRING_INDEX(dec1, '.', -1);

    # calculating the exponent(E)

    IF n >= 1 THEN
        SET exponent = LENGTH(whole) - 1;
        SET mantissa = CONCAT(SUBSTR(whole, 2), dec1);
    ELSE
        SET exponent = -1;
        WHILE SUBSTR(dec1, 1, 1) = '0' AND exponent > -1023 DO
                SET exponent = exponent - 1;
                SET dec1 = SUBSTR(dec1, 2);
            END WHILE;

        IF exponent = -1023 THEN
            SET mantissa = dec1;
        ELSE
            SET mantissa = SUBSTR(dec1, 2);
        END IF;
    END IF;

    RETURN CONV(CONCAT(sign, LPAD(BIN(1023 + exponent), 11, '0'), RPAD(mantissa, 52, '0')), 2, 16);
END//

DELIMITER ;
分隔符//
如果存在浮箱,则删除功能//
创建函数FLOAT_BIN(数字FLOAT,places INT)
返回文本字符集utf8mb4
开始
声明整型整数;
宣布12月1日浮动;
声明res文本;
整组=楼层(编号);
设置dec1=数字-整数;
设置res=CONCAT(料仓(整体)”;
而0<的地方可以
设置dec1=dec1*2;
整组=地板(dec1);
设置dec1=dec1-整体;
设置res=混凝土(res,整体);
设置位置=位置-1;
结束时;
返回res;
结束//
如果存在IEEE754,则删除功能;
创建函数IEEE754(n FLOAT)返回字符(8)
开始
声明符号INT;
声明整个VARCHAR(256);
声明dec1 VARCHAR(256);
声明指数INT;
声明尾数VARCHAR(256);
#检查数字是否为负数
设置符号=0;
如果n<0,则
设置符号=1;
设置n=n*-1;
如果结束;
#将浮点转换为二进制
SET dec1=FLOAT_BIN(n,256);#好的上界是最大指数的两倍
#分隔小数部分
#还有整数部分
整组=子串索引(dec1,'.',1);
设置dec1=子串索引(dec1,',-1);
#计算指数(E)
如果n>=1,则
设定指数=长度(整数)-1;
集合尾数=CONCAT(SUBSTR(整数,2),dec1);
其他的
设定指数=-1;
而SUBSTR(dec1,1,1)='0'和指数>-127则
设置指数=指数-1;
设置dec1=SUBSTR(dec1,2);
结束时;
如果指数=-127,则
设定尾数=dec1;
其他的
设定尾数=SUBSTR(dec1,2);
如果结束;
如果结束;
返回CONV(CONCAT(符号,LPAD(BIN(127+指数),8,'0'),RPAD(尾数,23,'0')),2,16);
结束//
如果存在DROP函数IEEE754_DOUBLE;
创建函数IEEE754_DOUBLE(n FLOAT)返回字符(16)
开始
声明符号INT;
声明整个VARCHAR(4096);
宣布dec1 VARCHAR(4096);
声明指数INT;
声明尾数VARCHAR(4096);
#检查数字是否为负数
设置符号=0;
如果n<0,则
设置符号=1;
设置n=n*-1;
如果结束;
#将浮点转换为二进制
SET dec1=浮箱(n,4096);
#分隔小数部分
#还有整数部分
整组=子串索引(dec1,'.',1);
设置dec1=子串索引(dec1,',-1);
#计算指数(E)
如果n>=1,则
设定指数=长度(整数)-1;
集合尾数=CONCAT(SUBSTR(整数,2),dec1);
其他的
设定指数=-1;
而SUBSTR(dec1,1,1)='0'和指数>-1023则
设置指数=指数-1;
设置dec1=SUBSTR(dec1,2);
结束时;
如果指数=-1023,则
设定尾数=dec1;
其他的
设定尾数=SUBSTR(dec1,2);
如果结束;
如果结束;
返回CONV(CONCAT(符号,LPAD(BIN(1023+指数),11,'0'),RPAD(尾数,52,'0')),2,16);
结束//
定界符;

我会将10.0转换为A,10.9也转换为A。我不确定您到底想做什么。您能举一些例子吗please@nbk我希望10.9变成412E6666,假设它是一个单精度浮点(float)。412E6666是10.9的IEEE二进制表示的十六进制。您需要一个存储函数(或等效代码)它接受字符串“412E6666”,并返回一个值,如果存储到
FLOAT
中,该值将为10.9?(我知道如何在PHP中实现它;我将从头开始在MySQL中实现它。)注意:type type
DECIMAL
的存储方式与
FLOAT
@RickJames No的存储方式不同。我有十进制数,我想将其转换为我可以使用的412E6666
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
DELIMITER //

DROP FUNCTION IF EXISTS FLOAT_BIN//

CREATE FUNCTION FLOAT_BIN(number FLOAT, places INT)
RETURNS TEXT CHARSET utf8mb4 DETERMINISTIC
BEGIN
    DECLARE whole INT;
    DECLARE dec1 FLOAT;
    DECLARE res TEXT;

    SET whole = FLOOR(number);
    SET dec1 = number - whole;

    SET res = CONCAT(BIN(whole), '.');

    WHILE 0 < places DO
        SET dec1 = dec1 * 2;

        SET whole = FLOOR(dec1);
        SET dec1 = dec1 - whole;

        SET res = CONCAT(res, whole);
        SET places = places - 1;
    END WHILE;
    RETURN res;
END//

DROP FUNCTION IF EXISTS IEEE754;

CREATE FUNCTION IEEE754(n FLOAT) RETURNS CHAR(8)
BEGIN
    DECLARE sign INT;
    DECLARE whole VARCHAR(256);
    DECLARE dec1 VARCHAR(256);
    DECLARE exponent INT;
    DECLARE mantissa VARCHAR(256);

    # check if number is negative
    SET sign = 0;
    IF n < 0 THEN
        SET sign = 1;
        SET n = n * -1;
    END IF;

    # convert float to binary
    SET dec1 = FLOAT_BIN(n, 256); # good upper bound is twice the max exponent

    # separate the decimal part
    # and the whole number part
    SET whole = SUBSTRING_INDEX(dec1, '.', 1);
    SET dec1 = SUBSTRING_INDEX(dec1, '.', -1);

    # calculating the exponent(E)

    IF n >= 1 THEN
        SET exponent = LENGTH(whole) - 1;
        SET mantissa = CONCAT(SUBSTR(whole, 2), dec1);
    ELSE
        SET exponent = -1;
        WHILE SUBSTR(dec1, 1, 1) = '0' AND exponent > -127 DO
            SET exponent = exponent - 1;
            SET dec1 = SUBSTR(dec1, 2);
        END WHILE;

        IF exponent = -127 THEN
            SET mantissa = dec1;
        ELSE
            SET mantissa = SUBSTR(dec1, 2);
        END IF;
    END IF;

    RETURN CONV(CONCAT(sign, LPAD(BIN(127 + exponent), 8, '0'), RPAD(mantissa, 23, '0')), 2, 16);
END//

DROP FUNCTION IF EXISTS IEEE754_DOUBLE;

CREATE FUNCTION IEEE754_DOUBLE(n FLOAT) RETURNS CHAR(16)
BEGIN
    DECLARE sign INT;
    DECLARE whole VARCHAR(4096);
    DECLARE dec1 VARCHAR(4096);
    DECLARE exponent INT;
    DECLARE mantissa VARCHAR(4096);

    # check if number is negative
    SET sign = 0;
    IF n < 0 THEN
        SET sign = 1;
        SET n = n * -1;
    END IF;

    # convert float to binary
    SET dec1 = FLOAT_BIN(n, 4096);

    # separate the decimal part
    # and the whole number part
    SET whole = SUBSTRING_INDEX(dec1, '.', 1);
    SET dec1 = SUBSTRING_INDEX(dec1, '.', -1);

    # calculating the exponent(E)

    IF n >= 1 THEN
        SET exponent = LENGTH(whole) - 1;
        SET mantissa = CONCAT(SUBSTR(whole, 2), dec1);
    ELSE
        SET exponent = -1;
        WHILE SUBSTR(dec1, 1, 1) = '0' AND exponent > -1023 DO
                SET exponent = exponent - 1;
                SET dec1 = SUBSTR(dec1, 2);
            END WHILE;

        IF exponent = -1023 THEN
            SET mantissa = dec1;
        ELSE
            SET mantissa = SUBSTR(dec1, 2);
        END IF;
    END IF;

    RETURN CONV(CONCAT(sign, LPAD(BIN(1023 + exponent), 11, '0'), RPAD(mantissa, 52, '0')), 2, 16);
END//

DELIMITER ;