我正在尝试将十进制数42540528727106962370088967606034759680
转换为IPV6十六进制地址分段
2001:200:102:200:F:FF:0:0
但我正在
2001:200:102:fbd9:4195:ff:0:0
来自实际结果的第五和第六个十六进制地址段
200:F
与我的代码的第五和第六段转换结果不匹配
fbd9:4195
我的功能是
CREATE OR REPLACE FUNCTION ipv6_from_number(ip_number decimal)
RETURNS character varying AS
$BODY$
DECLARE
ip_1 bigint :=null;
ip_2 bigint :=null;
ip_3 bigint :=null;
ip_4 bigint :=null;
ip_5 bigint :=null;
ip_6 bigint :=null;
ip_7 bigint :=null;
ip_8 bigint :=null;
BEGIN
ip_1=TRUNC((ip_number / POWER(65536,7)));
ip_2=TRUNC(MOD(ip_number,CAST (POWER(65536,7) as numeric)) / POWER(65536,6));
ip_3=TRUNC(MOD(ip_number,CAST (POWER(65536,6) as numeric)) / POWER(65536,5));
ip_4=TRUNC(MOD(ip_number,CAST (POWER(65536,5) as numeric)) / POWER(65536,4));
ip_5=TRUNC(MOD(ip_number,CAST (POWER(65536,4) as numeric)) / POWER(65536,3));
ip_6=TRUNC(MOD(ip_number,CAST (POWER(65536,3) as numeric)) / POWER(65536,2));
ip_7=TRUNC(MOD(ip_number,CAST (POWER(65536,2) as numeric)) / 65536);
ip_8=TRUNC(MOD(ip_number,65536));
return to_hex(ip_1)||':'||to_hex(ip_2)||':'||to_hex(ip_3)||':'||to_hex(ip_4)||':'||to_hex(ip_5)||':'||to_hex(ip_6)||':'||to_hex(ip_7)||':'||to_hex(ip_8);
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
答案 0 :(得分:1)
我没有足够的热情来分析你的计算中的数学错误在哪里,但这不是一些错字或类似的东西 - 我的结果很简单:
t=# with v(ip_number) as (values (42540528727106962370088967606034759680::decimal))
, p as (select generate_series(0,7) g)
select
g
, TRUNC(MOD(ip_number,CAST (POWER(2,16*(g+1)) as numeric)) / POWER(2,16*g))
, to_hex(TRUNC(MOD(ip_number,CAST (POWER(2,16*(g+1)) as numeric)) / POWER(2,16*g))::bigint)
from v
join p on true;
g | trunc | to_hex
---+-------+--------
0 | 0 | 0
1 | 0 | 0
2 | 255 | ff
3 | 16789 | 4195
4 | 64473 | fbd9
5 | 258 | 102
6 | 512 | 200
7 | 8193 | 2001
(8 rows)
在根据this post进行操作时 - 我得到了正确的计算:
t=# WITH RECURSIVE r AS (
select 1 i, 42540528727106962370088967606034759680 ip, null::text mod, null::text ff
union
select i+1 AS i,
div(ip,16),
mod(ip,16)::text,
to_hex(mod(ip,16)::int)
from r
where ip > 0
)
SELECT *,reverse(string_agg(ff,'') over ()) FROM r;
i | ip | mod | ff | reverse
----+----------------------------------------+-----+----+----------------------------------
1 | 42540528727106962370088967606034759680 | | | 2001020001020200000f00ff00000000
2 | 2658783045444185148130560475377172480 | 0 | 0 | 2001020001020200000f00ff00000000
3 | 166173940340261571758160029711073280 | 0 | 0 | 2001020001020200000f00ff00000000
4 | 10385871271266348234885001856942080 | 0 | 0 | 2001020001020200000f00ff00000000
5 | 649116954454146764680312616058880 | 0 | 0 | 2001020001020200000f00ff00000000
6 | 40569809653384172792519538503680 | 0 | 0 | 2001020001020200000f00ff00000000
7 | 2535613103336510799532471156480 | 0 | 0 | 2001020001020200000f00ff00000000
8 | 158475818958531924970779447280 | 0 | 0 | 2001020001020200000f00ff00000000
9 | 9904738684908245310673715455 | 0 | 0 | 2001020001020200000f00ff00000000
10 | 619046167806765331917107215 | 15 | f | 2001020001020200000f00ff00000000
11 | 38690385487922833244819200 | 15 | f | 2001020001020200000f00ff00000000
12 | 2418149092995177077801200 | 0 | 0 | 2001020001020200000f00ff00000000
13 | 151134318312198567362575 | 0 | 0 | 2001020001020200000f00ff00000000
14 | 9445894894512410460160 | 15 | f | 2001020001020200000f00ff00000000
15 | 590368430907025653760 | 0 | 0 | 2001020001020200000f00ff00000000
16 | 36898026931689103360 | 0 | 0 | 2001020001020200000f00ff00000000
17 | 2306126683230568960 | 0 | 0 | 2001020001020200000f00ff00000000
18 | 144132917701910560 | 0 | 0 | 2001020001020200000f00ff00000000
19 | 9008307356369410 | 0 | 0 | 2001020001020200000f00ff00000000
20 | 563019209773088 | 2 | 2 | 2001020001020200000f00ff00000000
21 | 35188700610818 | 0 | 0 | 2001020001020200000f00ff00000000
22 | 2199293788176 | 2 | 2 | 2001020001020200000f00ff00000000
23 | 137455861761 | 0 | 0 | 2001020001020200000f00ff00000000
24 | 8590991360 | 1 | 1 | 2001020001020200000f00ff00000000
25 | 536936960 | 0 | 0 | 2001020001020200000f00ff00000000
26 | 33558560 | 0 | 0 | 2001020001020200000f00ff00000000
27 | 2097410 | 0 | 0 | 2001020001020200000f00ff00000000
28 | 131088 | 2 | 2 | 2001020001020200000f00ff00000000
29 | 8193 | 0 | 0 | 2001020001020200000f00ff00000000
30 | 512 | 1 | 1 | 2001020001020200000f00ff00000000
31 | 32 | 0 | 0 | 2001020001020200000f00ff00000000
32 | 2 | 0 | 0 | 2001020001020200000f00ff00000000
33 | 0 | 2 | 2 | 2001020001020200000f00ff00000000
(33 rows)
所以你可以SELECT DISTINCT reverse
来获取十六进制,我只显示中间计算来演示算法。当然你可以用smth分割结果:
t=# select regexp_split_to_array('2001020001020200000f00ff00000000', E'(?=(....)+$)');
regexp_split_to_array
-------------------------------------------
{2001,0200,0102,0200,000f,00ff,0000,0000}
(1 row)
甚至:
t=# select translate(regexp_split_to_array('2001020001020200000f00ff00000000', E'(?=(....)+$)')::text,',{}',':');
translate
-----------------------------------------
2001:0200:0102:0200:000f:00ff:0000:0000
(1 row)
或进行任何进一步的简化或以其他方式获得想要的展望