Erlang 进制转换

http://www.cnblogs.com/me-sa/archive/2012/03/20/erlang0047.html

bnot unary bitwise not integer
div integer division integer
rem integer remainder of X/Y integer
band bitwise and integer
bor bitwise or integer
bxor arithmetic bitwise xor integer
bsl arithmetic bitshift left integer
bsr bitshift right integer

去年读过的好书之一就是这本《编码:隐匿在计算机软硬件背后的语言》(豆瓣链接 )里面对进制有一段非常有意思的描述:

如果人类像卡通人物那样,每只手上只有 4个手指会怎样呢?我们可能永远都不会想到要发明一种以10为基础的数字系统的问题, 取而代之的是我们可能会认为数字系统基于 8是正常、自然、合理、必然的,是毫无疑问的,是非常合适的。这时,就不能称之为十进制了,得将它称作为以8为基础的数字系统或八进制。

... ...

龙虾根本没有手指,但它两只前爪的末端都有螯。适合于龙虾的数字系统是四进制数字系统或称为基于4的数字系统.

我们平常编程经常会遇到进制转换的问题,有时候是为了把机器可处理的转换成人类可读的,有时候是把人类可读的转成机器可处理的;有时候是把一台机器可处理的转成另外一台机器可以处理的;进制转换几乎是所有开发者的公共话题,这个问题也经常作为面试题出现......有中枪的么?

在.net中,做进制转换可以使用Convert.ToInt32(String,Base)做 2, 8, 10, 16进制之间的转换:

Convert.ToInt32("10101010",2);  Convert.ToInt32("12",16);

Convert.ToInt32 Method (String, Int32)The base of the number in value, which must be 2, 8, 10, or 16. 
Converts the string representation of a number in a specified base to an equivalent 32-bit signed integer.

Erlang

Erlang中进行进制转换是比较方便的,首先在Shell中可以通过Base#Number的形式计算各种进制对应的十进制数值;

Eshell V5.9  (abort with ^G)1> 2#1011.112> 2#1111.153> 16#12.184> 16#1F.315> 8#121.816> 7#11.87>

Erlang BIF 提供了两个基础方法方便从十进制数值转到各种进制字符串,以及其逆过程,目前支持的进制是2到36:

Eshell V5.9  (abort with ^G)1> integer_to_list(1234,8)."2322"2> integer_to_list(1234,16)."4D2"3> list_to_integer("2322",8).12344> list_to_integer("4d2",16).1234

integer_to_list(Integer, Base) -> string()

Types:

Integer = integer()

Base = 2..36

Returns a string which corresponds to the text representation of Integer in base Base.

list_to_integer(String, Base) -> integer()

Types:

String = string()

Base = 2..36

Returns an integer whose text representation in base Base is String.

群里面有人问如何把"abc"转换成 "110000111000101100011"的形式,即逐字符转成二进制,不管他转成这样的格式做什么用,实现起来还是比较简单的:lists:concat([erlang:integer_to_list(Item,2) || Item<-"abc"  ]).

这里看下从十进制到其它进制转换是怎么实现的,这是一个通用的方法:

%%Code Path:\erl5.9\lib\erts-5.9\src\erlang.erlinteger_to_list(I0, Base, R0) ->    D = I0 rem Base,    I1 = I0 div Base,    R1 = if D >= 10 ->            [D-10+$A|R0];         true ->            [D+$0|R0]     end,    if I1 =:= 0 ->         R1;       true ->         integer_to_list(I1, Base, R1)    end.

