Author Topic: READMEM возвращает целые числа. Как пересчитать в 4 байта с точкой.  (Read 2903 times)

0 Members and 1 Guest are viewing this topic.

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Считываю координаты из процесса игрушки. READMEM возвращает целые числа. Как пересчитать в 4 байта с точкой.

Для примера:
в игре y=-5000.00   получаю -979615744, бегу на север(т.е. x не изменяется)
в игре y=-6000.00   получаю -977567744.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
мои наработки по переводу из 4 байт, полученных как целое число, в float. пока так и не понял откуда взять то, что после точки :( . но целую часть расчитывает вроде правильно. буду рад за инфу по определению циферак после точки.

конвертеры тут http://www.binaryconvert.com + калькулятор в помощь
брал инфу отсюль http://www.softelectro.ru/ieee754.html https://blog2k.ru/archives/3321

Code: (clickermann) [Select]

SUB(toBIN, $DEC) 
   $BIN = ""
 
   IF($DEC > 0)
      WHILE($DEC > 0)
         $DEC = $DEC/2
         IF($DEC > int($DEC))
            $BIN = STRCONCAT("1", $BIN)
         else
            $BIN = STRCONCAT("0", $BIN)
         END_IF
         $DEC = int($DEC)
      END_CYC
      WHILE(STRLEN ($BIN) < 32)       //4 байта
         $BIN = STRCONCAT("0", $BIN)
      END_CYC
   ELSE
      $DEC = abs($DEC+1)
      WHILE($DEC > 0)
         $DEC = $DEC/2
         IF($DEC > int($DEC))
            $BIN = STRCONCAT("0", $BIN)
         else
            $BIN = STRCONCAT("1", $BIN)
         END_IF
         $DEC = int($DEC)
      END_CYC
      WHILE(STRLEN ($BIN) < 32)       //4 байта
         $BIN = STRCONCAT("1", $BIN)
      END_CYC
   END_IF
 
END_SUB
 
 
 
SUB(toDEC, $BIN_str)
   $DEC = 0
   IF(ARRSIZE ($arr) = 0) 
      $num_arr = 1
      FOR($i=0,$i<32)
         arrpush($arr, $num_arr)
         $num_arr = $num_arr*2
      END_CYC
   END_IF
 
   FOR($i=0,$i < STRLEN($BIN_str))
      $DEC = $DEC + ($arr[$i]*int(STRCUT($BIN_str, STRLEN($BIN_str)-$i, 1)))
   END_CYC
END_SUB
 
 
////////////////////////////////////////////////////////////////////////////
 
toBIN(-979615744)     // твои 4 байта без точки
//toBIN(-977567744)  // -6000
//print($BIN)
 
 
toDEC(STRCUT ($BIN,2, 8))
$exp = $DEC - 127
//print($exp)
 
toDEC(STRCONCAT("1",STRCUT ($BIN,10, $exp)))
 
IF(STRCUT ($BIN,1,1) = 1)
   $DEC = $DEC*-1
END_IF
 
 
 
print($DEC)   // твое число с точкой, но только целая часть -5000
 
 
halt

на сегодня итак перегруз   :P
« Last Edit: January 14, 2018, 03:17:08 AM by dramster »

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Огромное спасибо.
Пойду допилю автопилот.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
все оказалось намного проще. вчера не дочитал до самого главного, есть готовая формула перевода из бинарного кода в число с точкой.
 
пример:

 число  -    01000011000110111010000000000000 , в целочисленном десятичном = 1125883904 (проверяем в калькуляторе)
 S- бит знака (31-й бит)  -  0
 E- смещенная экспонента (30-23 биты)  -  10000110
 M - остаток от мантиссы (22-0 биты)  -  00110111010000000000000

 формула:


для кликера это будет выглядеть так:

Code: (clickermann) [Select]
//$exp - экспонента в десятичном виде
//$mant - мантиса в десятичном виде
//$BIN = вся двоичная строка
 POW(-1,int(STRCUT ($BIN,1,1))) * pow(2,$exp-127) * (1+($mant/POW(2,23)))

после расчетов получаем 155.625, как и в примере http://www.softelectro.ru/ieee754.html §4.

код:
Code: (clickermann) [Select]
//перевод числа в двоичную строку $BIN  (строка выйдет длиной в 32бит)
SUB(dec_to_BIN, $DEC)
   $BIN = ""
   
   IF($DEC > 0)   //если положительное
      WHILE($DEC > 0)
         $DEC = $DEC/2
         IF($DEC > int($DEC))
            $BIN = STRCONCAT("1", $BIN)
         else
            $BIN = STRCONCAT("0", $BIN)
         END_IF
         $DEC = int($DEC)
      END_CYC
      WHILE(STRLEN ($BIN) < 32)       //4 байта
         $BIN = STRCONCAT("0", $BIN)
      END_CYC
   ELSE               //если отрицательное
      $DEC = abs($DEC+1)
      WHILE($DEC > 0)
         $DEC = $DEC/2
         IF($DEC > int($DEC))
            $BIN = STRCONCAT("0", $BIN)
         else
            $BIN = STRCONCAT("1", $BIN)
         END_IF
         $DEC = int($DEC)
      END_CYC
      WHILE(STRLEN ($BIN) < 32)       //4 байта
         $BIN = STRCONCAT("1", $BIN)
      END_CYC
   END_IF
   
END_SUB


//перевод из двоичной строки в десятичное число $DEC
SUB(bin_to_DEC, $BIN_str)
   $DEC = 0
   IF(ARRSIZE ($arr) = 0)
      $num_arr = 1
      FOR($i=0,$i<32)
         arrpush($arr, $num_arr)
         $num_arr = $num_arr*2
      END_CYC
   END_IF
   
   FOR($i=0,$i < STRLEN($BIN_str))
      $DEC = $DEC + ($arr[$i]*int(STRCUT($BIN_str, STRLEN($BIN_str)-$i, 1)))
   END_CYC
END_SUB


//перевод из целочисленного в дробное $float. целочисленное 4 байт -  long (Signed int) от -2147483648 до 2147483647
SUB(int_to_Float, $int_in)
     
   dec_to_BIN($int_in)
   
   bin_to_DEC(STRCUT ($BIN,2, 8))
   $exp = $DEC   //экспонента в десятичном
   
   bin_to_DEC(STRCUT ($BIN,10, 32))
   $mant = $DEC   //мантиса в десятичном
   
   $float =  POW(-1,int(STRCUT ($BIN,1,1))) * pow(2,$exp-127) * (1+($mant/POW(2,23)))

END_SUB

///////////////////////////////////////////////////////////////////////////////
//основной код

int_to_Float(-979615744)
print($float)  //  -5000

int_to_Float(1125883904)
print($float)  //  155.625


halt




 

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Перекодирование 4 байтного числа с плавающей точкой (в СЕ тип Float; в Delphi тип Single), полученного функцией READMEM, в целое число.

Поскольку CALL("Plugin.DLL", ...) передает в DLL и принимает  числа в диапазоне от
-2 147 483 648 до 2 147 483 647, а READMEM считывает беззнаковое число в диапазоне от
0 до 4294967295, то READMEM должен считывать это число не 1 раз по 4, а 2 раза по 2 байта с шагом в 2 байта.

CALL("float_int".dll, x0, x1)
x0 - старшие байты
x1 - младшие байты

Code: (clickermann) [Select]
CALL("float_int.dll", 0xC67b, 0xd000)
print($_return1)
halt

Код float_int.dll на DELPHI
Code: (DELPHI) [Select]
library float_int;

uses
  SysUtils;
//------------------------------------------------------------------------------
// Основное тело функции, идет на экспорт, вызывается из кликера
function execute( _mas: pInteger; _size: Integer): Integer; export; stdcall;
type
  pIntArr = array[0..0] of Integer;
var
  tmp, tmp0, tmp1: Integer;
  sum: Int64;
  float: Single;
begin
 // _mas  - указатель на начало массива параметров integer
 // _size - размер массива (число параметров)
   tmp0:= pIntArr(_mas^)[0];
   tmp1:= pIntArr(_mas^)[_size-1];
   sum:= tmp0*65536 + tmp1;
   Move(sum, float, 4);
   tmp:= Round(float);

  result:= tmp // присваиваем возвращаемое значение

end;
//------------------------------------------------------------------------------
 
// список экспорта
exports execute;
 
begin
  // тело пусто
end.

« Last Edit: September 01, 2018, 02:24:47 PM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
Перекодирование 4 байтного числа с плавающей точкой (в СЕ тип Float; в Delphi тип Single), полученного функцией READMEM, в целое число.

Поскольку CALL("Plugin.DLL", ...) передает в DLL и принимает  числа в диапазоне от
-2 147 483 648 до 2 147 483 647, а READMEM считывает беззнаковое число в диапазоне от
0 до 4294967295, то READMEM должен считывать это число не 1 раз по 4, а 2 раза по 2 байта с шагом в 2 байта.


Странно это как то. по сути то какая разница что там передается в длл если это по сути тупо 4 байта. Может кликер че там делает, что они 8байтными в какойто момент становятся  :-\  ;D

как вариант:
Code: (clickermann) [Select]
print(0xC67bd000)  // 3330002944

print((0xC67bd000-2147483648)xor(-2147483648))  // -964964352

//в бинарном одно и тоже    11000110011110111101000000000000

halt

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
все оказалось намного проще. вчера не дочитал до самого главного, есть готовая формула перевода из бинарного кода в число с точкой.
 
пример:

 число  -    01000011000110111010000000000000 , в целочисленном десятичном = 1125883904 (проверяем в калькуляторе)
 S- бит знака (31-й бит)  -  0
 E- смещенная экспонента (30-23 биты)  -  10000110
 M - остаток от мантиссы (22-0 биты)  -  00110111010000000000000
...
...

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

Code: (clickermann) [Select]
$s = int($int/2147483648) //бит знака (31-й бит)
$exp = int($int/8388608) - $s*256 //смещенная экспонента (30-23 биты)
$mant = $int - $exp*8388608 - $s*2147483648 //остаток от мантиссы (22-0 биты)

Теперь можно переводить из int во float одной строкой, только она уж очень длинная  :D:
Code: (clickermann) [Select]
$float = POW(-1,int($int/2147483648)) * pow(2,int($int/8388608) - int($int/2147483648)*256-127) * (1+(($int - (int($int/8388608) - int($int/2147483648)*256)*8388608 - int($int/2147483648)*2147483648)/POW(2,23)))
Но данная формула работает только с беззнаковыми числами в диапазоне от 0 до 4294967295. Поэтому, если на входе отрицательное число, то переводим его в беззнаковое:

Code: (clickermann) [Select]
//перевод в беззнаковое число
IF($int < 0)
   $int = ($int xor (-2147483648)) + 2147483648
END_IF

Вместе перевод из целого числа в число с точкой выглядит так:
Code: (clickermann) [Select]
$int =   -979615744 // входящее число, целое

//перевод в беззнаковое число, если оно отрицательное
IF($int < 0)
   $int = ($int xor (-2147483648)) + 2147483648
END_IF

$float = POW(-1,int($int/2147483648)) * pow(2,int($int/8388608) - int($int/2147483648)*256-127) * (1+(($int - (int($int/8388608) - int($int/2147483648)*256)*8388608 - int($int/2147483648)*2147483648)/POW(2,23))) //расчет

print($float)  // -5000.00

halt

Добавлено:

Черт возьми, с чего я вообще взял, что нужны такие сложности для перевода отрицательного числа в беззнаковое  :o , ума не приложу. Взял тогда из предыдущего поста и немого изменил. А ведь достаточно просто прибавить или отнять 4294967296  :-\

Code: (clickermann) [Select]
//перевод в беззнаковое число, если оно отрицательное
IF($int < 0)
   $int = $int + 4294967296
END_IF


Исправленный код:
Code: (clickermann) [Select]
$int =  -1021599744 // входящее число, целое
 
//перевод в беззнаковое число, если оно отрицательное
IF($int < 0)
   $int = $int + 4294967296
END_IF
 
$float = POW(-1,int($int/2147483648)) * pow(2,int($int/8388608) - int($int/2147483648)*256-127) * (1+(($int - (int($int/8388608) - int($int/2147483648)*256)*8388608 - int($int/2147483648)*2147483648)/POW(2,23))) //расчет
 
print($float)  // -155.625
 
halt


« Last Edit: October 26, 2018, 12:39:58 AM by dramster »