From 9eb5b60d546aaedf012c46ca48d430dae609d580 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 3 Aug 2026 11:00:56 +0200 Subject: [PATCH 1/2] add testing of 32bytes floats for rntuple --- demo/node/rntuple_test32.js | 80 ++++++++++++++++++++++++++++++++++ demo/node/rntuple_test32.json | 42 ++++++++++++++++++ demo/node/rntuple_test32.root | Bin 0 -> 3398 bytes 3 files changed, 122 insertions(+) create mode 100644 demo/node/rntuple_test32.js create mode 100644 demo/node/rntuple_test32.json create mode 100644 demo/node/rntuple_test32.root diff --git a/demo/node/rntuple_test32.js b/demo/node/rntuple_test32.js new file mode 100644 index 000000000..8fecacdb9 --- /dev/null +++ b/demo/node/rntuple_test32.js @@ -0,0 +1,80 @@ +import { openFile, TSelector } from 'jsroot'; +import { rntupleProcess } from 'jsroot/rntuple'; +import { readFileSync } from 'fs'; + + +// convert float to hex representation based on IEEE-754 and C99 standard +function floatToHex(num) +{ + if (num === 0) + return (Object.is(num, -0) ? '-' : '') + '0x0p+0'; + + const buf = new ArrayBuffer(8), // 8 Byte == 64 Bit + view = new DataView(buf); + view.setFloat64(0, num, false); + + const bits = view.getBigUint64(0, false), // bitwise operations only work with integer + sign = Number(bits >> 63n), // sign on first bit + rawExp = Number((bits >> 52n) & 0x7ffn), // exponent on next 11 bits + fraction = bits & 0xfffffffffffffn; // fraction on next 52 bits + + let exp, leading, mantBits; + if (rawExp === 0) { + // check for really small numbers + if (fraction === 0n) + return (sign ? '-' : '') + '0x0p+0'; + exp = -1022; + leading = '0'; + mantBits = fraction; + } else { + exp = rawExp - 1023; + leading = '1'; + mantBits = fraction; + } + + const hex = mantBits.toString(16).padStart(13, '0').replace(/0+$/, ''), + frac = hex ? '.' + hex : '', + expStr = (exp >= 0 ? '+' : '-') + Math.abs(exp); + + return (sign ? '-' : '') + '0x' + leading + frac + 'p' + expStr; +} + +async function read_file(input_root = 'rntuple_test32.root', input_ref = 'rntuple_test32.json') +{ + const file = await openFile(input_root), rntuple = await file.readObject('ntpl'), + original = JSON.parse(readFileSync(input_ref)), + selector = new TSelector(), + fields = [ + 'FloatReal32Quant1', + 'FloatReal32Quant8', + 'FloatReal32Quant32', + 'DoubleReal32Quant1', + 'DoubleReal32Quant20', + 'DoubleReal32Quant32', + ]; + + for (const f of fields) + selector.addBranch(f); + + selector.Process = function(entryIndex) { + for (const field of fields) { + try { + const value = floatToHex(this.tgtobj[field]), expected = original[entryIndex][field]; + + if (value !== expected) { + console.error(`FAILURE: ${field} at entry ${entryIndex} expected ${expected},`+ + `got ${value}`); + } else + console.log(`OK: ${field} at entry ${entryIndex} = ${value}`); + } catch (err) { + console.error(`ERROR: Failed to read ${field} at entry ${entryIndex}: ${err.message}`); + } + } + }; + + await rntupleProcess(rntuple, selector); +} + +const [input_root, input_ref] = process.argv.slice(2); + +read_file(input_root, input_ref); diff --git a/demo/node/rntuple_test32.json b/demo/node/rntuple_test32.json new file mode 100644 index 000000000..bd8ba384c --- /dev/null +++ b/demo/node/rntuple_test32.json @@ -0,0 +1,42 @@ +[ + { + "FloatReal32Quant1": "-0x1p+0", + "FloatReal32Quant8": "-0x1.fdfdfdfdfdfep-2", + "FloatReal32Quant32": "0x1.0000000a1516p-2", + "DoubleReal32Quant1": "0x1p+0", + "DoubleReal32Quant20": "0x1p+0", + "DoubleReal32Quant32": "0x1.000000118p+1" + }, + { + "FloatReal32Quant1": "0x1p+0", + "FloatReal32Quant8": "0x1.0101010101p-8", + "FloatReal32Quant32": "0x1.921fbp-31", + "DoubleReal32Quant1": "0x1p+0", + "DoubleReal32Quant20": "0x1.00001p-20", + "DoubleReal32Quant32": "0x0p+0" + }, + { + "FloatReal32Quant1": "0x1p+0", + "FloatReal32Quant8": "0x1.0101010101p-8", + "FloatReal32Quant32": "0x1.921fbp-31", + "DoubleReal32Quant1": "0x1p+0", + "DoubleReal32Quant20": "0x1.00001p-20", + "DoubleReal32Quant32": "-0x1.2bfffffe0cp+5" + }, + { + "FloatReal32Quant1": "-0x1p+0", + "FloatReal32Quant8": "-0x1p+0", + "FloatReal32Quant32": "-0x1.921fb6p+1", + "DoubleReal32Quant1": "-0x1p+0", + "DoubleReal32Quant20": "-0x1p+0", + "DoubleReal32Quant32": "-0x1.9p+6" + }, + { + "FloatReal32Quant1": "0x1p+0", + "FloatReal32Quant8": "0x1p+0", + "FloatReal32Quant32": "0x1.921fb6p+1", + "DoubleReal32Quant1": "0x1p+0", + "DoubleReal32Quant20": "0x1p+0", + "DoubleReal32Quant32": "0x1.9p+4" + } +] diff --git a/demo/node/rntuple_test32.root b/demo/node/rntuple_test32.root new file mode 100644 index 0000000000000000000000000000000000000000..c6db2b932aa27d978390fe8185e8a686735d66d8 GIT binary patch literal 3398 zcmcgvU1%It6h1qdo|_h;0;t8ee<8@FQA88 zCM(EjOE{ItYHYVv%&~klQ_xlA1k)`=i<(T)TH~)46y1uN=8rw<1q8FTSw#!^yd}jxS$a6i$dr`i*>*X1V^8j<10&VpE{zEtG3z0tNBd{n@o(`krW>@H}= z{xbb|?A`{*Lz0>XTI0(NJZ!H+nPwj4ssKC1B0I?dSU6)(E$pvg)^pU#mMDB zwc#vwsg^5t0zg??*-i^kW>&^TfP$}JhRTomJHI|QK99p6@blPF zy~l&jNpSc01AnyqIXwO`EXbu2l&4PpC{Is)@=g4sr>4+GNqj(bS2lc_+xGM1s1iC`L1{3nG^BS;C2qJ6wU^@DGnfELIO{F;3tpnZEVy0Bb59lvJ^*l_xQlIAg;{^ zj(Gch;OJ%<_JJc_y#{V!%Yk&u0{dk>*+@kn}kBzv73yY8GYsy5P9+}=Le zn=0fq7UGw*4A6y#hlt!G6lk|Kq}l4aZnxcc6EQ=58NavRO*Wm1@1%2clKarkeK_Fw zfUk`$s=tTJesot64!zFgKxm#jaL{!C-)$~xIMtKQTMbDIpVSk~JfvrgCVu4>BU)A; zXDU{CONP)@yjLhKt^{!K0xep~tBmo7K8Jc4;30(D3RqU>8XljIqgNmy_#JMdFMYhz zG?gN$PvA{h#k3Kjl-EKPTbGj09!=p-1DbjnBrH=9!m>gPNSqmBWi+{vzhbRAW3Pyey#$g> zKO1RXcDNe?05)cljEx^;ipqGtHsKgP3U`-AcU3e)ACm!;lD#OyAYm_AYw3HtiWbYS zg=9pK3~`cvPO{w_M}4M;>1$!|nW+T+%DwNIS__H4Os$2%N2ZP_uODW`WcCdPDF1O! ck;(wSuIsC>YyQ`VW_@1Qbl)W=o_Qbs1u0{$c>n+a literal 0 HcmV?d00001 From 3635f9dc945c9593cba495e38b229172384309b1 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 3 Aug 2026 11:05:04 +0200 Subject: [PATCH 2/2] Add rntuple_test32.js to CI --- .github/workflows/jsroot-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/jsroot-ci.yml b/.github/workflows/jsroot-ci.yml index 57081f38d..4b6a52cf4 100644 --- a/.github/workflows/jsroot-ci.yml +++ b/.github/workflows/jsroot-ci.yml @@ -67,6 +67,7 @@ jobs: node demo/node/file_proxy.js buffer ./hsimple.root node demo/node/rntuple_buffer_test.js node demo/node/rntuple_test.js demo/node/rntuple_test.root + node demo/node/rntuple_test32.js demo/node/rntuple_test32.root demo/node/rntuple_test32.json tests_ubuntu: runs-on: ubuntu-latest @@ -184,6 +185,8 @@ jobs: node demo/node/file_proxy.js buffer ./hsimple.root node demo/node/rntuple_buffer_test.js node demo/node/rntuple_test.js demo/node/rntuple_test.root + node demo/node/rntuple_test32.js demo/node/rntuple_test32.root demo/node/rntuple_test32.json + build-windows: runs-on: windows-latest @@ -235,3 +238,5 @@ jobs: node demo/node/file_proxy.js buffer ./hsimple.root node demo/node/rntuple_buffer_test.js node demo/node/rntuple_test.js demo/node/rntuple_test.root + node demo/node/rntuple_test32.js demo/node/rntuple_test32.root demo/node/rntuple_test32.json +