Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions web/src/gofixed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// goFixed is strconv.FormatFloat(v, 'f', digits, 64). toFixed already rounds
// the exact binary value; the one difference is an exact tie, which toFixed
// takes away from zero and Go takes to even. A tie is a multiple of
// 2^-(digits+1), and that test is exact (a power-of-two scale).
//
// It lives here so the page chrome and the run route can both print with it.
// page.js must not import run.js: run.js imports the page.
export function goFixed(v, digits) {
const m = 10 ** digits;
const x = v * m;
if (Number.isInteger(v * 2 ** (digits + 1)) && !Number.isInteger(x)) {
const f = Math.floor(x);
return ((f % 2 === 0 ? f : f + 1) / m).toFixed(digits);
}
return v.toFixed(digits);
}
6 changes: 5 additions & 1 deletion web/src/page.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { goFixed } from "./gofixed.js";

// The chrome every page shares.
//
// One stylesheet, inline, because the pages are small and a published run
Expand Down Expand Up @@ -222,5 +224,7 @@ export function esc(s) {
// `?`; never print a default you did not observe).
export function fmt(n) {
if (!n) return "?";
return n >= 100 ? n.toFixed(0) : n.toFixed(1);
// The card's formatRate. goFixed is the tie rule; toFixed would print the
// other way on an exact half.
return n >= 100 ? goFixed(n, 0) : goFixed(n, 1);
}
15 changes: 1 addition & 14 deletions web/src/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// a door — the id is the secret (§9.3).

import { avatarPath } from "./author.js";
import { goFixed } from "./gofixed.js";
import { fail, json } from "./http.js";
import { esc, fmt, head, layout } from "./page.js";

Expand Down Expand Up @@ -659,20 +660,6 @@ function formatProbeMs(v) {
return `${goFixed(v, 0)} ms`;
}

// goFixed is strconv.FormatFloat(v, 'f', digits, 64). toFixed already rounds
// the exact binary value; the one difference is an exact tie, which toFixed
// takes away from zero and Go takes to even. A tie is a multiple of
// 2^-(digits+1), and that test is exact (a power-of-two scale).
export function goFixed(v, digits) {
const m = 10 ** digits;
const x = v * m;
if (Number.isInteger(v * 2 ** (digits + 1)) && !Number.isInteger(x)) {
const f = Math.floor(x);
return ((f % 2 === 0 ? f : f + 1) / m).toFixed(digits);
}
return v.toFixed(digits);
}

// memoryRow is the card's MEMORY lines that the index carries, in one cell:
// "GPU0 10.4/12.0 GiB · host RSS 11.6 GiB (file 11.1 / anon 0.2)". Each
// gpu_mem entry is "GPUn used/total GiB", or "GPUn used GiB" when the
Expand Down
10 changes: 9 additions & 1 deletion web/test/gofixed.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import assert from "node:assert/strict";
import test from "node:test";

import { goFixed } from "../src/run.js";
import { fmt } from "../src/page.js";
import { goFixed } from "../src/gofixed.js";

test("an exact tie rounds to even, as Go does", () => {
assert.equal(goFixed(0.25, 1), "0.2");
Expand All @@ -16,6 +17,13 @@ test("an exact tie rounds to even, as Go does", () => {
assert.equal(goFixed(-0.25, 1), "-0.2");
});

test("fmt uses that tie rule for the figures the page shares with the card", () => {
assert.equal(fmt(0.25), "0.2");
assert.equal(fmt(0.75), "0.8");
assert.equal(fmt(150.5), "150");
assert.equal(fmt(0), "?");
});

test("a value that only looks like a tie rounds by its exact value", () => {
// 0.15 and 1.45 are stored just under the tie (0.1499…, 1.4499…): Go prints 0.1 and 1.4.
assert.equal(goFixed(0.15, 1), "0.1");
Expand Down
Loading