簡體   English   中英

SICP 練習 2.5 - 如何表示負數?

[英]SICP Exercise 2.5 - How to represent negative numbers?

我目前正在閱讀 SICP,並在練習 2.5:

練習 2.5。 .證明如果我們將ab表示為乘積的整數,我們可以僅使用數字和算術運算來表示非負整數對。 給出過程conscarcdr的相應定義。

我找到了一個代碼

(define (my-cons a b)
  (* (expt 2 a) (expt 3 b)))

(define (my-car x)
  (define (car-iter x count)
    (if (= 0 (remainder x 2))
        (car-iter (/ x 2) (+ 1 count))
        count))
  (car-iter x 0))

(define (my-cdr x)
  (define (cdr-iter x count)
    (if (= 0 (remainder x 3))
        (cdr-iter (/ x 3) (+ 1 count))
        count))
  (cdr-iter x 0))

我的問題是:如果需要將“非負整數”的要求更改為“接受負整數和非負整數”怎么辦?

例子 :

> (define x (my-cons 2 -5))
> (my-car x)
2
> (my-cdr x)
-5

如何修改代碼? 我想不通。

謝謝你。 願你有一個美好的一天。

正如 amalloy 在評論中所說,這確實是一個數學問題。 這種編碼之所以有效是因為算術的基本定理,即任何正自然數都有一個唯一的素數因式分解:每個正自然數都可以唯一地表示為多個素數的乘積,其中特別是 1 是乘積沒有素數。

因此,您可以使用一個或多個額外的素數對整數的符號進行編碼(實際上,您只需要一個,因為您可以將事物寫為 2^a3^b5^s 其中 s 是 [0, 3] 對兩個元素的符號進行編碼)。

另一種方法是簡單地使用現有的表示,但將整數映射到自然數。 這很好,因為它是一個實際證明,沒有比自然數更多的整數。 這樣的地圖可能是:

  • 如果 i >= 0 則為 2i。
  • 否則 -2i - 1。

很容易看出這是一對一的對應關系,而且 0 映射到 0 (這使得 0 成為nil的一個很好的值)。

這是這些地圖,寫在(對不起)打字球拍,因為我正在努力弄清楚我是否可以使用它。

(define (Z->N (i : Integer)) : Natural
  ;; map an integer to a natural
  (if (>= i 0)
      (* i 2)
      (- (* (- i) 2) 1)))

(define (N->Z (n : Natural)) : Integer
  ;; map the naturals into the integers
  (let-values ([(q r) (quotient/remainder n 2)])
    (if (zero? r)
        q
        (- (- q) 1))))

現在你的實現還有另一個問題:它會很高興地處理不是 2^a3^b 形式的數字,例如任何具有其他主要因素的數字。 處理這個問題的方法是在提取冪時檢查數字是否具有該形式:實際上這意味着檢查數字是否為 2^a*3^b*1 的形式。

因此,下面的代碼會執行此操作,以及對上面的整數進行編碼。 這又是在類型化的 Racket 中(對不起,再次),它還使用了多個值,並且可能還使用了僅存在於 Racket 中的其他一些東西。

(define (defactor (n : Natural) (p : Natural)) : (Values Natural Natural)
  ;; Given n and a factor p, return m where p does not divide m,
  ;; and j, the number of factors of p removed (so n = m*p^j)
  (let df-loop ([m : Natural n]
                [j : Natural 0])
    (let-values ([(q r) (quotient/remainder m p)])
      (if (zero? r)
          (df-loop q (+ j 1))
          (values m j)))))
  
(define (kar&kdr (k : Positive-Integer)) : (Values Integer Integer)
  ;; Given something which should be a kons, return its kar & kdr.
  ;; If it is not a kons signal an error
  (let*-values ([(k2 encoded-kar) (defactor k 2)]
                [(k23 encoded-kdr) (defactor k2 3)])
    (unless (= k23 1)
      (error 'kar&kdr "not a cons"))
    (values (N->Z encoded-kar) (N->Z encoded-kdr))))

(define (kons (the-kar : Integer) (the-kdr : Integer)) : Positive-Integer
  (* (expt 2 (Z->N the-kar))
     (expt 3 (Z->N the-kdr))))

(define (kar (the-kons : Positive-Integer)) : Integer
  (let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
    the-kar))

(define (kdr (the-kons : Positive-Integer)) : Integer
  (let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
    the-kdr))

我們可以更進一步,定義一個空列表的表示,它將是0和一種制作列表的方式:

;;; since 2^a3^b is never zero, 0 is a good candidate for the empty
;;; list: 'kill' is a pun on 'nil'.
;;;

(define kill : Zero 0)

;;; And now we can write some predicates and a version of list.
;;; (kist 1 2 3) takes a very, very long time.
;;;

(define (kill? (x : Natural)) : Boolean
  (zero? x))

(define (kons? (x : Natural)) : Boolean
  (not (kill? x)))
               
(define (kist . (l : Integer *)) : Natural
  (let kist/spread ((lt l))
    (if (null? lt)
        kill
        (kons (first lt) (kist/spread (rest lt))))))

現在

> (define d (kons 123 -456))
> d
- : Integer [more precisely: Nonnegative-Integer]
51385665200410193914365219310409629004573395973849642473134969706165383608831740620563388986738635202925909198851954060195023302783671526117732269828652603388431987979605951272414330987611274752111186624164906143978901704325355283206259678088536996807776750955110998323447711166379786727609752016045005681785186498933895920793982869940159108073471074955985333560653268614500306816876936016985137986665262182684386364851688838680773491949813254691225004097103180392486216812280763694296818736638062547181764608
> (kar d)
- : Integer
123
> (kdr d)
- : Integer
-456
> (kdr (+ d 1))
kar&kdr: not a cons [,bt for context]

如果您嘗試計算,例如(kist 1 2 3) ,它將花費非常非常長的時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM