Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wgsl: Change the term bounds to endpoints for intervals #3207

Merged
merged 2 commits into from
Dec 6, 2023
Merged
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
27 changes: 17 additions & 10 deletions docs/fp_primer.md
Original file line number Diff line number Diff line change
@@ -39,7 +39,8 @@ A floating point number system defines
- Arithmetic operations on those representatives, trying to approximate the
ideal operations on real numbers.

The cardinality mismatch alone implies that any floating point number system necessarily loses information.
The cardinality mismatch alone implies that any floating point number system
necessarily loses information.

This means that not all numbers in the bounds can be exactly represented as a
floating point value.
@@ -114,7 +115,7 @@ Implementations may assume that infinities are not present. When an evaluation
at runtime would produce an infinity, an indeterminate value is produced
instead.

When a value goes out of bounds for a specific precision there are special
When a value goes out-of-bounds for a specific precision there are special
rounding rules that apply. If it is 'near' the edge of finite values for that
precision, it is considered to be near-overflowing, and the implementation may
choose to round it to the edge value or the appropriate infinity. If it is not
@@ -163,7 +164,7 @@ the rules for compile time execution will be discussed below.)

Signaling NaNs are treated as quiet NaNs in the WGSL spec. And quiet NaNs have
the same "may-convert-to-indeterminate-value" behaviour that infinities have, so
for the purpose of the CTS they are handled by the infinite/out of bounds logic
for the purpose of the CTS they are handled by the infinite/out-of-bounds logic
normally.

## Notation/Terminology
@@ -231,14 +232,20 @@ referred to as the beginning of the interval and `b` as the end of the interval.

When talking about intervals, this doc and the code endeavours to avoid using
the term **range** to refer to the span of values that an interval covers,
instead using the term bounds to avoid confusion of terminology around output of
operations.
instead using the term **endpoints** to avoid confusion of terminology around
output of operations.

The term **endpoints** is generally used to refer to the conceptual numeric
spaces, i.e. f32 or abstract float.

Thus a specific interval can have **endpoints** that are either in or out of
bounds for a specific floating point precision.

## Accuracy

As mentioned above floating point numbers are not able to represent all the
possible values over their bounds, but instead represent discrete values in that
interval, and approximate the remainder.
possible values over their range, but instead represent discrete values in that
space, and approximate the remainder.

Additionally, floating point numbers are not evenly distributed over the real
number line, but instead are more densely clustered around zero, with the space
@@ -398,7 +405,7 @@ That would be very inefficient though and make your reviewer sad to read.

For mapping intervals to intervals the key insight is that we only need to be
concerned with the extrema of the operation in the interval, since the
acceptance interval is the bounds of the possible outputs.
acceptance interval is defined by largest and smallest of the possible outputs.

In more precise terms:
```
@@ -652,7 +659,7 @@ the theoretical world that the intervals being used for testing are infinitely
precise, when in actuality they are implemented by the ECMAScript `number` type,
which is implemented as a f64 value.

For the vast majority of cases, even out of bounds and overflow, this is
For the vast majority of cases, even out-of-bounds and overflow, this is
sufficient. There is one small slice where this breaks down. Specifically if
the result just outside the finite range by less than 1 f64 ULP of the edge
value. An example of this is `2 ** -11 + f32.max`. This will be between `f32.max`
@@ -752,7 +759,7 @@ const_assert upper > foo(x) // Result was above the acceptance interval
```

where lower and upper would actually be string replaced with literals for the
bounds of the acceptance interval when generating the shader text.
endpoints of the acceptance interval when generating the shader text.

