How to convert integer to hex notation? - firebird

Using: Firebird 2.5.3
In a stored procedure (PSQL), converting a number from hex notation to decimal notation is done easily:
DECLARE VARIABLE I INTEGER;
BEGIN
I = CAST('0x0FFFE' AS INTEGER); -- I will have the value 65534
How can the reverse be achieved? ie. Convert from decimal notation to hex notation?

Short of using a UDF (which would mean using an external library file), the solution is to write a stored procedure to accomplish this:
SET TERM ^^ ;
CREATE PROCEDURE INTTOHEX (
INPUTNUMBER BigInt)
returns (
OUTPUTNUMBER VarChar(8))
AS
DECLARE VARIABLE Q BigInt;
DECLARE VARIABLE R BigInt;
DECLARE VARIABLE T BigInt;
DECLARE VARIABLE H VARCHAR(1);
DECLARE VARIABLE S VARCHAR(6);
begin
/* Max input value allowed is: 4294967295 */
S = 'ABCDEF';
Q = 1;
OUTPUTNUMBER = '';
T = INPUTNUMBER;
WHILE (Q <> 0) DO
BEGIN
Q = T / 16;
R = MOD(T, 16);
T = Q;
IF (R > 9) THEN
H = SUBSTRING(S FROM (R-9) FOR 1);
ELSE
H = R;
OUTPUTNUMBER = H || OUTPUTNUMBER ;
END
SUSPEND;
end ^^
SET TERM ; ^^
You can call this stored procedure from standard SQL or another stored procedure like this:
For example:
SELECT OUTPUTNUMBER FROM INTTOHEX(65534);

just did a short firebird function,
could handle bigger number,
maybe could help someone
CREATE OR ALTER FUNCTION INT64TOHEX (
C BIGINT)
RETURNS VARCHAR(32)
AS
DECLARE VARIABLE IREM INTEGER;
DECLARE VARIABLE HEX VARCHAR(32);
BEGIN
IREM = MOD(C, 0XFF);
HEX = '';
WHILE (IREM > 0) DO
BEGIN
HEX = SUBSTRING('0123456789abcdef' FROM BIN_SHR(BIN_AND(C, 0XFF), 4) + 1 FOR 1) || SUBSTRING('0123456789abcdef' FROM BIN_AND(BIN_AND(C, 0XFF), 15) + 1 FOR 1) || HEX;
C = BIN_SHR(C, 8);
IREM = MOD(C, 0XFF);
END
RETURN TRIM(HEX);
END

Related

Function to return N significant digits of given number

