Skip to content

Implement double32 type #41

Open

Description

@nsmith-

Example files:

uproot-Event.root
uproot-double32-float16.root
uproot-issue-308.root

Activity

  1. linked a pull request that will close this issueDouble32 format support in progress #43on May 18, 2026
  2. nsmith- commented on Sep 18, 2026

    @nsmith-
    OwnerAuthor

    🤖 AI generated content

    From the root-io-spec reference now vendored at reference/root-io-spec (pin 9c3f776): ElementTypes.md §5 / §5.2, StreamerInfo.md §7 (§7.1, "The range fields moved out of the record"), and TLeaf.md §7.

    Title grammar (TStreamerElement.cxx:118-185), applied only when kHasRange = BIT(6) of the element's own fBits is set:

    • the first [...] may be an array dimension — if it contains no comma, retry after it. Real cases: [fNvertex][0,0,6], [fNsp][0,3].
    • pi, 2pi, 2*pi, twopi, pi/2, pi/4 are literals, with a leading - negating.
    • nbits absent or outside [2,32] → 32.
    • bigint = nbits<32 ? 1<<nbits : 0xffffffff; if xmin<xmax: factor = bigint/(xmax-xmin); if xmin>=xmax and nbits<15: xmin = nbits+0.1.

    Widths — never 8:

    condition bytes decode
    factor != 0 4 aint:u32 → aint/factor + xmin
    factor == 0, (int)xmin != 0 3 exp:u8,man:u16, nbits = (int)xmin
    factor == 0, xmin == 0, kDouble32 4 plain binary32
    factor == 0, xmin == 0, kFloat16 3 exp/man with nbits = 12

    Mantissa path: i = exp<<23 | (man & ((1<<(nbits+1))-1)) << (23-nbits), negate if man & (1<<(nbits+1)). Traps: [0,0,15] and above silently degrade to a plain 4-byte float and don't even set kHasRange — wider than [0,0,14]; and the range path costs 4 bytes whatever nbits says. Array form is +20, counted pointer +40.

    Against bootstrap/double32.py today:

    • :22-24 sizes the read from nbits — and "BHIQ"[(nbytes-1)//2] mis-indexes too (nbits 32 → 2 bytes read).
    • :74 divides by 2**nbits - 1; ROOT's divisor is 1<<nbits. Only nbits=32 agrees; [-1,1,2] is off by 4/3.
    • :71-72 "pi"→3.1415… turns 2pi into 23.14 and makes pi/2 raise.
    • no array-dim retry → [fNvertex][0,0,6] raises ValueError; mantissa path absent; kHasRange never consulted.

    Status: uproot-Event.root / uproot-issue-308.root xfail on the array form (container.py:125-127); uproot-double32-float16.root xfails on float16 (structutil.py:17-19) — those are TLeafF16::fMinimum/fMaximum at 3 bytes each, vs TLeafD32's 4 (TLeaf.md §7). uproot-demo-double32.root passes but is silently mis-generated; it is the ideal vector (fF32 plain, fI32…fI2 range, fR14…fR2 mantissa). Byte-level assertions: gen/cases/serialization/double32/case.toml.

  3. nsmith- commented on Sep 18, 2026

    @nsmith-
    OwnerAuthor

    🤖 AI generated content

    Addendum from the bootstrap review (#66), which looked at the same code independently. Points not already in the comment above:

    1. Float16_t never reaches Double32Serde. TStreamerBasicType.member_definition special-cases only kDouble32 (src/rootfilespec/bootstrap/TStreamerInfo.py:351-358); kFloat16 maps to the sentinel format "float16" at :274, which raises in src/rootfilespec/structutil.py:17-19.
    2. There is a third raise site: src/rootfilespec/container.py:63-65 (BasicArray.build_reader, the counted-pointer +40 form), besides container.py:125-127 (the fixed-array +20 form).
    3. The spec fixture fails today: reference/root-io-spec/data/serialization/double32.root → NotImplementedError: Unimplemented format float16. Its case.toml has byte-level expected values for every form (see also Use the root-io-spec data/ fixtures as a parametrized test corpus #76).
    4. The nbits clamp is missing: the rule "nbits outside [2, 32] becomes 32" is not applied in src/rootfilespec/bootstrap/double32.py:48-77.
    5. Reproduced widths: [0,1] reads 2 bytes instead of 4; [0,0,14] reads 1 instead of 3; [-1,1,2] reads 1 instead of 4. [0,0,15] must be a plain f32 (the fixture's fBits15 member asserts the value 1.5).
    6. Why the array-dimension failure takes down whole files: the title is parsed without first testing kHasRange (BIT(6) of the element's fBits), so an ordinary comment such as [3] a fixed array raises during class generation, and that kills every class in the file, not just the member. Related: TObjFlag.__repr__ raises on valid fBits, and several enum members mislabel class-specific bits as TObject bits #109 notes that TObjFlag labels that very bit (0x40) kCannotPick.

    Design note: Double32_t/Float16_t decoding depends on streamer-element state (fTitle, fBits, and for old files fXmin/fXmax/fFactor, see #95), not on the member's Python type — one of the motivations listed in #67.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions