powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / msb (most significant bit) на pl/sql есть готовый?
87 сообщений из 87, показаны все 4 страниц
msb (most significant bit) на pl/sql есть готовый?
    #39999748
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Внезапно потребовался алгоритм нахождения most significant bit на pl/sql
Хотелось бы, чтобы он надежно и быстро работал в диапазоне чисел:
0 - 170141183460469231731687303715884105727 (power(2,127)-1)

К сожалению, стандартный Log(2,x) не пригоден к использованию на всем диапазоне,
он быстро перестает различать Log(2,x) и Log(2, x-1), и трюками сорта Round(L,20) это не вылечишь.

Деление в цикле с наращиванием счётчика сразу отбрасываем.

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

Что к этому делу еще можно было бы приспособить, работающего хотя бы за логарифм от максимальной разрядности?
Может кто покажет прямые трюки со значениями utl_raw.cast_from_number.
Наверно что-то понятное и легко проверяемое там можно получать, стартуя с HexToRaw,
но меня пока смущает необходимость приведения числа к строковому представлению в таком варианте...

Что присоветуете, коллеги?
а вдруг где-то в стандартных пакетах стандартная функция зашита...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999751
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
msb применительно к какому типу данных?
За логарифм от разрядности - можно, полагаю, делением с двоичным поиском.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999753
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

неотрицательный number, укладывающийся в набор значений до максимального беззнакового 126-битного целого.
(диапазон я указал в первом посте)

Двоичный поиск я вижу..
Сейчас думаю,как понизить его глубину.
Вроде вдвое она должна разделяться в смысле максимального размера массива 63 а не 126,
но пока не сообразил, как это точно выписать.

Мне пока верится, что может найтись что-то чуть умнее/хитрее чем двоичный поиск.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999754
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
boobyДеление в цикле с наращиванием счётчика сразу отбрасываем.

А почему, собственно? Делишь, например, на 65536 пока значение не войдёт в диапазон целого
или хотя бы область определения логарифма.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999759
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
хитрее чем двоичный поиск.
to_char(…, 'fmXXX…') + length + …
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999761
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,

понял, 4 деления, на 64-битных значениях Log уже какие-то признаки жизни показывает вроде.
Спасибо. Положил на ум.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999765
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
booby
хитрее чем двоичный поиск.
to_char(…, 'fmXXX…') + length + …

to_char(…, 'fmXXX…') - такого сорта начало мне понятно, дальше что-то про utl_raw.

Что про цену to_char по отношению к логарифму можно сказать?
Как-то to_char меня пока пугает, побаиваюсь я его....
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999770
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
дальше что-то про utl_raw.
Нет.
Код: plsql
1.
length(hex)*4 - case substr(hex,1,1) … 0 … 1 … 2 … 3 end

...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999820
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic,

над raw код такого типа будет за "константу" отрабатывать, на varchar2 - время length,
например, окажется функцией текущей кодировки бд.

я подумаю.
msb - это фрагмент задачи.
Может быть, внутреннее представление данных в ней целиком и правда разумно будет перевести в raw,
отдавая только конечный результат в виде числа.
Поток входного to_char, мне пока всё равно не нравится.
Но, может быть...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999833
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Логарифм...
Есть жеж методы против Кольки Сапрыкина
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
declare 
--  x number := 10+16+32+100043435;
  x number := 170141183460469231731687303715884105727;
  y integer;
  function r(x integer, n number:=1) return integer is
     offs integer := power(2,n);
     x2 integer := trunc(x - bitand(x, x/offs)+ trunc(x/offs));
  begin
    if n < 7 and x2 <> x then return r(x2,n+1); 
    else return x2;
    end if;
  end;
