Arhn - архитектура программирования

Преобразование MySQL DECIMAL в шестнадцатеричное представление IEEE с плавающей запятой

Я пытаюсь добавить шестнадцатеричные данные в шестнадцатеричную строку, и мне нужно добавить в эту строку числа с плавающей запятой, используя их представление 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, содержащий шестнадцатеричную строку. Этот трюк работает для целых чисел, но для десятичных он обрезает десятичную часть и преобразует целую часть в шестнадцатеричное целое число. Как я могу преобразовать значение в шестнадцатеричное представление IEEE с плавающей запятой десятичного числа, если размер десятичного числа фиксирован (либо java float, либо double)?


  • Я бы преобразовал 10.0 в A и 10.9 также в A. Я не уверен, что именно вы хотите сделать. не могли бы вы привести несколько примеров, пожалуйста 13.11.2019
  • @nbk Я хочу, чтобы 10.9 превратилось в 412E6666, предполагая, что это число с плавающей запятой одинарной точности (float). 412E6666 - это шестнадцатеричное представление IEEE 10.9 в двоичном формате. 13.11.2019
  • Вам нужна сохраненная функция (или эквивалентный код), которая принимает строку 412E6666 и возвращает значение, которое при сохранении в FLOAT было бы 10,9? (Я знаю, как это сделать в PHP; я почешу голову, делая это в MySQL.) Примечание: тип типа DECIMAL хранится иначе, чем FLOAT. 18.11.2019
  • @RickJames Нет, я хочу наоборот. У меня есть DECIMAL, и я хочу преобразовать его в этот 412E6666, который я смогу прочитать позже (на Java). Мне в основном нужен способ хранения IEEE (те, которые мы могли бы легко реализовать на Java, PHP или C). На самом деле меня не волнует, как MySQL хранит FLOAT. Я читал больше о представлении с плавающей запятой, и мы могли легко найти смещенную экспоненту, знаковый бит и мантиссу, но объединение их в INTEGER было бы сложной задачей без бинарных операторов. (‹<, & и | в основном) 18.11.2019
  • @Winter - MySQL действительно имеет ‹<, & и | (с BIGINT), но у него нет никакого способа нарушить проверку типов, чтобы попасть между типами данных FLOAT и BIGINT. 19.11.2019

Ответы:


1

Итак, через некоторое время я получил решение, которое состоит из двух функций и одной хранимой процедуры (это также может быть реализовано как функция, но мне нравятся процедуры.

Это основано на этом скрипте Python, https://www.geeksforgeeks.org/python-program-to-present-floating-number-as-hexadecimal-by-ieee-754-standard/

и использует следующий подход

  • Проверьте, положительное или отрицательное число. Сохраните знак как 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 ;

И последняя хранимая процедура

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
21.11.2019

2

Хотя в ответе @ nbk была правильная идея, его реализация не работала для субнормальных чисел и реализации для плавающих чисел двойной точности точка отсутствовала. Вот упрощенная версия его ответа, поддерживающего одинарную и двойную точность и работу с субнормальными числами. Мне лично не нужно было преобразовывать запятые в десятичные дроби, потому что мой язык базы данных - английский, но в вашем случае вам, возможно, придется.

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 ;
05.12.2019

3

Это невозможно сделать в MySQL. Даже новенький (8.0.17):

CAST(UNHEX('412E6666') AS FLOAT)

Кроме того, нет возможности пойти в другом направлении, поскольку любая форма CAST или HEX будет принимать только строку, то есть «10.9», а не биты / байты / шестнадцатеричные числа 10.9.

Если вы сможете отступить на один шаг, возможно, более крупную цель можно будет достичь каким-то другим способом.

18.11.2019
  • Что, если мы сделаем это вручную, найдя смещенную экспоненту, знаковый бит и мантиссу, а затем сложив их вместе? В MySQL отсутствуют побитовые операции для этого? 18.11.2019
  • Также вопрос не в том, чтобы преобразовать представление IEEE в FLOAT или DECIMAL, а наоборот. 18.11.2019
  • Я добавил в свой ответ. Было бы сложно пойти в любом направлении, используя арифметику для извлечения / выталкивания битов / байтов числа. Смещенная экспонента, скрытый бит, денормализованные числа, inf / NaN и т. Д. 19.11.2019
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..