上面是一个通用的处理方法;对于一些特例的情况,比如十进制转到16进制的情况,可以通过移位和逻辑运算完成:4bit的最大值是15 (2#1111) ,N band 15 获得最后四位的值,不断进行右移4位和band操作就可以完成10进制到16进制的转换;

%% @spec hexdigit(integer()) -> char()%% @doc Convert an integer less than 16 to a hex digit.hexdigit(C) when C >= 0, C =< 9 ->    C + $0;hexdigit(C) when C =< 15 ->    C + $a - 10.

to_hex_int(0, Acc) ->    Acc;to_hex_int(I, Acc) ->    to_hex_int(I bsr 4, [hexdigit(I band 15) | Acc]).

同样的思路,可以完成10进制到2进制的转换,以及10进制到8进制的转换:

de2bin(0,Acc)->   Acc;de2bin(N,Acc) ->   de2bin(N bsr 1,[((N band 1)+$0)|Acc]).

de2oct(0,Acc) ->   Acc;de2oct(N,Acc) ->   de2oct(N bsr 3 ,[((N band 7)+$0)|Acc]).

看下调用的效果:

Eshell V5.9  (abort with ^G)1> zen:de2oct(1234,[])."2322"2> 8#2322.12343> zen:de2oct(1,[]).  "1"4> zen:de2bin(1234,[])."10011010010"5> list_to_integer(zen:de2oct(1234,[]),8).12346> 

Erlang开源项目mochiweb包含了一个处理十六进制数据的模块,(下面的代码我按照调用关系调整了一下):

%% @author Bob Ippolito <[email protected]>%% @copyright 2006 Mochi Media, Inc.

%% @doc Utilities for working with hexadecimal strings.

-module(mochihex).-author(‘[email protected]‘).

-export([test/0, to_hex/1, to_bin/1, to_int/1, dehex/1, hexdigit/1]).

%% @type iolist() = [char() | binary() | iolist()]%% @type iodata() = iolist() | binary()

%% @spec to_hex(integer | iolist()) -> string()%% @doc Convert an iolist to a hexadecimal string.to_hex(0) ->    "0";to_hex(I) when is_integer(I), I > 0 ->    to_hex_int(I, []);to_hex(B) ->    to_hex(iolist_to_binary(B), []).

to_hex(<<>>, Acc) ->    lists:reverse(Acc);to_hex(<<C1:4, C2:4, Rest/binary>>, Acc) ->    to_hex(Rest, [hexdigit(C2), hexdigit(C1) | Acc]).

%% @spec hexdigit(integer()) -> char()%% @doc Convert an integer less than 16 to a hex digit.hexdigit(C) when C >= 0, C =< 9 ->    C + $0;hexdigit(C) when C =< 15 ->    C + $a - 10.

to_hex_int(0, Acc) ->    Acc;to_hex_int(I, Acc) ->    to_hex_int(I bsr 4, [hexdigit(I band 15) | Acc]).

%% @spec to_bin(string()) -> binary()%% @doc Convert a hexadecimal string to a binary.to_bin(L) ->    to_bin(L, []).

to_bin([], Acc) ->    iolist_to_binary(lists:reverse(Acc));to_bin([C1, C2 | Rest], Acc) ->    to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).

%% @spec dehex(char()) -> integer()%% @doc Convert a hex digit to its integer value.dehex(C) when C >= $0, C =< $9 ->    C - $0;dehex(C) when C >= $a, C =< $f ->    C - $a + 10;dehex(C) when C >= $A, C =< $F ->    C - $A + 10.

%% @spec to_int(string()) -> integer()%% @doc Convert a hexadecimal string to an integer.to_int(L) ->    erlang:list_to_integer(L, 16).

%% @spec test() -> ok%% @doc Test this module.test() ->    "ff000ff1" = to_hex([255, 0, 15, 241]),    <<255, 0, 15, 241>> = to_bin("ff000ff1"),    16#ff000ff1 = to_int("ff000ff1"),    "ff000ff1" = to_hex(16#ff000ff1),    ok.

二进制数据处理代码段:

hexdigit(C) when C < 10 -> $0 + C;
hexdigit(C) when C < 16 -> $A + (C - 10).

unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.

quote_plus([], Acc) ->
    lists:reverse(Acc);
quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
    quote_plus(Rest, [C | Acc]);
quote_plus([$\s | Rest], Acc) ->
    quote_plus(Rest, [$+ | Acc]);
