İkili bitleri (örneğin, 0/1 listesi) tersine çevrilebilir şekilde dönüştürmenin en iyi yolu nedir? Swi'de yerel bir yüklem yazdım ama daha iyi bir çözüm var mı? Saygılarımızlageri dönüşümlü "ikiliden numaraya" yüklemi
cevap
Kullanım CLP örneğin (FD) kısıtları,:
:- 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.
Örnek sorguları:
?- 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.
Bu cevap bir yüklemi sağlamaya çalışır çözüm binary_number/2
Hem logical-purity hem de en iyi sonlandırma özelliklerini sunar. canonical_binary_number(B, 10)
gibi sorguları ilk (benzersiz) çözümü bulduktan sonra sonsuz döngüye girmeden durdurmak için when/2
kullandım. Bir takas var elbette, program şimdi gereksiz hedefleri vardır.
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).
Saflık ve sonlandırma
Bu yüklem inşaat logical-purity sunar iddia etmektedirler. Umarım bu cevaplardan doğru anladım: one, two ve three.
Uygun argümanlarla herhangi bir hedef sonlanır.
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
Örnek bit ile oynarken
?- 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 .
'binary_number (L, -1)' döngüler – false
İkinci bağımsız değişken etki alanının dışında. Length (_, Number) 'gibi bazı koşulları ekleyebilirim ve istisnalar atılır. –
.... veya "binary_predicate/2" için "ground (Number), Number> = 0)' ifadelerini ekleyin. –
sorgular ...
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 = []).
: argümanlar kontrol edilmesi gerekiyorsa, en basit yolu dahili
length/2
kullanarak bu başarmak için
İşte düşündüğüm, ya da umduğum çözüm.
:- 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).
Bu çözüm aynı zamanda gibi sorgular için sonlandırır:
?- Bs = [1|_], N #=< 5, binary_number(Bs, N).
aşağıdaki sorgu için cevap ne olmalıdır
Bu, sonlandırma sorunu (+1) çevresinde zarif ve basit bir yoldur ve üstelleştirmeyi (:)) engeller. – lurker
"M" nin amacını anlamıyorum. Onu kaldıramaz ve 'N' yerine' M #> N1' ile değiştiremez misiniz? – Fatalize
@Fatalize: 'M', bu nedenle, yüklemenin gerçekten geri döndürülebilir olmasını sağlamak için 4. argüman gereklidir. Orijinal değişken ... – false
: 'binary_number (B, -5) .': * Alan hata gibi bir istisna: \ 'not_less_than_zero 'bekleniyor, \' -5' * ** ya da ** hatası ('' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '] bulundu? –
@TudorBerariu: İstediğiniz gibi. Hem başarısızlık hem de bazı hatalar iyidir. (BTW; Daha önce sorunuzu okumadım, bana ihtiyacınız var) – false