This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-js.git
The following commit(s) were added to refs/heads/main by this push:
new af1efd9 fix: Fix precision loss in IntervalMonthDayNano nanosecond
(#321)
af1efd9 is described below
commit af1efd9255b6e1d909954f965abe6412b01681a9
Author: George <[email protected]>
AuthorDate: Mon Nov 3 19:45:53 2025 -0500
fix: Fix precision loss in IntervalMonthDayNano nanosecond (#321)
## Rationale for this change
Integration tests were failing when JavaScript produced
IntervalMonthDayNano data that was consumed by C++, Rust, or nanoarrow
implementations. The nanosecond values differed by small amounts (e.g.,
216 nanoseconds) due to precision loss during BigInt to Number
conversion.
**Example failure:**
- Expected: `6684525287992311000ns`
- JS Output: `6684525287992310784ns`
- Difference: 216ns
## What changes are included in this PR?
Fixed the `toIntervalMonthDayNanoInt32Array` function in
`src/util/interval.ts` to properly handle unsigned 32-bit integer
conversion without precision loss. The issue was that `Number(BigInt)`
conversion for large values (>2^53-1) loses precision. Applied unsigned
right shift (`>>> 0`) to ensure correct unsigned 32-bit representation.
**Changed:**
```typescript
// Before (loses precision):
data[ai++] = Number(BigInt(nanoseconds) & BigInt(0xFFFFFFFF));
data[ai++] = Number(BigInt(nanoseconds) >> BigInt(32));
// After (preserves precision):
const ns = BigInt(nanoseconds);
data[ai++] = Number(ns & BigInt(0xFFFFFFFF)) >>> 0;
data[ai++] = Number(ns >> BigInt(32)) >>> 0;
```
Fixes apache/arrow#46203
Closes #15.
---
src/util/interval.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/util/interval.ts b/src/util/interval.ts
index a601807..597ccf9 100644
--- a/src/util/interval.ts
+++ b/src/util/interval.ts
@@ -46,8 +46,10 @@ export function toIntervalMonthDayNanoInt32Array(objects:
Partial<IntervalMonthD
data[ai++] = interval['days'] ?? 0;
const nanoseconds = interval['nanoseconds'];
if (nanoseconds) {
- data[ai++] = Number(BigInt(nanoseconds) & BigInt(0xFFFFFFFF));
- data[ai++] = Number(BigInt(nanoseconds) >> BigInt(32));
+ const ns = BigInt(nanoseconds);
+ // Convert to unsigned 32-bit integers to avoid precision loss
+ data[ai++] = Number(ns & BigInt(0xFFFFFFFF)) >>> 0;
+ data[ai++] = Number(ns >> BigInt(32)) >>> 0;
} else {
ai += 2;
}