klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

numbers.k (17540B)


      1 ;; check.k & test-helpers.k should be loaded
      2 ;;
      3 ;; I fixed all of the bugs and added some rationale to some of the tests
      4 ;; marked as FAIL. In some cases, as you say, the specification is unclear.
      5 ;; In these cases I tried to include my interpretation (which could be wrong),
      6 ;; and changed the test to reflect this.
      7 ;;
      8 ;; I am inclined to wait for the next revision of the report before working
      9 ;; too much with numeric features, but some of these could be asked to John 
     10 ;; Shutt for clarification (but I warn you that while he is very cooperative
     11 ;; with this kind of things he sometimes takes a while to answer).
     12 ;;
     13 ;; The round thing was actually a bug in the IMath division routine
     14 ;; I fixed it (I think!) and have sent an email to the maintainer to 
     15 ;; report the bug and hopefully confirm the correctness of the fix
     16 ;;
     17 ;; Andres Navarro
     18 ;;
     19 ;; Please look for the keyword FAIL in the source code.
     20 ;; The marked lines include
     21 ;;  - failing tests
     22 ;;  - tests corresponding to incorrect or unclear specification
     23 ;;
     24 ;; Other bugs:
     25 ;;
     26 ;;  - evaluating
     27 ;;     
     28 ;;     ($check equal? (round -1.1) -1)
     29 ;;    freezes the interpreter
     30 ;;
     31 
     32 ;; 12.4 External representation of numbers.
     33 ;;
     34 ;; check various formats against plain decimals
     35 ;;
     36 
     37 ($check equal? #d000 0)
     38 ($check equal? #d099 99)
     39 ($check equal? #d-099 -99)
     40 ($check equal? #d35/67 35/67)
     41 
     42 ($check equal? #x00 0)
     43 ($check equal? #x0FF 255)
     44 ($check equal? #x-0FF -255)
     45 ($check equal? #x-AB/CD -171/205)
     46 
     47 ($check equal? #b00000 0)
     48 ($check equal? #b01111 15)
     49 ($check equal? #b-01111 -15)
     50 ($check equal? #b#e101 5)
     51 
     52 ($check equal? #o0000 0)
     53 ($check equal? #o0777 511)
     54 ($check equal? #o-0777 -511)
     55 ($check equal? #e#o-16 -14)
     56 
     57 ($check equal? #e-infinity #e-infinity)
     58 ($check equal? #e+infinity #e+infinity)
     59 ($check equal? #i-infinity #i-infinity)
     60 ($check equal? #i+infinity #i+infinity)
     61 
     62 ;; 12.5.1 number? finite? integer?
     63 ($check-predicate (number? 0 1 3/5 -3.14e0 #real))
     64 ($check-not-predicate (number? 5 "6" 7))
     65 
     66 ($check-predicate (finite? 0 1/3 -99999999))
     67 ($check-not-predicate (finite? #e+infinity))
     68 ($check-not-predicate (finite? #e-infinity))
     69 
     70 ($check-error (finite? #real))
     71 ($check-error (finite? #undefined))
     72 
     73 ($check-predicate (integer? 0 8/2 -12/6 1.0 -1.25e2))
     74 ($check-not-predicate (integer? #e+infinity))
     75 ($check-not-predicate (integer? #e-infinity))
     76 ($check-not-predicate (integer? #real))
     77 ($check-not-predicate (integer? "0"))
     78 
     79 ;; 12.?? exact-integer?
     80 ($check-predicate (exact-integer? 0 8/2 -12/6))
     81 ($check-not-predicate (exact-integer? 1.0))
     82 ($check-not-predicate (exact-integer? #e+infinity))
     83 ($check-not-predicate (exact-integer? #e-infinity))
     84 ($check-not-predicate (exact-integer? #real))
     85 ($check-not-predicate (exact-integer? "0"))
     86 
     87 
     88 ;; 12.5.2 =?
     89 
     90 ($check-predicate (=?))
     91 ($check-predicate (=? -1))
     92 ($check-predicate (=? 0 0.0 0/1 -0.0 -0/1))
     93 ($check-predicate (=? #e+infinity #e+infinity))
     94 ($check-predicate (=? #e-infinity #e-infinity))
     95 ($check-predicate (=? . #0=(1 . #0#)))
     96 ($check-not-predicate (=? 0 1))
     97 ($check-not-predicate (=? 1 #e-infinity))
     98 ($check-not-predicate (=? #e+infinity #e-infinity))
     99 ($check-not-predicate (=? 2 5/2))
    100 ($check-not-predicate (=? . #0=(1 2 . #0#)))
    101 ($check-error (=? 0 #f))
    102 ($check-error (=? 1 #t))
    103 ($check-error (=? #real #real))
    104 ($check-error (=? 1 #real))
    105 ($check-error (=? #real -1/2))
    106 ($check-error (=? #real #e+infinity))
    107 
    108 ;; 12.5.3 <? <=? >=? >?
    109 
    110 ($check-predicate (<?))
    111 ($check-predicate (<? 1))
    112 ($check-predicate (<? 1 3 7 15))
    113 ($check-not-predicate (<? 1 7 3 7 15))
    114 ($check-predicate (<? #e-infinity -1 0 1 #e+infinity))
    115 
    116 ;; 12.5.4 +
    117 
    118 ($check equal? (+ 1 1) 2)
    119 ($check equal? (+) 0)
    120 ($check equal? (+ . #0=(0 . #0#)) 0)
    121 ($check equal? (+ . #0=(1 . #0#)) #e+infinity)
    122 ($check equal? (+ . #0=(-1 . #0#)) #e-infinity)
    123 ($check equal? (+ . #0=(1 -1 . #0#)) #real)
    124 
    125 ;; 12.5.5 *
    126 
    127 ($check equal? (* 2 3) 6)
    128 ($check equal? (*) 1)
    129 ($check equal? (* 0 #e+infinity) #real)
    130 ($check equal? (* 0 #e-infinity) #real)
    131 ($check equal? (* . #0=(1 . #0#)) 1)
    132 ($check equal? (* . #0=(2 . #0#)) #e+infinity)
    133 ($check equal? (* . #0=(1/2 . #0#)) 0)
    134 ($check equal? (* . #0=(1/2 2 . #0#)) #real)
    135 ($check equal? (* . #0=(-1 . #0#)) #real)
    136 
    137 ;; 12.5.5 -
    138 
    139 ($check equal? (- 5 3) 2)
    140 ($check-error (-))
    141 ($check-error (- 0))
    142 
    143 ;; 12.5.7 zero?
    144 
    145 ($check-predicate (zero? 0 0/1 -0 -0/1 0.0 -0.0 #i0))
    146 ($check-not-predicate (zero? 1))
    147 ($check-not-predicate (zero? -0.0001))
    148 ($check-not-predicate (zero? #e+infinity))
    149 ($check-not-predicate (zero? #e-infinity))
    150 ($check-error (zero? #real))
    151 ($check-error (zero? #undefined))
    152 
    153 ;; 12.5.8 div, mod, div-and-mod
    154 
    155 ($check equal? (div 10 2) 5)
    156 ($check equal? (div -10 2) -5)
    157 ($check equal? (div 10 -2) -5)
    158 ($check equal? (div -10 -2) 5)
    159 
    160 ($check equal? (div 10 7) 1)
    161 ($check equal? (div -10 7) -2)
    162 
    163 ;; (div real1 real2) ... Let n be the greatest integer such that
    164 ;; real2 * n <= real1. Applicative div returns n.
    165 ;;
    166 ;; If real2 is negative, then such integer n does not exist.
    167 ;; interpretation : result shall be #undefined
    168 ;;
    169 ;; I followed Scheme r6rs and r7rs draft here. The definition in the 
    170 ;; Kernel report didn't make much sense to me. I'm still waiting the
    171 ;; next installement of the report to see if this is changed.
    172 ;;
    173 ;; Andres Navarro
    174                                         ;--- ($check equal? (div 10 -7) #undefined)         ; FAIL
    175                                         ;--- ($check equal? (div -10 -7) #undefined)        ; FAIL
    176 
    177 ($check equal? (mod 10 7) 3)
    178 ($check equal? (div-and-mod 10 7) (list 1 3))
    179 
    180 ;; 12.5.9 div0, mod0, div-and-mod0
    181 ;; Test cases from R6RS. The commented test cases
    182 ;; contradict the KernelReport.
    183 
    184 ($check equal? (div-and-mod 123 10) (list 12 3))
    185                                         ;----- ($check equal? (div-and-mod 123 -10) (list -12 3))
    186 ($check equal? (div-and-mod -123 10) (list -13 7))
    187                                         ;----- ($check equal? (div-and-mod -123 -10) (list 13 7))
    188 ($check equal? (div0-and-mod0 123 10) (list 12 3))
    189                                         ;----- ($check equal? (div0-and-mod0 123 -10) (list -12 3))
    190 ($check equal? (div0-and-mod0 -123 10) (list -12 -3))
    191                                         ;----- ($check equal? (div0-and-mod0 -123 -10) (list 12 -3))
    192 
    193 ;; 12.5.10 positive? negative?
    194 
    195 ($check-predicate (positive? 1 1.0 1/1 999999999999 #e+infinity))
    196 ($check-not-predicate (positive? 0))
    197 ($check-not-predicate (positive? #e-infinity))
    198 ($check-error (positive? #real))
    199 ($check-error (positive? #undefined))
    200 
    201 ($check-predicate (negative? -1 -1.0 -1/1 -999999999999 #e-infinity))
    202 ($check-not-predicate (negative? 0))
    203 ($check-not-predicate (negative? #e+infinity))
    204 ($check-error (negative? #real))
    205 ($check-error (negative? #undefined))
    206 
    207 ;; 12.5.11 even? odd?
    208 
    209 ($check-predicate (even? 0 2 -2 4/2 9999999999998))
    210 ($check-error (even? #e+infinity))
    211 ($check-error (even? #e-infinity))
    212 
    213 ($check-predicate (odd? 1 -1 6/2 9999999999999))
    214 ($check-error (odd? #e+infinity))
    215 ($check-error (odd? #e-infinity))
    216 
    217 ;; 12.5.12 abs
    218 
    219 ($check equal? (abs 0) 0)
    220 ($check equal? (abs 1) 1)
    221 ($check equal? (abs -1) 1)
    222 ($check equal? (abs #e+infinity) #e+infinity)
    223 ($check equal? (abs #e-infinity) #e+infinity)
    224 
    225 ;; 12.5.12 max min
    226 
    227 ($check equal? (max) #e-infinity)
    228 ($check equal? (max 1 2 3 4) 4)
    229 ($check equal? (max #e-infinity #e+infinity) #e+infinity)
    230 
    231 ($check equal? (min) #e+infinity)
    232 ($check equal? (min 1 2 3 4) 1)
    233 ($check equal? (min #e-infinity #e+infinity) #e-infinity)
    234 
    235 ;; 12.5.12 lcm gcd
    236 ;; TODO
    237 
    238 ;; 12.6.1 exact? inexact? robust? undefined?
    239 
    240 ($check-predicate (exact? 0 1 -1 1/2 999999999999 #e-infinity))
    241 ($check-not-predicate (exact? 3.14))
    242 ($check-not-predicate (exact? #i-infinity))
    243 ($check-not-predicate (exact? #real))
    244 ($check-not-predicate (exact? #undefined))
    245 
    246 ($check-predicate (inexact? #real 3.14 #undefined #i+infinity))
    247 ($check-not-predicate (inexact? 0))
    248 ($check-not-predicate (inexact? #e+infinity))
    249 
    250 ($check-predicate (robust? 0 1 -1 1/3 999999999999 #e-infinity #e+infinity))
    251 ;; For now klisp doesn't support precise bounds or robust tagging of inexact
    252 ;; numbers. This is, however, allowed by the report (see section 12.2, 
    253 ;; Inexactness):
    254 ;;
    255 ;; "(...) The implementation might simply take all inexact real numbers
    256 ;; to be non-robust with upper bound positive infinity and lower bound
    257 ;; negative infinity (...)"
    258 ;;
    259 ;; Andres Navarro
    260 ;; was ($check-predicate (robust? 3.14))         ; FAIL
    261 ($check-not-predicate (robust? #real))
    262 ($check-not-predicate (robust? #undefined))
    263 
    264 ($check-predicate (undefined? #undefined))
    265 ($check-not-predicate (undefined? 0))
    266 
    267 ;; 12.6.2 get-real-internal-bounds get-real-exact-bounds
    268 ;; TODO: How to test it?
    269 ($check equal? (get-real-internal-bounds 0) (list 0 0))
    270 ($check equal? (get-real-exact-bounds 0) (list 0 0))
    271 
    272 ;; 12.6.3 get-real-internal-primary get-real-exact-primary
    273 ;; TODO: How to test it?
    274 
    275 ;; 12.6.4 make-inexact
    276 ;; TODO
    277 
    278 ;; 12.6.5 real->inexact real->exact
    279 ;; TODO
    280 
    281 ;; 12.6.6 with-strict-arithmetic get-strict-arithmetic?
    282 ;; TODO
    283 
    284 ;; 12.7.1 with-narrow-arithmetic get-narrow-arithmetic?
    285 ;; TODO
    286 
    287 ;; 12.8.1 rational?
    288 
    289 ($check-predicate (rational? 0 1 1/2))
    290 ;; For now (and probably forever) klisp doesn't support non-rational
    291 ;; reals. While this is certainly doable it implies the use of a complex
    292 ;; algebraic module that is well beyond the scope of this project.
    293 ;; See following paragraph from the report: "It would seem a daunting task to
    294 ;; implement module Real without module Inexact, but in case someone has a 
    295 ;; reason to do so, the report doesn’t preclude it, i.e., module Real doesn’t
    296 ;;  assume module Inexact."
    297 ;;
    298 ;; Then, in section 12.2, Inexactness, it says: " However, sometimes
    299 ;; there may be no way for an internal number to capture a mathematical 
    300 ;; number that the client wants to reason about, either because the intended
    301 ;;  mathematical number cannot be represented by an internal number (as with
    302 ;; exclusively rational internal number formats confronted with an irrational
    303 ;;  mathematical number) ..."
    304 ;; and then on the definition of rational? (12.8.1)
    305 ;; "An inexact real is a rational iff its primary value is a ratio of 
    306 ;;  integers." which is true of all finite reals supported by klisp
    307 ;; as they are represented in floating point format and are therefore
    308 ;; expressible by the formula (sign + or -) mantissa / 2 ^ (-expt)
    309 ;;
    310 ;; Andres Navarro
    311                                         ; was ($check-not-predicate (rational? (sqrt 2)))    ; FAIL
    312 ($check-not-predicate (rational? #e+infinity))
    313 
    314 ;; 12.8.2 /
    315 
    316 ($check equal? (/ 2 3) 2/3)
    317 ($check equal? (/ 1 2 3) 1/6)
    318 ($check-error (/ 1 0))
    319 ($check-error (/ #e+infinity #e+infinity))
    320 
    321 ;; 12.8.3 numerator denominator
    322 
    323 ($check equal? (numerator 3/4) 3)
    324 ($check equal? (numerator -3/4) -3)
    325 ($check equal? (denominator 3/4) 4)
    326 ($check equal? (denominator -3/4) 4)
    327 
    328 ;; 12.8.4 floor ceiling truncate bound
    329 
    330 ;; By my interpretation of the report, these applicatives return inexact
    331 ;; integers (they could in principle return exact integers if the reals
    332 ;; passed were correctly bounded, and this is the case in klisp for exact
    333 ;; rationals for example, but not for inexact reals in general). The report
    334 ;; only says that exact arguments means exact results (when possible).
    335 ;; I could be wrong of course, I should consult this with John Shutt
    336 ;;
    337 ;; Andres Navarro
    338 
    339 ($check equal? (floor 0) 0)
    340 ($check equal? (floor #e1.23) 1) 
    341 ($check equal? (floor #e-1.23) -2)
    342 ($check =? (floor 1.23) 1) 
    343 ($check =? (floor -1.23) -2)
    344 
    345 ($check equal? (ceiling 0) 0)
    346 ($check equal? (ceiling #e1.23) 2)
    347 ($check equal? (ceiling #e-1.23) -1)
    348 ($check =? (ceiling 1.23) 2)
    349 ($check =? (ceiling -1.23) -1)
    350 
    351 ($check equal? (truncate 0) 0)
    352 ($check equal? (truncate #e1.99) 1)    
    353 ($check equal? (truncate #e-1.99) -1)  
    354 ($check =? (truncate 1.99) 1)    
    355 ($check =? (truncate -1.99) -1)  
    356 
    357 ($check equal? (round 0) 0)
    358 ($check equal? (round 1/2) 0)
    359 ($check equal? (round #e1.1) 1)
    360 ($check =? (round 1.1) 1)
    361 ($check equal? (round 3/2) 2)
    362 ($check equal? (round #e1.9) 2)
    363 ($check =? (round 1.9) 2)
    364 ($check equal? (round -1/2) 0)
    365 ($check =? (round #e-1.1) -1)
    366 ($check equal? (round #e-1.1) -1)
    367 ($check equal? (round -3/2) -2)
    368 ($check equal? (round #e-1.9) -2)
    369 ($check =? (round -1.9) -2)
    370 
    371 ;; 12.8.5 rationalize simplest-rational
    372 
    373 ($check equal? (rationalize 0 1) 0)
    374 
    375 ;; I would think the same as for floor, truncate, etc apply here
    376 ;; Here the reports even says this explicitly, in 12.8.5:
    377 ;; "If real1 and real2 are exact, the applicative (whichever it is) 
    378 ;; returns exact x0. If one or both of real1 and real2 are inexact, 
    379 ;; the applicative returns an inexact approximating x0 
    380 ;; (as by real->inexact , §12.6.5).
    381 ;;
    382 ;; Andres Navarro
    383 
    384 ;; (I think you meant 1/7 here, 1/6 is about 0.16, and so, outside the range)
    385 ;;
    386 ;; Andres Navarro
    387 ;; was ($check equal? (rationalize 0.1 0.05) 1/6) ; FAIL
    388 ($check =? (rationalize 0.1 0.05) 1/7)
    389 ($check equal? (rationalize #e0.1 #e0.05) 1/7)
    390 
    391 ($check equal? (simplest-rational 2/7 3/5) 1/2)
    392 ($check =? (simplest-rational 0.1 0.3) 1/4)
    393 ($check equal? (simplest-rational #e0.1 #e0.3) 1/4)
    394 
    395 ;; 12.9.1 real?
    396 
    397 ($check-predicate (real? 0 1 -1 1/2 999999999999 #e-infinity))
    398 ($check-not-predicate (real? #undefined))
    399 
    400 ;; 12.9.2 exp log
    401 ;; These functions are not described in the Report, but let us try...
    402 
    403 ($check equal? (exp 0.0) 1.0)
    404 ($check equal? (log 1.0) 0.0)
    405 
    406 ;; 12.9.2 sin cos tan
    407 ($check equal? (sin 0.0) 0.0)
    408 ($check equal? (cos 0.0) 1.0)
    409 ($check equal? (tan 0.0) 0.0)
    410 
    411 ;; 12.9.2 asin acos atan
    412 ($check equal? (asin 0.0) 0.0)
    413 ($check equal? (acos 1.0) 0.0)
    414 ($check equal? (atan 0.0) 0.0)
    415 
    416 ;; 12.9.5 sqrt
    417 ($check equal? (sqrt 0.0) 0.0)
    418 ($check equal? (sqrt 1.0) 1.0)
    419 ($check equal? (sqrt 4.0) 2.0)
    420 
    421 ;; 12.9.6 expt
    422 ($check equal? (expt 2.0 4.0) 16.0)
    423 
    424 ;; 12.10 Complex features
    425 ;; not implemented
    426 
    427 ;; String conversion
    428 
    429 ;; 12.? number->string
    430 ($check string-ci=? (number->string 0) "0")
    431 ($check string-ci=? (number->string 1) "1")
    432 ($check string-ci=? (number->string -1) "-1")
    433 ($check string-ci=? (number->string 2 2) "10")
    434 ($check string-ci=? (number->string -2 2) "-10")
    435 ($check string-ci=? (number->string 8 8) "10")
    436 ($check string-ci=? (number->string -8 8) "-10")
    437 ($check string-ci=? (number->string 10 10) "10")
    438 ($check string-ci=? (number->string -10 10) "-10")
    439 ($check string-ci=? (number->string 16 16) "10")
    440 ($check string-ci=? (number->string -16 16) "-10")
    441                                         ; default base
    442 ($check string-ci=? (number->string 10) (number->string 10 10))
    443 ;; infinities, undefined and reals with no primary value
    444 ($check string-ci=? (number->string #undefined) "#undefined")
    445 ($check string-ci=? (number->string #real) "#real")
    446 ($check string-ci=? (number->string #e+infinity) "#e+infinity")
    447 ($check string-ci=? (number->string #e-infinity) "#e-infinity")
    448 ($check string-ci=? (number->string #i+infinity) "#i+infinity")
    449 ($check string-ci=? (number->string #i-infinity) "#i-infinity")
    450 ;; rationals
    451 ($check string-ci=? (number->string 13/17) "13/17")
    452 ($check string-ci=? (number->string -17/13) "-17/13")
    453 ($check string-ci=? (number->string #o-21/15 8) "-21/15")
    454 ;; bigints
    455 ($check string-ci=? (number->string #x1234567890abcdef 16) 
    456         "1234567890abcdef")
    457 
    458                                         ; only bases 2, 8, 10, 16
    459 ($check-error (number->string 10 3))
    460                                         ; only numbers
    461 ($check-error (number->string #inert))
    462 ($check-error (number->string #inert 2))
    463                                         ; only numbers
    464 ($check-error (number->string "2"))
    465 ($check-error (number->string "2" 8))
    466                                         ; only base 10 with inexact numbers
    467 ($check-error (number->string -1.0 2))
    468 ($check-error (number->string 1.25 8))
    469 ($check-error (number->string 3.0 16))
    470 
    471 ;; 12.? string->number
    472 ($check =? (string->number "0") 0)
    473 ($check =? (string->number "1") 1)
    474 ($check =? (string->number "-1") -1)
    475 ($check =? (string->number "10" 2) 2)
    476 ($check =? (string->number "-10" 2) -2)
    477 ($check =? (string->number "10" 8) 8)
    478 ($check =? (string->number "-10" 8) -8)
    479 ($check =? (string->number "10" 10) 10)
    480 ($check =? (string->number "-10" 10) -10)
    481 ($check =? (string->number "10" 16) 16)
    482 ($check =? (string->number "-10" 16) -16)
    483                                         ; default base
    484 ($check =? (string->number "10") (string->number "10" 10))
    485 ;; infinities, undefined and reals with no primary value
    486 ;; #undefined and #real can't be compared with =?
    487 ($check equal? (string->number "#undefined") #undefined)
    488 ($check equal? (string->number "#real") #real)
    489 ($check =? (string->number "#e+infinity") #e+infinity)
    490 ($check =? (string->number "#e-infinity") #e-infinity)
    491 ($check =? (string->number "#i+infinity") #i+infinity)
    492 ($check =? (string->number "#i-infinity") #i-infinity)
    493 ;; rationals
    494 ($check =? (string->number "13/17") 13/17)
    495 ($check =? (string->number "-17/13") -17/13)
    496 ($check =? (string->number "-21/15" 8) #o-21/15)
    497 ;; bigints
    498 ($check =? (string->number "1234567890abcdef" 16) 
    499         #x1234567890abcdef)
    500 ($check =? (string->number "1234567890ABCDEF" 16) 
    501         #x1234567890abcdef)
    502 ;; doubles
    503 ($check =? (string->number "1.25e10") 1.25e10)
    504 ($check =? (string->number "-1.25e10" 10) -1.25e10)
    505 
    506                                         ; only bases 2, 8, 10, 16
    507 ($check-error (string->number "10" 3))
    508                                         ; only strings
    509 ($check-error (string->number #inert))
    510 ($check-error (string->number #inert 2))
    511 ($check-error (string->number 2))
    512 ($check-error (string->number 2 8))
    513                                         ; only base 10 with inexact numbers
    514 ($check-error (string->number "-1.0" 2))
    515 ($check-error (string->number "1.25" 8))
    516 ($check-error (string->number "3.0" 16))