以可逆方式将二进制位(例如,可能是0/1的列表)转换为数字的最佳方法是什么。我在swi中编写了一个原生谓词,但有更好的解决方案吗? 最好的问候
答案 0 :(得分:10)
使用CLP(FD)约束,例如:
:- use_module(library(clpfd)).
binary_number(Bs0, N) :-
reverse(Bs0, Bs),
foldl(binary_number_, Bs, 0-0, _-N).
binary_number_(B, I0-N0, I-N) :-
B in 0..1,
N #= N0 + B*2^I0,
I #= I0 + 1.
示例查询:
?- binary_number([1,0,1], N).
N = 5.
?- binary_number(Bs, 5).
Bs = [1, 0, 1] .
?- binary_number(Bs, N).
Bs = [],
N = 0 ;
Bs = [N],
N in 0..1 ;
etc.
答案 1 :(得分:7)
这是我想到的解决方案,或者更确切地说是我希望存在的解决方案。
:- use_module(library(clpfd)).
binary_number(Bs, N) :-
binary_number_min(Bs, 0,N, N).
binary_number_min([], N,N, _M).
binary_number_min([B|Bs], N0,N, M) :-
B in 0..1,
N1 #= B+2*N0,
M #>= N1,
binary_number_min(Bs, N1,N, M).
此解决方案也会针对以下查询终止:
?- Bs = [1|_], N #=< 5, binary_number(Bs, N).
答案 2 :(得分:3)
解决方案
此答案旨在提供一个谓词binary_number/2
,它同时显示logical-purity和最佳终止属性。我使用when/2
来阻止canonical_binary_number(B, 10)
之类的查询在找到第一个(唯一)解决方案后进入无限循环。当然,有一个权衡,该计划现在有冗余目标。
canonical_binary_number([0], 0).
canonical_binary_number([1], 1).
canonical_binary_number([1|Bits], Number):-
when(ground(Number),
(Number > 1,
Pow is floor(log(Number) / log(2)),
Number1 is Number - 2 ^ Pow,
( Number1 > 1
-> Pow1 is floor(log(Number1) / log(2)) + 1
; Pow1 = 1
))),
length(Bits, Pow),
between(1, Pow, Pow1),
length(Bits1, Pow1),
append(Zeros, Bits1, Bits),
maplist(=(0), Zeros),
canonical_binary_number(Bits1, Number1),
Number is Number1 + 2 ^ Pow.
binary_number(Bits, Number):-
canonical_binary_number(Bits, Number).
binary_number([0|Bits], Number):-
binary_number(Bits, Number).
纯度和终止
我声称这个谓词表示logical-purity来自构造。我希望从这些答案中得到正确答案:one,two和three。
任何具有正确参数的目标都会终止。如果需要检查参数,最简单的方法是使用内置的length/2
:
binary_number(Bits, Number):-
length(_, Number),
canonical_binary_number(Bits, Number).
?- binary_number(Bits, 2+3).
ERROR: length/2: Type error: `integer' expected, found `2+3'
Exception: (6) binary_number(_G1642009, 2+3) ? abort
% Execution Aborted
?- binary_number(Bits, -1).
ERROR: length/2: Domain error: `not_less_than_zero' expected, found `-1'
Exception: (6) binary_number(_G1642996, -1) ? creep
示例查询
?- binary_number([1,0,1|Tail], N).
Tail = [],
N = 5 ;
Tail = [0],
N = 10 ;
Tail = [1],
N = 11 ;
Tail = [0, 0],
N = 20 .
?- binary_number(Bits, 20).
Bits = [1, 0, 1, 0, 0] ;
Bits = [0, 1, 0, 1, 0, 0] ;
Bits = [0, 0, 1, 0, 1, 0, 0] ;
Bits = [0, 0, 0, 1, 0, 1, 0, 0] ;
Bits = [0, 0, 0, 0, 1, 0, 1, 0, 0] .
?- binary_number(Bits, N).
Bits = [0],
N = 0 ;
Bits = [1],
N = 1 ;
Bits = [1, 0],
N = 2 ;
Bits = [1, 1],
N = 3 ;
Bits = [1, 0, 0],
N = 4 ;
Bits = [1, 0, 1],
N = 5 .
答案 3 :(得分:1)
玩位......
binary_number(Bs, N) :-
var(N) -> foldl(shift, Bs, 0, N) ; bitgen(N, Rs), reverse(Rs, Bs).
shift(B, C, R) :-
R is (C << 1) + B.
bitgen(N, [B|Bs]) :-
B is N /\ 1 , ( N > 1 -> M is N >> 1, bitgen(M, Bs) ; Bs = [] ).