Skip to content

Commit eba61f9

Browse files
committed
[tree] Fix long64 tree index losing precision on 64-bit long double platforms
The conditional `long64major ? GetLong64() : GetAndRangeCheck()` mixes Long64_t and LongDouble_t, so the exact value was promoted through long double regardless of branch. This rounded large values where long double is 64-bit (macOS arm64, Windows), making roottest-root-tree-index-indexl64 fail there while passing on Linux. Fix this with an explicit `static_cast<Long64_t>(ret)`. 🤖 Done with the help of [Claude Code](https://claude.com/claude-code) (Claude Opus 4.8)
1 parent 0a8f816 commit eba61f9

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

tree/treeplayer/src/TTreeIndex.cxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ TTreeIndex::TTreeIndex(const TTree *T, const char *majorname, const char *minorn
189189
Error("TTreeIndex", "In tree entry %lld, Ndata in formula is zero for both '%s' and '%s'", i,
190190
fMajorName.Data(), fMinorName.Data());
191191
}
192+
192193
auto GetAndRangeCheck = [this](bool isMajor, Long64_t entry) {
193194
LongDouble_t ret = (isMajor ? fMajorFormula : fMinorFormula)->EvalInstance<LongDouble_t>();
194195
// Check whether the value (vs significant bits) of ldRet can represent
@@ -206,11 +207,15 @@ TTreeIndex::TTreeIndex(const TTree *T, const char *majorname, const char *minorn
206207
"In tree entry %lld, %s value %s=%Lf possibly out of range for internal `long double`", entry,
207208
isMajor ? "major" : "minor", isMajor ? fMajorName.Data() : fMinorName.Data(), ret);
208209
}
209-
return ret;
210+
return static_cast<Long64_t>(ret); // static_cast necessary for use in ternary expression below
210211
};
211212
auto GetLong64 = [this](bool isMajor) {
212213
return (isMajor ? fMajorFormula : fMinorFormula)->EvalInstance<Long64_t>();
213214
};
215+
// Note: in ternary expression ensure both branches have same return data type Long64_t.
216+
// otherwise, with LongDouble_t, the expression is implicitly cast to their
217+
// common type `long double` regardless of the branch taken. On platforms where
218+
// `sizeof(long double) == sizeof(double)` (macOS arm64, Windows) this silently
214219
tmp_major[i] = long64major ? GetLong64(true) : GetAndRangeCheck(true, i);
215220
tmp_minor[i] = long64minor ? GetLong64(false) : GetAndRangeCheck(false, i);
216221
}

0 commit comments

Comments
 (0)