8 / 24 · Lab
Lab: execute the quantization contract
Quantize −40 with the same uint8 settings. What are its code and dequantized value, and which assertion would you add?
Lessons are free to read. Enroll to save your learning progress.
Goal and preparation
Execute code mapping, negative ties, saturation and a centered integer dot product. This file needs Node.js and no external package. Create quantize-lab.mjs in a new empty folder, copy the code below and run node quantize-lab.mjs. Without Node, complete the prediction table by hand. If your installed Digital Design Studio provides a supported create/open-file workflow for this file type, you may manually create and inspect the same file there. These instructions do not claim automatic project creation or execution inside DDS.
Predict before running
At scale 0.25 and zero point 128, −0.625 becomes tie −2.5, rounds to even −2 and gives code 126. Input −0.375 also gives 126. Zero gives 128; 0.375 and 0.625 both give 130. Input 40 would give 288, so uint8 saturation changes it to 255. Predict [126,126,128,130,130,255]. These cases distinguish negative ties, positive ties, real zero and clipping.
Center [130,126] to [2,−2]. With weights [3,−2], the sum is ten. Combined scale 0.125 represents real 1.25; output scale 0.25 and zero point 128 give 133. The code is a numerical-contract exercise, rather than a model importer or accuracy benchmark.
First run the unmodified assertions. Then replace 0.625 by 0.875. Predict tie 3.5 rounding to four and code 132 before changing the expected value. Temporarily replace roundEven with Math.round and observe the negative-tie assertion fail, then restore it. An intentional failure demonstrates that the test observes the required behavior.
Finally, dequantize the saturated code 255: it represents 31.75, an error of −8.25 relative to 40. This is much larger than the ordinary half-step rounding bound. Choosing scale involves a range-versus-resolution tradeoff; measuring model accuracy requires a separate model and dataset. Record your predictions, command output and changed-case reasoning.
Runnable file
import assert from 'node:assert/strict';
// An exact tie is handled with nearest-even, including negative input.
export function roundEven(v) {
const f = Math.floor(v), d = v - f;
return d < 0.5 ? f : d > 0.5 ? f + 1 : f % 2 === 0 ? f : f + 1;
}
export const quantize = (x, s, z) => Math.min(255, Math.max(0, roundEven(x / s) + z));
const values = [-0.625, -0.375, 0, 0.375, 0.625, 40];
const codes = values.map(x => quantize(x, 0.25, 128));
assert.deepEqual(codes, [126, 126, 128, 130, 130, 255]);
assert.equal(roundEven(-1.5), -2);
assert.equal(roundEven(-2.5), -2);
const xq = [130, 126], wq = [3, -2];
const acc = xq.reduce((sum, x, i) => sum + (x - 128) * wq[i], 0);
assert.equal(acc, 10);
assert.equal(acc * 0.25 * 0.5, 1.25);
assert.equal(quantize(1.25, 0.25, 128), 133);
console.log(JSON.stringify({codes, acc, real: 1.25, output: 133}));Try it yourself
Quantize −40 with the same uint8 settings. What are its code and dequantized value, and which assertion would you add?
Read the explanation
The unbounded code is −32, so it clips to zero. Dequantization is (0−128)×0.25=−32. Add an assertion that quantize(−40,0.25,128) equals zero to cover negative saturation.