# Inconsistent mantissa size auto-scaling between packedFloat encoding and calculations will lead to unacceptable rounding errors

Float128's packedFloat encoder auto-scales mantissa to 72 digits while arithmetic ops force 38-digit M-mantissa, causing 9-ULP rounding errors in add/sub chains.

- Payout: Contest reward
- Severity: medium
- Program: Forte
- Credited: montecristo
- Disclosed: 2025-04-29
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-04-forte-float128-solidity-library#m-01
- Library page: https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AM-01
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:precision-loss

**Target:** Float128 fixed-point math library (packedFloat encoding and arithmetic)
**Root cause:** toPackedFloat applies extra auto-scaling rules (#1, #2) that keep 72-digit L-mantissa even when exponent < -52, but add/sub/mul/div only apply rule #3, so results are downscaled to 38-digit M-mantissa, discarding precision the encoder preserved.
**Steps:**
1. Encode a = toPackedFloat(1e71, -53) and b = toPackedFloat(1e72-1, -56); both become 72-digit L-mantissa despite exp < -52.
2. Compute left = a.add(b).sub(b) and right = a.sub(b).add(b).
3. Decode both: left mantissa 99999999999999999999999999999999999990, right mantissa 99999999999999999999999999999999999999, same exponent -20.
4. assertEq(rMan - lMan, 9) confirms 9-ULP divergence, exceeding README's 1-ULP add/sub tolerance.
**How found:** Compared the auto-scaling rule documented for toPackedFloat encoding against the rule implemented in arithmetic ops (mul's Loperation/maxExp check), noticing encoding has extra rules #1/#2 absent from calculations; then constructed operands with exp < -52 and 72-digit mantissas to expose the mismatch.
**Insight:** When a fixed-point/decimal library documents a precision policy, diff the encoder's scaling rule against each arithmetic op's scaling rule line-by-line; operands that encode as high-precision L-mantissa but compute as low-precision M-mantissa are where ULP tolerances silently break.
