Was ist der beste Weg, um binäre Bits (es könnte eine Liste von 0/1, zum Beispiel) in reversible Weise in Zahlen umzuwandeln. Ich habe ein natives Prädikat in swi geschrieben, aber gibt es eine bessere Lösung? Mit freundlichen Grüßenreversibel "binär zu Nummer" Prädikat
Antwort
Verwendung CLP (FD) Einschränkungen, zum Beispiel:
:- 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.
Beispielabfragen:
?- 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.
Die Lösung
Diese Antwort ein Prädikat zu schaffen sucht binary_number/2
das zeigt sowohl logical-purity als auch die besten Abschlusseigenschaften. Ich habe when/2
verwendet, um Abfragen wie canonical_binary_number(B, 10)
davon abzuhalten, in Endlosschleife zu gehen, nachdem ich die erste (einzigartige) Lösung gefunden habe. Es gibt einen Kompromiss, natürlich hat das Programm redundante Ziele jetzt.
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).
Reinheit und Beendigung
ich behaupten, dass dieses Prädikat präsentiert logical-purity von der Konstruktion. Ich hoffe, ich habe es richtig aus diesen Antworten: one, two und three.
Jedes Ziel mit geeigneten Argumenten wird beendet. Wenn Argumente geprüft werden müssen, auf die einfachste Art und Weise zu erreichen ist dies mit dem eingebauten in 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
Beispiel fragt
?- 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)' Schleifen – false
Es ist außerhalb der Domäne des zweiten Arguments. Ich kann einige Bedingungen hinzufügen wie 'length (_, Number)' und Ausnahmen werden ausgelöst. –
.... oder füge 'when (ground (Number), Number> = 0)' zu 'binary_predicate/2' hinzu. –
mit Bits spielen ...
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 = []).
Hier ist die Lösung, an die ich gedacht habe, oder eher, was ich erhoffte, existiert.
:- 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).
Diese Lösung endet auch für Anfragen wie:
?- Bs = [1|_], N #=< 5, binary_number(Bs, N).
Dies ist ein eleganter, einfacher Weg um das Terminierungsproblem (+1) zu umgehen und vermeidet die Potenzierung (:)). – lurker
Ich verstehe nicht den Zweck von 'M'. Kannst du es nicht entfernen und ersetzen es in 'M #> = N1' durch' N'? – Fatalize
@Fatalize: 'M', daher wird das 4. Argument benötigt, um sicherzustellen, dass das Prädikat wirklich reversibel ist. Es ist die ursprüngliche Variable ... – false
- 1. Ist bilineare Filterung reversibel?
- 2. Prädikat kodieren in Prolog
- 3. Dezimal zu Bit (Binär)
- 4. Ungültige Operanden zu Binär "|"
- 5. Integer zu Binär Erlang
- 6. C++ int zu binär
- 7. Hex zu Binär konvertieren
- 8. Tracing-Quelle zu binär
- 9. numpy.array Boolesch zu binär?
- 10. JavaScript konvertieren dezimal zu binär
- 11. Binär zu Text in Java
- 12. Fehler ungültige Operanden zu binär
- 13. Java | Binär String zu Byte
- 14. Konverter binär zu Bild WPF;
- 15. Mit binär zu booleschen Array zu komprimieren
- 16. IndexOf Prädikat?
- 17. Binär-String in Binär- oder Dezimalwert umwandeln
- 18. MySQL "binär" vs "Char Zeichensatz binär"
- 19. Unicode-String zu Binär-String und Binär-String zu Unicode C#
- 20. Wie man Passwort mit Python unter Linux reversibel speichert?
- 21. Binär von Charcodes zu lesbaren String?
- 22. binär zu dezimal in C Programmierung
- 23. Schnellste Möglichkeit, String in Binär zu konvertieren?
- 24. Ruby: Hexadezimal String zu Binär String
- 25. Binär zu WAV Konvertierung in Android?
- 26. hexadezimal zu binär und dezimal in Matlab
- 27. C++ Von Text-Datei zu Binär-Datei
- 28. Bash Shell Dezimal zu Binär Konvertierung
- 29. C++ konvertieren binär zu dezimal, oktal
- 30. Konvertieren von Dezimal zu Binär in Python
Was die Antwort für die folgende Abfrage sein sollte: 'binary_number (B, -5) .': eine Ausnahme wie * Domain-Fehler: \ 'not_less_than_zero 'erwartet, gefunden \' -5 '* ** oder ** Fehler (' no'/'false')? –
@TudorBerariu: Wie du willst. Beide Fehler und ein Fehler ist in Ordnung. (BTW; ich habe deine Frage vorher nicht gelesen, du musst @ mich) – false