Erlang数学计算中保留几位小数的方法

Erlang里数字格式化的问题,常用的取整方法都很简单BIF也很方便,对于保留几位小数的需求,做起来就相当复杂。
如果用BIF实现,就是类似如下的代码了

float(FormatNumber) ->
     list_to_float(hd(io_lib:format(FormatNumber))).

在SHELL里执行下是这样的

Erlang R14A (erts-5.8) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
 
Eshell V5.8  (abort with ^G)
1> F = fun(FormatNumber) -> list_to_float(hd(io_lib:format(Format, [Number]))) end.
#Fun<erl_eval.12.113037538>
2> F("~.3f", 8.22186).
8.222
3> F("~.3f", 8.22986).
8.23
4>

看上去实现目标了,可转念想想效率问题就会觉得值得商榷。先不说io_lib:format内做了多少工作,多次类型转换是不可避免了。在大量计算时这个效率还是需要关注的。
那么有没有更好的办法呢?
先看代码:

%% Number 需要处理的小数
%% X 要保留几位小数
%% float(8.22986, 3).
%% output: 8.230
float(Number, X) ->
    N = math:pow(10,X),
    round(Number*N)/N.

简单的做了一个测试,对比两种算法的性能,测试过程如下

Erlang R14A (erts-5.8) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
 
Eshell V5.8  (abort with ^G)
1> F = fun(FormatNumber) -> list_to_float(hd(io_lib:format(Format, [Number]))) end.
#Fun<erl_eval.12.113037538>
2> F2 fun(Number, X) -> N = math:pow(10,X), round(Number*N)/N end.
#Fun<erl_eval.12.113037538>
3> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F2(8.22986,3) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,566386,554041}
{1284,566406,825180}
ok
4> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F2(8.22986,3) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,566414,636460}
{1284,566435,343760}
ok
5> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F2(8.22986,3) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,566441,340788}
{1284,566462,91849}
ok
6> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F2(8.22986,3) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,566658,838273}
{1284,566679,614082}
ok
7> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F("~.3f", 8.22986) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,567099,125790}
{1284,567126,250011}
ok
8> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F("~.3f", 8.22986) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,567129,977330}
{1284,567157,426363}
ok
9> io:format("~p~n",[now()]), lists:foreach(fun(_I)-> F("~.3f", 8.22986) endlists:seq(1,1000000)), io:format("~p~n",[now()]).
{1284,567161,47234}
{1284,567188,442978}
ok
10>

做100w次计算可以看出,io_lib方法需要27~28秒钟,自己写的算法需要19~20秒钟,同时我观察了CPU的使用情况,自己写的算法会低10%左右的消耗,推荐适时DIY

posted @ 2010-11-17 17:29  麦飞  阅读(2268)  评论(0编辑  收藏  举报