From f4bc7d3eb59789446daacfbfc618d90cc58798a5 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Mon, 11 Mar 2024 11:56:48 -0400 Subject: [PATCH] wgsl: Enable Absolute Error intervals for AbstractFloat (#3460) --- src/resources/cache/hashes.json | 186 +++++++++++++-------------- src/unittests/floating_point.spec.ts | 43 ++++--- src/webgpu/util/floating_point.ts | 2 +- 3 files changed, 121 insertions(+), 110 deletions(-) diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 69cb91f857c4..d178aba9e161 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,109 +1,109 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "cc90f705", + "webgpu/shader/execution/binary/af_addition.bin": "360aab58", "webgpu/shader/execution/binary/af_logical.bin": "4269127d", - "webgpu/shader/execution/binary/af_division.bin": "303c23c9", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "bf3f432a", - "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "f262ebd9", - "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "ac0e04e3", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "ac5cd859", - "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "44a39136", - "webgpu/shader/execution/binary/af_multiplication.bin": "4fa27383", - "webgpu/shader/execution/binary/af_remainder.bin": "4fa868c6", - "webgpu/shader/execution/binary/af_subtraction.bin": "8d5c9b21", + "webgpu/shader/execution/binary/af_division.bin": "2a1ae6a9", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "135913e7", + "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "83a7b6ab", + "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "5959bc9f", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "9c125148", + "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "efbe60ca", + "webgpu/shader/execution/binary/af_multiplication.bin": "923ed423", + "webgpu/shader/execution/binary/af_remainder.bin": "c17bb87f", + "webgpu/shader/execution/binary/af_subtraction.bin": "6457d271", "webgpu/shader/execution/binary/ai_arithmetic.bin": "f89aeb4", - "webgpu/shader/execution/binary/f16_addition.bin": "f2313284", + "webgpu/shader/execution/binary/f16_addition.bin": "85c17d72", "webgpu/shader/execution/binary/f16_logical.bin": "36a51091", - "webgpu/shader/execution/binary/f16_division.bin": "6d276852", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "7a8dd641", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "352fbb8f", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "7f315242", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "6e623bf7", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "bc0e0051", - "webgpu/shader/execution/binary/f16_multiplication.bin": "5ddc6615", - "webgpu/shader/execution/binary/f16_remainder.bin": "a7d11cc7", - "webgpu/shader/execution/binary/f16_subtraction.bin": "9a16a043", - "webgpu/shader/execution/binary/f32_addition.bin": "c5b2f15e", + "webgpu/shader/execution/binary/f16_division.bin": "7c38f4b7", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "9e6258d7", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "916ca7e6", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "a4f59720", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "5e94030b", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "45b64fd9", + "webgpu/shader/execution/binary/f16_multiplication.bin": "ee7ba392", + "webgpu/shader/execution/binary/f16_remainder.bin": "ea8f78e", + "webgpu/shader/execution/binary/f16_subtraction.bin": "f5e0d152", + "webgpu/shader/execution/binary/f32_addition.bin": "d82339c6", "webgpu/shader/execution/binary/f32_logical.bin": "e1d07173", - "webgpu/shader/execution/binary/f32_division.bin": "583afe1", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "d568c885", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "ddcd0f48", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "99892730", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "3ea99dec", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "d5235751", - "webgpu/shader/execution/binary/f32_multiplication.bin": "a465f647", - "webgpu/shader/execution/binary/f32_remainder.bin": "8402dd76", - "webgpu/shader/execution/binary/f32_subtraction.bin": "63832192", + "webgpu/shader/execution/binary/f32_division.bin": "46721765", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "6fdf77f1", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "73520069", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "5ea144ba", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "5f5213d2", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "2ff78c70", + "webgpu/shader/execution/binary/f32_multiplication.bin": "3eb2748f", + "webgpu/shader/execution/binary/f32_remainder.bin": "a6728c3e", + "webgpu/shader/execution/binary/f32_subtraction.bin": "6d3120c0", "webgpu/shader/execution/binary/i32_arithmetic.bin": "936d712", "webgpu/shader/execution/binary/i32_comparison.bin": "5db8f3b0", "webgpu/shader/execution/binary/u32_arithmetic.bin": "415ac05e", "webgpu/shader/execution/binary/u32_comparison.bin": "f90d60f3", - "webgpu/shader/execution/abs.bin": "5f333", - "webgpu/shader/execution/acos.bin": "2abc764c", - "webgpu/shader/execution/acosh.bin": "accd2622", - "webgpu/shader/execution/asin.bin": "514f90a0", - "webgpu/shader/execution/asinh.bin": "55b36d3a", - "webgpu/shader/execution/atan.bin": "1e5c011e", - "webgpu/shader/execution/atan2.bin": "51bc4048", - "webgpu/shader/execution/atanh.bin": "3c86dc17", - "webgpu/shader/execution/bitcast.bin": "e10e2bf5", - "webgpu/shader/execution/ceil.bin": "9e9f3783", - "webgpu/shader/execution/clamp.bin": "f160e302", - "webgpu/shader/execution/cos.bin": "f0047dd0", - "webgpu/shader/execution/cosh.bin": "58d620e5", - "webgpu/shader/execution/cross.bin": "f5c1fd91", - "webgpu/shader/execution/degrees.bin": "fbbc1fa3", - "webgpu/shader/execution/determinant.bin": "35335634", - "webgpu/shader/execution/distance.bin": "c0783351", - "webgpu/shader/execution/dot.bin": "fe3b0bf4", - "webgpu/shader/execution/exp.bin": "10e9c894", - "webgpu/shader/execution/exp2.bin": "6fef9b0b", - "webgpu/shader/execution/faceForward.bin": "596738cf", - "webgpu/shader/execution/floor.bin": "d2efe779", - "webgpu/shader/execution/fma.bin": "25db025e", - "webgpu/shader/execution/fract.bin": "8d9072e", - "webgpu/shader/execution/frexp.bin": "49afbf7f", - "webgpu/shader/execution/inverseSqrt.bin": "5bffd293", - "webgpu/shader/execution/ldexp.bin": "d0947f57", - "webgpu/shader/execution/length.bin": "3d4adcaa", - "webgpu/shader/execution/log.bin": "703cca75", - "webgpu/shader/execution/log2.bin": "7fa8bb66", - "webgpu/shader/execution/max.bin": "a9f6689f", - "webgpu/shader/execution/min.bin": "51966c50", - "webgpu/shader/execution/mix.bin": "b9f407dc", - "webgpu/shader/execution/modf.bin": "1e9c1919", - "webgpu/shader/execution/normalize.bin": "a3c6ac4", + "webgpu/shader/execution/abs.bin": "3bcfb49e", + "webgpu/shader/execution/acos.bin": "86824420", + "webgpu/shader/execution/acosh.bin": "95f9a9a4", + "webgpu/shader/execution/asin.bin": "1d017518", + "webgpu/shader/execution/asinh.bin": "56df3876", + "webgpu/shader/execution/atan.bin": "6aaa6b50", + "webgpu/shader/execution/atan2.bin": "82bcc1a2", + "webgpu/shader/execution/atanh.bin": "36a1f68a", + "webgpu/shader/execution/bitcast.bin": "6b7ea46b", + "webgpu/shader/execution/ceil.bin": "7308c54f", + "webgpu/shader/execution/clamp.bin": "9bfd2fce", + "webgpu/shader/execution/cos.bin": "2fa872d3", + "webgpu/shader/execution/cosh.bin": "2e6538aa", + "webgpu/shader/execution/cross.bin": "71a7e274", + "webgpu/shader/execution/degrees.bin": "31d8728f", + "webgpu/shader/execution/determinant.bin": "399a64cb", + "webgpu/shader/execution/distance.bin": "4282ab43", + "webgpu/shader/execution/dot.bin": "b4940f90", + "webgpu/shader/execution/exp.bin": "3801f256", + "webgpu/shader/execution/exp2.bin": "fb531b99", + "webgpu/shader/execution/faceForward.bin": "ac35ad68", + "webgpu/shader/execution/floor.bin": "177dc3a6", + "webgpu/shader/execution/fma.bin": "27a3e818", + "webgpu/shader/execution/fract.bin": "8ed3cd4b", + "webgpu/shader/execution/frexp.bin": "b6d69258", + "webgpu/shader/execution/inverseSqrt.bin": "b08786b3", + "webgpu/shader/execution/ldexp.bin": "6b8bcdb3", + "webgpu/shader/execution/length.bin": "3dc4b222", + "webgpu/shader/execution/log.bin": "9219d5e4", + "webgpu/shader/execution/log2.bin": "d5ca64af", + "webgpu/shader/execution/max.bin": "9051c302", + "webgpu/shader/execution/min.bin": "e950d75f", + "webgpu/shader/execution/mix.bin": "3a720d24", + "webgpu/shader/execution/modf.bin": "ef00e883", + "webgpu/shader/execution/normalize.bin": "52231704", "webgpu/shader/execution/pack2x16float.bin": "54f11627", - "webgpu/shader/execution/pow.bin": "87e8391c", - "webgpu/shader/execution/quantizeToF16.bin": "c5be64e5", - "webgpu/shader/execution/radians.bin": "5bd5a987", - "webgpu/shader/execution/reflect.bin": "e6ba9df9", - "webgpu/shader/execution/refract.bin": "7f1a1889", - "webgpu/shader/execution/round.bin": "f3376643", - "webgpu/shader/execution/saturate.bin": "2a8d20df", - "webgpu/shader/execution/sign.bin": "e7232801", - "webgpu/shader/execution/sin.bin": "8acb35", - "webgpu/shader/execution/sinh.bin": "f356d922", - "webgpu/shader/execution/smoothstep.bin": "24299f69", - "webgpu/shader/execution/sqrt.bin": "724c8512", - "webgpu/shader/execution/step.bin": "4fe42940", - "webgpu/shader/execution/tan.bin": "3366acbb", - "webgpu/shader/execution/tanh.bin": "b4f80ddb", - "webgpu/shader/execution/transpose.bin": "9a65abfa", - "webgpu/shader/execution/trunc.bin": "9292ec12", - "webgpu/shader/execution/unpack2x16float.bin": "81649bef", - "webgpu/shader/execution/unpack2x16snorm.bin": "fbbaa36f", - "webgpu/shader/execution/unpack2x16unorm.bin": "37f1917", - "webgpu/shader/execution/unpack4x8snorm.bin": "46b063cd", - "webgpu/shader/execution/unpack4x8unorm.bin": "ffb80fc5", - "webgpu/shader/execution/unary/af_arithmetic.bin": "8f9a3824", - "webgpu/shader/execution/unary/af_assignment.bin": "d8fab2f2", + "webgpu/shader/execution/pow.bin": "9fdb1669", + "webgpu/shader/execution/quantizeToF16.bin": "e980118b", + "webgpu/shader/execution/radians.bin": "a676aec1", + "webgpu/shader/execution/reflect.bin": "a951c771", + "webgpu/shader/execution/refract.bin": "d8953376", + "webgpu/shader/execution/round.bin": "eee2fc9", + "webgpu/shader/execution/saturate.bin": "161df54c", + "webgpu/shader/execution/sign.bin": "9d9a22ff", + "webgpu/shader/execution/sin.bin": "29f7032a", + "webgpu/shader/execution/sinh.bin": "9d282f12", + "webgpu/shader/execution/smoothstep.bin": "f4230ffb", + "webgpu/shader/execution/sqrt.bin": "1dba9696", + "webgpu/shader/execution/step.bin": "2048f771", + "webgpu/shader/execution/tan.bin": "adc5217b", + "webgpu/shader/execution/tanh.bin": "20f7d479", + "webgpu/shader/execution/transpose.bin": "727afd91", + "webgpu/shader/execution/trunc.bin": "bc14dd25", + "webgpu/shader/execution/unpack2x16float.bin": "b8428e59", + "webgpu/shader/execution/unpack2x16snorm.bin": "e38f4982", + "webgpu/shader/execution/unpack2x16unorm.bin": "c7cdd947", + "webgpu/shader/execution/unpack4x8snorm.bin": "71e176b1", + "webgpu/shader/execution/unpack4x8unorm.bin": "5e61d6ea", + "webgpu/shader/execution/unary/af_arithmetic.bin": "29bc881a", + "webgpu/shader/execution/unary/af_assignment.bin": "33c25997", "webgpu/shader/execution/unary/ai_arithmetic.bin": "497ec1e1", "webgpu/shader/execution/unary/ai_assignment.bin": "fc978bdd", "webgpu/shader/execution/unary/bool_conversion.bin": "bcab7d9a", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "13caa810", - "webgpu/shader/execution/unary/f16_conversion.bin": "3699afe4", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "9236999", - "webgpu/shader/execution/unary/f32_conversion.bin": "416b0d0", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "925ed6d", + "webgpu/shader/execution/unary/f16_conversion.bin": "751ff969", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "b26d9187", + "webgpu/shader/execution/unary/f32_conversion.bin": "482ee20f", "webgpu/shader/execution/unary/i32_arithmetic.bin": "8f3c4616", "webgpu/shader/execution/unary/i32_conversion.bin": "972063c", "webgpu/shader/execution/unary/u32_conversion.bin": "168fcf74" diff --git a/src/unittests/floating_point.spec.ts b/src/unittests/floating_point.spec.ts index 7f4388c2eaa9..64f3bec47d08 100644 --- a/src/unittests/floating_point.spec.ts +++ b/src/unittests/floating_point.spec.ts @@ -1836,24 +1836,27 @@ interface AbsoluteErrorCase { const kSmallAbsoluteErrorValue = { f32: 2 ** -11, // Builtin cos and sin has a absolute error 2**-11 for f32 f16: 2 ** -7, // Builtin cos and sin has a absolute error 2**-7 for f16 + abstract: 2 ** -11, // Builtin cos and sin has a absolute error 2**-11 for AbstractFloat } as const; // A large absolute error value is a representable value x that much smaller than maximum // positive, but positive.max - x is still exactly representable. const kLargeAbsoluteErrorValue = { f32: 2 ** 110, // f32.positive.max - 2**110 = 3.4028104e+38 = 0x7f7fffbf in f32 f16: 2 ** 10, // f16.positive.max - 2**10 = 64480 = 0x7bdf in f16 + abstract: 2 ** 977, // f64.positive.man - 2**977 = 1.79769e+308 = 0x7fefffffffffffbf in f64 } as const; // A subnormal absolute error value is a subnormal representable value x of kind, which ensures // that positive.subnormal.min +/- x is still exactly representable. const kSubnormalAbsoluteErrorValue = { f32: 2 ** -140, // f32 0x00000200 f16: 2 ** -20, // f16 0x0010 + abstract: 2 ** -1065, // f64 0x0000_0000_0000_0200 } as const; g.test('absoluteErrorInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .expandWithParams(p => { const trait = FP[p.trait]; @@ -1861,6 +1864,27 @@ g.test('absoluteErrorInterval') const smallErr = kSmallAbsoluteErrorValue[p.trait]; const largeErr = kLargeAbsoluteErrorValue[p.trait]; const subnormalErr = kSubnormalAbsoluteErrorValue[p.trait]; + + // Additional testing for non-f64 values, since JS number is f64 internally + // prettier-ignore + const additionalSubnormal64bit = p.trait !== 'abstract' ? + [ + // 64-bit subnormals, expected to be treated as 0.0 or smallest subnormal of kind. + { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: 0, expected: [0, constants.positive.subnormal.min] }, + { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: subnormalErr, expected: [-subnormalErr, constants.positive.subnormal.min + subnormalErr] }, + // Note that f32 minimum subnormal is so smaller than 1.0, adding them together may result in the f64 results 1.0. + { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: 1, expected: [-1, constants.positive.subnormal.min + 1] }, + { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: 0, expected: [0, constants.positive.subnormal.min] }, + { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: subnormalErr, expected: [-subnormalErr, constants.positive.subnormal.min + subnormalErr] }, + { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: 1, expected: [-1, constants.positive.subnormal.min + 1] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: 0, expected: [constants.negative.subnormal.max, 0] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: subnormalErr, expected: [constants.negative.subnormal.max - subnormalErr, subnormalErr] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 0, expected: [constants.negative.subnormal.max, 0] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: subnormalErr, expected: [constants.negative.subnormal.max - subnormalErr, subnormalErr] }, + { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, + ] as const : [] as const; + // prettier-ignore return [ // Edge Cases @@ -1903,21 +1927,6 @@ g.test('absoluteErrorInterval') { value: constants.negative.subnormal.max, error: smallErr, expected: [constants.negative.subnormal.max - smallErr, smallErr] }, { value: constants.negative.subnormal.max, error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, - // 64-bit subnormals, expected to be treated as 0.0 or smallest subnormal of kind. - { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: 0, expected: [0, constants.positive.subnormal.min] }, - { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: subnormalErr, expected: [-subnormalErr, constants.positive.subnormal.min + subnormalErr] }, - // Note that f32 minimum subnormal is so smaller than 1.0, adding them together may result in the f64 results 1.0. - { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: 1, expected: [-1, constants.positive.subnormal.min + 1] }, - { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: 0, expected: [0, constants.positive.subnormal.min] }, - { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: subnormalErr, expected: [-subnormalErr, constants.positive.subnormal.min + subnormalErr] }, - { value: reinterpretU64AsF64(0x0000_0000_0000_0002n), error: 1, expected: [-1, constants.positive.subnormal.min + 1] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: 0, expected: [constants.negative.subnormal.max, 0] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: subnormalErr, expected: [constants.negative.subnormal.max - subnormalErr, subnormalErr] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_ffffn), error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 0, expected: [constants.negative.subnormal.max, 0] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: subnormalErr, expected: [constants.negative.subnormal.max - subnormalErr, subnormalErr] }, - { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, - // Zero { value: 0, error: 0, expected: 0 }, { value: 0, error: smallErr, expected: [-smallErr, smallErr] }, @@ -1930,6 +1939,8 @@ g.test('absoluteErrorInterval') { value: -2, error: 0, expected: -2 }, { value: -2, error: smallErr, expected: [-2 - smallErr, -2 + smallErr] }, { value: -2, error: 1, expected: [-3, -1] }, + + ...additionalSubnormal64bit, ]; }) ) diff --git a/src/webgpu/util/floating_point.ts b/src/webgpu/util/floating_point.ts index 2c850695cef1..9b6fbeac39bd 100644 --- a/src/webgpu/util/floating_point.ts +++ b/src/webgpu/util/floating_point.ts @@ -5091,7 +5091,7 @@ class FPAbstractTraits extends FPTraits { public readonly sparseMatrixRange = sparseMatrixF64Range; // Framework - Fundamental Error Intervals - Overrides - public readonly absoluteErrorInterval = this.unboundedAbsoluteErrorInterval.bind(this); + public readonly absoluteErrorInterval = this.absoluteErrorIntervalImpl.bind(this); public readonly correctlyRoundedInterval = this.correctlyRoundedIntervalImpl.bind(this); public readonly correctlyRoundedMatrix = this.correctlyRoundedMatrixImpl.bind(this); public readonly ulpInterval = (n: number, numULP: number): FPInterval => {