Add ULP based assertion for testing WebNN API operations. (#35789)
diff --git a/webnn/resources/utils.js b/webnn/resources/utils.js
new file mode 100644
index 0000000..5754de2
--- /dev/null
+++ b/webnn/resources/utils.js
@@ -0,0 +1,56 @@
+'use strict';
+
+/**
+ * Get bitwise of the given value.
+ * @param {number} value
+ * @param {string} dataType A data type string, like "float32", "int8",
+ * more data type strings, please see:
+ * https://webmachinelearning.github.io/webnn/#enumdef-mloperandtype
+ * @return {number} A 64-bit signed integer.
+ */
+ function getBitwise(value, dataType) {
+ const buffer = new ArrayBuffer(8);
+ const int64Array = new BigInt64Array(buffer);
+ int64Array[0] = value < 0 ? ~BigInt(0) : BigInt(0);
+ let typedArray;
+
+ if (dataType === "float32") {
+ typedArray = new Float32Array(buffer);
+ } else {
+ throw new AssertionError(`Data type ${dataType} is not supported`);
+ }
+
+ typedArray[0] = value;
+
+ return int64Array[0];
+}
+
+/**
+ * Assert that each array property in ``actual`` is a number being close enough to the corresponding
+ * property in ``expected`` by the acceptable ULP distance ``nulp`` with given ``dataType`` data type.
+ *
+ * @param {string} op
+ * @param {Array} actual - Array of test values.
+ * @param {Array} expected - Array of values expected to be close to the values in ``actual``.
+ * @param {number} [nulp=0] - A BigInt value indicates acceptable ULP distance, default 0.
+ * @param {string} [dataType="float32"] - A data type string, default "float32",
+ * more data type strings, please see:
+ * https://webmachinelearning.github.io/webnn/#enumdef-mloperandtype
+ */
+function assert_array_approx_equals_ulp(actual, expected, nulp, dataType)
+{
+ /*
+ * Test if two primitive arrays are equal within acceptable ULP distance
+ */
+ assert_true(actual.length === expected.length,
+ `assert_array_approx_equals_ulp actual length ${actual.length} should be equal to expected length ${expected.length}`);
+ let actualBitwise, expectedBitwise, distance;
+ for (let i = 0; i < actual.length; i++) {
+ actualBitwise = getBitwise(actual[i], dataType);
+ expectedBitwise = getBitwise(expected[i], dataType);
+ distance = actualBitwise - expectedBitwise;
+ distance = distance >= 0 ? distance : -distance;
+ assert_true(distance <= nulp,
+ `The distance of ${actual[i]} should be close enough to the distance of ${expected[i]} by the acceptable ULP distance ${nulp}, while current they have ${distance} ULP distance`);
+ }
+}
\ No newline at end of file