Skocz do zawartości
PrzMas

Systemy liczbowe

Rekomendowane odpowiedzi

W niniejszym temacie publikuję zestaw funkcji do przeliczania
liczby całkowitej na dowolny system liczbowy
(2-36) i
z dowolnego systemu liczbowego (2-36) na liczbę całkowitą.


Wymagana biblioteka (plik uint.inc) do operacji na liczbach nieujemnych (unsigned integer):

[pastebin]

Implementacje (i makrodefinicje) przedmiotowych w temacie funkcji:

Spoiler

stock int2str(val, const base, maxlen= 0, bool: signed= false)
{
  new str[1+32+1]= "0";
  if (2 <= base <= 36 && (val != 0 || maxlen > 0))
  {
    new val2= val, idx= 0;
    new const chr[]= "0123456789abcdefghijklmnopqrstuvwxyz";
    if (signed && val&0x80000000) { val2= 0xffffffff^--val; str[0]= '-'; idx++; }
    for(new unsigned: dec= val2; dec != 0; idx++) dec /= base;
    if (0 < maxlen <= 32 && maxlen > idx) idx= (str[0] == '-')?(++maxlen):(maxlen);
    for(new unsigned: dec= val2; dec != 0 || (idx > 0 && str[idx-1] != '-');) { str[--idx]= chr[dec%base]; dec /= base; }
  }

  return str;
}

 

Spoiler

stock str2int(str[], const base)
{
  new res= 0;
  if (str[0] != 0 && 1 <= base <= 36)
  {
    for(new i= strlen(str)-1, val= str[i], exp= 1; i >= 0; val= str[--i])
    {
      if ('0' <= val <= '9') val= val -'0';
      else if ('A' <= val <= 'Z') val= val -'A' +10;
      else if ('a' <= val <= 'z') val= val -'a' +10;
      else if (val == '-') return 0xffffffff^--res;
      else return 0;

      res += (val*exp);
      exp *= base;
    }
  }

  return res;
}

 

Spoiler

#define BIN  2  // binary
#define TRI  3  // trinary
#define SETP 7  // septem
#define OCT  8  // octal
#define DEC  10 // decimal
#define DDEC 12 // duodecimal
#define HEX  16 // hexadecimal

// ...

#define uint2bin(%0) int2str(%0, BIN, 0, false)
#define uint2oct(%0) int2str(%0, OCT, 0, false)
#define uint2dec(%0) int2str(%0, DEC, 0, false)
#define uint2hex(%0) int2str(%0, HEX, 0, false)

#define int2bin(%0) int2str(%0, BIN, 0, true)
#define int2oct(%0) int2str(%0, OCT, 0, true)
#define int2dec(%0) int2str(%0, DEC, 0, true)
#define int2hex(%0) int2str(%0, HEX, 0, true)

#define bin2int(%0) str2int(%0, BIN)
#define oct2int(%0) str2int(%0, OCT)
#define dec2int(%0) str2int(%0, DEC)
#define hex2int(%0) str2int(%0, HEX)

Edytowano: 2016-05-04


Sposób użycia:

Spoiler

Kod:


printf("int2dec: %s", int2dec(0xf3f3f3f3));   // 1
printf("int2hex: %s", int2hex(0xf3f3f3f3));   // 2
printf("uint2dec: %s", uint2dec(0xf3f3f3f3)); // 3
printf("uint2hex: %s", uint2hex(0xf3f3f3f3)); // 4

Wynik:


int2dec: -202116109  // 1
int2hex: -c0c0c0d    // 2
uint2dec: 4092851187 // 3
uint2hex: f3f3f3f3   // 4

 

Spoiler

Kod:


printf("dec2int: %s", int2dec(dec2int("4092851187")));  // 1
printf("hex2int: %s", int2dec(hex2int("f3f3f3f3")));    // 2
printf("dec2int: %s", uint2dec(dec2int("-202116109"))); // 3
printf("hex2int: %s", uint2dec(hex2int("-c0c0c0d")));   // 4

Wynik:


dec2int: -202116109 // 1
hex2int: -202116109 // 2
dec2int: 4092851187 // 3
hex2int: 4092851187 // 4

 

Spoiler

Kod:


printf("%s", int2str(0xff00ff00, HEX, 0, true));   // 1
printf("%s", int2str(0xff00ff00, HEX, 5, true));   // 2
printf("%s", int2str(0xff00ff00, HEX, 10, true));  // 3
printf("%s", int2str(0xff00ff00, HEX, 15, true));  // 4
printf("%s", int2str(0xff00ff00, HEX, 0, false));  // 5
printf("%s", int2str(0xff00ff00, HEX, 5, false));  // 6
printf("%s", int2str(0xff00ff00, HEX, 10, false)); // 7
printf("%s", int2str(0xff00ff00, HEX, 15, false)); // 8

Wynik:


-ff0100          // 1
-ff0100          // 2
-0000ff0100      // 3
-000000000ff0100 // 4
ff00ff00         // 5
ff00ff00         // 6
00ff00ff00       // 7
0000000ff00ff00  // 8

Edytowano: 2016-05-04


Objaśnienie:

Potrzeba zastosowania powyższych rozwiązań bierze się stąd, że wartości liczbowe mają swoje ograniczenia, są zapisane na 32-bitach ze znakiem lub bez (signed/unsigned):

signed integer:   0x80000000 (-2147483648) - 0x7fffffff (2147483647)
unsigned integer: 0x00000000 (0)           - 0xffffffff (4294967295)

oraz dlatego, że nie dostarczono takich funkcji ze środowiskiem SA-MP, natomiast funkcje strval i valstr"dziurawe" - mają ograniczone możliwości i są niezabezpieczone.

Jeśli zależy nam na wartościach ujemnych to pozostajemy przy zwykłych liczbach Pawn, deklarowanych następująco:

new val= 1234; // signed

jednak mają one ograniczony przedział liczbowy (patrz wyżej). Natomiast jeżeli wiemy, że dla danej liczby nie chcemy wartości ujemnych i zachodzi potrzeba zastosowania większego zakresu liczbowego, to w tym celu zmienną przechowującą duże wartości, którą będziemy traktować jak nieujemną, należy oznaczyć następująco:

new uint: val1= 1234; // unsigned
new unsigned val2= 1234; // unsigned

Plik uint.inc najlepiej wkleić do folderu pawno\include, a w pliku gdzie znajdują się implementacje powyższych funkcji należy dopisać:

#include <uint>

a jeśli niniejszy plik został wklejony do folderu include, znajdującym się w głównym katalogu serwera to:

#include "..\include\uint.inc"

 

Edytowane przez PrzMas
maxlen

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

  • Przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×