I have seen several questions on this topic, but the answers do not seem useful to me.
I must create a function in PostgreSQL 10.5 that returns a number with N significant digits. I have tried different solutions for this problem, however I have a problem with a particular case. Below the example, where nmNumber is the number of the input parameters and nmSf is the number of significant digits.
SELECT round(nmNumber * power(10, nmSf-1-floor(log(abs(nmNumber ))))) / power(10, nmSf-1-floor(log(abs(nmNumber)))) result1,
round(nmNumber, cast(-floor(log(abs(nmNumber))) as integer)) result2,
floor(nmNumber / (10 ^ floor(log(nmNumber) - nmSf + 1))) * (10 ^ floor(log(nmNumber) - nmSf + 1)) result3;
If nmNumber = 0.0801 and nmSf = 2 then:
result 1 = 0.08; result2 = 0.08; result 3 = 0.08
The three results are incorrect given that:
The zeros immediately after the decimal point are not significant digits.
All non-zero digits are significant.
The zeros after digits other than zero in a decimal are significant.
According to point 3, the correct result of the previous example is: 0.080 and not 0.08 and although mathematically it turns out to be the same, visually I must obtain this result. Some idea of ​​how I can solve my problem? I suppose that returning a VARCHAR in exchange for a NUMERIC is part of the solution to be proposed.
Some idea or I'm missing something. Thank you.
This would implement what you ask for:
CREATE OR REPLACE FUNCTION f_significant_nr(_nr numeric, _sf int, OUT _nr1 text) AS
$func$
DECLARE
_sign bool; -- record negative sign
_int int; -- length of integral part
_nr_text text; -- intermediate text state
BEGIN
IF _sf < 1 THEN
RAISE EXCEPTION '_sf must be > 0!';
ELSIF _nr IS NULL THEN
RETURN; -- returns NULL
ELSIF _nr = 0 THEN
_nr1 := '0'; RETURN;
ELSIF _sf >= length(translate(_nr::text, '-.','')) THEN -- not enough digits, optional shortcut
_nr1 := _nr; RETURN;
ELSIF abs(_nr) < 1 THEN
_nr1 := COALESCE(substring(_nr::text, '^.*?[1-9]\d{' || _sf-1 || '}'), _nr::text); RETURN;
ELSIF _nr < 0 THEN -- extract neg sign
_sign := true;
_nr := _nr * -1;
END IF;
_int := trunc(log(_nr))::int + 1; -- <= 0 was excluded above!
IF _sf < _int THEN -- fractional digits not touched
_nr1 := rpad(left(_nr::text, _sf), _int, '0');
ELSE
_nr1 := trunc(_nr)::text;
IF _sf > _int AND (_nr % 1) > 0 THEN -- _sf > _int and we have significant fractional digits
_nr_text := right((_nr % 1)::text, -1); -- remainder: ".123"
_nr1 := _nr1 || COALESCE(substring(_nr_text, '^.*?[1-9]\d{' || (_sf - _int - 1)::text || '}'), _nr_text);
END IF;
END IF;
IF _sign THEN
_nr1 := '-' || _nr1;
END IF;
END
$func$ LANGUAGE plpgsql;
db<>fiddle here - with test case.
Deals with everything you throw at it, incl NULL, 0, 0.000 or negative numbers.
But I have doubts about your point 3 as commented.
postgres knows how to do that (even point 3), you just need to ask it the right way.
create or replace function
sig_fig(num numeric,prec int) returns numeric
language sql as
$$
select to_char($1, '9.'||repeat('9',$2-1)||'EEEE')::numeric
$$;
That creates a format string producing scientific
notation with a 3 digit mantissa. Uses that that
to get the number as text Then converts that back to numeric yielding a conventional number with that many significant figures.
demo:
with v as ( values (3.14159),(1234567),(0.02),(1024),(42),(0.0098765),(-6666) ) select column1 ,sig_fig(column1,3) as "3sf" from v;
column1 | 3sf
-----------+---------
3.14159 | 3.14
1234567 | 1230000
0.02 | 0.0200
1024 | 1020
42 | 42.0
0.0098765 | 0.00988
-6666 | -6670
(7 rows)

Reduce length of the pseudo-encrypt function ouput

