Skip to content

Commit ab729c1

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) (cherry picked from commit d9fae25)
1 parent d4d535d commit ab729c1

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

tree/treeplayer/src/TTreeIndex.cxx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +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-
auto GetAndRangeCheck = [this](bool isMajor, Long64_t entry) {
192+
auto GetAndRangeCheck = [this](bool isMajor, Long64_t entry) -> Long64_t {
193193
LongDouble_t ret = (isMajor ? fMajorFormula : fMinorFormula)->EvalInstance<LongDouble_t>();
194194
// Check whether the value (vs significant bits) of ldRet can represent
195195
// the full precision of the returned value. If we return 10^60, the
@@ -206,11 +206,16 @@ TTreeIndex::TTreeIndex(const TTree *T, const char *majorname, const char *minorn
206206
"In tree entry %lld, %s value %s=%Lf possibly out of range for internal `long double`", entry,
207207
isMajor ? "major" : "minor", isMajor ? fMajorName.Data() : fMinorName.Data(), ret);
208208
}
209-
return ret;
209+
return static_cast<Long64_t>(ret); // static_cast necessary for use in ternary expression below
210210
};
211211
auto GetLong64 = [this](bool isMajor) {
212212
return (isMajor ? fMajorFormula : fMinorFormula)->EvalInstance<Long64_t>();
213213
};
214+
// Note: in ternary expression ensure both branches have same return data type Long64_t.
215+
// otherwise, with LongDouble_t, the expression is implicitly cast to their
216+
// common type `long double` regardless of the branch taken. On platforms where
217+
// `sizeof(long double) == sizeof(double)` (macOS arm64, Windows) this silently
218+
// rounds the exact Long64_t value, defeating the purpose of the long64 flag.
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)