begin 
  y := r(x/2)+1;
  dbms_output.put_line('Игого: '||y||' (0x'||to_char(y,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')||')');
end;
/
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #39999873
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

вау, красота-то какая.
Пойду глаза промою, а то слепит, аж невмоготу.

Премного благодарен.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000000
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

Еще раз спасибо.
И ведь я видел этот вариант в интернете, перед тем как писать, в виде кода на C,
но целиком просклизил мимо него, теперь даже досадно.
В частичное оправдание под капот кладу рядом с твоим, то, что получается после линеаризации и возвращения к "классическому" виду.

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

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
declare 
--  x number := 10+16+32+100043435;
  x number := power(2,126) + power(2,65)+power(2,33)+power(2,17)+power(2,9)+1; --170141183460469231731687303715884105727; -- 5316911983139663491615228241121378303; -- 170141183460469231731687303715884105727;
  y integer;
  function r(x integer, n number:=1) return integer is
     offs integer :=  power(2,n);
     x2 integer := trunc(x) - bitand(x, x/offs)+ trunc(x/offs);   
  begin
    if n < 7 and x2 <> x then return r(floor(x2),n+1); 
    else return x2;
    end if;
  end;
  ---- линеаризованный вариант
  function r2(px Number) return integer is
     offs Number;
     n_mask Number;
     x Number;
     x2 Number; 
     -- шаг вычисления, удваивающего число единиц от msb вправо
     Procedure step_mask 
     Is
     Begin
      offs := 2*offs; x := x2; n_mask := floor(x/offs);
      x2 := x - bitand(x, n_mask) + n_mask;   -- вычисляет битовый OR           
     End;    
  begin

    offs := 1;
    x2 := Floor(px); -- на моих данных это перестраховка
    -- 
    For i in 1..1
    Loop
      -- 1 (2 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;
      
      -- 2 (4 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;      
      
      -- 3 (8 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;
      
      -- 4 (16 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;      
      
      -- 5 (32 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;      
      
      -- 6 (64 соседних к msb bit-ов установлены в 1)
      step_mask(); 
      Exit When x=x2;      
      
      -- 7 (128 соседних к msb bit-ов установлены в 1)
      step_mask(); 
    End Loop;    
    -- здесь гарантированы все единицы, начиная с msb
    -- переходим в следующий разряд и возвращаем половину
    Return (x2+1)/2;
  end;  
begin 
  y := r(x/2)+1;
  dbms_output.put_line('Игого aa            : '||y||' (0x'||to_char(y,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')||')');
  y := r2(x);
  dbms_output.put_line('Игого bb, спасибо aa: '||y||' (0x'||to_char(y,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')||')');  
end;
/

...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000010
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
слепит, аж невмоготу.

Это от отсутствия bitOr :(
...кстати, я там накосячил с порядками. Рекурсия не n+1, а n*2 плюс поправить кондиции

...а если немного вспомнить алгебру, то можно и чуть попроще...

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
SQL> 
with s0 as
 (select power(2,127) x from dual
 union all select 258 from dual
 union all select 1 from dual
 union all select 0 from dual
 union all select abs(dbms_random.value(1,170141183460469231731687303715)) from dual
 union all select abs(dbms_random.value(1,170141183460469231731687303715884105727)) from dual
 union all select 170141183460469231731687303715884105727 from dual
 )
, s1 as  (select x, bitand(-x/2-1, -x/4-1) y from s0)
, s2 as  (select x, bitand(y, y/4 - 1) y from s1)
, s8 as  (select x, bitand(y, y/16 - 1) y from s2)
, s16 as (select x, bitand(y, y/256 - 1) y from s8)
, s32 as (select x, bitand(y, y/65536 - 1) y from s16)
, s64 as (select x, bitand(y, y/4294967296 - 1) y from s32)
, s128 as(select x, -(bitand(y, y/18446744073709551616 - 1)) y from s64)
select to_char(x,'fm9999999999999999999999999999999999999999') X_Dec
     , '0x'||to_char(x, 'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  X_Hex
     , to_char(y,'fm9999999999999999999999999999999999999999') MSB_Dec
     , '0x'||to_char(y, 'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  MSB_Hex
     , log(2,y) Msb_pos
from s128
;
 
X_DEC                                     X_HEX                               MSB_DEC                                   MSB_HEX                                MSB_POS
----------------------------------------- ----------------------------------- ----------------------------------------- ----------------------------------- ----------
170141183460469231731687303715884105728   0x80000000000000000000000000000000  170141183460469231731687303715884105728   0x80000000000000000000000000000000         127
258                                       0x102                               256                                       0x100                                        8
1                                         0x1                                 1                                         0x1                                          0
0                                         0x0                                 1                                         0x1                                          0
133443245482288878540034551612            0x1af2daa60c54cd8f9c6662f3c         79228162514264337593543950336             0x1000000000000000000000000                 96
119211094692360684699054379122744794223   0x59af38c12477e5bcb50f833e0ff29c6f  85070591730234615865843651857942052864    0x40000000000000000000000000000000         126
170141183460469231731687303715884105727   0x7fffffffffffffffffffffffffffffff  85070591730234615865843651857942052864    0x40000000000000000000000000000000         126
 
7 rows selected
 
SQL> 
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000015
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну а если выбросить из головы глупости и двигать по-нашенски, по-базейски...
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
with s0 as
 (select power(2,127) x from dual
 union all select 258 from dual
 union all select 1 from dual
 union all select 0 from dual
 union all select abs(dbms_random.value(1,170141183460469231731687303715)) from dual
 union all select abs(dbms_random.value(1,170141183460469231731687303715884105727)) from dual
 union all select 170141183460469231731687303715884105727 from dual
 )
, powers as  (select power(2,level-1) msb, level-1 msb_pos from dual connect by level < 129)
select to_char(x,'fm9999999999999999999999999999999999999999') X_Dec
     , '0x'||to_char(x, 'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  X_Hex
     , to_char(y,'fm9999999999999999999999999999999999999999') MSB_Dec
     , '0x'||to_char(y, 'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')  MSB_Hex
     , Msb_pos
from s0
   , lateral(-- закос под трюк "поиск максимума, не превосходящего N", на этом форуме впервые продемонстрированый коллегой Elic лет... много тому :)
            select msb y, msb_pos from powers where msb<x+1 order by msb desc fetch first 1 row only)
;
 
X_DEC                                     X_HEX                               MSB_DEC                                   MSB_HEX                                MSB_POS
----------------------------------------- ----------------------------------- ----------------------------------------- ----------------------------------- ----------
170141183460469231731687303715884105728   0x80000000000000000000000000000000  170141183460469231731687303715884105728   0x80000000000000000000000000000000         127
258                                       0x102                               256                                       0x100                                        8
1                                         0x1                                 1                                         0x1                                          0
47086713355477066368238054730             0x98253765c2b19b926e696d4a          39614081257132168796771975168             0x800000000000000000000000                  95
108485719561466938268229125408222236127   0x519d96eefd2e32e8825ed710730a4ddf  85070591730234615865843651857942052864    0x40000000000000000000000000000000         126
170141183460469231731687303715884105727   0x7fffffffffffffffffffffffffffffff  85070591730234615865843651857942052864    0x40000000000000000000000000000000         126
 
6 rows selected
 
SQL> 



...на pl/sql аналогично используется ассоциативный массив, но там чуть сложнее - надо бить number на 4 binary_integer, в pl/sql оно 32-битное.
Ну или длинный case сгенерить.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000024
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

как bitor получить я понимал, как и то, почему в нём сначала минус кошерно риовать, а не плюс последний член.
проскользил я мимо того обстоятельства, что между 32 разрядами и 128ю всего два шага алгоритма.

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

PS
я как раз агрегатный bitor сочиняю.
и msb мне нужен, чтобы корректно обыгрывать случай применения в качестве аналитической функции.
Так что в кишках чистый pl/sql будет.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000028
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby

я как раз агрегатный bitor сочиняю.
и msb мне нужен, чтобы корректно обыгрывать случай применения в качестве аналитической функции.
Так что в кишках чистый pl/sql будет.

Ну дык bitor(a,b) - он жеж -bitand(-a-1,-b-1)-1
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000032
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
booby,

> Деление в цикле с наращиванием счётчика сразу отбрасываем.

На C это был бы наверное самый быстрый способ (после разбивания по размеру слова архитектуры, по 32/64),
т.к. цикл из двух-трех инструкций повтором в 30-60 выполняется быстрее чем вызов функции и возврат.

Поиск в дереве - это всего 7 сравнений (но 128 бит, считаем как 14 сравнений машинных слов) тоже очень быстро
если машинный код генерится хороший.

Лукап по таблице еще не обсуждали? В сях это коротко и быстро. PL/SQL проверяет индексы, поэтому вряд ли.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// возвращает позицию старшего бита в переменной произвольной длины
// предполагает little-endian архитектуру
// использование:  GetTopBitPosition( &var, sizeof( var ) )
// полагается на массив из 256 элементов, который подсчитывается заранее
// 
inline int GetTopBitPosition( const uchar* p, size_t cbSize ) // cbSize in bytes
{
   assert( cbSize > 0 && !IsBadReadPtr(p, cbSize) );

   for( size_t i = maxSize ; --i && !p[i] )
       ;
   return table256[p[i]]+ i*8;
}



Больше таблица - больше скорость.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000034
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

мне лично bitor(a,b) = a - bitand(a, b) + b

намного приятнее.
Такой я на автомате, с закрытыми глазами и не задумываясь, писать умею.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000038
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
про хранение поднабора степеней в массиве на небольшое число элементов я может быть посмотрю.
Так что в кишках чистый pl/sql будет.


Про BitOr я уже вроде сказал - если делать агрегатку, то зачем следить за msb я не очень понимаю.
Про решение на pl/sql - всё достаточно просто, но ограничения на индексы ассоциативных массивов требуют либо уходить в строку, либо заниматься такой хренотенью:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
declare
x number := 0;  
y number;  
  -- Это разместить на уровне пакета
  type t is table of number index by pls_integer;
  powers t;
  magics t;
  procedure init_powers is
  begin
    for i in 0..30 loop
      powers(power(2,i)-1) := i;
    end loop;
    magics(1) := power(2,120);
    magics(2) := power(2,90);
    magics(3) := power(2,60);
    magics(4) := power(2,30);
    magics(5) := power(2,0);
  end;
  function get_msb(x number) return number is
    lx binary_integer;
    lpow binary_integer;
  begin
    -- Инициализацию можно разместить в секции инициализации пакета
    if powers.count = 0 then init_powers; end if;
    if x <=0 then return 0; end if;
    for i in 1..5 loop
      lx := trunc(x/magics(i));
      lpow := i;
    exit when lx > 0; 
    end loop;
    return (powers.prior(lx)+1)*magics(lpow);
  end;
begin
  for i in 0..128 loop
--    x := power(2,i);
    x := x+power(2,i);
    dbms_output.put_line('    X: '||' (0x'||to_char(x,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')||')');
    y := get_msb(x);
    dbms_output.put_line('Игого: '||' (0x'||to_char(y,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')||')');
  end loop;  
end;
/
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000039
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
andrey_anonymous,
мне лично bitor(a,b) = a - bitand(a, b) + b
намного приятнее.

Ну я бы потестил по производительности.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000042
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous

... если делать агрегатку, то зачем следить за msb я не очень понимаю.
...


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

Правда может состоять в том, что это, на самом деле, всего лишь замедляющее агрегат излишество.
Пока я еще не вполне понимаю, останется поддержка такого сорта кода, или нет в окончательном варианте.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000046
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
про "медленную проверку индекса массива".
Ну, эта проверка все равно идет на атрибутах экземпляра типа, так что смертельно медленной она не будет.

И, если уж смерть как хочется, чтобы "как в C по смещению" - извлечение подстроки из raw всегда есть, правда за счет
работы с вызовом функции на стеке.
(Может быть, так я и сделаю счетчик занятых битов в агрегате, пока не знаю еще, пока все это - ковыряния в носу.)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000047
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby

Имея годный по скорости msb это можно поддержать.

С ходу что-то не соображу как, было бы интересно при случае взглянуть.
...и вот еще, если данные изначально лежат в raw, то utl_raw умеет и or, и xor и даже complement :)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000051
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
booby

Имея годный по скорости msb это можно поддержать.

С ходу что-то не соображу как, было бы интересно при случае взглянуть.
...и вот еще, если данные изначально лежат в raw, то utl_raw умеет и or, и xor и даже complement :)


вторую часть вопроса я потенциально держу в голове.
Но тогда либо сам агрегат должен сразу работать с raw, а не с number,
либо откуда-то надо брать тайные знания.
Для number понятные мне продолжения в таком написании стартуют с hextoRaw.
А to_char-у, который тот hex должен получить, я не доверяю в плане производительности.

По первой части: потенциально одни и те же значения могут попадать в агрегат произвольное число раз.
При оговоренной максимальной разрядности думаю держать счетчик попаданий в соответствующий бит счётчика-абака,
Дальше, пока "разряд" абака больше единицы, он уменьшается на единицу, а если равен единице,
то вместе с уменьшением значения в разряде абака, обнуляется бит агрегата.
Для поданного на удаление из агрегата числа работа с ним должна начинаться с msb этого удаляемого числа.

Вот всё.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000057
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
либо откуда-то надо брать тайные знания.

Хранение number в oracle не предполагает его прозрачную конвертацию в бинарное целое и, соответственно, в raw - там банально десятичная степень, а не двоичная - т.е. мантисса не сохраняется при умножении/делении на степени 2.
Потому и написал - "если данные хранятся в raw"
hextoRaw принимает на вход только Hex, т.е. без to_char не обойтись (явно или неявно).
Есть вариант cast_from_number, но он тоже потребует битовых операций - выделить мантиссу, степень, как-то домножить одно на другое но уже в виде целого - затем уже компоновать целевой целочисленный raw.

booby

Для поданного на удаление из агрегата числа работа с ним должна начинаться с msb этого удаляемого числа.

Насколько я понимаю, в описанном варианте достаточно все равно с какого байта браться дерибанить число на биты (дабы вычитать побитовый абак). Если справа и делением - то окончание по достижению 0 и не требуется никакой msb...
Впрочем, хозяин-барин, я не настаиваю :)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000060
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

возможно я не понял последнюю ремарку.
Начиная справа я должен проверить все разряды (126 по задуманному дизайну).
Начиная с msb и двигаясь вниз по разрядам, я смогу останавливаться только на выставленных в 1 разрядах, игнорируя нулевые.
У меня такая идея была - я не знаю, как двигаясь с младшего разряда, проскакивать в анализируемом числе нулевые.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000064
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
Начиная с msb и двигаясь вниз по разрядам, я смогу останавливаться только на выставленных в 1 разрядах, игнорируя нулевые.

Должно быть я не догоняю.
Пропускать нулевые двигаясь слева - это ведь опять вычисление msb?
Если да, то не дешевле тупо делить на два или даже пройтись по строке?
Если нет - то как пропустить нулевой бит и почему не выполнить ту же операцию над исходным числом вместо вычисления msb?
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000065
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообще я бы попробовал сразу разделить число на целые покороче (бит по 16, к примеру) и обрабатывать ненулевые, это +-константное время.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000067
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...промеждупрочим, а для зачем вообще на биты уходить?
Можно же обойтись десятичными разрядами.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000073
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
booby
Начиная с msb и двигаясь вниз по разрядам, я смогу останавливаться только на выставленных в 1 разрядах, игнорируя нулевые.

Должно быть я не догоняю.
Пропускать нулевые двигаясь слева - это ведь опять вычисление msb?
Если да, то не дешевле тупо делить на два или даже пройтись по строке?
Если нет - то как пропустить нулевой бит и почему не выполнить ту же операцию над исходным числом вместо вычисления msb?

В общем, все да.

msb выглядит полезным при любом варианте - он даёт верхнюю оценку размера цикла и разряд, за которым "битов нет".
если в исследуемом числе биты сильно разрекжены, то bitand(x, msb-1) даст возможность пропустить "много разрядов".
Как дальше этим воспользоваться наилучшим образом - пока открыто..

Утром мне казалось, что я уже вроде знаю как, а сейчас забыл.
Не помню, может быть мне так казалось потому, что поначалу я верил в то, что смогу обойтись просто стандартной реализацией логарифма.

Даже если двигаться по каждому разряду - при наличии msb я могу обойтись простым делением в цикле,
и мне не потребуется сравнение на превышении степени значения анализируемого числа на каждом шаге,
как это было бы при движении от младшего разряда.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000074
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
...промеждупрочим, а для зачем вообще на биты уходить?
Можно же обойтись десятичными разрядами.


Там всего 16 байтов. Начиная со старшего, пропускаем все нулевые (допустим, байты 15,14,13 нулевые, 12й-ненулевой).
сузили ответ до 88 -95 (0-based).
Допустим в байте 12 число 66 - это бит номер 6, посчитать или сдвигом вправо, не более 7 раз, или в таблице посмотреть.
88 +6 = 94й бит.

Скан снизу вверх займет дольше, т.к. надо посмотреть все байты.
Скан сверху вниз останавливается найдя первый неноль.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000075
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
...промеждупрочим, а для зачем вообще на биты уходить?
Можно же обойтись десятичными разрядами.

ну, я десятичной арифметики не знаю.
Может и не знал никогда, я в школе уже давно учился.
И вообще - это голландские методы.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000087
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
голландские методы.

Применительно к number с его bcd-мантиссой и десятичным порядком самое оно, деление на 10 - то же что деление на 2 в сях
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000088
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

по поводу 22199621 - цикл м.б. я бы case-ом сравнения заменил,
но массивы тут не самое главное, принципиально интересна манипуляция показателями степени.

как смутная пока идея - идеально было бы получать два соседних показателя степени
для заполненных разрядов в числе, стартуя с некоторого заданного
(в общем - не важно даже, в каком обязательно направлении двигаясь).

Тогда стартуя с msb (или даже lsb, в расчете, что он "где-то рядом"), можно было бы быстро и точно вставать только на значимые разряды.
Думаю, для обоих вариантов (право/лево, msb/lsb) подходящий код должен обнаружиться и быть сходной степени сложности.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000089
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
booby
голландские методы.

Применительно к number с его bcd-мантиссой и десятичным порядком самое оно, деление на 10 - то же что деление на 2 в сях

Уговорил, обращусь к изучению наследия Симона Стевина - изобретателя десятичного поиска.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000091
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
...промеждупрочим, а для зачем вообще на биты уходить?
Можно же обойтись десятичными разрядами.


Действительно, я только что для себя обнаружил что NUMBER хранится в десятичном виде, с основанием 100.
поэтому любые битовые операции приводят к медленным преобразованиям в обе стороны.

Зато центнерная ордината хранится прямо в числе - ничего не надо считать.
Код: plaintext
1.
2.
3.
4.
SQL> select dump(170141183460469231731687303715884105727) from dual
  2  /
DUMP(1701411834604692317316873
--------------------------------------------------------------------------
Typ=2 Len=21:  212 ,2,71,15,12,84,47,5,70,24,18,32,69,74,4,72,59,85,11,58,28

В первом байте хранится центнерная ордината 19 для 100^19 (там надо 193 вычесть) а
по следующему байту сразу видна самая старшая десятичная цифра.

Это значит что все арифметические операции с NUMBER выполняются практически в столбик,
без привлечения скоростных возможностей процессора, а с делением таких чисел вообще атас.
Зато их удобно хранить и печатать. И еще log10 наверное быстро работает.

Ради любопытства, посчитал простую арифметику миллион раз на PL/SQL и на сях. Разница в скорости около 300 раз.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000092
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
booby
голландские методы.

Применительно к number с его bcd-мантиссой и десятичным порядком самое оно, деление на 10 - то же что деление на 2 в сях


Лучше делить на 100 (декремент мантиссы на 1), иначе будет все число двигать на полбайта.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000096
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня впечатление, что тема, по крупному, исчерпана.
Спасибо всем, кто так или иначе участвовал.

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

Ещё раз всем спасибо.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000101
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
НеофитSQL
Действительно, я только что для себя обнаружил что NUMBER хранится в десятичном виде
НеофитSQL
Зато центнерная ордината хранится прямо в числе - ничего не надо считать.
Код: plaintext
ну зачем опять что-то придумывать от себя... Чти доку:
https://docs.oracle.com/en/database/oracle/oracle-database/19/lnoci/data-types.html#LNOCI-GUID-91151345-2C67-41BC-A782-AD4816B89BCF


НеофитSQL
Ради любопытства, посчитал простую арифметику миллион раз на PL/SQL и на сях. Разница в скорости около 300 раз.
нашел что сравнивать...



andrey_anonymous,

почему в PL/SQL с NUMBER, а не simple_double? a в SQL c binary_double?
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000102
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
xtender
почему в PL/SQL с NUMBER, а не simple_double? a в SQL c binary_double?
т.е. т.к. ищется только старший бит, то погрешностью младших разрядов в binary_double можно спокойно пренебречь
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000105
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

Number заказывал я как топикстартер.
У binary_double другой диапазон, да и для него нет самостоятельного определения bitand в pl/sql.
Он быстрый, но в этой задаче - не нужный.
Думаю, что всё-таки ты pls_integer подразумевал.

это хороший короткий вариант.
Но тут уж точно поле состояния агрегата в объекте будет raw.
С учетом его знаковости - я не проверял, правильно ли он держит 31 бит в процессе вычисления.
Но то, что на 30 битах с ним можно работать без опасений и быстро - это очевидно.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000107
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
booby
У binary_double другой диапазон
достаточный для твоих условий
booby
Думаю, что всё-таки ты pls_integer подразумевал.
нет, именно binary_double как раз из-за диапазона


booby
для него нет самостоятельного определения bitand в pl/sql.
вообще в первую очередь я подумал про dump для него:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
  1  with t(x) as (
  2  select cast(column_value as binary_double) from table(sys.odcinumberlist(1,2,4,8,32,64,128,1024,170141183460469231731687303715884105727))
  3  )
  4  select
  5  x,
  6  dump(x,16) dd
  7* from t
SQL> /

         X DD
---------- --------------------------------------------------
  1.0E+000 Typ=101 Len=8: bf,f0,0,0,0,0,0,0
  2.0E+000 Typ=101 Len=8: c0,0,0,0,0,0,0,0
  4.0E+000 Typ=101 Len=8: c0,10,0,0,0,0,0,0
  8.0E+000 Typ=101 Len=8: c0,20,0,0,0,0,0,0
  3.2E+001 Typ=101 Len=8: c0,40,0,0,0,0,0,0
  6.4E+001 Typ=101 Len=8: c0,50,0,0,0,0,0,0
 1.28E+002 Typ=101 Len=8: c0,60,0,0,0,0,0,0
1.024E+003 Typ=101 Len=8: c0,90,0,0,0,0,0,0
1.701E+038 Typ=101 Len=8: c7,e0,0,0,0,0,0,0

9 rows selected.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000108
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
booby,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
with t(x) as (
select cast(column_value as binary_double) from table(sys.odcinumberlist(1,2,4,8,32,64,128,1024,170141183460469231731687303715884105727))
)
select 
x,
dump(x,16) dd,
regexp_replace(dump(x,16), '.*: .(.),(.).*','\1\2') bb,
to_number(regexp_replace(dump(x,16), '.*: .(.),(.).*','\1\2'),'XX')+1 msb
from t;

         X DD                                                 BB                MSB
---------- -------------------------------------------------- ---------- ----------
  1.0E+000 Typ=101 Len=8: bf,f0,0,0,0,0,0,0                   ff                256
  2.0E+000 Typ=101 Len=8: c0,0,0,0,0,0,0,0                    00                  1
  4.0E+000 Typ=101 Len=8: c0,10,0,0,0,0,0,0                   01                  2
  8.0E+000 Typ=101 Len=8: c0,20,0,0,0,0,0,0                   02                  3
  3.2E+001 Typ=101 Len=8: c0,40,0,0,0,0,0,0                   04                  5
  6.4E+001 Typ=101 Len=8: c0,50,0,0,0,0,0,0                   05                  6
 1.28E+002 Typ=101 Len=8: c0,60,0,0,0,0,0,0                   06                  7
1.024E+003 Typ=101 Len=8: c0,90,0,0,0,0,0,0                   09                 10
1.701E+038 Typ=101 Len=8: c7,e0,0,0,0,0,0,0                   7e                127

9 rows selected.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000109
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
xtender,

ff + 1 = 0, просто лень допилить
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000199
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и чем это предпочтительнее to_char с прямым подсчетом?
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000209
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous,

Код: plsql
1.
to_number(replace(substr(dump(x,16), 17,3),','),'XX')+1


to_char(x,'fmXXXXXXXXXXXXXXXX') + что именно? хардкодинг через decode от substr + length * 8? или to_number от substr(to_char(x,'fmXXXXXXXXXXXXXXXX'),1,1) + что?
Покажи, что именно ты имеешь ввиду? сравним
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000212
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous,

или 22199578 предпочтительнее чем простой короткий to_number(replace(substr(dump(x,16), 17,3),','),'XX')+1
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000220
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
andrey_anonymous,
или 22199578 предпочтительнее чем простой короткий to_number(replace(substr(dump(x,16), 17,3),','),'XX')+1


А в чем тут проблема, короткий поиск по крошечному наглухо закэшированному индексу без преобразований типов - вполне себе вариант на мой взгляд для sql-решения.

Твой метод предполагает:
1. расходы на cast (сопоставимо с to_char)
2. dump-преобразование double в строку
2.1 нештатное использование dump (где-то гарантируется формат его выдачи?)
3. строчные операции над результатом dump (особенно regexp)
4. to_number

Метод Elic:
1. to_char
2. substr 1-го байта и его decode.
3. обратный to_number

Если уж идти в строчку - я бы предпочел вариант Виталия уже ввиду отсутствия рисков side-effect.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000221
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous,

ну закодь - посмотрим, сравним
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000226
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous,

вот как точка отсчета:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
with 
  t(n) as (select level from dual connect by level<=5e3) 
 ,s0(x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 - 38.7sec - 757085000
select 
   sum(to_number(replace(substr(dump(cast(x as binary_double),16), 17,3),','),'XX')+1) sum_msb
from s0 
/


Этих двух я не дождался:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
with 
  t(n) as (select level from dual connect by level<=5e3) 
 ,s0 (x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 - 38.7 - 757085000
 , powers as  (select power(2,level-1) msb, level-1 msb_pos from dual connect by level < 129)
select sum(Msb_pos)
from s0
   , lateral(-- закос под трюк "поиск максимума, не превосходящего N", на этом форуме впервые продемонстрированый коллегой Elic лет... много тому :)
            select msb y, msb_pos from powers where msb<x+1 order by msb desc fetch first 1 row only)
;
/
with 
  t(n) as (select level from dual connect by level<=5e3) -- 5e3 - 38.7 - 757085000
 ,s0 (x) as (select t1.n*1e6 + t2.n as x from t t1,t t2)
, s1 as  (select x, bitand(-x/2-1, -x/4-1) y from s0)
, s2 as  (select x, bitand(y, y/4 - 1) y from s1)
, s8 as  (select x, bitand(y, y/16 - 1) y from s2)
, s16 as (select x, bitand(y, y/256 - 1) y from s8)
, s32 as (select x, bitand(y, y/65536 - 1) y from s16)
, s64 as (select x, bitand(y, y/4294967296 - 1) y from s32)
, s128 as(select x, -(bitand(y, y/18446744073709551616 - 1)) y from s64)
select sum(log(2,y)) Msb_pos
from s128
;

...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000246
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
Код: plsql
1.
dump

booby
на pl/sql
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000247
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
andrey_anonymous,

вот как точка отсчета:

Ну держи:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
SQL> with
  2    t(n) as (select level from dual connect by level<=5e3)
  3   ,s0(x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 - 38.7sec - 757085000
  4  select
  5     sum(to_number(replace(substr(dump(cast(x as binary_double),16), 17,3),','),'XX')+1) sum_msb
  6  from s0
  7  /

   SUM_MSB
----------
 757085000

Elapsed: 00:01:23.79
SQL>
SQL> with
  2    t(n) as (select level from dual connect by level<=5e3)
  3   ,s0(x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 - 38.7sec - 757085000 --94c
  4  select sum ( length(s)*4
  5             - case
  6                 when substr(s,1,1) >= '8' then 1
  7                 when substr(s,1,1) >= '4' then 2
  8                 when substr(s,1,1) >= '2' then 3
  9                 when substr(s,1,1) >= '1' then 4
 10               end
 11              ) msb_sum
 12  from(
 13  select to_char(x,'fmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') s
 14  from s0 )
 15  /

   MSB_SUM
----------
 757085000

Elapsed: 00:00:16.95
SQL>
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000255
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
т.к. ищется только старший бит, то погрешностью младших разрядов в binary_double можно спокойно пренебречь
Точно?
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SQL> select to_char(n, 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  2       , to_char(cast(cast(n as binary_double) as number), 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  3    from (select power(2, 100) + power(2, 20) as n from dual);

TO_CHAR(N,FMXXXXXXXXXXXXXXXXXXXXXX
-----------------------------------
TO_CHAR(CAST(CAST(NASBINARY_DOUBLE)
-----------------------------------
10000000000000000000100000
FFFFFFFFFFFFFFEA385898000
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000256
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
[quote Elic#22199957]Точно?
Код: plsql
1.
2.
3.
4.
5.
[/SRC][/quote][SRC oracle]select n
     , to_char(n                       , 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
     , to_number(replace(substr(dump(cast(n as binary_double),16), 17,3),','),'XX')+1 msb
  from (select power(2, 100) + power(2, 20) as n from dual);
/

и?
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000258
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
xtender
Код: plsql
1.
dump

Код: plsql
1.
to_number(substr(utl_raw.cast_from_binary_double(d),2,2),'XX')+1
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000259
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
Этих двух я не дождался:

Не, ну так кто угодно "победит".
Сказано же - трюк от Elic, тестить надо соответственно.
Это решение вполне сопоставимо с твоим:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SQL> with
  2    t(n) as (select level from dual connect by level<=5e3)
  3   ,s0 (x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 - 38.7 - 757085000
  4   , powers as  (select /*+ materialize*/ power(2,level-1) msb, level-1 msb_pos from dual connect by level < 129 order by power(2,level-1) desc)
  5  select sum(Msb_pos)
  6  from s0
  7     , lateral(select * from (
  8              select msb_pos from dropme_powers where msb<=x order by msb desc
  9              ) where rownum =1
 10              )
 11  ;

SUM(MSB_POS)
------------
   757085000

Elapsed: 00:01:11.96
SQL>
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000261
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
и?
msb разве не "съехал"?
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000263
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
xtender
и?
msb разве не "съехал"?

Саян не конвертит обратно в number, он прямо использует показатель степени binary_double.
Но очень много операций + решение на side-effect по сути банят этот вариант.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000265
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous,

да, длинно, но шустро.

andrey_anonymous
2.1 нештатное использование dump (где-то гарантируется формат его выдачи?)
ну формат же известен и документирован
andrey_anonymous
2. dump-преобразование double в строку
немного ускоряется обрезанием до первых 2 байтов:
Код: plsql
1.
dump(dd,16,1,2)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000268
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно, наверное, заморочиться и попробовать брать показатель из scientific-нотации с последующей трансформацией в двоичную степень :)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000269
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous
Код: plsql
1.
dropme_powers 

ну...зависит...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000271
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
andrey_anonymous
2.1 нештатное использование dump (где-то гарантируется формат его выдачи?)
ну формат же известен и документирован

Он не предназначен для машинного разбора, потому я бы не рискнул - возьмут и "улучшат", а у тебя система завалится...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000274
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
ну...зависит...

Код: plsql
1.
2.
3.
4.
create table dropme_powers(msb primary key, msb_pos) organization index
as 
select power(2,level-1) msb, level-1 msb_pos from dual connect by level < 129 order by power(2,level-1) desc
;
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000276
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous
заморочиться
если уж совсем заморочиться, я бы сделал сишную функцию доставания экспоненты для любых типов
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000277
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
andrey_anonymous
заморочиться
если уж совсем заморочиться, я бы сделал сишную функцию доставания экспоненты для любых типов

Ага, и прилинковал бы ее к оракелю как когда-то Бегун тут выделывался :)
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000280
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
Elic
пропущено...
msb разве не "съехал"?
Саян не конвертит обратно в number, он прямо использует показатель степени binary_double.
Я всего лишь визуализировал "съезд". А съезжает ещё при конвертации в binary_double.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000282
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Elic,

Msb не съезжает...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000283
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic
andrey_anonymous
пропущено...
Саян не конвертит обратно в number, он прямо использует показатель степени binary_double.
Я всего лишь визуализировал "съезд". А съезжает ещё при конвертации в binary_double.

Ну если покажешь разницу в вычисленном msb по методу Саяна и строчной реализацией...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000285
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous
xtender
пропущено...
если уж совсем заморочиться, я бы сделал сишную функцию доставания экспоненты для любых типов

Ага, и прилинковал бы ее к оракелю как когда-то Бегун тут выделывался :)
не ну самом деле, обидно, что достать пару полубайт так долго... И не какую-нибудь, а экспоненту...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000288
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
И не какую-нибудь, а экспоненту...

Ну это значило бы благословить в потрохах ковыряться.
Лучше бы просто сделали целочисленный бинарный тип большой разрядности.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000291
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
andrey_anonymous
Лучше бы просто сделали целочисленный бинарный тип большой разрядности.
да, когда с фигней математической возился, приходилось в java лезть за biginteger, да и в целом такого типа многим не хватает, например в CERN где рассчеты в oracle гоняют
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000292
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous
Ну если покажешь разницу в вычисленном msb по методу Саяна
Два числа с очевидно разными msb дают этим методом одно и то же значение:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
SQL> with
  2    t as (select power(2, 100) + power(2, 20) as n from dual union all
  3          select power(2, 100) - power(2, 20) as n from dual
  4         )
  5  select to_char(n, 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  6       , to_number(replace(substr(dump(cast(n as binary_double),16), 17,3),','),'XX')+1 msb
  7    from t;

TO_CHAR(N,FMXXXXXXXXXXXXXXXXXXXXXX         MSB
----------------------------------- ----------
10000000000000000000100000                 100
FFFFFFFFFFFFFFFFFFFF00000                  100
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000293
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Elic,

ах, я думал он округляет в большую сторону...
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000301
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender
ах, я думал он округляет в большую сторону...
Неважно в какую, главное что округляет.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000319
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
погонял то, что adrey_anonymous наваял по заветам Elic-а против прямой манипуляции битами.
получилось 56/69 в пользу заветов Elic-а.
Вот такая она, прямая манипуляция.

Как-то надо это пережить.
Пора объявлять пятницу.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000328
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
прямая манипуляция.

Прямая манипуляция битами над числом с плавающей точкой - нонсенс.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000340
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
точность формулировки не имеет значения.
Значение имеет то, что bitand над number-ом "безумно дорог".
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000352
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
xtender
пропущено...
если уж совсем заморочиться, я бы сделал сишную функцию доставания экспоненты для любых типов

Ага, и прилинковал бы ее к оракелю как когда-то Бегун тут выделывался :)


И так можно? Интересно, как будет выглядеть передача параметра NUMBER переменной длины.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000438
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Если важна точность (т.е. чтоб 2^N-1 и 2^N различало), то вот самое короткое, что работает по 2^128 включительно.

Код: plsql
1.
2.
3.
trunc(case when val < 4398046511104 then log(2,val+0.5)
           when val < 19342813113834066795298816 then 42+log(2,trunc(val/4398046511104)+0.5)
           else 42+42+log(2,trunc(val/19342813113834066795298816)+0.5) end)



Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
with pow2 (val) as
(
  select 2 as val from dual union all
  select 2*val    from pow2 where val <= 170141183460469231731687303715884105728
),
 args as (select val-1 as val from pow2 union select val from pow2)
-- константы посвящаются Дугласу Адамсу
select val, trunc(case when val < 4398046511104 then log(2,val+0.5)
                   when val < 19342813113834066795298816 then 42+log(2,trunc(val/4398046511104)+0.5)
                   else 42+42+log(2,trunc(val/19342813113834066795298816)+0.5) end)
from args;
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000531
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в выложенном мной коде была ошибка в шаге вычисления.
выкладываю исправление, для порядка

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
-- получает двоичную степень числа, соответствующую 2**msb (most significant bit) входного параметра
-- (под диапазон значений 0 - 170141183460469231731687303715884105727 - power(2,127)-1 )
  function msb(px in Number) return number deterministic parallel_enable
  is
     offs Number;
     n_mask Number;
     x Number;
     x2 Number; 

     -- шаг вычисления, удваивающего число единиц от msb вправо
     Procedure step_mask 
     Is
     Begin      
      x := x2; n_mask := floor(x/offs);
      x2 := x - bitand(x, n_mask) + n_mask;   -- вычисляет битовый OR           
      offs := offs*offs;
     End;    
  begin

    if px = 0 Or px Is Null Then Return px; End if;
   
    offs := 2;
    x2 := floor(px); 
   
    Loop 
      -- 1 (2 соседних к msb bit-ов установлены в 1)
      step_mask;
      Exit When x=x2;
                
      -- 2 (4 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit When x=x2;
          
      -- 3 (8 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit When x=x2;
      
      -- 4 (16 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit When x=x2;

      -- 5 (32 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit When x=x2;      

      -- 6 (64 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit When x=x2;

      -- 7 (128 соседних к msb bit-ов установлены в 1)
      step_mask; 
      Exit;
    End Loop;    
    -- гарантированы все единицы, начиная с msb
    -- переходим в следующий разряд и возвращаем половину
    Return floor((x2+1)/2);
  end;  

...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40000580
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Мне очень нравится решение Booby с развернутым циклом.

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

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
create or replace function aa_topbit_noloop(v in number) return integer deterministic is
  m number;
  b06 constant integer := 64;
  b12 constant integer := 4096;
  b18 constant integer := 262144;
  b24 constant integer := 16777216;
  b28 constant integer := 268435456;
  b56 constant number  := 72057594037927936;
  b94 constant number  := 19342813113834066795298816;
  bb2 constant number  := 5192296858534827628530496329220096;
  x binary_integer;
  n binary_integer;
  l binary_integer;
begin
  m := case when v >= bb2 then bb2 when v >= b94 then b94 when v >= b56 then b56 when v >= b28 then b28 else 1 end;
  x := v/m;
  n := case when x >= b24 then b24 when x >= b18 then b18 when x >= b12 then b12 when x >= b06 then b06 else 1 end;
  x := x/n;
  l := case when x >= 32 then 32 when x >= 16 then 16 when x >= 8 then 8 when x >= 4 then 4 when x >= 2 then 2 else 1 end;
  return l*n*m;
end aa_topbit_noloop;



Вопрос к знатокам - инициализация констант в декларациях функции занимает время, или это оптимизируется, т.к. константы?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SQL> declare
  2    val number;
  3  begin
  4    for i in 1..1000000
  5    loop
  6      val := aa_topbit_noloop( i+70000000000000000000000000000000000000 );
  7    end loop;
  8  end;
  9  /
PL/SQL procedure successfully completed
Executed in 4,813 seconds



Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SQL> declare
  2    val number;
  3  begin
  4    for i in 1..1000000
  5    loop
  6      val := msb( i+70000000000000000000000000000000000000 );
  7    end loop;
  8  end;
  9  /
PL/SQL procedure successfully completed
Executed in 34,641 seconds
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40001095
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Итог пока такой:
остановился промежуточно на комбинации захардкоженного
двоичного поиска в комбинации с поиском по двум массивам на 256 значений в "последнем байте".
(процедура возвращает и показатель степени и её значение).

Не готов подтвердить "медленность массивов" - ровно то же время поиска по двум массивам,
с оговоркой на погрешности измерений, что и прямой двоичный поиск на байте.
Время против "классического" варианта с bitand-ом сократилось процентов на 40.

В общем, теперь осталось только понять, пойдет ли оно в дело.

2НеофитSQL
насколько быстро сможете найти ошибку в своем коде?
(внимательно не смотрел, но подозреваю, что она на втором шаге).

PS
Вообще, "изящный код" и pl/sql - антонимы.
Правильный для pl/sql девиз - "пишите проще, а лучше всего - как все ."
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40001147
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
booby,

Я пока нашел у себя ошибку на 0 шаге (нет проверки на ноль).

Пока не подсказывайте, я подумаю.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40001148
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
НеофитSQL,

Вы не подозревайте, что я знаю, где она точно.
я просто вижу, что она есть и носит систематический и серийный характер.


Так-то я сам не пишу код влёт без ошибок, и не могу показать пальцем, по крайней мере на лиц мужского пола,
обладающих таким достоинством.
Среди женщин-программистов такие вершины внимания и скурпулёзности допустимы,
но и у них - такой недостаток большая редкость.
(Последний раз что-то похожее на Аду Лавлейс я встречал уже очень много лет назад).


Ошибка - обычное житейское дело.
Как вы планируете жить с нею, с учётом того, что вы всех своих ошибок точно не выловите,
и какие-то из них достанутся следующему товарищу, вот в чём вопрос.

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

Тогда остаётся действовать дедовскими способами.
(В старину, кстати, программист опознавался не по наличию или отсутствию пиджака, свитера,
или смешной шапочки на голове, а по наличию сразу нескольких точёных простых карандашей в нагрудном кармане.)
Так вот дедовский способ заключается в использовании карандаша и листка бумаги, на котором рисуются загогулины,
и после чего изящный код выбрасывается в помойку и заменяется на пригодный к сопровождению.
Как-то так.

По делу - проверьте, что возвращается для значений 101, 1001, 10001, 10...01 и соседних.
В первой сотне лаг начинается с 96.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40001149
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел! Без использования trunc(), присваивание дробного числа целой переменной не обрезает дробную часть, а округляет, по всей видимости.

Другими словами, int n := 127/64 даст двойку, а не единицу.
Это важное отличие Pl/SQL от других мне известных языков.

Добавил trunc() - функция заработала еще быстрее, и уже без ошибок :)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SQL> set timing on
SQL> 
SQL> declare
  2    val number;
  3  begin
  4    for i in 1..1000000
  5    loop
  6      val := aa_topbit_noloop( i+70000000000000000000000000000000000000 );
  7    end loop;
  8  end;
  9  /
PL/SQL procedure successfully completed
Executed in 3,375 seconds



Меньше 4 микросекунд на вызов.
Для сравнения, вызов пустой функции занимает около 0.8 микросекунд, т.е. инлайн ускорит еще процентов на 20, до < 3 мкс.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40001364
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в общем, поковыряв немного, решил в дело не пускать.
Последнее, с чем игрался выглядит так:
спецификация пакета
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
create or replace package msb_pkg is

  -- Author  : booby
  -- Created : 2020-09-22 12:23:08
  -- Purpose : поддержка операций получения most significant bit 
  ----------------------------------------------------------------------


 -- инициализация внутреннего состояния пакета
 procedure init_msb; 
 ----------------------------------------------------------------
 -- вычисление msb (most significant bit), процедура
 -- проектировалось под диапазон значений 0 - 170141183460469231731687303715884105727 - power(2,127)-1 
 -- выбрасывает ошибку -20203 при потере состояния пакетом,
 -- или подаче на вход "слишком большого" числа ( > 128 разрядов) 
 -- msb_pkg.msb_2p(px in Number,msb Out nocopy Number,i_exponent Out Nocopy Pls_Integer);
 Procedure msb_2p(px in Number, -- входное значение
                  msb Out nocopy Number, -- значение степени для msb
                  i_exponent Out Nocopy Pls_Integer -- показатель степени
                  );  
 -----------------------------------------------------------------
-- вычисление msb (most significant bit)
-- проектировалось под диапазон значений 0 - 170141183460469231731687303715884105727 - power(2,127)-1 
-- получает двоичную степень числа, соответствующую 2**(старший_разряд)
-- msb_pkg.msb_t(px in Number)
  function msb_t(px in Number) return number deterministic parallel_enable;
 ------------------------------------------------------------------ 

end msb_pkg;
/



тело

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
create or replace package body msb_pkg is
  
  TYPE T_MSB8_MAP Is Table Of pls_integer index by pls_integer;
  a_msb_val T_MSB8_MAP; -- для значений msb в интервале 1 - 255
  a_msb_exp T_MSB8_MAP; -- для значений показателя степени в интервале 1 - 255
  -----------------
 -- инициализация внутреннего состояния пакета
 procedure init_msb
 Is
 -- только для инициализации a_msb_val
 -- (возвращает 1 для x2=0)
   Function msb8(x2 in pls_integer) Return pls_integer
   Is     
   Begin   
     
     Return Case When x2 >= 16
                Then
                Case When x2 >= 128 Then 128
                     When x2 >= 64 Then 64
                     When x2 >= 32 Then 32
                Else 16
                End
              When x2 > 7 Then 8
              When x2 > 3 Then 4
              When x2 > 1 Then 2    
              Else 1
            End;            
    End;
 Begin
   
   For i in 0..255    
   Loop
     -- a_msb_val(0) = 1 -- в нулевом индексе единица,
     -- (не использовать массив вне контекста msb_inner)
     a_msb_val(i) := msb8(i);
     a_msb_exp(i) := Case 
                       When i Between 0 And 1 Then 0
                       When i Between 2 And 3 Then 1
                       When i Between 4 And 7 Then 2
                       When i Between 8 And 15 Then 3
                       When i Between 16 And 31 Then 4
                       When i Between 32 And 63 Then 5
                       When i Between 64 And 127 Then 6
                       When i Between 128 And 255 Then 7      
                     End;
   End Loop;    
 End;    
 -----------------------------------------------------------------
 -- msb_pkg.msb_2p(px in Number,msb Out nocopy Number,i_exponent Out Nocopy Pls_Integer); 
 Procedure msb_2p(px in Number, -- входное значение
                  msb Out nocopy Number, -- значение степени для msb
                  i_exponent Out Nocopy Pls_Integer -- показатель степени
                  )
 Is 
    i pls_integer := 0;
    k pls_integer := 0;
    
    x Number;
    x2 pls_integer;
    --
    m Number := 1.0;
    t Number := 1.0;
    
  begin  
      -- из агрегатной функции Null сюда не приедет.    
      -- оставлено на случай прямого использования. 
    If Coalesce(px, 0) = 0 Then      
      msb := 0; -- спорное место для (px Is Null), экономим if-ы в местах использования
      i_exponent := 0;
      Return;
    End If;  
    
    x := Floor(px);
    -- 
    Case 
      When x < 18446744073709551616 -- 2**64
          Then -- [0 -- 2**64) -- младшие разряды
         Case When x < 4294967296 -- 2**32, i := 32
             Then -- [0 - 2**32)
             Case When x < 65536 -- 2**16
                 Then -- [0 - 2**16)
               Case When x < 256 -- 2**8
                   Then
                 i:=0;
               Else  
                 i:= 8;
                 m:= 256;
               End Case;  
             When x < 16777216 -- 2**24 
                   Then -- [2**16 - 2**24) 
                   i := 16;
                   m := 65536;                 
             Else  -- [2**24 - 2**32)
                   i := 24;
                   m := 16777216;            
             End Case;
         Else 
           -- [2**32 - 2*64)
           Case 
         When x < 281474976710656 -- 2**48 
             Then -- [2**32 - 2**48)
             Case When x < 1099511627776 -- 2**40
               Then
                 i := 32;
                 m := 4294967296;
             Else
                 i := 40;
                 m := 1099511627776;
             End Case;      
             
         -- [2*48 - 2**64)
         When x < 72057594037927936 -- 2*56 
               Then -- [2**48 - 2**56)
                i := 48;
                m := 281474976710656; -- 2**48;  
         Else -- [2**56 - 2**64)
                i := 56;
                m := 72057594037927936; -- 2**56      
          End Case;  
         End Case;        

     -- старшие разряды - между [2**64 - 2**128)
     When x < 79228162514264337593543950336    -- 2**96
         Then -- [2**64 - 2**96)
           Case When x < 1208925819614629174706176  -- 2**80 
             Then -- [2**64 - 2**80)               
             Case When x <  4722366482869645213696  -- 2**72  
               Then -- [2**64 - 2**72)
                i := 64;
                m := 18446744073709551616;
             Else -- [2**72 - 2**80)
                i := 72;
                m := 4722366482869645213696;  
             End Case;    
           Else 
             -- [2**80 - 2**96)
             Case When x < 309485009821345068724781056   -- 2**88
               Then -- [2*80 - 2*88)
               i := 80;
               m := 1208925819614629174706176;  -- 2**80
             Else
               -- [2**88 - 2**96)
               i := 88;
               m := 309485009821345068724781056; -- 2**88
             End Case;       
           End Case;  -- 2**80 - 2*96    

     -- [2**96 - 2**128) 
     When x <  5192296858534827628530496329220096 -- 2**112
           Then -- [2**96 - 2**112)
           Case When x < 20282409603651670423947251286016  -- 2**104    
             Then -- [2**96 - 2**104)
               i := 96;
               m := 79228162514264337593543950336; -- 2**96 
           Else
             -- [2**104 - 2**112)
               i := 104;
               m := 20282409603651670423947251286016;
           End Case;      

     -- [2**112 - 2*128)         
     When x < 1329227995784915872903807060280344576   -- 2**120 
             Then -- [ 2**112 - 2**120)
               i := 112;
               m := 5192296858534827628530496329220096; 
           Else
                 -- [2**120 - 2**128)
               i := 120;
               m := 1329227995784915872903807060280344576;      
    End Case;  
    x2 := case when i > 0 Then floor(x/m ) else x End;
    --
    If x2 > 1 Then   
      Begin 
        t := a_msb_val(x2);
        k := a_msb_exp(x2);
      Exception
        When no_data_found Then
          -- ошибка программиста: потеряно состояние пакета или на входе число вне ожидаемого диапазона.
          Raise_Application_Error(-20203
                                 , 'msb_pkg.msb_inner.PE.1: index <'||x2        
                                 ||'> out of bounds (0-256) or array state lost, px='||px
                                 ||' .First='||a_msb_val.First
                                 ||' .Last='||a_msb_val.Last
                                 , True
                                 );
      End;
    End If;     
    
    msb := m*t; 
    i_exponent := (i+k);
    
 End;                         
                     
 ---------------------------------------------------------------
  function msb_t(px in Number) return number deterministic parallel_enable  
  is
  
    i pls_integer;
    m Number;
        
  begin 
    PRAGMA INLINE(msb_2p,'YES'); 
    msb_2p(px => px
          , msb => m
          , i_exponent => i
          );
    Return m;  

  End;    
 ---------------------------------------------------------------
begin
  -- Initialization
  init_msb;
end msb_pkg;
/



тестовый запрос из топика

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
with 
  t(n) as (select level from dual connect by level<=5e3) 
 ,s0(x) as (select t1.n*1e6 + t2.n as x from t t1,t t2) -- 5e3^2 
select 
   -- count(*) as rn, to_char( max(x), 'TM9') ,
   to_char(sum(msb_pkg.msb_t(x)),'TM9') sum_msb
from s0 
;



еще раз всем спасибо.
...
Рейтинг: 0 / 0
msb (most significant bit) на pl/sql есть готовый?
    #40005028
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Читал книжку по SQL, понял что моя 4-микросекундная функция ездила с тормозами.
Убрал тормоза - ускорилась до одной микросекунды.
...
Рейтинг: 0 / 0
87 сообщений из 87, показаны все 4 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / msb (most significant bit) на pl/sql есть готовый?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]