// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
// Regression test: arithmetic with uint128 types.
// Bug: newyork pipeline produces wrong results for uint128 arithmetic with
// values that trigger overflow checking in Solidity 0.8+.
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": { "Solidity": { "contract": "Uint128Arithmetic", "solc_optimizer": false } }
}
},
{
"Call": {
"dest": { "Instantiated": 0 },
"data": "ba517410000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000100000000000000000000000000000000"
}
},
{
"Call": {
"dest": { "Instantiated": 0 },
"data": "ba51741000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f"
}
}
]
}
*/
contract Uint128Arithmetic {
uint128 constant EPS = 1E10;
uint128 constant PRECISION = 100;
uint128 constant MAX_U128_SQRT = 18446744073709551615;
function entry(uint128 a, uint128 mb, uint128 c) public pure returns (bool, uint128, uint128) {
(bool p, uint128 x1, uint128 x2) = main(a, mb, c);
x1 *= PRECISION;
x1 /= EPS;
x2 *= PRECISION;
x2 /= EPS;
return (p, x1, x2);
}
function sqrt(uint128 n) private pure returns (uint128) {
uint128 l = 0;
uint128 r = MAX_U128_SQRT;
while (l < r) {
uint128 m = (l + r + 1) / 2;
if (m * m <= n) {
l = m;
} else {
r = m - 1;
}
}
if (n - l * l < (l + 1) * (l + 1) - n) {
return l;
} else {
return l + 1;
}
}
function main(uint128 a, uint128 mb, uint128 c) private pure returns (bool, uint128, uint128) {
if (mb * mb < 4 * a * c) {
return (false, 0, 0);
}
uint128 d = (mb * mb - 4 * a * c) * EPS * EPS;
uint128 sd = sqrt(d);
uint128 x1 = (mb * EPS + sd) / 2 / a;
uint128 x2 = (mb * EPS - sd) / 2 / a;
return (true, x1, x2);
}
}