2014-01-29 5 views
3

У меня есть требование для преобразования двоичного числа в десятичное. Преобразованный десятичный диапазон будет не больше 256. (100 миллионов в двоичном формате)Преобразование двоичного в десятичное число в заданной последовательности

Это приложение iOS, в котором для чтения отчета о расследовании проблемы четыре динамических целых числа выбираются динамически и основываются на tht. (Некоторые элементы UI находятся внутри с 0s и 1s).

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

Say, 10.100.1.11 (вход) может стать 2.4.1.3 (выход)

переживают многочисленные доклады и Objective-C. Буквально потерял рассудок. Будучи в iOS-разработчике, я не смог скомпилировать PL/SQL. Итак, я должен выполнить с SQL.

EDIT:

К счастью, я был в состоянии написать что-то вроде этого. (Но только один номер, в то время :()

SQL> var NUM number; 
SQL> exec :NUM := 100000000; 

PL/SQL procedure successfully completed. 

SQL> SELECT SUM(value) 
FROM 
    (SELECT POWER(2,LENGTH(TO_CHAR(:NUM))-level)*to_number(SUBSTR(TO_CHAR(:NUM),level,1),'FM9') AS value 
    FROM DUAL 
    CONNECT BY level <= LENGTH(TO_CHAR(:NUM)) 
); 2 3 4 5 6 

SUM(VALUE) 
---------- 
     256 
+0

@Ben 10 в двоичной в десятичном 2 .. 100 есть 3 ... и т.д .. –

+0

@MaheswaranRavisankar '100 3' не так ... (ее 4);) – user2989408

+0

@ user2989408' 2:00 AM эффект, в вопросе у меня все в порядке, извините !! –

ответ

6

Существует различные способы, вы можете подойти к этому. Так что, я выбираю то, что может показаться довольно загадочным способом. Мотивация для этого является то, что to_number() принимает шестнадцатеричные форматы, но не бинарные форматы.Что было бы так сложно поддерживать двоичный и восьмеричный, а также шестнадцатеричный? Ну, это не вопрос для меня. Oracle не делает.

Но мы можем легко конвертировать от двоичного до шестнадцатеричного. Вы имеете дело только с 8 двоичными цифрами, так что это всего лишь две шестнадцатеричные цифры. Вот код:

with bin2hex as (
     select '0000' as bin, '0' as hex from dual union all 
     select '0001' as bin, '1' as hex from dual union all 
     select '0010' as bin, '2' as hex from dual union all 
     select '0011' as bin, '3' as hex from dual union all 
     select '0100' as bin, '4' as hex from dual union all 
     select '0101' as bin, '5' as hex from dual union all 
     select '0110' as bin, '6' as hex from dual union all 
     select '0111' as bin, '7' as hex from dual union all 
     select '1000' as bin, '8' as hex from dual union all 
     select '1001' as bin, '9' as hex from dual union all 
     select '1010' as bin, 'A' as hex from dual union all 
     select '1011' as bin, 'B' as hex from dual union all 
     select '1100' as bin, 'C' as hex from dual union all 
     select '1101' as bin, 'D' as hex from dual union all 
     select '1110' as bin, 'E' as hex from dual union all 
     select '1111' as bin, 'F' as hex from dual 
    ) 
select t.*, c1.bin as bin1, c2.bin as bin2, c1.hex as hex1, c2.hex as hex2, 
     to_number(c2.hex||c1.hex, 'xx') 
from (select '10010010' as num from dual union all 
     select '10010' from dual 
    ) t left outer join 
    bin2hex c1 
    on substr('00000000'||t.num, -4) = c1.bin left outer join 
    bin2hex c2 
    on substr('00000000'||t.num, -8, 4) = c2.bin; 
