Doris-Breakwater commented on issue #69215:
URL: https://github.com/apache/doris/issues/69215#issuecomment-6235711253

   Breakwater-GitHub-Analysis-Slot: slot_b3c00c5020a2
   
   The reported numerical discrepancy is independently reproducible. Suggested 
triage area: BE expression CAST / DECIMAL correctness, with the decimal-backed 
VARIANT path also affected by the shared conversion.
   
   ### Verified evidence
   
   I inspected current master at `f937d950d45313f20864d287df453e1b90f5c615`. A 
standalone C++ reproduction of the integer conversion, division, and direct 
`fast_float` parsing paths produced **5,273,258 mismatches / 20,000,000 
values**, matching the generator in this issue. This was a numeric-only 
reproduction, not an execution of the SQL against a Doris cluster. Exact 
rational comparisons independently confirm the nearest results for both 
witnesses:
   
   | Source decimal | Existing arithmetic / intermediate-double result | Direct 
target-type parsing result |
   | --- | --- | --- |
   | `29201.024999999998` → DOUBLE | `0x1.c84419999999ap+14` | 
`0x1.c844199999999p+14` |
   | `-9000000000.000000009` → FLOAT | `-8999999488` | `-9000000512` |
   
   The DOUBLE results differ by one ULP. The exact unscaled integer 
`29201024999999998` first becomes `29201025000000000` in binary64, so the 
division operates on an already changed numerator. The [DECIMAL conversion 
code](https://github.com/apache/doris/blob/f937d950d45313f20864d287df453e1b90f5c615/be/src/exprs/function/cast/cast_to_basic_number_common.h#L330-L354)
 confirms this mechanism; its DECIMALV2 overload uses the same arithmetic 
pattern. A separate test is still needed to establish the DECIMALV2 runtime 
scope.
   
   For FLOAT, the exact input lies `0.000000009` below the midpoint 
`-9000000000` between the two binary32 candidates. Parsing to binary64 loses 
that distinction and produces the midpoint; narrowing then chooses the even 
candidate `-8999999488`. Thus the original decimal is **not itself a tie**. 
[StringParser currently parses into a local `double` and returns it as the 
requested 
type](https://github.com/apache/doris/blob/f937d950d45313f20864d287df453e1b90f5c615/be/src/util/string_parser.hpp#L776-L782).
 Consequently, the current STRING→FLOAT route is not a reliable 
correctly-rounded oracle or workaround for this case.
   
   The VARIANT V2 mechanism also checks out: 
[`append_decimal`](https://github.com/apache/doris/blob/f937d950d45313f20864d287df453e1b90f5c615/be/src/exprs/function/cast/variant_v2/cast_variant_to_scalar.cpp#L156-L166)
 groups values by scale into Decimal128 columns, and [group 
execution](https://github.com/apache/doris/blob/f937d950d45313f20864d287df453e1b90f5c615/be/src/exprs/function/cast/variant_v2/cast_variant_to_scalar.cpp#L357-L387)
 invokes the ordinary scalar cast. This supports the reported decimal-backed 
path; it does not establish identical behavior for every VARIANT representation.
   
   ### Suggested PR checks
   
   The proposed direct-to-target digit conversion addresses both demonstrated 
mechanisms. Keeping the division path for DOUBLE when the numerator is exact 
and scale ≤22 is justified under round-to-nearest: those powers of ten are 
exactly representable in binary64, leaving only the final division rounding. 
The proposed strict `< 2^53` numerator bound is conservative; `2^53` itself is 
also exactly representable. Above scale 22 the denominator can also round, 
independently of numerator size.
   
   Please cover:
   
   - Both witnesses and their positive/negative counterparts, numerator 
boundaries around `2^53`, and scales 22/23. Include a denominator-rounding case 
with a small numerator.
   - Direct target-type expectations rather than the existing two-rounding 
formula in 
[`cast_to_float_double`](https://github.com/apache/doris/blob/f937d950d45313f20864d287df453e1b90f5c615/be/test/exprs/function/cast/cast_to_float_double.cpp#L974-L1015).
 Pin witness bits or exact expected values independently of the production 
conversion helper.
   - Relevant DECIMAL32/64/128/256 paths and an explicit decision on the 
DECIMALV2 overload; runtime columns, constant folding, nullable inputs, and 
strict/non-strict modes. Preserve the intended overflow-to-infinity behavior 
for large DECIMAL256→FLOAT values.
   - A decimal-backed VARIANT regression. If the change is limited to DECIMAL 
casts, document that STRING→FLOAT still has its separate intermediate-double 
issue.
   
   ### Remaining information and next step
   
   Please attach the exact FE/BE build commit(s) and link the forthcoming PR. 
For the VARIANT coverage, a small synthetic DDL/INSERT/SELECT reproducer 
showing how the element becomes decimal-backed would be sufficient; production 
data is unnecessary.
   
   The arithmetic evidence is sufficient to review the conversion fix without 
additional logs or a query profile. End-to-end Doris behavior, the reported 
fixed-run result, and the 40–60 ns/value cost have not been independently 
verified here. Next step: review the PR with the boundary and 
independent-oracle tests above, then run the supplied SQL on the exact affected 
build and patched build before deciding release/backport scope. For the 
demonstrated DOUBLE discrepancy, parsing the decimal's text directly to DOUBLE 
avoids the numerator/divisor rounding and provides a temporary workaround; it 
should not be generalized to FLOAT.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to