quote_plus([C | Rest], Acc) ->
    <<Hi:4, Lo:4>> = <<C>>,
    quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).

qs_revdecode(S) ->
    qs_revdecode(S, []).

qs_revdecode([], Acc) ->
    Acc;
qs_revdecode([$+ | Rest], Acc) ->
    qs_revdecode(Rest, [$\s | Acc]);
qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
    qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
qs_revdecode([C | Rest], Acc) ->
    qs_revdecode(Rest, [C | Acc]).

IP地址和整形互转

还有一个常见的问题就是IP地址到整形的互相转换,也可以按照同样的思路如法炮制:

首先,我们先确定一些常量的值:

4> integer_to_list(16711680,2).
"11111111,00000000,00000000"
6> integer_to_list(65280,2).
"1111111100000000"
7> integer_to_list(16777216,2).
"1000000000000000000000000"
8> integer_to_list(65536,2).
"10000000000000000"
9> integer_to_list(256,2).
"100000000"

现在可以做转换了:

10> Ip_to_integer=fun({A,B,C,D}) -> (A*16777216)+(B*65536)+(C*256)+D end.
#Fun<erl_eval.6.111823515>
11> Ip_to_integer({192,168,0,188}).
3232235708
12> Integer_to_ip=fun(Ip)-> {Ip bsr 24, (Ip band 16711680) bsr 16, (Ip band 65280) bsr 8, Ip band 255} end.
#Fun<erl_eval.6.111823515>
14> Integer_to_ip(3232235708).
{192,168,0,188}

附:

bnot unary bitwise not integer
div integer division integer
rem integer remainder of X/Y integer
band bitwise and integer
bor bitwise or integer
bxor arithmetic bitwise xor integer
bsl arithmetic bitshift left integer
bsr bitshift right integer

P.S 有人问到列表解析的用法,这个可以看下官方文档:http://www.erlang.org/doc/programming_examples/list_comprehensions.html

列表解析很强大的说,看下面的例子

sort([Pivot|T]) ->    sort([ X || X <- T, X < Pivot]) ++    [Pivot] ++    sort([ X || X <- T, X >= Pivot]);sort([]) -> [].

上面是用两行代码实现了快速排序,在看一个实现全排列的

perms([]) -> [[]];perms(L)  -> [[H|T] || H <- L, T <- perms(L--[H])].

勾股定理数

pyth(N) ->    [ {A,B,C} ||        A <- lists:seq(1,N),        B <- lists:seq(1,N),        C <- lists:seq(1,N),        A+B+C =< N,        A*A+B*B == C*C     ].

%%优化版本pyth1(N) ->   [{A,B,C} ||       A <- lists:seq(1,N-2),       B <- lists:seq(A+1,N-1),       C <- lists:seq(B+1,N),       A+B+C =< N,       A*A+B*B == C*C ].

另外列表解析可以在Erlang Shell中方便的实现for循环和if

12> [io:format("abc")|| _<-lists:seq(1,10)]. abcabcabcabcabcabcabcabcabcabc[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok]13> E=34.3414> [io:format("abc")|| E>35].             []15> [io:format("abc")|| E>32].abc[ok]16> 

时间: 2024-08-29 07:01:31

Erlang 进制转换的相关文章

任意进制转换算法

任意进制转换算法 N年没有写博客,发个进制转换的玩下,支持负数:功能属于简化版的 Convert.ToInt32 ,特点是: 1.任意位,如:0,1(二进制),0...7(八进制),0...9,A...F(16进制),0...N(N进制),或者是:[email protected]#$%^&*(8进制,字符符号),也可以是中文. 2.8 byte 最大长度. 3.C#源码. 最近写markdown格式习惯啦,cnblogs啥时候全改掉算了,别用这个htmleditor算了. 先说明下进制转换的基

03 php 数据类型:整数,进制转换,浮点,字符,布尔,数组,空类型,类型转换,算术运算,比较运算