1
with bin2hex as (
select '0000' as bin, '0' as hex from dual union all 
select '0001' as bin, '1' as hex from dual union all 
select '0010' as bin, '2' as hex from dual union all 
select '0011' as bin, '3' as hex from dual union all 
select '0100' as bin, '4' as hex from dual union all 
select '0101' as bin, '5' as hex from dual union all 
select '0110' as bin, '6' as hex from dual union all 
select '0111' as bin, '7' as hex from dual union all 
select '1000' as bin, '8' as hex from dual union all 
select '1001' as bin, '9' as hex from dual union all 
select '1010' as bin, 'A' as hex from dual union all 
select '1011' as bin, 'B' as hex from dual union all 
select '1100' as bin, 'C' as hex from dual union all 
select '1101' as bin, 'D' as hex from dual union all 
select '1110' as bin, 'E' as hex from dual union all 
select '1111' as bin, 'F' as hex from dual 
) 
select LISTAGG(t.num,'.')WITHIN GROUP (order by row_label) as source, 
     LISTAGG(c1.bin,'.') WITHIN GROUP (order by row_label) as bin1, 
     LISTAGG(c2.bin,'.') WITHIN GROUP (order by row_label) as bin2, 
     LISTAGG(c1.hex,'.')WITHIN GROUP (order by row_label) as hex, 
     LISTAGG(to_number(c2.hex||c1.hex, 'xx') ,'.') WITHIN GROUP (order by row_label) as deci 
    -- c1.bin as bin1, c2.bin as bin2, c1.hex as hex1, c2.hex as hex2, 
--to_number(c2.hex||c1.hex, 'xx') 
from (SELECT level as row_label,REGEXP_SUBSTR('10.100.1.11','[^.]+',1,LEVEL) AS num 
    FROM dual 
CONNECT BY REGEXP_SUBSTR('10.100.1.11','[^.]+',1,LEVEL) IS NOT NULL 
) t left outer join 
bin2hex c1 
on substr('00000000'||t.num, -4) = c1.bin left outer join 
bin2hex c2 
on substr('00000000'||t.num, -8, 4) = c2.bin; 

Результат:

SOURCE  BIN1    BIN2    HEX  DECI 
10.100.1.11 0010.0100.0001.0011 0000.0000.0000.0000 2.4.1.3 2.4.1.3 

демо: SQL Fiddle

3

Просто для удовольствия, версия с использованием рекурсивного ОТВ (так требует 11gR2), потому что, видимо, я смотрю на какой-либо предлог для играйте с ними на данный момент:

with data as (
select '10.100.1.11' as str from dual 
), 
t as (
select level as pos, 
regexp_substr(str, '[^\.]+', 1, level) as val 
from data 
connect by level <= regexp_count(str, '[^\.]+') 
), 
r (pos, val, len, lvl, pos_val) as (
select pos, val, length(val), 0, 0 
from t 
union all 
select pos, val, len, lvl + 1, 
power(2, lvl) * substr(val, len - lvl, 1) 
from r 
where lvl < length(val) 
) 
select listagg(sum(pos_val), '.') within group (order by pos) 
from r 
group by pos; 


2.4.1.3 

SQL Fiddle.

Еще не так аркан, как Гордон, хотя ...

+0

Алекс, это то, что у меня в голове! счастлив, что, я думаю, как ты !! :) –

+0

My db is exadata, так идеально !!! Еще раз спасибо ... Я буду спать сейчас счастливо! –

1

Несколько вдохновлен подходом Гордона, вот нерекурсивна версия:

with data as (
select '10.100.1.11' as str from dual 
), 
t as (
select level as pos, 
lpad(regexp_substr(str, '[^\.]+', 1, level), 16, '0') as val 
from data 
connect by level <= regexp_count(str, '[^\.]+') 
), 
r as (
    select power(2, level - 1) as digit_val, 
    lpad(power(10, level - 1), 16, '0') as raw_val, 
    lpad('0', 16, '0') as zero_val 
    from dual 
    connect by level <= 16 
) 
select listagg(sum(
    case when utl_raw.bit_and(t.val, r.raw_val) = r.zero_val then 0 else 1 end 
    * r.digit_val), '.') within group (order by pos) 