This approach has a number of limitations that made it unacceptable for the CTS.
First, how errors are reported is a pain to debug. Someone working with the CTS
180 changes: 90 additions & 90 deletions src/resources/cache/hashes.json
Original file line number Diff line number Diff line change
@@ -1,103 +1,103 @@
{
"webgpu/shader/execution/binary/af_addition.bin": "b5345cca",
"webgpu/shader/execution/binary/af_addition.bin": "a9c5cce6",
"webgpu/shader/execution/binary/af_logical.bin": "9ec85311",
"webgpu/shader/execution/binary/af_division.bin": "23dd840e",
"webgpu/shader/execution/binary/af_matrix_addition.bin": "ee95539e",
"webgpu/shader/execution/binary/af_matrix_subtraction.bin": "a2e64d57",
"webgpu/shader/execution/binary/af_multiplication.bin": "94d7a574",
"webgpu/shader/execution/binary/af_remainder.bin": "79f5abc4",
"webgpu/shader/execution/binary/af_subtraction.bin": "62dce5bf",
"webgpu/shader/execution/binary/f16_addition.bin": "ab3b4d9c",
"webgpu/shader/execution/binary/af_division.bin": "8d23c845",
"webgpu/shader/execution/binary/af_matrix_addition.bin": "63a6a1ac",
"webgpu/shader/execution/binary/af_matrix_subtraction.bin": "120cfedf",
"webgpu/shader/execution/binary/af_multiplication.bin": "94eed575",
"webgpu/shader/execution/binary/af_remainder.bin": "7d4767a5",
"webgpu/shader/execution/binary/af_subtraction.bin": "5a18e960",
"webgpu/shader/execution/binary/f16_addition.bin": "7a67e7b1",
"webgpu/shader/execution/binary/f16_logical.bin": "1edd08ec",
"webgpu/shader/execution/binary/f16_division.bin": "849eed26",
"webgpu/shader/execution/binary/f16_matrix_addition.bin": "54afc3f8",
"webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "df5d3ccc",
"webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "3be6032e",
"webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "98a29837",
"webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "c463d7e0",
"webgpu/shader/execution/binary/f16_multiplication.bin": "cdf0775d",
"webgpu/shader/execution/binary/f16_remainder.bin": "e82ef89f",
"webgpu/shader/execution/binary/f16_subtraction.bin": "5125b5b0",
"webgpu/shader/execution/binary/f32_addition.bin": "d3b8004",
"webgpu/shader/execution/binary/f16_division.bin": "127a1260",
"webgpu/shader/execution/binary/f16_matrix_addition.bin": "f3a630df",
"webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "e396f4b8",
"webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "bfbed0d7",
"webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "50d9bac9",
"webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "9b0ddaa2",
"webgpu/shader/execution/binary/f16_multiplication.bin": "6b29214d",
"webgpu/shader/execution/binary/f16_remainder.bin": "c45c8326",
"webgpu/shader/execution/binary/f16_subtraction.bin": "44437355",
"webgpu/shader/execution/binary/f32_addition.bin": "ef227af",
"webgpu/shader/execution/binary/f32_logical.bin": "fab7cfc5",
"webgpu/shader/execution/binary/f32_division.bin": "e9fdb0a9",
"webgpu/shader/execution/binary/f32_matrix_addition.bin": "d1165469",
"webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "45a79521",
"webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "bf8da7d0",
"webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "82d7fa9",
"webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "57eebe84",
"webgpu/shader/execution/binary/f32_multiplication.bin": "eb0baa56",
"webgpu/shader/execution/binary/f32_remainder.bin": "e6059990",
"webgpu/shader/execution/binary/f32_subtraction.bin": "d57cfa1",
"webgpu/shader/execution/binary/f32_division.bin": "c2df73c9",
"webgpu/shader/execution/binary/f32_matrix_addition.bin": "18502449",
"webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "96cda4b2",
"webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "5570ca6f",
"webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "a0d7e8d1",
"webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "90b6aeb9",
"webgpu/shader/execution/binary/f32_multiplication.bin": "f6dff4c7",
"webgpu/shader/execution/binary/f32_remainder.bin": "1d5f3a8",
"webgpu/shader/execution/binary/f32_subtraction.bin": "b9a951e9",
"webgpu/shader/execution/binary/i32_arithmetic.bin": "de93ee2a",
"webgpu/shader/execution/binary/i32_comparison.bin": "aaa1f21b",
"webgpu/shader/execution/binary/u32_arithmetic.bin": "d79a1011",
"webgpu/shader/execution/binary/u32_comparison.bin": "31764c75",
"webgpu/shader/execution/abs.bin": "9278901c",
"webgpu/shader/execution/acos.bin": "9c77ebf9",
"webgpu/shader/execution/acosh.bin": "2baaf7cc",
"webgpu/shader/execution/asin.bin": "8fd7a678",
"webgpu/shader/execution/asinh.bin": "321a7294",
"webgpu/shader/execution/atan.bin": "d3dada7e",
"webgpu/shader/execution/atan2.bin": "2871596c",
"webgpu/shader/execution/atanh.bin": "e7158ef",
"webgpu/shader/execution/bitcast.bin": "aa7d6f0e",
"webgpu/shader/execution/ceil.bin": "3c1d91ad",
"webgpu/shader/execution/clamp.bin": "a53fdbda",
"webgpu/shader/execution/cos.bin": "73b83288",
"webgpu/shader/execution/cosh.bin": "39ca32a4",
"webgpu/shader/execution/cross.bin": "409c3e26",
"webgpu/shader/execution/degrees.bin": "a44bb2b1",
"webgpu/shader/execution/determinant.bin": "41a06528",
"webgpu/shader/execution/distance.bin": "fe3ea84f",
"webgpu/shader/execution/dot.bin": "f70abfec",
"webgpu/shader/execution/exp.bin": "7587e11b",
"webgpu/shader/execution/exp2.bin": "c6f34d2b",
"webgpu/shader/execution/faceForward.bin": "8eb57a7d",
"webgpu/shader/execution/floor.bin": "b9ea647b",
"webgpu/shader/execution/fma.bin": "b9f657b2",
"webgpu/shader/execution/fract.bin": "73a18e4f",
"webgpu/shader/execution/frexp.bin": "857fe9b7",
"webgpu/shader/execution/inverseSqrt.bin": "a595983a",
"webgpu/shader/execution/ldexp.bin": "a04aaeca",
"webgpu/shader/execution/length.bin": "695740fb",
"webgpu/shader/execution/log.bin": "6703ec1a",
"webgpu/shader/execution/log2.bin": "8339559d",
"webgpu/shader/execution/max.bin": "ec000a56",
"webgpu/shader/execution/min.bin": "156cf7cc",
"webgpu/shader/execution/mix.bin": "32064d21",
"webgpu/shader/execution/modf.bin": "a5003ce0",
"webgpu/shader/execution/normalize.bin": "c12bac96",
"webgpu/shader/execution/abs.bin": "9e12d146",
"webgpu/shader/execution/acos.bin": "d72227bc",
"webgpu/shader/execution/acosh.bin": "b3008340",
"webgpu/shader/execution/asin.bin": "2348666b",
"webgpu/shader/execution/asinh.bin": "1fcc0429",
"webgpu/shader/execution/atan.bin": "34f29ec8",
"webgpu/shader/execution/atan2.bin": "33c3196c",
"webgpu/shader/execution/atanh.bin": "79cffc5a",
"webgpu/shader/execution/bitcast.bin": "c6e7405c",
"webgpu/shader/execution/ceil.bin": "4cabf37c",
"webgpu/shader/execution/clamp.bin": "8b4c84c7",
"webgpu/shader/execution/cos.bin": "dd4f0d54",
"webgpu/shader/execution/cosh.bin": "cf2303ea",
"webgpu/shader/execution/cross.bin": "f231a725",
"webgpu/shader/execution/degrees.bin": "216634ac",
"webgpu/shader/execution/determinant.bin": "3a4c5761",
"webgpu/shader/execution/distance.bin": "45c1bcee",
"webgpu/shader/execution/dot.bin": "553f268b",
"webgpu/shader/execution/exp.bin": "13f273d5",
"webgpu/shader/execution/exp2.bin": "215379e7",
"webgpu/shader/execution/faceForward.bin": "dfcee405",
"webgpu/shader/execution/floor.bin": "422b808a",
"webgpu/shader/execution/fma.bin": "df385cdd",
"webgpu/shader/execution/fract.bin": "416f144f",
"webgpu/shader/execution/frexp.bin": "48323de7",
"webgpu/shader/execution/inverseSqrt.bin": "b5d88ed0",
"webgpu/shader/execution/ldexp.bin": "82257924",
"webgpu/shader/execution/length.bin": "eef942e5",
"webgpu/shader/execution/log.bin": "6889843e",
"webgpu/shader/execution/log2.bin": "97bae6ee",
"webgpu/shader/execution/max.bin": "9369c070",
"webgpu/shader/execution/min.bin": "85cd40d4",
"webgpu/shader/execution/mix.bin": "f24ecba4",
"webgpu/shader/execution/modf.bin": "6914406e",
"webgpu/shader/execution/normalize.bin": "56db74b3",
"webgpu/shader/execution/pack2x16float.bin": "b2cb12ea",
"webgpu/shader/execution/pow.bin": "ee87eccb",
"webgpu/shader/execution/quantizeToF16.bin": "f77ae7e3",
"webgpu/shader/execution/radians.bin": "7ecbe5be",
"webgpu/shader/execution/reflect.bin": "d37034bd",
"webgpu/shader/execution/refract.bin": "6dc9adcf",
"webgpu/shader/execution/round.bin": "d91faa0f",
"webgpu/shader/execution/saturate.bin": "93230980",
"webgpu/shader/execution/sign.bin": "fb1071b8",
"webgpu/shader/execution/sin.bin": "a9ed8361",
"webgpu/shader/execution/sinh.bin": "65ba80fc",
"webgpu/shader/execution/smoothstep.bin": "17e1e103",
"webgpu/shader/execution/sqrt.bin": "4c29a5d4",
"webgpu/shader/execution/step.bin": "aed08458",
"webgpu/shader/execution/tan.bin": "5f671594",
"webgpu/shader/execution/tanh.bin": "991e903a",
"webgpu/shader/execution/transpose.bin": "9d388797",
"webgpu/shader/execution/trunc.bin": "959fe8bc",
"webgpu/shader/execution/unpack2x16float.bin": "26e5b05e",
"webgpu/shader/execution/unpack2x16snorm.bin": "c756d8a3",
"webgpu/shader/execution/unpack2x16unorm.bin": "5257591a",
"webgpu/shader/execution/unpack4x8snorm.bin": "83fbd41a",
"webgpu/shader/execution/unpack4x8unorm.bin": "77d46acb",
"webgpu/shader/execution/unary/af_arithmetic.bin": "2edb2dc5",
"webgpu/shader/execution/unary/af_assignment.bin": "36c04bba",
"webgpu/shader/execution/pow.bin": "4559fe54",
"webgpu/shader/execution/quantizeToF16.bin": "6e7140c0",
"webgpu/shader/execution/radians.bin": "3d20d9af",
"webgpu/shader/execution/reflect.bin": "83096c2a",
"webgpu/shader/execution/refract.bin": "5ff885dc",
"webgpu/shader/execution/round.bin": "f8bdb72b",
"webgpu/shader/execution/saturate.bin": "fd71272f",
"webgpu/shader/execution/sign.bin": "5ac3fcf8",
"webgpu/shader/execution/sin.bin": "8eb2a6be",
"webgpu/shader/execution/sinh.bin": "33fffc1d",
"webgpu/shader/execution/smoothstep.bin": "33df4b5f",
"webgpu/shader/execution/sqrt.bin": "f0e8fd1",
"webgpu/shader/execution/step.bin": "eef87c59",
"webgpu/shader/execution/tan.bin": "4904b8c0",
"webgpu/shader/execution/tanh.bin": "b1afeda",
"webgpu/shader/execution/transpose.bin": "697e34a5",
"webgpu/shader/execution/trunc.bin": "4474ec0",
"webgpu/shader/execution/unpack2x16float.bin": "be34edc2",
"webgpu/shader/execution/unpack2x16snorm.bin": "68115c4",
"webgpu/shader/execution/unpack2x16unorm.bin": "b0a3bc8d",
"webgpu/shader/execution/unpack4x8snorm.bin": "778671b5",
"webgpu/shader/execution/unpack4x8unorm.bin": "686ea0d",
"webgpu/shader/execution/unary/af_arithmetic.bin": "b1492312",
"webgpu/shader/execution/unary/af_assignment.bin": "86ca08b5",
"webgpu/shader/execution/unary/bool_conversion.bin": "cb53bf65",
"webgpu/shader/execution/unary/f16_arithmetic.bin": "9f459fc4",
"webgpu/shader/execution/unary/f16_conversion.bin": "bf055ca9",
"webgpu/shader/execution/unary/f32_arithmetic.bin": "e15c49e7",
"webgpu/shader/execution/unary/f32_conversion.bin": "92e5069f",
"webgpu/shader/execution/unary/f16_arithmetic.bin": "69914092",
"webgpu/shader/execution/unary/f16_conversion.bin": "8a3ffbbb",
"webgpu/shader/execution/unary/f32_arithmetic.bin": "61e25fb6",
"webgpu/shader/execution/unary/f32_conversion.bin": "c47c9b05",
"webgpu/shader/execution/unary/i32_arithmetic.bin": "d322b73d",
"webgpu/shader/execution/unary/i32_complement.bin": "c4e6cbb",
"webgpu/shader/execution/unary/i32_conversion.bin": "d6905a0f",
1,147 changes: 577 additions & 570 deletions src/unittests/floating_point.spec.ts

Large diffs are not rendered by default.

105 changes: 55 additions & 50 deletions src/webgpu/util/floating_point.ts
Original file line number Diff line number Diff line change
@@ -99,12 +99,12 @@ export function deserializeFPKind(s: BinaryStream): FPKind {
// Containers

/**
* Representation of bounds for an interval as an array with either one or two
* elements. Single element indicates that the interval is a single point. For
* two elements, the first is the lower bound of the interval and the second is
* the upper bound.
* Representation of endpoints for an interval as an array with either one or
* two elements. Single element indicates that the interval is a single point.
* For two elements, the first is the lower edges of the interval and the
* second is the upper edge, i.e. e[0] <= e[1], where e is an IntervalEndpoints
*/
export type IntervalBounds = readonly [number] | readonly [number, number];
export type IntervalEndpoints = readonly [number] | readonly [number, number];

/** Represents a closed interval of floating point numbers */
export class FPInterval {
@@ -118,15 +118,18 @@ export class FPInterval {
* `FPTraits.toInterval` is the preferred way to create FPIntervals
*
* @param kind the floating point number type this is an interval for
* @param bounds beginning and end of the interval
* @param endpoints beginning and end of the interval
*/
public constructor(kind: FPKind, ...bounds: IntervalBounds) {
public constructor(kind: FPKind, ...endpoints: IntervalEndpoints) {
this.kind = kind;

const begin = bounds[0];
const end = bounds.length === 2 ? bounds[1] : bounds[0];
assert(!Number.isNaN(begin) && !Number.isNaN(end), `bounds need to be non-NaN`);
assert(begin <= end, `bounds[0] (${begin}) must be less than or equal to bounds[1] (${end})`);
const begin = endpoints[0];
const end = endpoints.length === 2 ? endpoints[1] : endpoints[0];
assert(!Number.isNaN(begin) && !Number.isNaN(end), `endpoints need to be non-NaN`);
assert(
begin <= end,
`endpoints[0] (${begin}) must be less than or equal to endpoints[1] (${end})`
);

this.begin = begin;
this.end = end;
@@ -138,7 +141,7 @@ export class FPInterval {
}

/** @returns begin and end if non-point interval, otherwise just begin */
public bounds(): IntervalBounds {
public endpoints(): IntervalEndpoints {
return this.isPoint() ? [this.begin] : [this.begin, this.end];
}

@@ -179,7 +182,7 @@ export class FPInterval {

/** @returns a string representation for logging purposes */
public toString(): string {
return `{ '${this.kind}', [${this.bounds().map(this.traits().scalarBuilder)}] }`;
return `{ '${this.kind}', [${this.endpoints().map(this.traits().scalarBuilder)}] }`;
}
}

@@ -328,7 +331,7 @@ interface ScalarToIntervalOp {
* occur and returns a span of those points to be used as the domain instead.
*
* Used by this.runScalarToIntervalOp before invoking impl.
* If not defined, the bounds of the existing domain are assumed to be the
* If not defined, the endpoints of the existing domain are assumed to be the
* extrema.
*
* This is only implemented for operations that meet all the following
@@ -359,10 +362,10 @@ interface ScalarPairToIntervalOp {
* occur and returns spans of those points to be used as the domain instead.
*
* Used by runScalarPairToIntervalOp before invoking impl.
* If not defined, the bounds of the existing domain are assumed to be the
* If not defined, the endpoints of the existing domain are assumed to be the
* extrema.
*
* This is only implemented for functions that meet all of the following
* This is only implemented for functions that meet all the following
* criteria:
* a) non-monotonic
* b) used in inherited accuracy calculations
@@ -572,7 +575,7 @@ export interface VectorMatrixToVector {
// Traits

/**
* Typed structure containing all the limits/constants defined for each
* Typed structure containing all the constants defined for each
* WGSL floating point kind
*/
interface FPConstants {
@@ -651,7 +654,7 @@ interface FPConstants {
/** A representation of an FPInterval for a case param */
export type FPIntervalParam = {
kind: FPKind;
interval: number | IntervalBounds;
interval: number | IntervalEndpoints;
};

/** Abstract base class for all floating-point traits */
@@ -666,7 +669,7 @@ export abstract class FPTraits {
// Utilities - Implemented

/** @returns an interval containing the point or the original interval */
public toInterval(n: number | IntervalBounds | FPInterval): FPInterval {
public toInterval(n: number | IntervalEndpoints | FPInterval): FPInterval {
if (n instanceof FPInterval) {
if (n.kind === this.kind) {
return n;
@@ -677,7 +680,7 @@ export abstract class FPTraits {
return this.constants().unboundedInterval;
}

return new FPInterval(this.kind, ...n.bounds());
return new FPInterval(this.kind, ...n.endpoints());
}

if (n instanceof Array) {
@@ -690,7 +693,7 @@ export abstract class FPTraits {
/**
* Makes a param that can be turned into an interval
*/
public toParam(n: number | IntervalBounds): FPIntervalParam {
public toParam(n: number | IntervalEndpoints): FPIntervalParam {
return {
kind: this.kind,
interval: n,
@@ -701,18 +704,18 @@ export abstract class FPTraits {
* Converts p into an FPInterval if it is an FPIntervalPAram
*/
public fromParam(
p: number | IntervalBounds | FPIntervalParam
): number | IntervalBounds | FPInterval {
p: number | IntervalEndpoints | FPIntervalParam
): number | IntervalEndpoints | FPInterval {
const param = p as FPIntervalParam;
if (param.interval && param.kind) {
assert(param.kind === this.kind);
return this.toInterval(param.interval);
}
return p as number | IntervalBounds;
return p as number | IntervalEndpoints;
}

/**
* @returns an interval with the tightest bounds that includes all provided
* @returns an interval with the tightest endpoints that includes all provided
* intervals
*/
public spanIntervals(...intervals: readonly FPInterval[]): FPInterval {
@@ -731,15 +734,15 @@ export abstract class FPTraits {
}

/** Narrow an array of values to FPVector if possible */
public isVector(v: ReadonlyArray<number | IntervalBounds | FPInterval>): v is FPVector {
public isVector(v: ReadonlyArray<number | IntervalEndpoints | FPInterval>): v is FPVector {
if (v.every(e => e instanceof FPInterval && e.kind === this.kind)) {
return v.length === 2 || v.length === 3 || v.length === 4;
}
return false;
}

/** @returns an FPVector representation of an array of values if possible */
public toVector(v: ReadonlyArray<number | IntervalBounds | FPInterval>): FPVector {
public toVector(v: ReadonlyArray<number | IntervalEndpoints | FPInterval>): FPVector {
if (this.isVector(v) && v.every(e => e.kind === this.kind)) {
return v;
}
@@ -778,7 +781,7 @@ export abstract class FPTraits {
}

/** Narrow an array of an array of values to FPMatrix if possible */
public isMatrix(m: Array2D<number | IntervalBounds | FPInterval> | FPVector[]): m is FPMatrix {
public isMatrix(m: Array2D<number | IntervalEndpoints | FPInterval> | FPVector[]): m is FPMatrix {
if (!m.every(c => c.every(e => e instanceof FPInterval && e.kind === this.kind))) {
return false;
}
@@ -803,7 +806,7 @@ export abstract class FPTraits {
}

/** @returns an FPMatrix representation of an array of an array of values if possible */
public toMatrix(m: Array2D<number | IntervalBounds | FPInterval> | FPVector[]): FPMatrix {
public toMatrix(m: Array2D<number | IntervalEndpoints | FPInterval> | FPVector[]): FPMatrix {
if (
this.isMatrix(m) &&
every2DArray(m, (e: FPInterval) => {
@@ -2282,7 +2285,7 @@ export abstract class FPTraits {
}

const result = this.spanIntervals(
...x.bounds().map(b => this.roundAndFlushScalarToInterval(b, op))
...x.endpoints().map(b => this.roundAndFlushScalarToInterval(b, op))
);
return result.isFinite() ? result : this.constants().unboundedInterval;
}
@@ -2312,8 +2315,8 @@ export abstract class FPTraits {
}

const outputs = new Set<FPInterval>();
x.bounds().forEach(inner_x => {
y.bounds().forEach(inner_y => {
x.endpoints().forEach(inner_x => {
y.endpoints().forEach(inner_y => {
outputs.add(this.roundAndFlushScalarPairToInterval(inner_x, inner_y, op));
});
});
@@ -2342,9 +2345,9 @@ export abstract class FPTraits {
}

const outputs = new Set<FPInterval>();
x.bounds().forEach(inner_x => {
y.bounds().forEach(inner_y => {
z.bounds().forEach(inner_z => {
x.endpoints().forEach(inner_x => {
y.endpoints().forEach(inner_y => {
z.endpoints().forEach(inner_z => {
outputs.add(this.roundAndFlushScalarTripleToInterval(inner_x, inner_y, inner_z, op));
});
});
@@ -2367,7 +2370,7 @@ export abstract class FPTraits {
return this.constants().unboundedInterval;
}

const x_values = cartesianProduct<number>(...x.map(e => e.bounds()));
const x_values = cartesianProduct<number>(...x.map(e => e.endpoints()));

const outputs = new Set<FPInterval>();
x_values.forEach(inner_x => {
@@ -2396,8 +2399,8 @@ export abstract class FPTraits {
return this.constants().unboundedInterval;
}

const x_values = cartesianProduct<number>(...x.map(e => e.bounds()));
const y_values = cartesianProduct<number>(...y.map(e => e.bounds()));
const x_values = cartesianProduct<number>(...x.map(e => e.endpoints()));
const y_values = cartesianProduct<number>(...y.map(e => e.endpoints()));

const outputs = new Set<FPInterval>();
x_values.forEach(inner_x => {
@@ -2423,7 +2426,7 @@ export abstract class FPTraits {
return this.constants().unboundedVector[x.length];
}

const x_values = cartesianProduct<number>(...x.map(e => e.bounds()));
const x_values = cartesianProduct<number>(...x.map(e => e.endpoints()));

const outputs = new Set<FPVector>();
x_values.forEach(inner_x => {
@@ -2467,8 +2470,8 @@ export abstract class FPTraits {
return this.constants().unboundedVector[x.length];
}

const x_values = cartesianProduct<number>(...x.map(e => e.bounds()));
const y_values = cartesianProduct<number>(...y.map(e => e.bounds()));
const x_values = cartesianProduct<number>(...x.map(e => e.endpoints()));
const y_values = cartesianProduct<number>(...y.map(e => e.endpoints()));

const outputs = new Set<FPVector>();
x_values.forEach(inner_x => {
@@ -2530,7 +2533,9 @@ export abstract class FPTraits {
}

const m_flat: readonly FPInterval[] = flatten2DArray(m);
const m_values: ROArrayArray<number> = cartesianProduct<number>(...m_flat.map(e => e.bounds()));
const m_values: ROArrayArray<number> = cartesianProduct<number>(
...m_flat.map(e => e.endpoints())
);

const outputs = new Set<FPMatrix>();
m_values.forEach(inner_m => {
@@ -3571,9 +3576,9 @@ export abstract class FPTraits {
if (e2 > bias + 1) {
return this.constants().unboundedInterval;
}
// The spec says the result of ldexp(e1, e2) = e1 * 2 ^ e2, and the accuracy is correctly
// rounded to the true value, so the inheritance framework does not need to be invoked to
// determine bounds.
// The spec says the result of ldexp(e1, e2) = e1 * 2 ^ e2, and the
// accuracy is correctly rounded to the true value, so the inheritance
// framework does not need to be invoked to determine endpoints.
// Instead, the value at a higher precision is calculated and passed to
// correctlyRoundedInterval.
const result = e1 * 2 ** e2;
@@ -4721,7 +4726,7 @@ class F32Traits extends FPTraits {
private unpack2x16floatIntervalImpl(n: number): FPVector {
assert(
n >= kValue.u32.min && n <= kValue.u32.max,
'unpack2x16floatInterval only accepts values on the bounds of u32'
'unpack2x16floatInterval only accepts valid u32 values'
);
this.unpackDataU32[0] = n;
if (this.unpackDataF16.some(f => !isFiniteF16(f))) {
@@ -4745,7 +4750,7 @@ class F32Traits extends FPTraits {
private unpack2x16snormIntervalImpl(n: number): FPVector {
assert(
n >= kValue.u32.min && n <= kValue.u32.max,
'unpack2x16snormInterval only accepts values on the bounds of u32'
'unpack2x16snormInterval only accepts valid u32 values'
);
const op = (n: number): FPInterval => {
return this.ulpInterval(Math.max(n / 32767, -1), 3);
@@ -4761,7 +4766,7 @@ class F32Traits extends FPTraits {
private unpack2x16unormIntervalImpl(n: number): FPVector {
assert(
n >= kValue.u32.min && n <= kValue.u32.max,
'unpack2x16unormInterval only accepts values on the bounds of u32'
'unpack2x16unormInterval only accepts valid u32 values'
);
const op = (n: number): FPInterval => {
return this.ulpInterval(n / 65535, 3);
@@ -4777,7 +4782,7 @@ class F32Traits extends FPTraits {
private unpack4x8snormIntervalImpl(n: number): FPVector {
assert(
n >= kValue.u32.min && n <= kValue.u32.max,
'unpack4x8snormInterval only accepts values on the bounds of u32'
'unpack4x8snormInterval only accepts valid u32 values'
);
const op = (n: number): FPInterval => {
return this.ulpInterval(Math.max(n / 127, -1), 3);
@@ -4797,7 +4802,7 @@ class F32Traits extends FPTraits {
private unpack4x8unormIntervalImpl(n: number): FPVector {
assert(
n >= kValue.u32.min && n <= kValue.u32.max,
'unpack4x8unormInterval only accepts values on the bounds of u32'
'unpack4x8unormInterval only accepts valid u32 values'
);
const op = (n: number): FPInterval => {
return this.ulpInterval(n / 255, 3);