2010-11-16 15 views
9

İ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

+0

: 'binary_number (B, -5) .': * Alan hata gibi bir istisna: \ 'not_less_than_zero 'bekleniyor, \' -5' * ** ya da ** hatası ('' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '] bulundu? –

+0

@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

cevap

10

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. 
+1

+1, zarif çözüm. –

+1

+1 çok akıllı! – sharky

+1

'binary_number (Bs, 5) .' sonlandırılmıyor. – false

3

Bu cevap bir yüklemi sağlamaya çalışır çözüm binary_number/2 Hem 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 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 . 
+0

'binary_number (L, -1)' döngüler – false

+0

İ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. –

+0

.... veya "binary_predicate/2" için "ground (Number), Number> = 0)' ifadelerini ekleyin. –

1

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
7

İş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
+1

Bu, sonlandırma sorunu (+1) çevresinde zarif ve basit bir yoldur ve üstelleştirmeyi (:)) engeller. – lurker

+0

"M" nin amacını anlamıyorum. Onu kaldıramaz ve 'N' yerine' M #> N1' ile değiştiremez misiniz? – Fatalize

+0

@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