from t 
cross join r 
group by pos; 

2.4.1.3 

SQL Fiddle.

В этой версии r генерируют все двоичные значения и их десятичные эквиваленты, а основной запрос обрабатывает эти и оригинальный «октет» в качестве сырья, чтобы сделать bit_and операцию, чтобы решить, если этот бит установлен, и, следовательно, является ли десятичный эквивалент должен быть включен в sum.

Это будет обрабатывать двоичные значения до 16 цифр, что здесь более чем необходимо; но 8 не хватает и 9, казалось, не так-то ...

1

Я сделал также вариант, основанный на решении Гордон Линофф, что является более общим (вы можете легко положить в больших количествах)

with bin2hex as (
     select '0000' as bin, '0' as hex from dual union all 
     select '0001' as bin, '1' as hex from dual union all 
     select '0010' as bin, '2' as hex from dual union all 
     select '0011' as bin, '3' as hex from dual union all 
     select '0100' as bin, '4' as hex from dual union all 
     select '0101' as bin, '5' as hex from dual union all 
     select '0110' as bin, '6' as hex from dual union all 
     select '0111' as bin, '7' as hex from dual union all 
     select '1000' as bin, '8' as hex from dual union all 
     select '1001' as bin, '9' as hex from dual union all 
     select '1010' as bin, 'A' as hex from dual union all 
     select '1011' as bin, 'B' as hex from dual union all 
     select '1100' as bin, 'C' as hex from dual union all 
     select '1101' as bin, 'D' as hex from dual union all 
     select '1110' as bin, 'E' as hex from dual union all 
     select '1111' as bin, 'F' as hex from dual 
    ) 
select listagg(hex) within group (order by lv desc), 
     to_number(listagg(hex) within group (order by lv desc), LPAD('x', max(lv), 'x')) 
from(
select substr('0000'||num, -4*level, 4) bin, level lv 
from (select '1001010100000010111110010000000' num --change value here 
     from dual 
    ) a 
    connect by level<=ceil(length(a.num)/4)) a 
join bin2hex b on b.bin=a.bin 
1

не так аркан версия ...

with bit as (
    select '0' b from dual union all 
    select '1' from dual 
), 
bin2dec as (
    select b7.b || b6.b || b5.b || b4.b || b3.b || b2.b || b1.b || b0.b bin, 
     b7.b*128+b6.b*64+b5.b*32+b4.b*16+b3.b*8+b2.b*4+b1.b*2+b0.b*1 dec 
    from bit b0 
    cross join bit b1 
    cross join bit b2 
    cross join bit b3 
    cross join bit b4 
    cross join bit b5 
    cross join bit b6 
    cross join bit b7 
), 
testdata as (
    select '10010010' as num from dual union all 
    select '10010' from dual 
) 

select testdata.num, bin2dec.dec from testdata join bin2dec 
on substr('00000000'||testdata.num,-8) = bin2dec.bin 

... ну на самом деле очень простой, основанный на conversion from binary to decimal как мы узнали в школе. Используя некоторые кросс-соединения, я строю все комбинации из 8 бит, сохраняя их двоичное представление и их десятичное значение. После этого преобразование само по себе представляет собой простой поиск в этой таблице.

0

Я пытался это сделать на Oracle с использованием CONNECT BY для преобразования двоичного кода в десятичное в простом SELECT заявление. Наконец, получил желаемый результат, используя код ниже.

WITH INPUT AS 
(SELECT REVERSE('&N') AS X FROM DUAL) 
SELECT SUM(TO_NUMBER(SUBSTR(X,LEVEL,1)*POWER(2,LEVEL-1))) AS OUTPUT 
FROM INPUT CONNECT BY LEVEL<=LENGTH(X); 
Смежные вопросы