mirror of https://github.com/GNOME/gimp.git
272 lines
8.1 KiB
Scheme
272 lines
8.1 KiB
Scheme
; test numerics of TS
|
|
|
|
; TinyScheme supports the numeric tower "fixnums and flonums"
|
|
; Meaning the tower is number=>real=>integer, omitting actual rational and complex.
|
|
; Also meaning the machine representations as integer or float
|
|
|
|
; Note "machine representation" is not "string representation"
|
|
; Former is a machine implementation.
|
|
; Latter is how the interpreter prints numbers.
|
|
|
|
; These tests only show what TinyScheme does.
|
|
; These tests might not reflect what a R5RS conforming implementation should do.
|
|
; See comments.
|
|
|
|
; TinyScheme is technically exactness-preserving,
|
|
; but silently returns the wrong answers when arithmetic operations overflow.
|
|
; Thus TinyScheme is non-conformant.
|
|
|
|
; !!! This must be also be tested with non-English locale
|
|
; e.g. export LANG="de_DE.UTF-8"
|
|
; In that locale, comma is used as a decimal point.
|
|
; In TinyScheme, string representation of numbers SHOULD use period as decimal point.
|
|
; But currently doesn't, in some locales using comman for decimal point.
|
|
; Because TinyScheme uses C standard lib snprintf
|
|
; which respects locale and can print comma for decimal point.
|
|
|
|
|
|
; float precision
|
|
|
|
; R5RS allows 1.0[s,e,d,l]0 notation
|
|
; meaning short-float, single-float, double-float and long-float.
|
|
; TinyScheme only supports e
|
|
|
|
(test! "e notation is supported")
|
|
(assert `(= 1.0e0 1.0))
|
|
(assert `(= 1.0e+0 1.0))
|
|
(assert `(= 1.0e-0 1.0))
|
|
|
|
(test! "e[s,d,l] notation is treated as a symbol, and is unbound")
|
|
(assert-error `1.0s0
|
|
"eval: unbound variable")
|
|
|
|
|
|
|
|
(test! "max integers")
|
|
|
|
; largest 64-bit integer
|
|
; 1234567890123456789 digit counter
|
|
; unsigned 18446744073709551615
|
|
; signed 9223372036854775807
|
|
; TinyScheme machine representation is signed 64-bit.
|
|
;
|
|
; Any int literal greater than 19 digits overflows silently.
|
|
; Int literal of 19 digits < max signed 64-bit int do not overflow.
|
|
|
|
(test! "integers overflow silently.")
|
|
; Adding one to the largest representable int yields the wrong result
|
|
(assert `(not
|
|
(=
|
|
(+ 9223372036854775807 1)
|
|
9223372036854775808)))
|
|
; And is in fact a negative int (overflowing into the sign bit)
|
|
(assert `(=
|
|
(+ 9223372036854775807 1)
|
|
-9223372036854775808))
|
|
; Numbers larger than the largest representable int
|
|
; can be represented as float literals, but not exact.
|
|
(assert `(inexact? 9223372036854775808.0))
|
|
; and they are not integers
|
|
(assert `(not (integer? 9223372036854775808.0)))
|
|
; Such numbers can be represented in equal e notation
|
|
(assert `(=
|
|
9223372036854775808.0
|
|
9.223372036854775808e+18))
|
|
; The string representation loses significant digits
|
|
; FIXME arbitrary limiting string repr to 10 decimal places is wrong.
|
|
(assert `(string=? (number->string 9223372036854775808.0)
|
|
"9.223372037e+18"))
|
|
; "9.2233720368547758e+18" when fixed, having more digits but still losing digits.
|
|
|
|
|
|
|
|
(test! "numeric type predicates")
|
|
; These do NOT tell you the machine representation.
|
|
; "The behavior of these type predicates on inexact numbers is unreliable, since any inaccuracy may affect the result."
|
|
(assert `(integer? 3.0))
|
|
(assert `(integer? (/ 8 4))) ; i.e. 2.0
|
|
(assert `(not (integer? (/ 1 3)))) ; i.e. 0.3333
|
|
|
|
; integer implies rational implies real implies complex implies number
|
|
; integer is a subset of all higher types
|
|
(assert `(integer? 3))
|
|
(assert `(rational? 3))
|
|
(assert `(real? 3))
|
|
(assert `(complex? 3))
|
|
(assert `(number? 3))
|
|
|
|
(test! "complex type is not implemented")
|
|
(assert-error `(imag-part 3)
|
|
"eval: unbound variable")
|
|
|
|
|
|
|
|
; exactness predicates
|
|
|
|
; The usual predicates are defined.
|
|
; R5RS says: "One of the predicates must be true. Exactly one of the two can be true."
|
|
(assert `(exact? 1))
|
|
(assert `(not (inexact? 1)))
|
|
|
|
; exact-integer? exact-nonnegative-integer? exact-rational? are not defined
|
|
(assert-error `(exact-integer? 1)
|
|
"eval: unbound variable")
|
|
|
|
|
|
|
|
; exactness
|
|
|
|
(test! "exact")
|
|
|
|
; small integers are exact
|
|
(assert `(exact? 1))
|
|
|
|
; some float notation (with all fractional digits zero) is exact
|
|
(assert `(exact? 4.0))
|
|
(assert `(real? 4.0))
|
|
(assert `(integer? 4.0))
|
|
|
|
; float notation with fractional digits nonzero is not exact
|
|
(assert `(inexact? 1.1))
|
|
|
|
|
|
|
|
|
|
; exactness and IEEE representability
|
|
;
|
|
; Note: exactness is not the same concept as
|
|
; "representable in IEEE float without loss of precision"
|
|
|
|
; Some large numbers seemingly integral
|
|
; are not representable in IEEE float:
|
|
; some integers having greater than 15 digits.
|
|
; This is moot for TinyScheme since if they have no non-zero fractional digits,
|
|
; they are integer?
|
|
|
|
; integers greater than 19 digits are exact but have overflowed
|
|
(assert `(exact? 12345678901234567890))
|
|
|
|
; 3122.55 is not representable in IEEE float
|
|
; but is represented by the nearest representable value.
|
|
; Which is 3122.5500000000001818989403545856475830078125
|
|
; 17 significant digits: 3122.5500000000002, with >10 decimal places.
|
|
; TS uses %.10g printf format.
|
|
(assert `(inexact? 3122.55))
|
|
; The string representation is only 10 digits
|
|
; so rounded and truncated trailing zeros.
|
|
; FIXME this fails in non-English locale
|
|
; Currently prints as 3122,55.0
|
|
(assert `(string=? (number->string 3122.55)
|
|
"3122.55"))
|
|
|
|
|
|
|
|
|
|
|
|
; exactness and operations
|
|
|
|
; "inexactness is a contagious property of a number", with exceptions
|
|
; I.E. any operations with an inexact operand produces an inexact result,
|
|
; with exceptions.
|
|
|
|
; Division of any two exact numbers is exact
|
|
; This is only an illustration, not an exhaustive test
|
|
(assert `(exact?
|
|
(/ 4.0 2.0)))
|
|
|
|
; exception:
|
|
; multiplication of any number by an exact zero may produce an exact zero result, even if the other argument is inexact.
|
|
(assert `(exact?
|
|
(* 0 3122.55)))
|
|
|
|
; equivalence of exact and inexact numbers
|
|
; Scheme says: never equivalent.
|
|
; The literals look the same, and are exact, but converting one to inexact.
|
|
; FUTURE: this fails because exact->inexact fails to produce an inexact
|
|
; This is extremely obscure, so wait for upstream fix.
|
|
;; (assert `(not (eqv? 4.0 (exact->inexact 4.0))))
|
|
|
|
|
|
; inexact->exact
|
|
|
|
; Non-integral numbers cannot be converted to exact
|
|
(assert-error `(inexact->exact 3122.55)
|
|
"inexact->exact: not integral:")
|
|
|
|
; A large integral number (only representable in float machine representation)
|
|
; can be converted to exact.
|
|
(assert `(exact? (inexact->exact 9223372036854775808.0)))
|
|
; But the result is not correct.
|
|
; Here the result is the least signed integer representable in signed 64-bit
|
|
(assert `(= (inexact->exact 9223372036854775808.0)
|
|
-9223372036854775808))
|
|
|
|
|
|
; exact->inexact
|
|
|
|
; Is defined
|
|
(assert `exact->inexact)
|
|
|
|
; FUTURE fails, TinyScheme is non-compliant
|
|
;; (assert `(inexact? (exact->inexact 4.0)))
|
|
|
|
|
|
(test! "Round-trip (string->number (number->string x))")
|
|
; conversions to and from strings
|
|
;
|
|
; Meets a round-trip conversion predicate.
|
|
; A string representation of a number converts back to the same number.
|
|
(define (round-trip-repr? number)
|
|
(eqv? number
|
|
(string->number (number->string number))))
|
|
|
|
; Note, no backtick on calls to predicate
|
|
(assert (round-trip-repr? 1.0))
|
|
(assert (round-trip-repr? 1.01))
|
|
(assert (round-trip-repr? 3122.55))
|
|
|
|
; The string representation is fixed at 10 digits after decimal point.
|
|
; So numbers with more precision don't round-trip
|
|
(assert (not (round-trip-repr? 1.01234567890123)))
|
|
; FIXME The test is inverted. This number should round-trip
|
|
; Currently prints as 1.012345679, losing 4 significant digits.
|
|
|
|
; Note that IEEE double can represent about 15 decimal places
|
|
; but TinyScheme somewhat arbitrarily limits the string representation
|
|
; to 10 decimal places
|
|
|
|
|
|
|
|
; Test various literals
|
|
(test! "string->number")
|
|
(assert `(= (string->number "100")
|
|
100))
|
|
(assert `(= (string->number "1e2")
|
|
100.0))
|
|
; the notation using # for unspecified digit is not supported
|
|
; TinyScheme returns #f, some Schemes return 1500.0
|
|
(assert `(not (string->number "15##")))
|
|
|
|
(test! "radix arg to string->number")
|
|
; hexadecimal
|
|
(assert `(= (string->number "100" 16)
|
|
256))
|
|
|
|
|
|
|
|
; numeric literals
|
|
|
|
; In Scheme, the #e prefix makes a literal exact
|
|
; but TinyScheme returns a syntax error.
|
|
; FUTURE: the test framework can't test syntax errors
|
|
;;(assert-error `#e1
|
|
;; "syntax: illegal sharp expression")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|