2010-11-16 21 views
9

Cách tốt nhất để chuyển đổi bit nhị phân (có thể là danh sách 0/1, ví dụ) thành số theo cách ngược lại. Tôi đã viết một vị ngữ bản địa trong swi, nhưng có giải pháp tốt hơn? Trân trọngbiến đổi "nhị phân thành số" vị ngữ

+0

gì nên là câu trả lời cho các truy vấn sau đây: 'binary_number (B, -5) .': một ngoại lệ như * lỗi miền: \ 'not_less_than_zero 'được mong đợi, tìm thấy \' -5' * ** hoặc ** lỗi ('no' /' false')? –

+0

@TudorBerariu: Như bạn muốn. Cả hai thất bại và một số lỗi là tốt. (BTW; Tôi đã không đọc câu hỏi của bạn trước đây, bạn cần phải @ tôi) – false

Trả lời

10

Sử dụng CLP (FD) hạn chế, ví dụ:

:- 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. 

Ví dụ truy vấn:

?- 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, giải pháp thanh lịch. –

+1

+1 rất thông minh! – sharky

+1

'binary_number (Bs, 5) .' không chấm dứt. – false

3

Giải pháp

Câu trả lời này nhằm cung cấp một vị binary_number/2 hiển thị cả và thuộc tính chấm dứt tốt nhất. Tôi đã sử dụng when/2 để dừng các truy vấn như canonical_binary_number(B, 10) không tham gia vào vòng lặp vô hạn sau khi tìm giải pháp đầu tiên (duy nhất). Có một sự cân bằng, tất nhiên, chương trình có mục tiêu dự phòng ngay bây giờ.

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). 

độ tinh khiết và chấm dứt

Tôi cho rằng vị này trình bày từ xây dựng. Tôi hy vọng tôi nhận được ngay từ những câu trả lời sau: one, twothree.

Bất kỳ mục tiêu nào có đối số thích hợp sẽ chấm dứt. Nếu lập luận cần phải được kiểm tra, cách đơn giản nhất để đạt được điều này là sử dụng được xây dựng trong 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 

Ví dụ truy vấn

?- 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)' vòng – false

+0

Nó nằm ngoài miền của đối số thứ hai. Tôi có thể thêm một số điều kiện như 'length (_, Number)' và các ngoại lệ sẽ được ném. –

+0

.... hoặc thêm 'khi (mặt đất (Số), Số> = 0)' thành 'binary_predicate/2'. –

1

chơi với bit ...

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 = []). 
7

Đây là giải pháp mà tôi đang nghĩ đến, hay đúng hơn là những gì tôi hy vọng tồn tại.

:- 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). 

Giải pháp này cũng chấm dứt cho các truy vấn như:

?- Bs = [1|_], N #=< 5, binary_number(Bs, N). 
+1

Đây là một cách đơn giản, thanh lịch xung quanh vấn đề chấm dứt (+1) và tránh sự lũy thừa (:)). – lurker

+0

Tôi không hiểu mục đích của 'M'. Bạn không thể xóa nó và thay thế nó trong 'M #> = N1' bằng' N'? – Fatalize

+0

@Fatalize: 'M', do đó đối số thứ 4 là cần thiết để đảm bảo rằng biến vị ngữ thực sự có thể đảo ngược. Đây là biến ban đầu ... – false