mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-03 17:33:25 +00:00
ScriptFu: test TinyScheme numerics
No changes except to tests. Many tests of TinyScheme compliance to R5RS re numbers. Tests issue 1049 "prints floats with commas" in non-English locale. Some tests pass in English but fail in German. Prepatory to a fix, so we know the fix works and doesn't break anything else.
This commit is contained in:
parent
ee9bb99801
commit
10bccee8b0
3 changed files with 274 additions and 0 deletions
|
@ -96,6 +96,7 @@ if not stable
|
|||
'tests' / 'TS' / 'testing.scm',
|
||||
'tests' / 'TS' / 'vector.scm',
|
||||
'tests' / 'TS' / 'no-memory.scm',
|
||||
'tests' / 'TS' / 'numeric.scm',
|
||||
# comprehensive, total test
|
||||
'tests' / 'TS' / 'tinyscheme.scm',
|
||||
]
|
||||
|
|
271
plug-ins/script-fu/test/tests/TS/numeric.scm
Normal file
271
plug-ins/script-fu/test/tests/TS/numeric.scm
Normal file
|
@ -0,0 +1,271 @@
|
|||
; 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")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
(testing:load-test "no-memory.scm")
|
||||
|
||||
(testing:load-test "numeric.scm")
|
||||
|
||||
; report the result
|
||||
(testing:report)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue