js-on-sx: Math.round/max/min spec edges (NaN, +/-Infinity, +/-0)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s

This commit is contained in:
2026-05-10 10:17:12 +00:00
parent 85414df868
commit 551c24c5a0
2 changed files with 41 additions and 7 deletions

View File

@@ -3879,45 +3879,77 @@
(define js-math-ceil (fn (x) (ceil (js-to-number x))))
(define js-math-round (fn (x) (floor (+ (js-to-number x) 0.5))))
(define
js-math-round
(fn
(x)
(let
((n (js-to-number x)))
(cond
((js-number-is-nan n) (js-nan-value))
((= n (js-infinity-value)) n)
((= n (- 0 (js-infinity-value))) n)
((= n 0) n)
(else (floor (+ n 0.5)))))))
(define
js-math-max
(fn
(&rest args)
(cond
((empty? args) -inf)
(else (js-math-max-loop (first args) (rest args))))))
((empty? args) (- 0 (js-infinity-value)))
(else (js-math-max-loop (js-to-number (first args)) (rest args))))))
(define
js-math-max-loop
(fn
(acc xs)
(cond
((js-number-is-nan acc) (js-nan-value))
((empty? xs) acc)
(else
(let
((h (js-to-number (first xs))))
(js-math-max-loop (if (> h acc) h acc) (rest xs)))))))
(cond
((js-number-is-nan h) (js-nan-value))
((> h acc) (js-math-max-loop h (rest xs)))
((and (= h 0) (= acc 0))
(js-math-max-loop (if (js-is-positive-zero? h) h acc) (rest xs)))
(else (js-math-max-loop acc (rest xs)))))))))
(define
js-math-min
(fn
(&rest args)
(cond
((empty? args) inf)
(else (js-math-min-loop (first args) (rest args))))))
((empty? args) (js-infinity-value))
(else (js-math-min-loop (js-to-number (first args)) (rest args))))))
(define
js-math-min-loop
(fn
(acc xs)
(cond
((js-number-is-nan acc) (js-nan-value))
((empty? xs) acc)
(else
(let
((h (js-to-number (first xs))))
(js-math-min-loop (if (< h acc) h acc) (rest xs)))))))
(cond
((js-number-is-nan h) (js-nan-value))
((< h acc) (js-math-min-loop h (rest xs)))
((and (= h 0) (= acc 0))
(js-math-min-loop (if (js-is-positive-zero? h) acc h) (rest xs)))
(else (js-math-min-loop acc (rest xs)))))))))
(define
js-is-positive-zero?
(fn
(n)
(cond
((not (= n 0)) false)
((= (type-of n) "rational") true)
(else (= (/ 1.0 (exact->inexact n)) (js-infinity-value))))))
(define js-math-random (fn () 0))

View File

@@ -158,6 +158,8 @@ Each item: implement → tests → update progress. Mark `[x]` when tests green.
Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta.
- 2026-05-10 — **`Math.round` / `Math.max` / `Math.min` honour spec edge cases for NaN, ±Infinity, and ±0.** `Math.round(NaN)` was returning 0 because `floor(NaN+0.5)` doesn't propagate NaN; ditto `±Infinity` paths. `Math.max({})` silently returned `-Infinity` (initial accumulator) because the first arg wasn't ToNumber'd. `Math.max(0, -0)` returned `-0` because `>` doesn't distinguish them. Rewrites: round NaN/±Infinity/±0 short-circuits; max/min ToNumber the first arg, propagate NaN immediately, and use a `js-is-positive-zero?` (rational-safe) tiebreaker so `Math.max(0, -0) === 0` per spec. Result: built-ins/Math/round 5/10 → 8/10 (+3). Math/max 6/9 → 8/9 (+2). Math/min 6/9 → 8/9 (+2). conformance.sh: 148/148.
- 2026-05-10 — **`Map.prototype.*` and `Set.prototype.*` raise TypeError when called on non-Map / non-Set `this`.** All five `js-map-do-*` and four `js-set-do-*` helpers were assuming `this` had `__map_keys__` / `__set_items__`, so `Map.prototype.clear.call({})` silently returned undefined (after creating dangling state) instead of throwing. Added `js-map-check!` / `js-set-check!` guards run as the first step of each method; raise spec-correct `TypeError` instances. Result: built-ins/Map 18/30 → 22/30 (+4). built-ins/Set 15/30 → 28/30 (+13). conformance.sh: 148/148.
- 2026-05-10 — **`Date.UTC` / `new Date(...)` propagate NaN/±Infinity arguments and return NaN.** `Date.UTC()` (no args) returned 0 instead of NaN; `Date.UTC(NaN, ...)` did the math and produced bogus ms; `new Date(year, NaN)` constructed a normal Date instead of an invalid one. Added `js-date-args-have-nan?` (also detects ±Infinity and propagates from rationals) used by both `Date.UTC` and the multi-arg constructor branch; UTC now returns NaN on no-arg / any-NaN-arg / out-of-range result, and `new Date(args)` stores NaN in `__date_value__` when any arg is NaN. Also fixed `js-date-from-one(undefined)` to return NaN. Result: built-ins/Date/UTC 6/16 → 10/16 (+4). Date 17/30 → 26/30 (timeouts dropped from 12 → 4 because invalid Dates now short-circuit). conformance.sh: 148/148.