i have a question about the pseudo-encrypt function for postgres.
Is there any way that I can reduce the output to 6? I really like this function and want to use it, but only need a output between 1 and 999999.
This question is related to my last question. I want to use it to created unqiue numbers between 1 and 999999.
Thank you.
Use mod on the generated value to generate number in range from start_value to end_value:
select start_value + mod(pseudo_encrypt(number), end_value - start_value + 1);
For your case this will be look like:
select 1 + mod(pseudo_encrypt(23452), 999999);
It's not quite straightforward to set an upper bound of 999999, as the algorithm operates on blocks of bits, so it's hard to get away from powers of two.
You can work around this by cycle walking - just try encrypt(n), encrypt(encrypt(n)), encrypt(encrypt(encrypt(n)))... until you end up with a result in the range [1,999999]. In the interest of keeping the number of iterations to a minimum, you want to adjust the block size to get you as close to this range as possible.
This version will let you specify a range for the input/output:
CREATE OR REPLACE FUNCTION pseudo_encrypt(
value INT8,
min INT8 DEFAULT 0,
max INT8 DEFAULT (2^62::NUMERIC)-1
) RETURNS INT8 AS
$$
DECLARE
rounds CONSTANT INT = 3;
L INT8[];
R INT8[];
i INT;
blocksize INT;
blockmask INT8;
result INT8;
BEGIN
max = max - min;
value = value - min;
IF NOT ((value BETWEEN 0 AND max) AND (max BETWEEN 0 AND 2^62::NUMERIC-1)) THEN
RAISE 'Input out of range';
END IF;
blocksize = ceil(char_length(ltrim(max::BIT(64)::TEXT,'0'))/2.0);
blockmask = (2^blocksize::NUMERIC-1)::INT8;
result = value;
LOOP
L[1] = (result >> blocksize) & blockmask;
R[1] = result & blockmask;
FOR i IN 1..rounds LOOP
L[i+1] = R[i];
R[i+1] = L[i] # ((941083981*R[i] + 768614336404564651) & blockmask);
END LOOP;
result = (L[rounds]::INT8 << blocksize) | R[rounds];
IF result <= max THEN
RETURN result + min;
END IF;
END LOOP;
END;
$$
LANGUAGE plpgsql STRICT IMMUTABLE;
I can't guarantee its correctness, but you can easily show that it maps [1,999999] back to [1,999999]:
SELECT i FROM generate_series(1,999999) s(i)
EXCEPT
SELECT pseudo_encrypt(i,1,999999) FROM generate_series(1,999999) s(i)

Got "Boolean" expected "LongInt" pascal

I get this error on my insertion sort algorithm:
insertionsort.lpr(19,17) Error: Incompatible types: got "Boolean" expected "LongInt"
Here's the line 19 of my code
while j > 0 and A[j]>key do
I have tried googling all over the internet but i couldn't find any syntax errors or anything.
Here's the full code if it helps :
program instert;
uses crt;
const
N = 5;
var
i:integer;
j:integer;
key:integer;
A : Array[1..N] of Integer;
procedure insertionsort;
begin
for i := 2 to N do
begin
key := A[1];
j:= i - 1;
while j > 0 and A[j]>key do
begin
A[j+1] := A[j] ;
j := j-1;
end;
A[j+1] := key ;
end;
end;
begin
A[1]:= 9;
A[2]:= 6;
A[3]:= 7;
A[4]:= 1;
A[5]:= 2;
insertionsort;
end.
I also get the same error on the bubble sort algorithm i did. Here's the error line
bubblesort.lpr(26,14) Error: Incompatible types: got "Boolean" expected "LongInt"
Here's line 26 of my algorithm:
until flag = false or N = 1 ;
Here's the full code:
program bubblesort;
uses crt;
var
flag:boolean;
count:integer;
temp:integer;
N:integer;
A : Array[1..N] of Integer;
procedure bubblesort ;
begin
Repeat
flag:=false;
for count:=1 to (N-1) do
begin
if A[count] > A[count + 1] then
begin
temp := A[count];
A[count] := A[count + 1];
A[count] := temp;
flag := true;
end;
end;
N := N - 1;
until flag = false or N = 1 ;
end;
begin
A[1]:= 9;
A[2]:= 6;
A[3]:= 7;
A[4]:= 1;
A[5]:= 2;
N := 5;
bubblesort;
end.
In Pascal, boolean operators and and or have higher precedence than the comparison operators >, =, etc. So in the expression:
while j > 0 and A[j] > key do
Given that and has higher precedence, Pascal sees this as:
while (j > (0 and A[j])) > key do
0 and A[j] are evaluated as a bitwise and (since the arguments are integers) resulting in an integer. Then the comparison, j > (0 and A[j]) is evaluated as a boolean result, leaving a check of that with > key, which is boolean > longint. You then get the error that a longint is expected instead of the boolean for the arithmetic comparison.
The way to fix it is to parenthesize:
while (j > 0) and (A[j] > key) do ...
The same issue applies with this statement:
until flag = false or N = 1 ;
which yields an error because or is higher precedence than =. So you can parenthesize:
until (flag = false) or (N = 1);
Or, more canonical for booleans:
until not flag or (N = 1); // NOTE: 'not' is higher precedence than 'or'
When in doubt about the precedence of operators, parenthesizing is a good idea, as it removes the doubt about what order operations are going to occur.

CRC32 function with PL/pgSQL

How to compute a 32 bits cyclic redundancy check (CRC-32) as a function in PostgreSQL, the same way as MySQL?
You can create the function yourself, this is a working example for PostgreSQL 9.6
CREATE OR REPLACE FUNCTION crc32(text_string text) RETURNS bigint AS $$
DECLARE
tmp bigint;
i int;
j int;
byte_length int;
binary_string bytea;
BEGIN
IF text_string = '' THEN
RETURN 0;
END IF;
i = 0;
tmp = 4294967295;
byte_length = bit_length(text_string) / 8;
binary_string = decode(replace(text_string, E'\\\\', E'\\\\\\\\'), 'escape');
LOOP
tmp = (tmp # get_byte(binary_string, i))::bigint;
i = i + 1;
j = 0;
LOOP
tmp = ((tmp >> 1) # (3988292384 * (tmp & 1)))::bigint;
j = j + 1;
IF j >= 8 THEN
EXIT;
END IF;
END LOOP;
IF i >= byte_length THEN
EXIT;
END IF;
END LOOP;
RETURN (tmp # 4294967295);
END
$$ IMMUTABLE LANGUAGE plpgsql;
Inspired from an old post with an non crc32 accepted answer. I couldn't find the original code from thinking sphinx.
create it in PG11.
text to crc32(for Little-endian)。
result is equal to java.util.zip.CRC32.
if you want crc32(t text), you can select crc32_update(0, t)
create or replace function crc32_update(crc bigint, t text) returns bigint as $$
declare
bytes bytea;
byte bigint;
len bigint;
long_mask bigint = 4294967295; -- 0xFFFFFFFF
byte_mask integer = 255; -- 0xFF
rt8_mask bigint = 16777215; -- 0xFF000000
crc_table bigint[] = array[
0, 1996959894, -301047508, -1727442502, 124634137, 1886057615, -379345611, -1637575261,
249268274, 2044508324, -522852066, -1747789432, 162941995, 2125561021, -407360249, -1866523247,
498536548, 1789927666, -205950648, -2067906082, 450548861, 1843258603, -187386543, -2083289657,
325883990, 1684777152, -43845254, -1973040660, 335633487, 1661365465, -99664541, -1928851979,
997073096, 1281953886, -715111964, -1570279054, 1006888145, 1258607687, -770865667, -1526024853,
901097722, 1119000684, -608450090, -1396901568, 853044451, 1172266101, -589951537, -1412350631,
651767980, 1373503546, -925412992, -1076862698, 565507253, 1454621731, -809855591, -1195530993,
671266974, 1594198024, -972236366, -1324619484, 795835527, 1483230225, -1050600021, -1234817731,
1994146192, 31158534, -1731059524, -271249366, 1907459465, 112637215, -1614814043, -390540237,
2013776290, 251722036, -1777751922, -519137256, 2137656763, 141376813, -1855689577, -429695999,
1802195444, 476864866, -2056965928, -228458418, 1812370925, 453092731, -2113342271, -183516073,
1706088902, 314042704, -1950435094, -54949764, 1658658271, 366619977, -1932296973, -69972891,
1303535960, 984961486, -1547960204, -725929758, 1256170817, 1037604311, -1529756563, -740887301,
1131014506, 879679996, -1385723834, -631195440, 1141124467, 855842277, -1442165665, -586318647,
1342533948, 654459306, -1106571248, -921952122, 1466479909, 544179635, -1184443383, -832445281,
1591671054, 702138776, -1328506846, -942167884, 1504918807, 783551873, -1212326853, -1061524307,
-306674912, -1698712650, 62317068, 1957810842, -355121351, -1647151185, 81470997, 1943803523,
-480048366, -1805370492, 225274430, 2053790376, -468791541, -1828061283, 167816743, 2097651377,
-267414716, -2029476910, 503444072, 1762050814, -144550051, -2140837941, 426522225, 1852507879,
-19653770, -1982649376, 282753626, 1742555852, -105259153, -1900089351, 397917763, 1622183637,
-690576408, -1580100738, 953729732, 1340076626, -776247311, -1497606297, 1068828381, 1219638859,
-670225446, -1358292148, 906185462, 1090812512, -547295293, -1469587627, 829329135, 1181335161,
-882789492, -1134132454, 628085408, 1382605366, -871598187, -1156888829, 570562233, 1426400815,
-977650754, -1296233688, 733239954, 1555261956, -1026031705, -1244606671, 752459403, 1541320221,
-1687895376, -328994266, 1969922972, 40735498, -1677130071, -351390145, 1913087877, 83908371,
-1782625662, -491226604, 2075208622, 213261112, -1831694693, -438977011, 2094854071, 198958881,
-2032938284, -237706686, 1759359992, 534414190, -2118248755, -155638181, 1873836001, 414664567,
-2012718362, -15766928, 1711684554, 285281116, -1889165569, -127750551, 1634467795, 376229701,
-1609899400, -686959890, 1308918612, 956543938, -1486412191, -799009033, 1231636301, 1047427035,
-1362007478, -640263460, 1088359270, 936918000, -1447252397, -558129467, 1202900863, 817233897,
-1111625188, -893730166, 1404277552, 615818150, -1160759803, -841546093, 1423857449, 601450431,
-1285129682, -1000256840, 1567103746, 711928724, -1274298825, -1022587231, 1510334235, 755167117
];
begin
crc = ~crc;
len = bit_length(t) / 8;
bytes = decode(t, 'escape');
for i in 0..len-1 loop
byte = (get_byte(bytes, i))::bigint;
crc = (crc >> 8 & rt8_mask) # crc_table[((crc # byte) & byte_mask) + 1];
end loop;
crc = ~crc;
return crc & long_mask;
end
$$ immutable language plpgsql
If you want a checksum of the results which does not need to be crc32, you can use md5:
select sum(('x' || lpad(substring(md5(mycolumn), 27, 6), 8, '0'))::bit(32)::int) from mytable
md5 returns hex (128 bits). I use the final 6 characters of the md5 so it does not overflow an int. If the sum overflows an int, it may error. This should give a rudimentary checksum of the results.
SELECT 'xffffffff'::bit(32)::int;
> -1
SELECT 'x7fffffff'::bit(32)::int + 1;
ERROR: integer out of range
SELECT 'x7fffffffffffffff'::bit(64)::bigint + 1;
ERROR: bigint out of range

What causes problems with this piece of code?

I was just wondering why this certain problem happens to me. If you can help me, I will appreciate it.
Program factorial;
uses crt;
var
f, i: Integer;
begin
f:=1;
for i:=1 to 5 do
f:= f * i;
write(f);
readkey;
end.
Okay, That works fine and the result is 120. And it's true.
Now, here's the problem. If I asked the user to enter the value of the number, it won't work.
Program factorial;
uses crt;
var
i,r: Integer;
begin
write('Enter the number');
read(r);
for i:=1 to r do
r:= r * i;
write(r);
readkey;
end.
If I wrote 5, the output will be 600.
You are using the value r as the stopping condition of the loop and modifying the value in the loop.
Program factorial;
uses crt;
var
i,r, f: Integer;
begin
write('Enter the number');
read(r);
f := 1;
for i:=1 to r do
f:= f * i;
write(f);
readkey;
end.
You reuse the r variable. If you input 5 for r your program will in effect one to many times. You should start with 1 as the first f.
Program factorial;
uses crt;
var
i,r, f: Integer;
begin
write('Enter the number');
read(r);
f:=1
for i:=1 to r do
f:= f * i;
write(r);
readkey;
end.
try:
Program factorial;
uses crt;
var
i,r,x: Integer;
begin
write('Enter the number');
read(x);
r:=1
for i:=1 to x do
r:= r * i;
write(r);
readkey;
end.