03 数据类型:整数,进制转换,浮点,字符,布尔,数组,空类型,类型转换, 算术运算,比较运算,逻辑运算,短路现象, 三目运算符,字符型运算: 数据类型 整体划分 标量类型: int, float, string, bool 复合类型: array,     object 特殊类型: null,     resouce 整数类型int, integer 3种整数表示法 十进制写法:123: $n1 = 123; 八进制写法: 0123 $n2 = 0123; 十六进制写法: 0x123 $n3

计算机进制转换

一.计算机只认识0和1,二进制. 二.2进制转换成 8进制 和 16进制,如下图: 二进制 > 八进制 :  研究上图发现,3位最高二进制可以用来表示一位八进制.所以,将二进制分解每3位,不够前面补0,然后每3位转换为10进制,顺序排列即可. 二进制 > 十六进制  :4位最高二进制可以用来表示一位十六进制.所以,将二进制分解每4位,不够前面补0,然后每4位转换为10进制,超过9用字母表示即可.顺序排列即可. 如下: 二进制 > 十进制:   11001001 = 2^7+2^6+2^3

原理之一,进制转换

原理之一,进制转换 日常生活中采用个数字都是十进制,而计算机采用的是运算更简单.易实现且可靠,为逻辑设计提供了有力途经的二进制,除此之外还有八进制和十六进制作为二进制的缩写. 进制:逢N进一,N是每种进位计数制表示一位数所需要的符号数目为基数. 二进制:逢二进一,借一当二,包含的数字(0.1) 八进制:逢八进一,借八当一,包含(0.1.2.3.4.5.6.7) 十六进制:逢十六当一,以一当十六,包含(0.1.2.3.4.5.6.7.8.9.10(A).11(B).12(C).13(D).14(E

NOIP2000 进制转换

题一   进制转换              (18分)  问题描述      我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1*102+2*101+3*100这样的形式. 与之相似的,对二进制数来说,也可表示成每个二进制数码乘以一个以该数字所处位置的(值-1)为指数,以2为底数的幂之和的形式.一般说来,任何一个正整数R或一个负整数-R都可以被选来作为一个数制系统的基数.如果是以R或-R为基

进制进制进制~转换

从刚学计算机器就对进制转换有着莫名的反感,2进制 8进制 10进制 16进制各种转换. 下面就说下逻辑地址转换成物理地址的求法吧 首先,用户输入一个16进制的数字cin>>hex>>logic_add;   hex的意思是告诉计算机输入的数是以16进制方式输入的 这个时候你要是输出cout<<logic_add;  你会发现输出的是把这个16进制的数转换为10进制以后输出的结果 cout<<hext<<logic_add;这样输出的才是16进制.

黑马程序员------进制转换

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 在java中数字的表现形式一般有二进制,八进制,十进制,十六进制等,在平时的编程中我们可以通过java提供的API函数方便的实现各个进制间的转换,如:Integer.toHexString(int i)--十进制转十六进制:Integer

c语言之进制转换(栈实现)

从上两篇博客中我们可以知道,栈具有后进先出的特性,而进制转换的打印输出刚好与计算过程相反,满足栈这后进先出的特性, 所以可以用栈很快的实现进制转换,下面是用栈实现进制转换的c函数 void conversion (SqStack *pstack,unsigned int N, const unsigned int d){ if( pstack == NULL)//当传入参数为指针,必须判空 exit(-1); int mod ;//保存mod = N %d while( N != 0){ mod

进制转换-课后作业

一. 其他进制转换成十进制 1.十六进制转成十进制 41bd  = 4*16^3+1*16^2+11*16+13 = 16384+256+176+13=16829 a10c.8  = 10*16^3+1*16^2+0+12  .  8/16 = 40960+256+12.5=41228.5 2.八进制转成十进制 146.1  = 1*8^2+4*8+6 . 1/8 = 64+32+6.125=102.125 5312.2  = 5*8^3+3*8^2+1*8+2 . 2/8 = 2560+192